From 2481a858f4313a70406acffb01314ca11fa70bb0 Mon Sep 17 00:00:00 2001 From: Chen Keinan Date: Tue, 5 Oct 2021 22:13:37 +0300 Subject: [PATCH] feat: add project structure --- .dev/README.md | 28 + .dev/Vagrantfile | 15 + .dev/setup.sh | 30 + .gitignore | 20 + .golangci.yml | 272 ++++++ .travis.yml | 20 + Makefile | 55 ++ api/README.md | 3 + cmd/mesh-kridik/README.md | 29 + cmd/mesh-kridik/mesh-kridik.go | 9 + configs/README.md | 3 + .../kube_mesh_kridik_sec_check_result_hook.go | 31 + go.mod | 21 + go.sum | 792 ++++++++++++++++++ internal/README.md | 3 + .../v1.0.0/1.1_filesystem_configuration.yml | 44 + .../v1.0.0/1.2_configure_software_updates.yml | 26 + .../lxd/v1.0.0/1.3_configure_sudo.yml | 58 ++ .../1.4_filesystem_integrity_checking.yml | 69 ++ .../1.5_additional_process_hardening.yml | 19 + .../v1.0.0/1.6_mandatory_access_control.yml | 46 + .../lxd/v1.0.0/1.7_warning_banners.yml | 89 ++ .../lxd/v1.0.0/1.8_ensure_updates.yml | 32 + .../lxd/v1.0.0/2.1_inetd_services.yml | 30 + .../v1.0.0/2.2_special_purpose_services.yml | 210 +++++ .../lxd/v1.0.0/2.3_service_clients.yml | 59 ++ .../lxd/v1.0.0/2.4_nonessential_services.yml | 28 + .../lxd/v1.0.0/3.1_network_parameters.yml | 43 + .../v1.0.0/3.2_network_parameters_host.yml | 191 +++++ .../benchmark/lxd/v1.0.0/3.3_tcp_wrappers.yml | 79 ++ .../lxd/v1.0.0/3.4_firewall_configuration.yml | 461 ++++++++++ .../lxd/v1.0.0/4.1_configure_logging.yml | 197 +++++ .../4.2_ensure_logrotate_configured.yml | 20 + ...rotate_assigns_appropriate_permissions.yml | 21 + .../lxd/v1.0.0/5.1_configure_cron.yml | 121 +++ .../v1.0.0/5.2_ssh_server_configuration.yml | 359 ++++++++ .../lxd/v1.0.0/5.3_configure_pam.yml | 96 +++ .../5.4_user_accounts_and_environment.yml | 134 +++ ...5_root_login_restricted_system_console.yml | 16 + ....6_ensure_access_su_command_restricted.yml | 27 + .../v1.0.0/6.1_system_file_permissions.yml | 175 ++++ .../v1.0.0/6.2_user_and_group_settings.yml | 316 +++++++ internal/cli/cli.go | 257 ++++++ internal/cli/commands/command-helper.go | 218 +++++ .../commands/fixtures/CheckInClause4.2.13.yml | 39 + .../fixtures/CheckInClauseOpposite.yml | 25 + .../CheckInClauseOppositeEmptyReturn.yml | 26 + .../fixtures/CheckInClauseOppositeWithNum.yml | 25 + .../fixtures/CheckMultiParamComplex.yml | 30 + .../commands/fixtures/CheckMultiParamNOK.yml | 24 + .../fixtures/CheckMultiParamNOKWithIN.yml | 24 + .../commands/fixtures/CheckMultiParamOK.yml | 24 + .../fixtures/CheckMultiParamOKWithIN.yml | 24 + .../CheckMultiParamPass1stResultToNext.yml | 26 + .../commands/fixtures/CheckTypeComparator.yml | 24 + .../CheckTypeMultiExprEmptyProcessParam.yml | 26 + .../CheckTypeMultiExprProcessParam.yml | 24 + .../CheckTypeMultiProcessInClause.yml | 24 + internal/cli/commands/help/synopsis | 7 + internal/cli/commands/kube-mesh-kridik.go | 179 ++++ internal/common/globalconsts.go | 100 +++ internal/hooks/worker.go | 54 ++ internal/hooks/worker_test.go | 18 + internal/logger/ldxlogger.go | 26 + internal/models/fixtures/manual.yml | 25 + internal/models/fixtures/no_applicable.yml | 25 + internal/models/seccheck.go | 72 ++ internal/models/seccheck_test.go | 47 ++ internal/reports/processor.go | 28 + internal/reports/processor_test.go | 16 + internal/startup/templates.go | 219 +++++ internal/startup/templates_test.go | 100 +++ jobs/lxd-probe.yaml | 50 ++ pkg/README.md | 3 + pkg/filters/predicate.go | 82 ++ pkg/filters/predicate_test.go | 71 ++ pkg/img/coverage_badge.png | Bin 0 -> 2265 bytes pkg/models/audit_results.go | 21 + pkg/utils/fileutil.go | 174 ++++ pkg/utils/fileutil_test.go | 223 +++++ pkg/utils/stringutil.go | 12 + pkg/utils/stringutil_test.go | 15 + scripts/lint.sh | 9 + ui/banners.go | 24 + ui/console.go | 28 + 85 files changed, 6765 insertions(+) create mode 100644 .dev/README.md create mode 100644 .dev/Vagrantfile create mode 100644 .dev/setup.sh create mode 100644 .gitignore create mode 100644 .golangci.yml create mode 100644 .travis.yml create mode 100644 Makefile create mode 100644 api/README.md create mode 100644 cmd/mesh-kridik/README.md create mode 100644 cmd/mesh-kridik/mesh-kridik.go create mode 100644 configs/README.md create mode 100644 examples/plugins/kube_mesh_kridik_sec_check_result_hook.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/README.md create mode 100644 internal/benchmark/lxd/v1.0.0/1.1_filesystem_configuration.yml create mode 100644 internal/benchmark/lxd/v1.0.0/1.2_configure_software_updates.yml create mode 100644 internal/benchmark/lxd/v1.0.0/1.3_configure_sudo.yml create mode 100644 internal/benchmark/lxd/v1.0.0/1.4_filesystem_integrity_checking.yml create mode 100644 internal/benchmark/lxd/v1.0.0/1.5_additional_process_hardening.yml create mode 100644 internal/benchmark/lxd/v1.0.0/1.6_mandatory_access_control.yml create mode 100644 internal/benchmark/lxd/v1.0.0/1.7_warning_banners.yml create mode 100644 internal/benchmark/lxd/v1.0.0/1.8_ensure_updates.yml create mode 100644 internal/benchmark/lxd/v1.0.0/2.1_inetd_services.yml create mode 100644 internal/benchmark/lxd/v1.0.0/2.2_special_purpose_services.yml create mode 100644 internal/benchmark/lxd/v1.0.0/2.3_service_clients.yml create mode 100644 internal/benchmark/lxd/v1.0.0/2.4_nonessential_services.yml create mode 100644 internal/benchmark/lxd/v1.0.0/3.1_network_parameters.yml create mode 100644 internal/benchmark/lxd/v1.0.0/3.2_network_parameters_host.yml create mode 100644 internal/benchmark/lxd/v1.0.0/3.3_tcp_wrappers.yml create mode 100644 internal/benchmark/lxd/v1.0.0/3.4_firewall_configuration.yml create mode 100644 internal/benchmark/lxd/v1.0.0/4.1_configure_logging.yml create mode 100644 internal/benchmark/lxd/v1.0.0/4.2_ensure_logrotate_configured.yml create mode 100644 internal/benchmark/lxd/v1.0.0/4.3_ensure_logrotate_assigns_appropriate_permissions.yml create mode 100644 internal/benchmark/lxd/v1.0.0/5.1_configure_cron.yml create mode 100644 internal/benchmark/lxd/v1.0.0/5.2_ssh_server_configuration.yml create mode 100644 internal/benchmark/lxd/v1.0.0/5.3_configure_pam.yml create mode 100644 internal/benchmark/lxd/v1.0.0/5.4_user_accounts_and_environment.yml create mode 100644 internal/benchmark/lxd/v1.0.0/5.5_root_login_restricted_system_console.yml create mode 100644 internal/benchmark/lxd/v1.0.0/5.6_ensure_access_su_command_restricted.yml create mode 100644 internal/benchmark/lxd/v1.0.0/6.1_system_file_permissions.yml create mode 100644 internal/benchmark/lxd/v1.0.0/6.2_user_and_group_settings.yml create mode 100644 internal/cli/cli.go create mode 100644 internal/cli/commands/command-helper.go create mode 100644 internal/cli/commands/fixtures/CheckInClause4.2.13.yml create mode 100644 internal/cli/commands/fixtures/CheckInClauseOpposite.yml create mode 100644 internal/cli/commands/fixtures/CheckInClauseOppositeEmptyReturn.yml create mode 100644 internal/cli/commands/fixtures/CheckInClauseOppositeWithNum.yml create mode 100644 internal/cli/commands/fixtures/CheckMultiParamComplex.yml create mode 100644 internal/cli/commands/fixtures/CheckMultiParamNOK.yml create mode 100644 internal/cli/commands/fixtures/CheckMultiParamNOKWithIN.yml create mode 100644 internal/cli/commands/fixtures/CheckMultiParamOK.yml create mode 100644 internal/cli/commands/fixtures/CheckMultiParamOKWithIN.yml create mode 100644 internal/cli/commands/fixtures/CheckMultiParamPass1stResultToNext.yml create mode 100644 internal/cli/commands/fixtures/CheckTypeComparator.yml create mode 100644 internal/cli/commands/fixtures/CheckTypeMultiExprEmptyProcessParam.yml create mode 100644 internal/cli/commands/fixtures/CheckTypeMultiExprProcessParam.yml create mode 100644 internal/cli/commands/fixtures/CheckTypeMultiProcessInClause.yml create mode 100644 internal/cli/commands/help/synopsis create mode 100644 internal/cli/commands/kube-mesh-kridik.go create mode 100644 internal/common/globalconsts.go create mode 100644 internal/hooks/worker.go create mode 100644 internal/hooks/worker_test.go create mode 100644 internal/logger/ldxlogger.go create mode 100644 internal/models/fixtures/manual.yml create mode 100644 internal/models/fixtures/no_applicable.yml create mode 100644 internal/models/seccheck.go create mode 100644 internal/models/seccheck_test.go create mode 100644 internal/reports/processor.go create mode 100644 internal/reports/processor_test.go create mode 100644 internal/startup/templates.go create mode 100644 internal/startup/templates_test.go create mode 100644 jobs/lxd-probe.yaml create mode 100644 pkg/README.md create mode 100644 pkg/filters/predicate.go create mode 100644 pkg/filters/predicate_test.go create mode 100644 pkg/img/coverage_badge.png create mode 100644 pkg/models/audit_results.go create mode 100644 pkg/utils/fileutil.go create mode 100644 pkg/utils/fileutil_test.go create mode 100644 pkg/utils/stringutil.go create mode 100644 pkg/utils/stringutil_test.go create mode 100755 scripts/lint.sh create mode 100644 ui/banners.go create mode 100644 ui/console.go diff --git a/.dev/README.md b/.dev/README.md new file mode 100644 index 0000000..c8262e3 --- /dev/null +++ b/.dev/README.md @@ -0,0 +1,28 @@ +# LXD-vagrantfile + +vagrant file to be used for lxd associated programs developments, file include : +- buntu/bionic64 +- lxd cluster +- dlv for remote debug + +### Quick Start + +``` + git clone git@github.com:chen-keinan/lxd-vagrantfile.git + cd lxd-vagrantfile + vagrant up + +``` + +### Compile binary with debug params +``` +GOOS=linux GOARCH=amd64 go build -v -gcflags='-N -l' demo.go +``` +### Run debug on remote machine +``` +dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec ./demo +``` + +### Tear down +``` + vagrant destroy diff --git a/.dev/Vagrantfile b/.dev/Vagrantfile new file mode 100644 index 0000000..b0ece8e --- /dev/null +++ b/.dev/Vagrantfile @@ -0,0 +1,15 @@ +Vagrant.configure("2") do |config| + config.vm.box = "ubuntu/bionic64" + config.vm.network "private_network", ip: "172.30.1.5" + config.vm.network "forwarded_port", guest: 2345, host: 2345 +config.vm.provider "virtualbox" do |v| + v.cpus = 2 + v.memory = 4048 + end + if Vagrant.has_plugin? "vagrant-vbguest" + config.vbguest.auto_update = false + end + config.vm.provision "shell" do |s| + s.path = "setup.sh" + end +end diff --git a/.dev/setup.sh b/.dev/setup.sh new file mode 100644 index 0000000..4b3a0bf --- /dev/null +++ b/.dev/setup.sh @@ -0,0 +1,30 @@ +echo "start vagrant provioning..." +sudo apt-get update + +echo "configure lxd user and group" +sudo adduser vagrant lxd +newgrp lxd + +echo "install lxd tools" +sudo apt install zfsutils-linux + +echo "setup lxd manager" +lxd init --preseed + +echo "install curl pkg..." +sudo apt-get install -y curl zfsutils-linux + +echo "install golang pkg" +sudo add-apt-repository ppa:longsleep/golang-backports +sudo apt update -y +sudo apt install -y golang-go + +echo "Install dlv pkg" + git clone https://github.com/go-delve/delve.git $GOPATH/src/github.com/go-delve/delve + cd $GOPATH/src/github.com/go-delve/delve + make install + +### export dlv bin path +export PATH=$PATH:/home/vagrant/go/bin + +echo "Finished provisioning." diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ff1777 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +.vscode +.tmp +.testCoverage.txt +.idea +statics +.history +client/node_modules +.DS_Store +lint.xml +cp.out +vendor/ +*/mocks* +coverage.html +a_startup-packr.go +fmtcoverage.html +coverage.md +coverage.out +mock* +*.iml +kube-mesh-kridik diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..e864600 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,272 @@ +# This file contains all available configuration options +# with their default values. + +# options for analysis running +run: + # default concurrency is a available CPU number + #concurrency: 4 + + # timeout for analysis, e.g. 30s, 5m, default is 1m + deadline: 1m + + # exit code when at least one issue was found, default is 1 + issues-exit-code: 1 + + # include test files or not, default is true + tests: true + + # list of build tags, all linters use it. Default is empty list. + + #build-tags: + # - mytag + + # which dirs to skip: they won't be analyzed; + # can use regexp here: generated.*, regexp is applied on full path; + # default value is empty list, but next dirs are always skipped independently + # from this option's value: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + + skip-dirs: + - resources + + # which files to skip: they will be analyzed, but issues from them + # won't be reported. Default value is empty list, but there is + # no need to include all autogenerated files, we confidently recognize + # autogenerated files. If it's not please let us know. + + #skip-files: + # - ".*\\.my\\.go$" + # - lib/bad.go + + # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": + # If invoked with -mod=readonly, the go command is disallowed from the implicit + # automatic updating of go.mod described above. Instead, it fails when any changes + # to go.mod are needed. This setting is most useful to check that go.mod does + # not need updates, such as in a continuous integration and testing system. + # If invoked with -mod=vendor, the go command assumes that the vendor + # directory holds the correct copies of dependencies and ignores + # the dependency descriptions in go.mod. + #modules-download-mode: (release|readonly|vendor) + + +# output configuration options +output: + # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" + format: colored-line-number + + # print lines of code with issue, default is true + print-issued-lines: true + + # print linter name in the end of issue text, default is true + print-linter-name: true + + +# all available settings of specific linters +linters-settings: + errcheck: + # report about not checking of errors in type assetions: `a := b.(MyStruct)`; + # default is false: such cases aren't reported by default. + check-type-assertions: true + + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. + check-blank: false + + # [deprecated] comma-separated list of pairs of the form pkg:regex + # the regex is used to ignore names within pkg. (default "fmt:.*"). + # see https://github.com/kisielk/errcheck#the-deprecated-method for details + ignore: fmt:.*,io/ioutil:^Read.* + + # path to a file containing a list of functions to exclude from checking + # see https://github.com/kisielk/errcheck#excluding-functions for details + #exclude: /path/to/file.txt + + govet: + # report about shadowed variables + check-shadowing: true + golint: + # minimal confidence for issues, default is 0.8 + min-confidence: 0.8 + gofmt: + # simplify code: gofmt with `-s` option, true by default + simplify: true + goimports: + # put imports beginning with prefix after 3rd-party packages; + # it's a comma-separated list of prefixes + local-prefixes: github.com/org/project + gocyclo: + # minimal code complexity to report, 30 by default (but we recommend 10-20) + min-complexity: 10 + maligned: + # print struct with more effective memory layout or not, false by default + suggest-new: true + dupl: + # tokens count to trigger issue, 150 by default + threshold: 150 + goconst: + # minimal length of string constant, 3 by default + min-len: 3 + # minimal occurrences count to trigger, 3 by default + min-occurrences: 3 + depguard: + list-type: blacklist + include-go-root: false + packages: + - github.com/davecgh/go-spew/spew + misspell: + # Correct spellings using locale preferences for US or UK. + # Default is to use a neutral variety of English. + # Setting locale to US will correct the British spelling of 'colour' to 'color'. + locale: US + ignore-words: + - someword + lll: + # max line length, lines longer will be reported. Default is 120. + # '\t' is counted as 1 character by default, and can be changed with the tab-width option + line-length: 120 + # tab width in spaces. Default to 1. + tab-width: 1 + unused: + # treat code as a program (not a library) and report unused exported identifiers; default is false. + # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: + # if it's called for subdir of a project it can't find funcs usages. All text editor integrations + # with golangci-lint call it on a directory with the changed file. + check-exported: false + unparam: + # Inspect exported functions, default is false. Set to true if no external program/library imports your code. + # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: + # if it's called for subdir of a project it can't find external interfaces. All text editor integrations + # with golangci-lint call it on a directory with the changed file. + check-exported: false + nakedret: + # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 + max-func-lines: 30 + prealloc: + # XXX: we don't recommend using this linter before doing performance profiling. + # For most programs usage of prealloc will be a premature optimization. + + # Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. + # True by default. + simple: true + range-loops: true # Report preallocation suggestions on range loops, true by default + for-loops: false # Report preallocation suggestions on for loops, false by default + gocritic: + # Which checks should be enabled; can't be combined with 'disabled-checks'; + # See https://go-critic.github.io/overview#checks-overview + # To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run` + # By default list of stable checks is used. + enabled-checks: + #- rangeValCopy + + # Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty + disabled-checks: + - regexpMust + + # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint` run to see all tags and checks. + # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". + enabled-tags: + - performance + + settings: # settings passed to gocritic + captLocal: # must be valid enabled check name + paramsOnly: true + rangeValCopy: + sizeThreshold: 32 + +linters: + enable: + - ineffassign + - deadcode + - typecheck + - unused + - gosimple + - structcheck + - varcheck + - errcheck + - staticcheck + - govet + - golint + - gosec + - unconvert + - dupl + - goconst + - gocyclo + - gofmt + enable-all: false + disable: + - scopelint + # - prealloc + disable-all: false + #presets: + # - bugs + # - unused + fast: false + + +issues: + # List of regexps of issue texts to exclude, empty list by default. + # But independently from this option we use default exclude patterns, + # it can be disabled by `exclude-use-default: false`. To list all + # excluded by default patterns execute `golangci-lint run --help` + exclude: + - abcdef + + # Excluding configuration per-path and per-linter + exclude-rules: + # Exclude some linters from running on tests files. + - path: _test\.go + linters: + - gocyclo + - errcheck + - dupl + - gosec + - goconst + + # Ease some gocritic warnings on test files. + - path: _test\.go + text: "(unnamedResult|exitAfterDefer)" + linters: + - gocritic + + # Exclude known linters from partially hard-vendored code, + # which is impossible to exclude via "nolint" comments. + - path: internal/hmac/ + text: "weak cryptographic primitive" + linters: + - gosec + - path: internal/hmac/ + text: "Write\\` is not checked" + linters: + - errcheck + + # Ease linting on benchmarking code. + - path: cmd/stun-bench/ + linters: + - gosec + - errcheck + + # Independently from option `exclude` we use default exclude patterns, + # it can be disabled by this option. To list all + # excluded by default patterns execute `golangci-lint run --help`. + # Default value for this option is true. + exclude-use-default: false + + # Maximum issues count per one linter. Set to 0 to disable. Default is 50. + max-per-linter: 0 + + # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. + max-same-issues: 0 + + # Show only new issues: if there are unstaged changes or untracked files, + # only those changes are analyzed, else only changes in HEAD~ are analyzed. + # It's a super-useful option for integration of golangci-lint into existing + # large codebase. It's not practical to fix all existing issues at the moment + # of integration: much better don't allow issues in new code. + # Default is false. + new: false + + # Show only new issues created after git revision `REV` + #new-from-rev: REV + + # Show only new issues created in git patch with set file path. + #new-from-patch: path/to/patch/file \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b911135 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,20 @@ +language: go +go: + - 1.15 + +env: + - "PATH=/home/travis/gopath/bin:$PATH" + +services: + - docker + +before_install: + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + +script: + - go get github.com/golang/mock/mockgen@latest + - go install -v github.com/golang/mock/mockgen && export PATH=$GOPATH/bin:$PATH; + - go generate ./... + - make test_travis + - make build_travis diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b2cebf2 --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +SHELL := /bin/bash + +GOCMD=go +MOVESANDBOX=mv ~/vms/kube-mesh-kridikkube-mesh-kridik ~/vms-local/kube-mesh-kridik +GOPACKR=$(GOCMD) get -u github.com/gobuffalo/packr/packr && packr +GOMOD=$(GOCMD) mod +GOMOCKS=$(GOCMD) generate ./... +GOBUILD=$(GOCMD) build +GOTEST=$(GOCMD) test +BINARY_NAME=kube-mesh-kridik +GOCOPY=cp kube-mesh-kridik ~/vagrant_file/. + +all:test lint build + +fmt: + $(GOCMD) fmt ./... +lint: + ./scripts/lint.sh +tidy: + $(GOMOD) tidy -v +test: + $(GOCMD) get github.com/golang/mock/mockgen@latest + $(GOCMD) install -v github.com/golang/mock/mockgen && export PATH=$GOPATH/bin:$PATH; + $(GOMOCKS) + $(GOTEST) ./... -coverprofile coverage.md fmt + $(GOCMD) tool cover -html=coverage.md -o coverage.html + $(GOCMD) tool cover -func coverage.md +build: + $(GOPACKR) + export PATH=$GOPATH/bin:$PATH; + export PATH=$PATH:/home/vagrant/go/bin + export PATH=$PATH:/home/root/go/bin + GOOS=linux GOARCH=amd64 $(GOBUILD) -v ./cmd/kube-mesh-kridik; +install:build_travis + cp $(BINARY_NAME) $(GOPATH)/bin/$(BINARY_NAME) +test_travis: + $(GOCMD) get github.com/golang/mock/mockgen@latest + $(GOCMD) install -v github.com/golang/mock/mockgen && export PATH=$GOPATH/bin:$PATH; + $(GOMOCKS) + $(GOTEST) -short ./... -coverprofile coverage.md fmt + $(GOCMD) tool cover -html=coverage.md -o coverage.html +build_travis: + $(GOPACKR) + GOOS=linux GOARCH=amd64 $(GOBUILD) -v ./cmd/kube-mesh-kridik; +build_remote: + $(GOPACKR) + GOOS=linux GOARCH=amd64 $(GOBUILD) -v -gcflags='-N -l' ./cmd/kube-mesh-kridik + mv kube-mesh-kridik ~/boxes/basic_box/kube-mesh-kridik +dlv: + dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec ./kube-mesh-kridik +build_beb: + $(GOPACKR) + GOOS=linux GOARCH=amd64 $(GOBUILD) -v -gcflags='-N -l' cmd/lxd/kube-mesh-kridik.go + scripts/deb.sh +.PHONY: all build install test diff --git a/api/README.md b/api/README.md new file mode 100644 index 0000000..43060f6 --- /dev/null +++ b/api/README.md @@ -0,0 +1,3 @@ +# `/api` + +check on kubelet-certificate-authority diff --git a/cmd/mesh-kridik/README.md b/cmd/mesh-kridik/README.md new file mode 100644 index 0000000..7570766 --- /dev/null +++ b/cmd/mesh-kridik/README.md @@ -0,0 +1,29 @@ +##Remote Debug +###Install dlv +$ git clone https://github.com/go-delve/delve.git $GOPATH/src/github.com/go-delve/delve +$ cd $GOPATH/src/github.com/go-delve/delve +$ make install + +### export dlv bin path +export PATH=$PATH:/home/vagrant/go/bin +export PATH=$PATH:/root/go/bin + +### compile binary with debug params +GOOS=linux GOARCH=amd64 go build -v -gcflags='-N -l' cmd/kube-mesh-kridik/kube-mesh-kridik.go + +### run on remote machine + +dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec ./kube-mesh-kridik + +docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -v /*/cni/*:/*/cni/* -t kube-mesh-kridik + +docker build ./ -t kube-mesh-kridik -f Dockerfile + + export KUBECONFIG=/etc/kubernetes/admin.conf +mkdir -p $HOME/.kube + sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config + sudo chown $(id -u):$(id -g) $HOME/.kube/config +https://github.com/oracle/vagrant-projects + + kubectl taint nodes master-node node-role.kubernetes.io/master- + kubectl create clusterrolebinding default-admin --clusterrole cluster-admin --serviceaccount=default:default diff --git a/cmd/mesh-kridik/mesh-kridik.go b/cmd/mesh-kridik/mesh-kridik.go new file mode 100644 index 0000000..1bd0789 --- /dev/null +++ b/cmd/mesh-kridik/mesh-kridik.go @@ -0,0 +1,9 @@ +package main + +import ( + "github.com/chen-keinan/kube-mesh-kridik/internal/cli" +) + +func main() { + cli.StartCLI() +} diff --git a/configs/README.md b/configs/README.md new file mode 100644 index 0000000..fd18993 --- /dev/null +++ b/configs/README.md @@ -0,0 +1,3 @@ +# `/configs` + +project config files diff --git a/examples/plugins/kube_mesh_kridik_sec_check_result_hook.go b/examples/plugins/kube_mesh_kridik_sec_check_result_hook.go new file mode 100644 index 0000000..3f46427 --- /dev/null +++ b/examples/plugins/kube_mesh_kridik_sec_check_result_hook.go @@ -0,0 +1,31 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "github.com/chen-keinan/kube-mesh-kridik/pkg/models" + "net/http" + "strings" +) + +//MeshKridikBenchAuditResultHook this plugin method accept mesh security check results +//event include test data , description , audit, remediation and result +func MeshKridikBenchAuditResultHook(lxdAuditResults models.MeshKridikSecurityResults) error { + var sb = new(bytes.Buffer) + err := json.NewEncoder(sb).Encode(lxdAuditResults) + fmt.Print(lxdAuditResults) + if err != nil { + return err + } + req, err := http.NewRequest("POST", "http://localhost:8090/audit-results", strings.NewReader(sb.String())) + if err != nil { + return err + } + client := http.Client{} + _, err = client.Do(req) + if err != nil { + return err + } + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..83e0b6a --- /dev/null +++ b/go.mod @@ -0,0 +1,21 @@ +module github.com/chen-keinan/kube-mesh-kridik + +go 1.16 + +require ( + github.com/cheggaaa/pb v1.0.29 + github.com/chen-keinan/go-command-eval v0.0.2 + github.com/chen-keinan/go-user-plugins v0.0.4 + github.com/gobuffalo/packr v1.30.1 + github.com/golang/mock v1.6.0 + github.com/gosuri/uitable v0.0.4 + github.com/magiconair/properties v1.8.5 + github.com/mitchellh/cli v1.1.2 + github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db + github.com/mitchellh/mapstructure v1.4.2 + github.com/olekukonko/tablewriter v0.0.5 + github.com/stretchr/testify v1.7.0 + go.uber.org/fx v1.14.2 + go.uber.org/zap v1.19.1 + gopkg.in/yaml.v2 v2.4.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5f0325c --- /dev/null +++ b/go.sum @@ -0,0 +1,792 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= +github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo= +github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30= +github.com/chen-keinan/go-command-eval v0.0.2 h1:AX61aKAWv8b/TUEk4HkvfWgheIbV0lKSwt/8r3whOU0= +github.com/chen-keinan/go-command-eval v0.0.2/go.mod h1:fpE+yYOq5AAybeT2iLG0v30o0L/2NtOHbEUtufWstk0= +github.com/chen-keinan/go-user-plugins v0.0.4 h1:0csMIC6TFLLVA4g5T+RRXXPnw/Dsr8nRgypIE9ZNEXw= +github.com/chen-keinan/go-user-plugins v0.0.4/go.mod h1:3EDlzuXfBL94XRyO5U0WR7UdwfpMSTbEE+W93in7+lQ= +github.com/chen-keinan/lxd-probe v0.2.0 h1:1H3gEc20ol5NiUBDiLU2AXjxwY7rXR5/4w1joK7G5TY= +github.com/chen-keinan/lxd-probe v0.2.0/go.mod h1:UMJjgIJHGxchNNpNGOS8HuhO5EMGm5be8HOS92KDYY0= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.9.0 h1:eZR0DuEgVLfeIb1zIKt3bT4YovIMf9O9LXQeCZLXpqE= +github.com/gobuffalo/envy v1.9.0/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM= +github.com/gobuffalo/logger v1.0.4/go.mod h1:/GRUdWb+gM3shxj0P5jiV6ecVS3X0aboJvl+hBu0HeE= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM= +github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI= +github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= +github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= +github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/gobuffalo/packr/v2 v2.8.1/go.mod h1:c/PLlOuTU+p3SybaJATW3H6lX/iK7xEz5OeMf+NnJpg= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= +github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/karrick/godirwalk v1.15.8/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= +github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.2 h1:PvH+lL2B7IQ101xQL63Of8yFS2y+aDlsFcsqNc+u/Kw= +github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/dig v1.12.0 h1:l1GQeZpEbss0/M4l/ZotuBndCrkMdjnygzgcuOjAdaY= +go.uber.org/dig v1.12.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/fx v1.13.1/go.mod h1:bREWhavnedxpJeTq9pQT53BbvwhUv7TcpsOqcH4a+3w= +go.uber.org/fx v1.14.2 h1:xT/BW51pc0D/Jn0Xihb6Z/XrbuSs2GNL56fUF95VneE= +go.uber.org/fx v1.14.2/go.mod h1:rwjmT7CaZIiLgflUER9FCWCSkDGiRv/VDBxg32Inoy8= +go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200308013534-11ec41452d41/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/README.md b/internal/README.md new file mode 100644 index 0000000..b7f3c10 --- /dev/null +++ b/internal/README.md @@ -0,0 +1,3 @@ +# `/internal` + +core project files \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/1.1_filesystem_configuration.yml b/internal/benchmark/lxd/v1.0.0/1.1_filesystem_configuration.yml new file mode 100644 index 0000000..668b17f --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/1.1_filesystem_configuration.yml @@ -0,0 +1,44 @@ +--- +benchmark_type: lxd +categories: + - + name: Initial Setup + sub_category: + name: 1.1 Filesystem Configuration + audit_tests: + - + name: '1.1.1 Ensure /tmp is configured (Automated)' + description: The /tmp directory is a world-writable directory used for temporary storage by all users and some applications. + profile_applicability: Level 1 + audit: + - mount | grep -E '\s/tmp\s' + - grep -E '\s/tmp\s' /etc/fstab | grep -E -v '^\s*#' + - systemctl is-enabled tmp.mount 2>/dev/null + remediation: 'Configure /etc/fstab as appropriate. Example: + tmpfs /tmp tmpfs defaults,rw,nosuid,nodev,noexec,relatime 0 0 + OR + Run the following commands to enable systemd /tmp mounting: + Edit /etc/systemd/system/local-fs.target.wants/tmp.mount to configure the /tmp mount: + [Mount] + What=tmpfs + Where=/tmp + Type=tmpfs Options=mode=1777,strictatime,noexec,nodev,nosuid' + check_type: multi_param + impact: 'Since the /tmp directory is intended to be world-writable, there is a risk of resource exhaustion if it is not bound to a separate partition. + Running out of /tmp space is a problem regardless of what kind of filesystem lies under it, but in a default installation a disk-based /tmp will essentially have the whole disk available, as it only creates a single / partition. On the other hand, a RAM-based /tmp as with tmpfs will almost certainly be much smaller, which can lead to applications filling up the filesystem much more easily. + /tmp utilizing tmpfs can be resized using the size={size} parameter on the Options line on the tmp.mount file' + eval_expr: "'${0}' == 'tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noexec,relatime)'; || '${1}' == 'tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev 0 0'; || '${2}' == 'enabled'" + additional_info: If an entry for /tmp exists in /etc/fstab it will take precedence over entries in the tmp.mount file + references: + - AJ Lewis, "LVM HOWTO", http://tldp.org/HOWTO/LVM-HOWTO/ + - https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems/ + - + name: '1.1.2 Ensure sticky bit is set on all world-writable directories (Automated)' + description: Setting the sticky bit on world writable directories prevents users from deleting or renaming files in that directory that are not owned by them. + profile_applicability: Level 1 + audit: + - df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' 2>/dev/null -xdev -type d \( -perm -0002 -a ! -perm -1000 \) 2>/dev/null + remediation: + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: Some distributions may not support the --local option to df. \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/1.2_configure_software_updates.yml b/internal/benchmark/lxd/v1.0.0/1.2_configure_software_updates.yml new file mode 100644 index 0000000..120ca6c --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/1.2_configure_software_updates.yml @@ -0,0 +1,26 @@ +--- +benchmark_type: lxd +categories: + - + name: Initial Setup + sub_category: + name: 1.2 Configure Software Updates + audit_tests: + - + name: '1.2.1 Ensure package manager repositories are configured (Manual)' + description: Systems need to have package manager repositories configured to ensure they receive the latest patches and updates. + profile_applicability: Level 1 + audit: + - apt-cache policy + remediation: 'Configure your package manager repositories according to site policy.' + check_type: multi_param + type: manual + - + name: '1.2.2 Ensure GPG keys are configured (Manual)' + description: Most packages managers implement GPG key signing to verify package integrity during installation. + profile_applicability: Level 1 + audit: + - apt-key list + remediation: 'Update your package manager GPG keys in accordance with site policy.' + check_type: multi_param + type: manual diff --git a/internal/benchmark/lxd/v1.0.0/1.3_configure_sudo.yml b/internal/benchmark/lxd/v1.0.0/1.3_configure_sudo.yml new file mode 100644 index 0000000..9c46ba4 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/1.3_configure_sudo.yml @@ -0,0 +1,58 @@ +--- +benchmark_type: lxd +categories: + - + name: Initial Setup + sub_category: + name: 1.3 Configure Sudo + audit_tests: + - + name: '1.3.1 Ensure sudo is installed (Automated)' + description: sudo allows a permitted user to execute a command as the superuser or another user, as specified by the security policy. + The invoking user's real (not effective) user ID is used to determine the user name with which to query the security policy. + profile_applicability: Level 1 + audit: + - 'dpkg -s sudo 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + - 'dpkg -s sudo-ldap 2> /dev/null|grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Install sudo using the following command. + # apt install sudo + OR + # apt install sudo-ldap' + check_type: multi_param + eval_expr: "'${0}' == 'install ok installed'; || '${1}' == 'install ok installed';" + additional_info: Use the sudo-ldap package if you need LDAP support for sudoers. + references: + - SUDO(8) + - http://www.sudo.ws/ + - + name: '1.3.2 Ensure sudo commands use pty (Automated)' + description: sudo can be configured to run only from a psuedo-pty + profile_applicability: Level 1 + audit: + - 'grep -Ei ''^\s*Defaults\s+([^#]+,\s*)?use_pty(,\s+\S+\s*)*(\s+#.*)?$'' /etc/sudoers /etc/sudoers.d/*' + remediation: 'edit the file /etc/sudoers or a file in /etc/sudoers.d/ with visudo -f and add the following line: + Defaults use_pty' + check_type: multi_param + eval_expr: "'${0}' != '';" + additional_info: isudo edits the sudoers file in a safe fashion, analogous to vipw(8). + visudo locks the sudoers file against multiple simultaneous edits, provides basic sanity checks, and checks or parse errors. + If the sudoers file is currently being edited you will receive a message to try again later. + references: + - SUDO(8) + - + name: '1.3.3 Ensure sudo log file exists (Automated)' + description: sudo can use a custom log file + profile_applicability: Level 1 + audit: + - 'grep -Ei ''^\s*Defaults\s+logfile=\S+'' /etc/sudoers /etc/sudoers.d/*' + remediation: 'edit the file /etc/sudoers or a file in /etc/sudoers.d/ with visudo -f and add the following line: and add the following line: + Defaults logfile="" + Example + Defaults logfile="/var/log/sudo.log"' + check_type: multi_param + eval_expr: "'${0}' != '';" + additional_info: visudo edits the sudoers file in a safe fashion, analogous to vipw(8). + visudo locks the sudoers file against multiple simultaneous edits, provides basic sanity checks, and checks or parse errors. + If the sudoers file is currently being edited you will receive a message to try again later. + references: + - SUDO(8) diff --git a/internal/benchmark/lxd/v1.0.0/1.4_filesystem_integrity_checking.yml b/internal/benchmark/lxd/v1.0.0/1.4_filesystem_integrity_checking.yml new file mode 100644 index 0000000..803358b --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/1.4_filesystem_integrity_checking.yml @@ -0,0 +1,69 @@ +--- +benchmark_type: lxd +categories: + - + name: Initial Setup + sub_category: + name: 1.4 Filesystem Integrity Checking + audit_tests: + - + name: '1.4.1 Ensure AIDE is installed (Automated)' + description: AIDE takes a snapshot of filesystem state including modification times, permissions, + and file hashes which can then be used to compare against the current state of the + filesystem to detect modifications to the system. + profile_applicability: Level 1 + audit: + - 'dpkg -s aide 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Install AIDE using the appropriate package manager or manual installation: + # apt install aide aide-common + Configure AIDE as appropriate for your environment. Consult the AIDE documentation for options. + Initialize AIDE: + # aideinit' + check_type: multi_param + eval_expr: "'${0}' == 'install ok installed';" + additional_info: The prelinking feature can interfere with AIDE because it alters binaries to speed up their start up times. + Run prelink -ua to restore the binaries to their prelinked state, thus avoiding false positives from AIDE. + - + name: '1.4.2 Ensure filesystem integrity is regularly checked (Automated)' + description: Periodic checking of the filesystem integrity is needed to detect changes to the filesystem. + profile_applicability: Level 1 + audit: + - 'crontab -u root -l 2> /dev/null | grep aide' + - 'grep -r aide /etc/cron.* /etc/crontab' + - 'systemctl is-enabled aidecheck.service 2> /dev/null' + - 'systemctl is-enabled aidecheck.timer 2> /dev/null' + - 'systemctl status aidecheck.timer 2> /dev/null' + remediation: 'If cron will be used to schedule and run aide check + Run the following command: + # crontab -u root -e + Add the following line to the crontab: + 0 5 * * * /usr/bin/aide.wrapper --config /etc/aide/aide.conf --check + OR + if aidecheck.service and aidecheck.timer will be used to schedule and run aide check: Create or edit the file /etc/systemd/system/aidecheck.service and add the following lines: + [Unit] + Description=Aide Check + [Service] + Type=simple + ExecStart=/usr/bin/aide.wrapper --config /etc/aide/aide.conf --check + [Install] + WantedBy=multi-user.target + Create or edit the file /etc/systemd/system/aidecheck.timer and add the following lines: + [Unit] + Description=Aide check every day at 5AM + [Timer] + OnCalendar=*-*-* 05:00:00 + Unit=aidecheck.service + [Install] + WantedBy=multi-user.target + Run the following commands: + # chown root:root /etc/systemd/system/aidecheck.* # chmod 0644 /etc/systemd/system/aidecheck.* + # systemctl daemon-reload + # systemctl enable aidecheck.service + # systemctl --now enable aidecheck.timer' + check_type: multi_param + eval_expr: "('${0}' != ''; && '${1}' != '';) || ('${2}' != ''; && '${3}' != ''; && '${4}' != 'Unit aidecheck.timer could not be found.';) " + additional_info: The checking in this recommendation occurs every day at 5am. Alter the frequency and time of the checks in compliance with site policy. + Note that Debian advises using /usr/bin/aide.wrapper rather than calling /usr/bin/aide directly in order to protect the database and prevent conflicts. + references: + - https://github.com/konstruktoid/hardening/blob/master/config/aidecheck.service + - https://github.com/konstruktoid/hardening/blob/master/config/aidecheck.timer diff --git a/internal/benchmark/lxd/v1.0.0/1.5_additional_process_hardening.yml b/internal/benchmark/lxd/v1.0.0/1.5_additional_process_hardening.yml new file mode 100644 index 0000000..f4a7f4c --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/1.5_additional_process_hardening.yml @@ -0,0 +1,19 @@ +--- +benchmark_type: lxd +categories: + - + name: Initial Setup + sub_category: + name: 1.5 Additional Process Hardening + audit_tests: + - + name: '1.5.1 Ensure prelink is disabled (Automated)' + description: prelink is a program that modifies ELF shared libraries and ELF dynamically linked binaries in + such a way that the time needed for the dynamic linker to perform relocations at startup significantly decreases. + profile_applicability: Level 1 + audit: + - 'dpkg -s prelink 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Run the following command to restore binaries to normal: # prelink -ua + Uninstall prelink using the appropriate package manager or manual installation: # apt purge prelink' + check_type: multi_param + eval_expr: "'${0}' != 'install ok installed';" diff --git a/internal/benchmark/lxd/v1.0.0/1.6_mandatory_access_control.yml b/internal/benchmark/lxd/v1.0.0/1.6_mandatory_access_control.yml new file mode 100644 index 0000000..afc54be --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/1.6_mandatory_access_control.yml @@ -0,0 +1,46 @@ +--- +benchmark_type: lxd +categories: + - + name: Initial Setup + sub_category: + name: 1.6 Mandatory Access Control + audit_tests: + - + name: '1.6.1.1 Ensure AppArmor is installed (Automated)' + description: AppArmor provides Mandatory Access Controls. + profile_applicability: Level 1 + audit: + - 'dpkg -s apparmor 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Install Apparmor. + # apt install apparmor' + check_type: multi_param + eval_expr: "'${0}' == 'install ok installed';" + - + name: '1.6.1.2 Ensure all AppArmor Profiles are in enforce or complain mode (Automated)' + description: AppArmor profiles define what resources applications are able to access. + profile_applicability: Level 1 + audit: + - 'apparmor_status | grep profiles | grep loaded |awk -F "profiles" ''{print $1}''' + - 'apparmor_status | grep profiles | grep ''enforce mode'' |awk -F "profiles" ''{print $1}''' + - 'apparmor_status | grep processes | grep unconfined | awk -F "processes" ''{print $1}''' + remediation: 'Run the following command to set all profiles to enforce mode: + # aa-enforce /etc/apparmor.d/* + OR + Run the following command to set all profiles to complain mode: + # aa-complain /etc/apparmor.d/* + Any unconfined processes may need to have a profile created or activated for them and then be restarted.' + check_type: multi_param + eval_expr: "${0} > 0; && ${0} == ${1}; && ${2} == 0;" + - + name: '1.6.1.3 Ensure all AppArmor Profiles are enforcing (Automated)' + description: AppArmor profiles define what resources applications are able to access. + profile_applicability: Level 1 + audit: + - 'apparmor_status |grep profile |grep complain |awk -F "profiles" ''{print $1}''' + - 'apparmor_status | grep processes | grep unconfined | awk -F "processes" ''{print $1}''' + remediation: 'Run the following command to set all profiles to enforce mode: + # aa-enforce /etc/apparmor.d/* + Any unconfined processes may need to have a profile created or activated for them and then be restarted.' + check_type: multi_param + eval_expr: "${0} == 0; && ${1} == 0;" diff --git a/internal/benchmark/lxd/v1.0.0/1.7_warning_banners.yml b/internal/benchmark/lxd/v1.0.0/1.7_warning_banners.yml new file mode 100644 index 0000000..638b182 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/1.7_warning_banners.yml @@ -0,0 +1,89 @@ +--- +benchmark_type: lxd +categories: + - + name: Initial Setup + sub_category: + name: 1.7 Warning Banners + audit_tests: + - + name: '1.7.1.1 Ensure message of the day is configured properly (Automated)' + description: 'The contents of the /etc/motd file are displayed to users after login and function as a message of the day for authenticated users. + Unix-based systems have typically displayed information about the OS release and patch level upon logging in to the system. + This information can be useful to developers who are developing software for a particular OS platform. + If mingetty(8) supports the following options, they display operating system information: + \m - machine architecture \r - operating system release \s - operating system name \v - operating system version' + profile_applicability: Level 1 + audit: + - 'grep -E -i "(\\\v|\\\r|\\\m|\\\s|$(grep ''^ID='' /etc/os-release | cut -d= -f2 | sed -e ''s/"//g''))" /etc/motd 2> /dev/null' + remediation: 'Edit the /etc/motd file with the appropriate contents according to your site policy, remove any instances of \m , \r , \s , \v or references to the OS platform + OR + # grep -E -i "(\\\v|\\\r|\\\m|\\\s|$(grep ''^ID='' /etc/os-release | cut -d= -f2 | sed -e ''s/"//g''))" /etc/motd + If the motd is not used, this file can be removed. + Run the following command to remove the motd file: + # rm /etc/motd' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '1.7.1.2 Ensure local login warning banner is configured properly (Automated)' + description: 'The contents of the /etc/issue file are displayed to users prior to login for local terminals. + Unix-based systems have typically displayed information about the OS release and patch level upon logging in to the system. + This information can be useful to developers who are developing software for a particular OS platform. + If mingetty(8) supports the following options, they display operating system information: + \m - machine architecture \r - operating system release \s - operating system name \v - operating system version - or the operating system''s name''' + profile_applicability: Level 1 + audit: + - 'grep -E -i "(\\\v|\\\r|\\\m|\\\s|$(grep ''^ID='' /etc/os-release | cut -d= -f2 | sed -e ''s/"//g''))" /etc/issue 2> /dev/null' + remediation: 'Edit the /etc/issue file with the appropriate contents according to your site policy, + remove any instances of \m , \r , \s , \v or references to the OS platform + # echo "Authorized uses only. All activity may be monitored and reported." > /etc/issue' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '1.7.1.3 Ensure remote login warning banner is configured properly (Automated)' + description: 'The contents of the /etc/issue.net file are displayed to users prior to login for remote connections from configured services. + Unix-based systems have typically displayed information about the OS release and patch level upon logging in to the system. + This information can be useful to developers who are developing software for a particular OS platform. + If mingetty(8) supports the following options, they display operating system information: + \m - machine architecture \r - operating system release \s - operating system name \v - operating system version' + profile_applicability: Level 1 + audit: + - 'grep -E -i "(\\\v|\\\r|\\\m|\\\s|$(grep ''^ID='' /etc/os-release | cut -d= -f2 | sed -e ''s/"//g''))" /etc/issue.net 2> /dev/null' + remediation: 'Edit the /etc/issue.net file with the appropriate contents according to your site policy, + remove any instances of \m , \r , \s , \v or references to the OS platform + # echo "Authorized uses only. All activity may be monitored and reported." > /etc/issue.net' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '1.7.1.4 Ensure permissions on /etc/motd are configured (Automated)' + description: 'The contents of the /etc/motd file are displayed to users after login and function as a message of the day for authenticated users.' + profile_applicability: Level 1 + audit: + - 'stat /etc/motd 2> /dev/null| grep "Access: ("' + remediation: 'Run the following commands to set permissions on /etc/motd : + # chown root:root /etc/motd + # chmod u-x,go-wx /etc/motd' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '1.7.1.5 Ensure permissions on /etc/issue are configured (Automated)' + description: 'The contents of the /etc/issue file are displayed to users prior to login for local terminals.' + profile_applicability: Level 1 + audit: + - 'stat /etc/issue 2> /dev/null| grep "Access: ("' + remediation: 'Run the following commands to set permissions on /etc/motd : + # chown root:root /etc/issue + # chmod u-x,go-wx /etc/issue' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '1.7.1.6 Ensure permissions on /etc/issue.net are configured (Automated)' + description: 'The contents of the /etc/issue.net file are displayed to users prior to login for remote connections from configured services.' + profile_applicability: Level 1 + audit: + - 'stat /etc/issue.net 2> /dev/null| grep "Access: ("' + remediation: 'Run the following commands to set permissions on /etc/motd : + # chown root:root /etc/issue.net + # chmod u-x,go-wx /etc/issue.net' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)';" diff --git a/internal/benchmark/lxd/v1.0.0/1.8_ensure_updates.yml b/internal/benchmark/lxd/v1.0.0/1.8_ensure_updates.yml new file mode 100644 index 0000000..25a9829 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/1.8_ensure_updates.yml @@ -0,0 +1,32 @@ +--- +benchmark_type: lxd +categories: + - + name: Initial Setup + sub_category: + name: 1.8 Ensure Updates + audit_tests: + - + name: '1.8.1 Ensure updates, patches, and additional security software are installed (Manual)' + description: Periodically patches are released for included software either due to security flaws or to include additional functionality. + profile_applicability: Level 1 + audit: + - 'apt -s upgrade' + remediation: 'Use your package manager to update all packages on the system according to site policy. + Run the following command to update all packages following local site policy guidance on applying updates and patches: + # apt upgrade + OR + # apt dist-upgrade' + check_type: multi_param + eval_expr: "'${0}' != 'install ok installed';" + additional_info: 'Site policy may mandate a testing period before install onto production systems for available updates. + upgrade: upgrade is used to install the newest versions of all packages currently installed on the system from the sources enumerated in /etc/apt/sources.list. + Packages currently installed with new versions available are retrieved and upgraded; + under no circumstances are currently installed packages removed, or packages not already installed retrieved and installed. + New versions of currently installed packages that cannot be upgraded without changing the install status of another package will be left at their current version. + An update must be performed first so that apt knows that new versions of packages are available. + dist-upgrade: dist-upgrade in addition to performing the function of upgrade, also intelligently handles changing dependencies with new versions of packages; + apt has a "smart" conflict resolution system, and it will attempt to upgrade the most important packages at the expense of less important ones if necessary. + So, dist-upgrade command may remove some packages. The /etc/apt/sources.list file contains a list of locations from which to retrieve desired package files. See also apt_preferences(5) for a mechanism for overriding the general settings for individual packages.' + type: manual + diff --git a/internal/benchmark/lxd/v1.0.0/2.1_inetd_services.yml b/internal/benchmark/lxd/v1.0.0/2.1_inetd_services.yml new file mode 100644 index 0000000..80ededb --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/2.1_inetd_services.yml @@ -0,0 +1,30 @@ +--- +benchmark_type: lxd +categories: + - + name: Services + sub_category: + name: 2.1 inetd Services + audit_tests: + - + name: '2.1.1 Ensure xinetd is not installed (Automated)' + description: The eXtended InterNET Daemon (xinetd) is an open source super daemon that replaced the original inetd daemon. + The xinetd daemon listens for well known services and dispatches the appropriate daemon to properly respond to service requests. + profile_applicability: Level 1 + audit: + - 'dpkg -s xinetd 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Run the following commands to remove xinetd: + # apt purge xinetd' + check_type: multi_param + eval_expr: "'${0}' != 'install ok installed';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + - + name: '2.1.2 Ensure openbsd-inetd is not installed (Automated)' + description: The inetd daemon listens for well known services and dispatches the appropriate daemon to properly respond to service requests. + profile_applicability: Level 1 + audit: + - 'dpkg -s openbsd-inetd 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Run the following command to uninstall openbsd-inetd: + apt purge openbsd-inetd' + check_type: multi_param + eval_expr: "'${0}' != 'install ok installed';" \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/2.2_special_purpose_services.yml b/internal/benchmark/lxd/v1.0.0/2.2_special_purpose_services.yml new file mode 100644 index 0000000..36c6e53 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/2.2_special_purpose_services.yml @@ -0,0 +1,210 @@ +--- +benchmark_type: lxd +categories: + - + name: Services + sub_category: + name: 2.2 Special Purpose Services + audit_tests: + - + name: '2.2.1 Ensure X Window System is not installed (Automated)' + description: The X Window System provides a Graphical User Interface (GUI) where users can have multiple windows in which to run programs and various add on. + The X Windows system is typically used on workstations where users login, but not on servers where users typically do not login. + profile_applicability: Level 1 + audit: + - 'dpkg -l xserver-xorg* 2> /dev/null' + remediation: 'Remove the X Windows System packages: + apt purge xserver-xorg*' + check_type: multi_param + eval_expr: "'${0}' != '';" + - + name: '2.2.2 Ensure Avahi Server is not enabled (Automated)' + description: Avahi is a free zeroconf implementation, including a system for multicast DNS/DNS-SD service discovery. + Avahi allows programs to publish and discover services and hosts running on a local network with no specific configuration. + For example, a user can plug a computer into a network and Avahi automatically finds printers to print to, files to look at and people to talk to, as well as network services running on the machine. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled avahi-daemon 2> /dev/null' + remediation: 'Run the following command to disable avahi-daemon: + # systemctl --now disable avahi-daemon' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + - + name: '2.2.3 Ensure CUPS is not enabled (Automated)' + description: The Common Unix Print System (CUPS) provides the ability to print to both local and network printers. + A system running CUPS can also accept print jobs from remote systems and print them to local printers. + It also provides a web based remote administration capability. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled cups 2> /dev/null' + remediation: 'Run one of the following commands to disable cups : # systemctl --now disable cups' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + references: + - More detailed documentation on CUPS is available at the project homepage at http://www.cups.org + - + name: '2.2.4 Ensure DHCP Server is not enabled (Automated)' + description: The Dynamic Host Configuration Protocol (DHCP) is a service that allows machines to be dynamically assigned IP addresses. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled isc-dhcp-server cups 2> /dev/null' + - 'systemctl is-enabled isc-dhcp-server6 2> /dev/null' + remediation: 'Run one of the following commands to disable dhcpd: + # systemctl --now disable isc-dhcp-server + # systemctl --now disable isc-dhcp-server6' + check_type: multi_param + eval_expr: "('${0}' == ''; && '${1}' == '';) || ('${0}' != 'disabled'; && '${1}' == 'disabled')" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + references: + - More detailed documentation on DHCP is available at http://www.isc.org/software/dhcp. + - + name: '2.2.5 Ensure LDAP server is not enabled (Automated)' + description: The Lightweight Directory Access Protocol (LDAP) was introduced as a replacement for NIS/YP. + It is a service that provides a method for looking up information from a central database. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled slapd 2> /dev/null' + remediation: 'Run one of the following commands to disable slapd: # systemctl --now disable slapd' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + references: + - For more detailed documentation on OpenLDAP, go to the project homepage at http://www.openldap.org. + - + name: '2.2.6 Ensure RPC is not enabled (Automated)' + description: The Remote Procedure Call Binding Server (rpcbind) provides the ability for applications to do remote procedure call through the network. + It is a service that provides a method for looking up information from a central database. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled rpcbind 2> /dev/null' + remediation: 'Run the following commands to disable rpcbind:# systemctl --now disable rpcbind' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + - + name: '2.2.7 Ensure DNS Server is not enabled (Automated)' + description: The Domain Name System (DNS) is a hierarchical naming system that maps names to IP addresses for computers, + services and other resources connected to a network. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled bind9 2> /dev/null' + remediation: 'un the following commands to disable DNS server:# systemctl --now disable bind9' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + - + name: '2.2.8 Ensure FTP Server is not enabled (Automated)' + description: The File Transfer Protocol (FTP) provides networked computers with the ability to transfer files. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled vsftpd 2> /dev/null' + remediation: 'Run the following command to disable vsftpd:# systemctl --now disable vsftpd' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + Additional FTP servers also exist and should be audited. + - + name: '2.2.9 Ensure HTTP server is not enabled (Automated)' + description: HTTP or web servers provide the ability to host web site content. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled apache2 2> /dev/null' + remediation: 'Run the following command to disable apache:# systemctl --now disable apache2' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + Several httpd servers exist and can use other service names. apache, apache2, lighttpd, and nginx are example services that provide an HTTP server. + These and other services should also be audited. + - + name: '2.2.10 Ensure email services are not enabled (Automated)' + description: dovecot is an open source mail submission and transport server for Linux based systems. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled dovecot 2> /dev/null' + remediation: 'Run one of the following commands to disable dovecot :# systemctl --now disable dovecot' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + Several IMAP/POP3 servers exist and can use other service names. courier-imap and cyrus-imap are example services that provide a mail server. + These and other services should also be audited. + - + name: '2.2.11 Ensure Samba is not enabled (Automated)' + description: The Samba daemon allows system administrators to configure their Linux systems to share file systems and directories with Windows desktops. + Samba will advertise the file systems and directories via the Server Message Block (SMB) protocol. + Windows desktop users will be able to mount these directories and file systems as letter drives on their systems. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled smbd 2> /dev/null' + remediation: 'Run the following command to disable Samba:systemctl --now disable smbd' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate met + - + name: '2.2.12 Ensure HTTP Proxy Server is not enabled (Automated)' + description: Squid is a standard proxy server used in many distributions and environments. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled squid 2> /dev/null' + remediation: 'Run the following command to disable squid:# systemctl --now disable squid' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + On some distributions the squid service is known as squid3, not squid. + Several HTTP proxy servers exist. These and other services should be checked. + - + name: '2.2.13 Ensure SNMP Server is not enabled (Automated)' + description: The Simple Network Management Protocol (SNMP) server is used to listen for SNMP commands from an SNMP management system, + execute the commands or collect the information and then send results back to the requesting system. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled snmpd 2> /dev/null' + remediation: 'Run the following command to disable snmpd: # systemctl --now disable snmpd' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + - + name: '2.2.14 Ensure mail transfer agent is configured for local-only mode (Automated)' + description: Mail Transfer Agents (MTA), such as sendmail and Postfix, are used to listen for incoming mail and transfer the messages to the appropriate user or mail server. + If the system is not intended to be a mail server, it is recommended that the MTA be configured to only process local mail. + profile_applicability: Level 1 + audit: + - 'ss -lntu 2> /dev/null| grep -E '':25\s'' | grep -E -v ''\s(127.0.0.1|::1):25\s''' + remediation: 'Edit /etc/exim4/update-exim4.conf.conf and and or modify following lines to look like the lines below: + dc_eximconfig_configtype=''local'' dc_local_interfaces=''127.0.0.1 ; ::1'' dc_readhost='''' + dc_relay_domains='''' + dc_minimaldns=''false'' + dc_relay_nets='''' + dc_smarthost='''' + dc_use_split_config=''false'' + dc_hide_mailname='''' + dc_mailname_in_oh=''true'' + dc_localdelivery=''mail_spool''' + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: This recommendation is designed around the exim4 mail server, + depending on your environment you may have an alternative MTA installed such as sendmail. + If this is the case consult the documentation for your installed MTA to configure the recommended state. + - + name: '2.2.15 Ensure rsync service is not enabled (Automated)' + description: The rsync service can be used to synchronize files between systems over network links. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled rsync 2> /dev/null' + remediation: 'Run the following command to disable rsync:# systemctl --now disable rsync' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + - + name: '2.2.16 Ensure NIS Server is not enabled (Automated)' + description: The Network Information Service (NIS) (formally known as Yellow Pages) is a client-server directory service protocolfor distributing system configuration files. + The NIS server is a collection of programs that allow for the distribution of configuration files. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled nis 2> /dev/null' + remediation: 'Run the following command to disable nis: # systemctl --now disable nis' + check_type: multi_param + eval_expr: "'${0}' == ''; || '${0}' == 'disabled';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + diff --git a/internal/benchmark/lxd/v1.0.0/2.3_service_clients.yml b/internal/benchmark/lxd/v1.0.0/2.3_service_clients.yml new file mode 100644 index 0000000..09dc633 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/2.3_service_clients.yml @@ -0,0 +1,59 @@ +--- +benchmark_type: lxd +categories: + - + name: Services + sub_category: + name: 2.3 Service Clients + audit_tests: + - + name: '2.3.1 Ensure NIS Client is not installed (Automated)' + description: The Network Information Service (NIS), formerly known as Yellow Pages, is a client-server directory service protocol used to distribute system configuration files. + The NIS client was used to bind a machine to an NIS server and receive the distributed configuration files. + profile_applicability: Level 1 + audit: + - 'dpkg -s nis 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Uninstall nis: apt purge nis' + check_type: multi_param + eval_expr: "'${0}' != 'install ok installed'; || '${0}' == '';" + - + name: '2.3.2 Ensure rsh client is not installed (Automated)' + description: The rsh-client package contains the client commands for the rsh services. + profile_applicability: Level 1 + audit: + - 'dpkg -s rsh-client 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Uninstall rsh: apt purge rsh-client' + check_type: multi_param + eval_expr: "'${0}' != 'install ok installed'; || '${0}' == '';" + additional_info: Additional methods of disabling a service exist. Consult your distribution documentation for appropriate methods. + - + name: '2.3.3 Ensure talk client is not installed (Automated)' + description: The talk software makes it possible for users to send and receive messages across systems through a terminal session. + The talk client, which allows initialization of talk sessions, is installed by default. + profile_applicability: Level 1 + audit: + - 'dpkg -s talk 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Uninstall talk: apt purge talk' + check_type: multi_param + eval_expr: "'${0}' != 'install ok installed'; || '${0}' == '';" + - + name: '2.3.4 Ensure telnet client is not installed (Automated)' + description: The telnet package contains the telnet client, which allows users to start connections to other systems via the telnet protocol. + profile_applicability: Level 1 + audit: + - 'dpkg -s telnet 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Uninstall telnet:# apt purge telnet' + check_type: multi_param + eval_expr: "'${0}' != 'install ok installed'; || '${0}' == '';" + - + name: '2.3.5 Ensure LDAP client is not installed (Automated)' + description: The Lightweight Directory Access Protocol (LDAP) was introduced as a replacement for NIS/YP. + It is a service that provides a method for looking up information from a central database. + profile_applicability: Level 1 + audit: + - 'dpkg -s ldap-utils 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Uninstall ldap-utils:# apt purge ldap-utils' + check_type: multi_param + eval_expr: "'${0}' != 'install ok installed'; || '${0}' == '';" + additional_info: The openldap-clients package can go by other names on some distributions. + openldap2-client, and ldap-utils are known alternative package names. diff --git a/internal/benchmark/lxd/v1.0.0/2.4_nonessential_services.yml b/internal/benchmark/lxd/v1.0.0/2.4_nonessential_services.yml new file mode 100644 index 0000000..b0cbd4a --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/2.4_nonessential_services.yml @@ -0,0 +1,28 @@ +--- +benchmark_type: lxd +categories: + - + name: Services + sub_category: + name: 2.4 Nonessential services + audit_tests: + - + name: '2.4.1 Ensure nonessential services are removed or masked (Manual)' + description: A network port is identified by its number, the associated IP address, and the type of the communication protocol such as TCP or UDP. + A listening port is a network port on which an application or process listens on, acting as a communication endpoint. + Each listening port can be open or closed (filtered) using a firewall. + In general terms, an open port is a network port that accepts incoming packets from remote locations. + profile_applicability: Level 1 + audit: + - 'Run the following command: + # lsof -i -P -n | grep -v "(ESTABLISHED)" + Review the output to ensure that all services listed are required on the system. + If a listed service is not required, remove the package containing the service. + If the package containing the service is required, stop and mask the service' + remediation: 'Run the following command to remove the package containing the service: + # yum remove + OR If required packages have a dependency: + Run the following command to stop and mask the service: + # systemctl --now mask ' + check_type: multi_param + type: manual \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/3.1_network_parameters.yml b/internal/benchmark/lxd/v1.0.0/3.1_network_parameters.yml new file mode 100644 index 0000000..4106f2a --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/3.1_network_parameters.yml @@ -0,0 +1,43 @@ +--- +benchmark_type: lxd +categories: + - + name: Network Configuration + sub_category: + name: 3.1 Network Parameters (Host Only) + audit_tests: + - + name: '3.1.1 Ensure packet redirect sending is disabled (Automated)' + description: ICMP Redirects are used to send routing information to other hosts. + As a host itself does not act as a router (in a host only configuration), there is no need to send redirects. + profile_applicability: Level 1 + audit: + - 'sysctl net.ipv4.conf.all.send_redirects 2> /dev/null' + - 'sysctl net.ipv4.conf.default.send_redirects 2> /dev/null' + - 'grep "net\.ipv4\.conf\.all\.send_redirects" /etc/sysctl.conf |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + - 'grep "net\.ipv4\.conf\.all\.send_redirects" /etc/sysctl.d/* |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + - 'grep "net\.ipv4\.conf\.default\.send_redirects" /etc/sysctl.conf | awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + - 'grep "net\.ipv4\.conf\.default\.send_redirects" /etc/sysctl.d/* |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Set the following parameters in /etc/sysctl.conf or a /etc/sysctl.d/* file: + Run the following commands to set the active kernel parameters: + net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 + # sysctl -w net.ipv4.conf.all.send_redirects=0 + # sysctl -w net.ipv4.conf.default.send_redirec' + check_type: multi_param + eval_expr: "'${0}' == 'net.ipv4.conf.all.send_redirects = 0'; && '${1}' == 'net.ipv4.conf.default.send_redirects = 0'; && '${2}' == 'net.ipv4.conf.all.send_redirects = 0'; && '${3}' == 'net.ipv4.conf.all.send_redirects = 0'; && '${4}' == 'net.ipv4.conf.default.send_redirects= 0'; && '${5}' == 'net.ipv4.conf.default.send_redirects= 0';" + - + name: '3.1.2 Ensure IP forwarding is disabled (Automated)' + description: The net.ipv4.ip_forward and net.ipv6.conf.all.forwarding flags are used to tell the system whether it can forward packets or not. + profile_applicability: Level 1 + audit: + - 'sysctl net.ipv4.ip_forward 2> /dev/null' + - 'grep -E -s "^\s*net\.ipv4\.ip_forward\s*=\s*1" /etc/sysctl.conf /etc/sysctl.d/*.conf /usr/lib/sysctl.d/*.conf /run/sysctl.d/*.conf 2> /dev/null' + - 'sysctl net.ipv6.conf.all.forwarding 2> /dev/null' + - 'grep -E -s "^\s*net\.ipv6\.conf\.all\.forwarding\s*=\s*1" /etc/sysctl.conf /etc/sysctl.d/*.conf /usr/lib/sysctl.d/*.conf /run/sysctl.d/*.conf 2> /dev/null' + - '# grep "^\s*linux" /boot/grub/grub.cfg 2> /dev/null | grep -v "ipv6.disable=1"' + remediation: 'Run the following command to restore the default parameter and set the active kernel parameter: + IF IPv6 is enabled: + Run the following command to restore the default parameter and set the active kernel parameter: + # grep -Els "^\s*net\.ipv6\.conf\.all\.forwarding\s*=\s*1" /etc/sysctl.conf /etc/sysctl.d/*.conf /usr/lib/sysctl.d/*.conf /run/sysctl.d/*.conf | while read filename; do sed -ri "s/^\s*(net\.ipv6\.conf\.all\.forwarding\s*)(=)(\s*\S+\b).*$/# *REMOVED* \1/" $filename; done; sysctl -w net.ipv6.conf.all.forwarding=0; sysctl -w net.ipv6.route.flush=1' + check_type: multi_param + eval_expr: "('${0}' == 'net.ipv4.ip_forward = 0'; && '${1}' == ''; && '${4}' == '';) || ('${2}' == 'net.ipv6.conf.all.forwarding = 0'; && '${3}' == '';) " \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/3.2_network_parameters_host.yml b/internal/benchmark/lxd/v1.0.0/3.2_network_parameters_host.yml new file mode 100644 index 0000000..d4faad0 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/3.2_network_parameters_host.yml @@ -0,0 +1,191 @@ +--- +benchmark_type: lxd +categories: + - + name: Network Configuration + sub_category: + name: 3.2 Network Parameters (Host and Router) + audit_tests: + - + name: '3.2.1 Ensure source routed packets are not accepted (Automated)' + description: In networking, source routing allows a sender to partially or fully specify the route packets take through a network. + In contrast, non-source routed packets travel a path determined by routers in the network. + In some cases, systems may not be routable or reachable from some locations + (e.g. private addresses vs. Internet routable), and so source routed packets would need to be used. + profile_applicability: Level 1 + audit: + - 'sysctl net.ipv4.conf.all.accept_source_route 2> /dev/null' + - 'sysctl net.ipv4.conf.default.accept_source_route 2> /dev/null' + - 'grep "net\.ipv4\.conf\.all\.accept_source_route" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null' + - 'grep "net\.ipv4\.conf\.default\.accept_source_route" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null' + - 'sysctl net.ipv6.conf.all.accept_source_route 2> /dev/null' + - 'sysctl net.ipv6.conf.default.accept_source_route 2> /dev/null' + - 'grep "net\.ipv6\.conf\.all\.accept_source_route" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + - 'grep "net\.ipv6\.conf\.default\.accept_source_route" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + - 'grep "^\s*linux" /boot/grub/grub.cfg 2> /dev/null | grep -v "ipv6.disable=1" |awk -F ":" ''{print $2}''' + remediation: 'Set the following parameters in /etc/sysctl.conf or a /etc/sysctl.d/* file: + Run the following commands to set the active kernel parameters: + IF IPv6 is enabled: + Set the following parameters in /etc/sysctl.conf or a /etc/sysctl.d/* file: + net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.default.accept_source_route = 0 + # sysctl -w net.ipv4.conf.all.accept_source_route=0 + # sysctl -w net.ipv4.conf.default.accept_source_route=0 # sysctl -w net.ipv4.route.flush=1 + net.ipv6.conf.all.accept_source_route = 0 + Run the following commands to set the active kernel parameters: + # sysctl -w net.ipv6.conf.all.accept_source_route=0 + # sysctl -w net.ipv6.conf.default.accept_source_route=0 # sysctl -w net.ipv6.route.flush=1' + + check_type: multi_param + eval_expr: "'${0}' == 'net.ipv4.conf.all.accept_source_route = 0'; && '${1}' == 'net.ipv4.conf.default.accept_source_route = 0'; && '$2' == 'net.ipv4.conf.all.accept_source_route= 0'; && '${3}' == 'net.ipv4.conf.default.accept_source_route= 0'; && '(${4}' == 'net.ipv4.conf.default.accept_source_route= 0'; && '${5}' == 'net.ipv6.conf.default.accept_source_route = 0'; && '${6}' == 'net.ipv4.conf.all.accept_source_route= 0'; && '${7}' == 'net.ipv6.conf.default.accept_source_route= 0'; || '${8}' == ''" + - + name: '3.2.2 Ensure ICMP redirects are not accepted (Automated)' + description: ICMP redirect messages are packets that convey routing information and tell your host + (acting as a router) to send packets via an alternate path. + It is a way of allowing an outside routing device to update your system routing tables. + By setting net.ipv4.conf.all.accept_redirects and net.ipv6.conf.all.accept_redirects to 0, + the system will not accept any ICMP redirect messages, and therefore, won't allow outsiders to update the system's routing tables. + profile_applicability: Level 1 + audit: + - 'sysctl net.ipv4.conf.all.accept_redirects 2> /dev/null' + - 'sysctl net.ipv4.conf.default.accept_redirects 2> /dev/null' + - 'grep "net\.ipv4\.conf\.all\.accept_redirects" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null' + - 'grep "net\.ipv4\.conf\.default\.accept_redirects" /etc/sysctl.conf/etc/sysctl.d/* 2> /dev/null' + - 'sysctl net.ipv6.conf.all.accept_redirects 2> /dev/null' + - 'sysctl net.ipv6.conf.default.accept_redirects 2> /dev/null' + - 'grep "net\.ipv6\.conf\.all\.accept_redirects" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + - 'grep "net\.ipv6\.conf\.default\.accept_redirects" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + - 'grep "^\s*linux" /boot/grub/grub.cfg 2> /dev/null | grep -v "ipv6.disable=1" |awk -F ":" ''{print $2}''' + remediation: 'Set the following parameters in /etc/sysctl.conf or a /etc/sysctl.d/* file: + Run the following commands to set the active kernel parameters: + IF IPv6 is enabled: + Set the following parameters in /etc/sysctl.conf or a /etc/sysctl.d/* file: + Run the following commands to set the active kernel parameters: + net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 + # sysctl -w net.ipv4.conf.all.accept_redirects=0 + # sysctl -w net.ipv4.conf.default.accept_redirects=0 # sysctl -w net.ipv4.route.flush=1 + + net.ipv6.conf.all.accept_redirects = 0 + net.ipv6.conf.default.accept_redirects = 0 + # sysctl -w net.ipv6.conf.all.accept_redirects=0 + # sysctl -w net.ipv6.conf.default.accept_redirects=0 # sysctl -w net.ipv6.route.flush=1' + check_type: multi_param + eval_expr: "'${0}' == 'net.ipv4.conf.all.accept_redirects = 0'; && '${1}' == 'net.ipv4.conf.default.accept_redirects = 0'; && '${2}' == 'net.ipv4.conf.all.accept_redirects= 0'; && '${3}' == 'net.ipv4.conf.default.accept_redirects= 0'; && '(${4}' == 'net.ipv6.conf.all.accept_redirects = 0'; && '${5}' == 'net.ipv6.conf.default.accept_redirects = 0'; && '${6}' == 'net.ipv6.conf.all.accept_redirects= 0'; && '${7}' == 'net.ipv6.conf.default.accept_redirects= 0'; || '${8}' == ''" + - + name: '3.2.3 Ensure secure ICMP redirects are not accepted (Automated)' + description: Secure ICMP redirects are the same as ICMP redirects, except they come from gateways listed on the default gateway list. + It is assumed that these gateways are known to your system, and that they are likely to be secure. + profile_applicability: Level 1 + audit: + - 'sysctl net.ipv4.conf.all.secure_redirects 2> /dev/null' + - 'sysctl net.ipv4.conf.default.secure_redirects 2> /dev/null' + - 'grep "net\.ipv4\.conf\.all\.secure_redirects" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + - 'grep "net\.ipv4\.conf\.default\.secure_redirects" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + remediation: 'Set the following parameters in /etc/sysctl.conf or a /etc/sysctl.d/* file: + Run the following commands to set the active kernel parameters: + net.ipv4.conf.all.secure_redirects = 0 net.ipv4.conf.default.secure_redirects = 0' + # sysctl -w net.ipv4.conf.all.secure_redirects=0 + # sysctl -w net.ipv4.conf.default.secure_redirects=0 # sysctl -w net.ipv4.route.flush=1' + check_type: multi_param + eval_expr: "'${0}' == 'net.ipv4.conf.all.secure_redirects = 0'; && '${1}' == 'net.ipv4.conf.default.secure_redirects = 0'; && '$2' == 'net.ipv4.conf.all.secure_redirects= 0'; && '${3}' == 'net.ipv4.conf.default.secure_redirects= 0';" + - + name: '3.2.4 Ensure suspicious packets are logged (Automated)' + description: When enabled, this feature logs packets with un-routable source addresses to the kernel log. + profile_applicability: Level 1 + audit: + - 'sysctl net.ipv4.conf.all.log_martians 2> /dev/null' + - 'sysctl net.ipv4.conf.default.log_martians 2> /dev/null' + - 'grep "net\.ipv4\.conf\.all\.log_martians" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + - 'grep "net\.ipv4\.conf\.default\.log_martians" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + remediation: 'Set the following parameters in /etc/sysctl.conf or a /etc/sysctl.d/* file: + Run the following commands to set the active kernel parameters: + net.ipv4.conf.all.log_martians = 1 net.ipv4.conf.default.log_martians = 1 + # sysctl -w net.ipv4.conf.all.log_martians=1 + # sysctl -w net.ipv4.conf.default.log_martians=1 # sysctl -w net.ipv4.route.flush=1' + + check_type: multi_param + eval_expr: "'${0}' == 'net.ipv4.conf.all.log_martians = 1'; && '${1}' == 'net.ipv4.conf.default.log_martians = 1'; && '$2' == 'net.ipv4.conf.all.log_martians = 1'; && '${3}' == 'net.ipv4.conf.default.log_martians = 1';" + - + name: '3.2.5 Ensure broadcast ICMP requests are ignored (Automated)' + description: Setting net.ipv4.icmp_echo_ignore_broadcasts to 1 will cause the system to ignore all ICMP echo and timestamp requests to broadcast and multicast addresses. + profile_applicability: Level 1 + audit: + - 'sysctl net.ipv4.icmp_echo_ignore_broadcasts 2> /dev/null' + - 'grep "net\.ipv4\.icmp_echo_ignore_broadcasts" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + remediation: 'Set the following parameters in /etc/sysctl.conf or a /etc/sysctl.d/* file: net.ipv4.icmp_echo_ignore_broadcasts = 1 + Run the following commands to set the active kernel parameters: + # sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1 # sysctl -w net.ipv4.route.flush=1' + + check_type: multi_param + eval_expr: "'${0}' == 'net.ipv4.icmp_echo_ignore_broadcasts = 1'; && '${1}' == 'net.ipv4.icmp_echo_ignore_broadcasts = 1';" + - + name: '3.2.6 Ensure bogus ICMP responses are ignored (Automated)' + description: Setting icmp_ignore_bogus_error_responses to 1 prevents the kernel from logging bogus responses (RFC-1122 non-compliant) + from broadcast reframes, keeping file systems from filling up with useless log messages. + profile_applicability: Level 1 + audit: + - 'sysctl net.ipv4.icmp_ignore_bogus_error_responses 2> /dev/null' + - 'grep "net.ipv4.icmp_ignore_bogus_error_responses" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + remediation: 'Set the following parameter in /etc/sysctl.conf or a /etc/sysctl.d/* file: net.ipv4.icmp_ignore_bogus_error_responses = 1 + Run the following commands to set the active kernel parameters: + # sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=1 # sysctl -w net.ipv4.route.flush=1' + + check_type: multi_param + eval_expr: "'${0}' == 'net.ipv4.icmp_ignore_bogus_error_responses = 1'; && '${1}' == 'net.ipv4.icmp_ignore_bogus_error_responses = 1';" + - + name: '3.2.7 Ensure Reverse Path Filtering is enabled (Automated)' + description: Setting net.ipv4.conf.all.rp_filter and net.ipv4.conf.default.rp_filter to 1 forces the + Linux kernel to utilize reverse path filtering on a received packet to determine if the packet was valid. + Essentially, with reverse path filtering, if the return packet does not go out the same interface that the + corresponding source packet came from, the packet is dropped (and logged if log_martians is set). + profile_applicability: Level 1 + audit: + - 'sysctl net.ipv4.conf.all.rp_filter 2> /dev/null' + - 'sysctl net.ipv4.conf.default.rp_filter 2> /dev/null' + - 'grep "net\.ipv4\.conf\.all\.rp_filter" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + - 'grep "net\.ipv4\.conf\.default\.rp_filter" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + remediation: 'Set the following parameters in /etc/sysctl.conf or a /etc/sysctl.d/* file: + net.ipv4.conf.all.rp_filter = 1 + net.ipv4.conf.default.rp_filter = 1 + Run the following commands to set the active kernel parameters: + # sysctl -w net.ipv4.conf.all.rp_filter=1 + # sysctl -w net.ipv4.conf.default.rp_filter=1 + # sysctl -w net.ipv4.route.flush=1' + check_type: multi_param + eval_expr: "'${0}' == 'net.ipv4.conf.all.rp_filter = 1'; && '${1}' == 'net.ipv4.conf.default.rp_filter = 1'; && '${2}' == 'net.ipv4.conf.all.rp_filter = 1'; && '${3}' == 'net.ipv4.conf.default.rp_filter = 1';" + - + name: '3.2.8 Ensure TCP SYN Cookies is enabled (Automated)' + description: When tcp_syncookies is set, the kernel will handle TCP SYN packets normally until the half-open connection queue is full, + at which time, the SYN cookie functionality kicks in. SYN cookies work by not using the SYN queue at all. + Instead, the kernel simply replies to the SYN with a SYN|ACK, but will include a specially crafted TCP sequence + number that encodes the source and destination IP address and port number and the time the packet was sent. + A legitimate connection would send the ACK packet of the three way handshake with the specially crafted sequence number. + This allows the system to verify that it has received a valid response to a SYN cookie and allow the connection, even though there is no corresponding SYN in the queue. + profile_applicability: Level 1 + audit: + - 'sysctl net.ipv4.tcp_syncookies 2> /dev/null' + - 'grep "net\.ipv4\.tcp_syncookies" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + remediation: 'Set the following parameters in /etc/sysctl.conf or a /etc/sysctl.d/* file: net.ipv4.tcp_syncookies = 1 + Run the following commands to set the active kernel parameters: + # sysctl -w net.ipv4.tcp_syncookies=1 + # sysctl -w net.ipv4.route.flush=1' + check_type: multi_param + eval_expr: "'${0}' == 'net.ipv4.tcp_syncookies = 1'; && '${1}' == 'net.ipv4.tcp_syncookies = 1';" + - + name: '3.2.9 Ensure IPv6 router advertisements are not accepted (Automated)' + description: This setting disables the systems ability to accept IPv6 router advertisements. + profile_applicability: Level 1 + audit: + - 'sysctl net.ipv6.conf.all.accept_ra 2> /dev/null' + - 'sysctl net.ipv6.conf.default.accept_ra 2> /dev/null' + - 'grep "net\.ipv6\.conf\.all\.accept_ra" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + - 'grep "net\.ipv6\.conf\.default\.accept_ra" /etc/sysctl.conf /etc/sysctl.d/* 2> /dev/null |awk -F ":" ''{print $2}''' + - 'grep "^\s*linux" /boot/grub/grub.cfg 2> /dev/null | grep -v "ipv6.disable=1"' + remediation: 'IF IPv6 is enabled: Set the following parameters in /etc/sysctl.conf or a /etc/sysctl.d/* file: + net.ipv6.conf.all.accept_ra = 0 + net.ipv6.conf.default.accept_ra = 0 + Run the following commands to set the active kernel parameters: + # sysctl -w net.ipv6.conf.all.accept_ra=0 + # sysctl -w net.ipv6.conf.default.accept_ra=0 + # sysctl -w net.ipv6.route.flush=1' + check_type: multi_param + eval_expr: "('${0}' == 'net.ipv6.conf.all.accept_ra = 0'; && '${1}' == 'net.ipv6.conf.default.accept_ra = 0'; && '$2' == 'net.ipv6.conf.all.accept_ra = 0'; && '${3}' == 'net.ipv6.conf.default.accept_ra = 0';) || '${4}' == '';" \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/3.3_tcp_wrappers.yml b/internal/benchmark/lxd/v1.0.0/3.3_tcp_wrappers.yml new file mode 100644 index 0000000..cd62082 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/3.3_tcp_wrappers.yml @@ -0,0 +1,79 @@ +--- +benchmark_type: lxd +categories: + - + name: Network Configuration + sub_category: + name: 3.3 TCP Wrappers + audit_tests: + - + name: '3.3.1 Ensure TCP Wrappers is installed' + description: Many Linux distributions provide value-added firewall solutions which provide easy, + advanced management of network traffic into and out of the local system. + When these solutions are available and appropriate for an environment they should be used. + In cases where a value-added firewall is not provided by a distribution, TCP Wrappers provides a simple access list + and standardized logging method for services capable of supporting it. + Services that are called from inetd and xinetd support the use of TCP wrappers. + Any service that can support TCP wrappers will have the libwrap.so library attached to it. + profile_applicability: Level 1 + audit: + - 'dpkg -s tcpd 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Run the following command to install TCP Wrappers: + # apt install tcpd' + check_type: multi_param + eval_expr: "'${0}' == 'install ok installed';" + additional_info: 'To verify if a service supports TCP Wrappers, run the following command: + # ldd | grep libwrap.so + If there is any output, then the service supports TCP Wrappers.' + - + name: '3.3.2 Ensure /etc/hosts.allow is configured (Manual)' + description: The /etc/hosts.allow file specifies which IP addresses are permitted to connect to the host. + It is intended to be used in conjunction with the /etc/hosts.deny file. + profile_applicability: Level 1 + audit: + - '# cat /etc/hosts.allow' + remediation: 'Run the following command to create /etc/hosts.allow: + # echo "ALL: /, /, ..." >/etc/hosts.allow + where each / combination (for example, "192.168.1.0/255.255.255.0") represents + one network block in use by your organization that requires access to this system.' + check_type: multi_param + eval_expr: "" + additional_info: 'Contents of the /etc/hosts.allow file will vary depending on your network configuration.' + type: manual + - + name: '3.3.3 Ensure /etc/hosts.deny is configured' + description: The /etc/hosts.deny file specifies which IP addresses are not permitted to connect to the host. + It is intended to be used in conjunction with the /etc/hosts.allow file. + profile_applicability: Level 1 + audit: + - 'cat /etc/hosts.deny | grep "ALL: ALL" 2> /dev/null' + remediation: 'Run the following command to create /etc/hosts.deny: + # echo "ALL: ALL" >> /etc/hosts.deny + Additional Information: + Contents of the /etc/hosts.deny file may include additional options depending on your network configuration.' + check_type: multi_param + eval_expr: "'${0}' == 'ALL: ALL';" + - + name: '3.3.4 Ensure permissions on /etc/hosts.allow are configured (Automated)' + description: The /etc/hosts.allow file contains networking information that is used by many applications + and therefore must be readable for these applications to operate. + profile_applicability: Level 1 + audit: + - 'stat /etc/hosts.allow | grep Access: 2> /dev/null | head -1' + remediation: 'Run the following commands to set permissions on /etc/hosts.allow: + # chown root:root /etc/hosts.allow + # chmod 644 /etc/hosts.allow' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '3.3.5 Ensure permissions on /etc/hosts.deny are configured (Automated)' + description: The /etc/hosts.deny file contains network information that is used by many system applications + and therefore must be readable for these applications to operate. + profile_applicability: Level 1 + audit: + - 'stat /etc/hosts.deny | grep Access: 2> /dev/null | head -1' + remediation: 'Run the following commands to set permissions on /etc/hosts.deny: + # chown root:root /etc/hosts.deny + # chmod 644 /etc/hosts.deny' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)';" \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/3.4_firewall_configuration.yml b/internal/benchmark/lxd/v1.0.0/3.4_firewall_configuration.yml new file mode 100644 index 0000000..688c94a --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/3.4_firewall_configuration.yml @@ -0,0 +1,461 @@ +--- +benchmark_type: lxd +categories: + - + name: Network Configuration + sub_category: + name: 3.4 Firewall Configuration + audit_tests: + - + name: '3.4.1.1 Ensure a Firewall package is installed (Automated)' + description: A Firewall package should be selected. Most firewall configuration utilities operate as a front end to nftables or iptables. + profile_applicability: Level 1 + audit: + - 'dpkg -s ufw 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + - 'dpkg -s nftables 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + - 'dpkg -s iptables 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Run one of the following commands to install the Firewall package that follows local site policy: + To install UFW, run the following command: + # apt install ufw + To install nftables, run the following command: + # apt install nftables + To install iptables, run the following command: + # apt install iptables' + check_type: multi_param + eval_expr: "'${0}' == 'install ok installed'; && '${1}' == 'install ok installed'; && '${2}' == 'install ok installed';" + - + name: '3.4.2.1 Ensure ufw service is enabled (Automated)' + description: UncomplicatedFirewall (ufw) is a frontend for iptables. ufw provides a framework for managing netfilter, as well as a command-line and available graphical user interface for manipulating the firewall. + Ensure that the ufw service is enabled to protect your system. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled ufw 2> /dev/null' + remediation: 'Remediation: + Run the following command to enable ufw: + # ufw enable' + check_type: multi_param + eval_expr: "'${0}' == 'enabled';" + referances: + - http://manpages.ubuntu.com/manpages/precise/en/man8/ufw.8.html + additional_info: 'When running ufw enable or starting ufw via its initscript, ufw will flush its chains. This is required so ufw can maintain a consistent state, but it may drop existing connections (eg ssh). ufw does support adding rules before enabling the firewall. + Run the following command before running ufw enable. + # ufw allow proto tcp from any to any port 22 + The rules will still be flushed, but the ssh port will be open after enabling the firewall. Please note that once ufw is ''enabled'', ufw will not flush the chains when adding or removing rules (but will when modifying a rule or changing the default policy). + By default, ufw will prompt when enabling the firewall while running under ssh. This can be disabled by using ufw --force enable.' + - + name: '3.4.2.2 Ensure default deny firewall policy (Automated)' + description: A default deny policy on connections ensures that any unconfigured network usage will be rejected. + profile_applicability: Level 1 + audit: + - 'ufw status verbose 2> /dev/null|grep Default: |awk -F ":" ''{print $2}'' |awk ''FNR <= 1'' |awk -F "," ''{print $1}'' |awk ''FNR <= 1''' + - 'ufw status verbose 2> /dev/null|grep Default: |awk -F ":" ''{print $2}'' |awk ''FNR <= 1'' |awk -F "," ''{print $2}'' |awk ''FNR <= 1''' + - 'ufw status verbose 2> /dev/null|grep Default: |awk -F ":" ''{print $2}'' |awk ''FNR <= 1'' |awk -F "," ''{print $3}'' |awk ''FNR <= 1''' + remediation: 'Run the following commands to implement a default deny policy: + # ufw default deny incoming + # ufw default deny outgoing + # ufw default deny routed' + check_type: multi_param + eval_expr: "('${0}' == 'deny (incoming)'; || '${0}' == 'reject (incoming)';) && ('${1}' == 'deny (outgoing)'; || '${1}' == 'reject (outgoing)';) && ('${2}' == 'deny (routed)'; || '${2}' == 'reject (routed)';)" + - + name: '3.4.2.3 Ensure loopback traffic is configured (Automated)' + description: Configure the loopback interface to accept traffic. + Configure all other interfaces to deny traffic to the loopback network (127.0.0.0/8 for IPv4 and ::1/128 for IPv6). + profile_applicability: Level 1 + audit: + - 'ufw status verbose 2> /dev/null | grep "Anywhere on lo" | grep "ALLOW IN" | awk -F " " ''{print $6}'' |awk ''FNR <= 1''' + - 'ufw status verbose 2> /dev/null | grep "Anywhere" | grep "DENY IN" | awk -F " " ''{print $4}'' |awk ''FNR <= 1''' + - 'ufw status verbose 2> /dev/null | grep "Anywhere (v6) on lo" | grep "ALLOW IN" | awk -F " " ''{print $7 $8}'' |awk ''FNR <= 1''' + - 'ufw status verbose 2> /dev/null | grep "Anywhere (v6)" | grep "DENY IN" | awk -F " " ''{print $5}'' |awk ''FNR <= 1''' + - 'ufw status verbose 2> /dev/null | grep "Anywhere" | grep "ALLOW OUT" | awk -F " " ''{print $4 $5 $6}'' |awk ''FNR <= 1''' + - 'ufw status verbose 2> /dev/null | grep "Anywhere (v6)" | grep "ALLOW OUT" | awk -F " " ''{print $5 $6 $7 $8}'' |awk ''FNR <= 1''' + remediation: 'Run the following commands to implement the loopback rules: + # ufw allow in on lo + # ufw allow out from lo + # sudo ufw deny in from 127.0.0.0/8 + # sudo ufw deny in from ::1' + check_type: multi_param + eval_expr: "'${0}' == 'Anywhere'; && '${1}' == '127.0.0.0/8'; && '${2}' == 'Anywhere(v6)'; && '${3}' == '::1'; && '${4}' == 'Anywhereonlo' && '${5}' == 'Anywhere(v6)onlo';" + - + name: '3.4.2.4 Ensure outbound connections are configured (Manual)' + description: Configure the firewall rules for new outbound connections. + profile_applicability: Level 1 + audit: + - 'ufw status numbered' + remediation: 'Configure ufw in accordance with site policy. The following commands will implement a policy to allow all outbound connections on all interfaces: + # ufw allow out on all' + check_type: multi_param + additional_info: 'Changing firewall settings while connected over network can result in being locked out of the system. + Unlike iptables, when a new outbound rule is added, ufw automatically takes care of associated established connections, + so no rules for the latter kind are required.' + type: manual + + - + name: '3.4.2.5 Ensure firewall rules exist for all open ports (Automated)' + description: Any ports that have been opened on non-loopback addresses need firewall rules to govern traffic. + profile_applicability: Level 1 + audit: + - 'ss -4tuln | grep -v 127.0.0 |grep -v lo | wc -l' + - 'ufw status | grep -v v6 | grep -v lo |grep -v 127.0.0 |wc -l' + remediation: 'For each port identified in the audit which does not have a firewall rule establish a proper rule for accepting inbound connections: + # ufw allow in / + Additional Information: + Changing firewall settings while connected over network can result in being locked out of the system. + The remediation command opens up the port to traffic from all sources. Consult ufw documentation and set any restrictions in compliance with site policy.' + check_type: multi_param + eval_expr: "${0} > 1 && ${1} > 5" + - + name: '3.4.3.1 Ensure iptables are flushed' + description: nftables is a replacement for iptables, ip6tables, ebtables and arptables + profile_applicability: Level 1 + audit: + - 'iptables -n -L -v --line-numbers |grep num | wc -l' + - 'ip6tables -n -L -v --line-numbers |grep num | wc -l' + remediation: 'Run the following commands to flush iptables: For iptables: + # iptables -F + For ip6tables + # ip6tables -F' + check_type: multi_param + eval_expr: "${0} == 3" + - + name: '3.4.3.2 Ensure a table exists (Automated)' + description: Tables hold chains. Each table only has one address family and only applies to packets of this family. + Tables can have one of five families. + profile_applicability: Level 1 + audit: + - 'nft list tables 2> /dev/null' + remediation: 'Run the following command to create a table in nftables + # nft create table inet + Example: + # nft create table inet filter' + check_type: multi_param + eval_expr: "'${0}' != '' && '${0}' == 'table inet filter'" + - + name: '3.4.3.3 Ensure base chains exist (Automated)' + description: Chains are containers for rules. They exist in two kinds, base chains and regular chains. + A base chain is an entry point for packets from the networking stack, + a regular chain may be used as jump target and is used for better rule organization. + profile_applicability: Level 1 + audit: + - 'nft list ruleset 2> /dev/null | grep ''hook input''| xargs |sed ''s/;//'' | sed ''s/;//''' + - 'nft list ruleset 2> /dev/null | grep ''hook forward''| xargs |sed ''s/;//'' | sed ''s/;//''' + - 'nft list ruleset 2> /dev/null | grep ''hook output''| xargs |sed ''s/;//'' | sed ''s/;//''' + remediation: 'Run the following command to create the base chains: + # nft create chain inet
{ type filter hook <(input|forward|output)> priority 0 \; } + Example: + # nft create chain inet filter input { type filter hook input priority 0 \; } + # nft create chain inet filter forward { type filter hook forward priority 0 \; } + # nft create chain inet filter output { type filter hook output priority 0 \; }' + check_type: multi_param + eval_expr: "'${0}' == 'type filter hook input priority 0 policy accept' && '${1}' == 'type filter hook forward priority 0 policy accept'&& '${2}' == 'type filter hook output priority 0 policy accept'" + - + name: '3.4.3.4 Ensure loopback traffic is configured (Automated)' + description: Configure the loopback interface to accept traffic. Configure all other interfaces to deny traffic to the loopback network + profile_applicability: Level 1 + audit: + - 'nft list ruleset 2> /dev/null| awk ''/hook input/,/}/'' | grep ''iif "lo" accept'' | xargs' + - 'nft list ruleset 2> /dev/null| awk ''/hook input/,/}/'' | grep ''ip sddr'' | xargs' + - 'sysctl -a 2>/dev/null | grep disable_ipv6 | awk -F "=" ''{print $2}''' + - 'nft list ruleset 2> /dev/null| awk ''/hook input/,/}/'' | grep ''ip6 saddr'' |xargs' + remediation: 'Run the following commands to implement the loopback rules: + # nft add rule inet filter input iif lo accept + # nft create rule inet filter input ip saddr 127.0.0.0/8 counter drop + IF IPv6 is enabled on the system, run the following command to implement the IPv6 loopback rule: + nft add rule inet filter input ip6 saddr ::1 counter drop' + check_type: multi_param + eval_expr: "('${0}' == 'iif lo accept'; && '${2}' == 'ip saddr 127.0.0.0/8 counter packets 0 bytes 0 drop';) || ('${3}' == '0'; && '${4}' == 'ip6 saddr ::1 counter packets 0 bytes 0 drop';)" + - + name: '3.4.3.5 Ensure outbound and established connections are configured (Manual)' + description: Configure the firewall rules for new outbound, and established connections + profile_applicability: Level 1 + audit: + - 'Run the following commands and verify all rules for established incoming connections match site policy: site policy: + Output should be similar to: + Run the folllowing command and verify all rules for new and established outbound connections match site policy + Output should be similar to: + ip protocol tcp ct state established,related,new accept + ip protocol udp ct state established,related,new accept + ip protocol icmp ct state established,related,new accept' + remediation: 'Configure nftables in accordance with site policy. + The following commands will implement a policy to allow all outbound connections and all established connections: + # nft add rule inet filter input ip protocol tcp ct state established accept + # nft add rule inet filter input ip protocol udp ct state established accept + # nft add rule inet filter input ip protocol icmp ct state established accept + # nft add rule inet filter output ip protocol tcp ct state new,related,established accept + # nft add rule inet filter output ip protocol udp ct state new,related,established accept + # nft add rule inet filter output ip protocol icmp ct state new,related,established accept' + check_type: multi_param + type: manual + - + name: '3.4.3.6 Ensure default deny firewall policy (Automated)' + description: Base chain policy is the default verdict that will be applied to packets reaching the end of the chain. + profile_applicability: Level 1 + audit: + - 'nft list ruleset 2> /dev/null | grep ''hook input''|xargs | sed ''s/;//'' | sed ''s/;//''' + - 'nft list ruleset 2> /dev/null | grep ''hook forward''|xargs | sed ''s/;//'' | sed ''s/;//''' + - 'nft list ruleset 2> /dev/null | grep ''hook output''|xargs | sed ''s/;//'' | sed ''s/;//''' + remediation: 'Run the following command for the base chains with the input, forward, and output hooks to implement a default DROP policy: + # nft chain
{ policy drop \; } + Example: + # nft chain inet filter input { policy drop \; } + # nft chain inet filter forward { policy drop \; } + # nft chain inet filter output { policy drop \; }' + check_type: multi_param + eval_expr: "'${0}' == 'type filter hook input priority 0 policy drop'; && '${1}' == 'type filter hook forward priority 0 policy drop'; && '${2}' == 'type filter hook output priority 0 policy drop';" + default_value: accept. + references: + - Manual Page nft + - + name: '3.4.3.7 Ensure nftables service is enabled (Automated)' + description: The nftables service allows for the loading of nftables rulesets during boot, or starting on the nftables service + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled nftables 2> /dev/null' + remediation: 'Run the following command to enable the nftables service: + # systemctl enable nftables' + check_type: multi_param + eval_expr: "'${0}' == 'enabled';" + - + name: '3.4.3.8 Ensure nftables rules are permanent (Automated)' + description: nftables is a subsystem of the Linux kernel providing filtering and classification of network packets/datagrams/frames. + The nftables service reads the /etc/nftables.conf file for a nftables file or files to include in the nftables ruleset. + A nftables ruleset containing the input, forward, and output base chains allow network traffic to be filtered. + profile_applicability: Level 1 + audit: + - 'Run the following commands to verify that input, forward, and output base chains are configured to be applied to a nftables ruleset on boot: + Run the following command to verify the input base chain: + Output should be similar to: + # awk ''/hook input/,/}/'' $(awk ''$1 ~ /^\s*include/ { gsub(""\"""","""",$2);print $2 }'' /etc/nftables.conf) + + type filter hook input priority 0; policy drop; + # Ensure loopback traffic is configured + iif "lo" accept + ip saddr 127.0.0.0/8 counter packets 0 bytes 0 drop + ip6 saddr ::1 counter packets 0 bytes 0 drop + # Ensure established connections are configured ip protocol tcp ct state established accept + ip protocol udp ct state established accept + ip protocol icmp ct state established accept + # Accept port 22(SSH) traffic from anywhere + tcp dport ssh accept + # Accept ICMP and IGMP from anywhere + icmpv6 type { destination-unreachable, packet-too-big, time- exceeded, parameter-problem, mld-listener-query, + mld-listener-report, mld- listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd- neighbor-advert, + ind-neighbor-solicit, ind-neighbor-advert, mld2-listener- report } accept + Note: Review the input base chain to ensure that it follows local site policy Run the following command to verify the forward base chain: + Output should be similar to: + Note: Review the forward base chain to ensure that it follows local site policy. Run the following command to verify the forward base chain: + Output should be similar to: + # awk ''/hook forward/,/}/'' $(awk ''$1 ~ /^\s*include/ { gsub(""\"""","""",$2);print $2 }'' /etc/nftables.conf) + + # Base chain for hook forward named forward (Filters forwarded network packets) + chain forward { + type filter hook forward priority 0; policy drop; + } + # awk ''/hook output/,/}/'' $(awk ''$1 ~ /^\s*include/ { gsub(""\"""","""",$2);print $2 }'' /etc/nftables.conf) + + # Base chain for hook output named output (Filters outbound network packets) + chain output { + type filter hook output priority 0; policy drop; + # Ensure outbound and established connections are configured ip protocol tcp ct state established,related,new accept + ip protocol tcp ct state established,related,new accept + ip protocol udp ct state established,related,new accept + ip protocol icmp ct state established,related,new accept + } + Note: Review the output base chain to ensure that it follows local site policy.' + remediation: 'Edit the /etc/nftables.conf file and un-comment or add a line with include for each nftables file you want included in the nftables ruleset on boot + example: + # vi /etc/nftables.conf + Add the line: + include "/etc/nftables.rules"' + check_type: multi_param + type: manual + - + name: '3.4.4.1.1 Ensure iptables packages are installed (Automated)' + description: The nftables service allows for the loading of nftables rulesets during boot, or starting on the nftables service + profile_applicability: Level 1 + audit: + - 'apt list iptables iptables-persistent 2> /dev/null | grep installed | awk -F " " ''{print $4}''' + remediation: 'Run the following command to install iptables and iptables-persistent # apt install iptables iptables-persistent' + check_type: multi_param + eval_expr: "'${0}' == '[installed,automatic]';" + - + name: '3.4.4.1.2 Ensure nftables is not installed (Automated)' + description: nftables is a subsystem of the Linux kernel providing filtering and classification of network + packets/datagrams/frames and is the successor to iptables. + profile_applicability: Level 1 + audit: + - 'dpkg -s nftables 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Run the following command to remove nftables: + # apt purge nftables' + check_type: multi_param + eval_expr: "'${0}' != 'install ok installed';" + - + name: '3.4.4.1.3 Ensure Uncomplicated Firewall (UFW) is not installed or stopped and masked (Automated)' + description: Uncomplicated Firewall (UFW) is a program for managing a netfilter firewall designed to be easy to use. + Uses a command-line interface consisting of a small number of simple commands + Uses iptables for configuration + Uncomplicated Firewall (UFW) is a program for managing a netfilter firewall designed to be easy to use. + Uses a command-line interface consisting of a small number of simple commands + Uses iptables for configuration + + profile_applicability: Level 1 + audit: + - 'dpkg -s ufw 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + - 'systemctl status ufw 2> /dev/null| grep "Active: " | grep -v "active (running) "' + - 'systemctl is-enabled ufw 2> /dev/null' + remediation: 'Run the following command to remove nftables: + # apt purge nftables' + check_type: multi_param + eval_expr: "'${0}' != 'install ok installed'; || ('${1}' == ''; && '$2' != 'masked';)" + - + name: '3.4.4.2.1 Ensure default deny firewall policy (Automated)' + description: A default deny all policy on connections ensures that any unconfigured network usage will be rejected. + profile_applicability: Level 1 + audit: + - 'iptables -L 2> /dev/null |grep Chain |awk -F "Chain INPUT " ''{print $2}''| awk ''FNR <= 3''' + remediation: 'Run the following commands to implement a default DROP policy: + # iptables -P INPUT DROP + # iptables -P OUTPUT DROP + # iptables -P FORWARD DROP' + check_type: multi_param + eval_expr: "'${0}' == '(policy DROP)';" + additional_info: 'Changing firewall settings while connected over network can result in being locked out of the system. + Remediation will only affect the active system firewall, be sure to configure the default + policy in your firewall management to apply on boot as well.' + - + name: '3.4.4.2.1 Ensure default deny firewall policy (Automated)' + description: A default deny all policy on connections ensures that any unconfigured network usage will be rejected. + profile_applicability: Level 1 + audit: + - 'iptables -L 2> /dev/null |grep Chain |awk -F "Chain INPUT " ''{print $2}''| awk ''FNR <= 3''' + remediation: 'Run the following commands to implement a default DROP policy: + # iptables -P INPUT DROP + # iptables -P OUTPUT DROP + # iptables -P FORWARD DROP' + check_type: multi_param + eval_expr: "'${0}' == '(policy DROP)';" + additional_info: 'Changing firewall settings while connected over network can result in being locked out of the system. + Remediation will only affect the active system firewall, be sure to configure the default + policy in your firewall management to apply on boot as well.' + - + name: '3.4.4.2.2 Ensure loopback traffic is configured (Automated)' + description: Configure the loopback interface to accept traffic. Configure all other interfaces to deny + traffic to the loopback network (127.0.0.0/8). + profile_applicability: Level 1 + audit: + - 'iptables -L INPUT -v -n |grep ACCEPT |grep -v Chain |awk -F " " ''{print $4}''| awk ''FNR <= 1''' + - 'iptables -L INPUT -v -n |grep ACCEPT |grep -v Chain |awk -F " " ''{print $6}''| awk ''FNR <= 1''' + - 'iptables -L INPUT -v -n |grep DROP |grep -v Chain |awk -F " " ''{print $6}''| awk ''FNR <= 1''' + - 'iptables -L INPUT -v -n |grep DROP |grep -v Chain |awk -F " " ''{print $8}''| awk ''FNR <= 1''' + - 'iptables -L OUTPUT -v -n |grep ACCEPT |grep -v Chain |awk -F " " ''{print $4}''| awk ''FNR <= 1''' + - 'iptables -L OUTPUT -v -n |grep ACCEPT |grep -v Chain |awk -F " " ''{print $7}''| awk ''FNR <= 1''' + remediation: 'Run the following commands to implement the loopback rules: + # iptables -A INPUT -i lo -j ACCEPT + # iptables -A OUTPUT -o lo -j ACCEPT + # iptables -A INPUT -s 127.0.0.0/8 -j DROP' + check_type: multi_param + eval_expr: "'${0}' == 'all'; && '${1}' == 'lo'; && '$2' == '*'; && '${3}' == '127.0.0.0/8'; && '${4}' == 'all'; && '${5}' == 'lo';" + additional_info: 'Changing firewall settings while connected over network can result in being locked out of the system. + Remediation will only affect the active system firewall, be sure to configure the default policy + in your firewall management to apply on boot as well.' + - + name: '3.4.4.2.3 Ensure outbound and established connections are configured (Manual)' + description: Configure the firewall rules for new outbound, and established connections. + profile_applicability: Level 1 + audit: + - 'iptables -L -v -n' + remediation: 'Configure iptables in accordance with site policy. + The following commands will implement a policy to allow all outbound connections and all established connections: + # iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT + # iptables -A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT + # iptables -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT + # iptables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT + # iptables -A INPUT -p udp -m state --state ESTABLISHED -j ACCEPT + # iptables -A INPUT -p icmp -m state --state ESTABLISHED -j ACCEPT' + check_type: multi_param + additional_info: 'Changing firewall settings while connected over network can result in being locked out of the system. + Remediation will only affect the active system firewall, be sure to configure the default policy in your firewall management to apply on boot as well.' + type: manual + - + name: '3.4.4.2.4 Ensure firewall rules exist for all open ports (Automated)' + description: Any ports that have been opened on non-loopback addresses need firewall rules to govern traffic. + profile_applicability: Level 1 + audit: + - 'ss -4tuln 2> /dev/null |grep -v 127.0.0. |grep -v Local |awk -F " " ''{print $5}''|awk -F ":" ''{print $2}''' + - 'iptables -L INPUT -v -n 2> /dev/null |grep NEW |grep dpt:${0} |awk ''FNR <= 1''' + remediation: 'For each port identified in the audit which does not have a firewall rule establish a proper rule for accepting inbound connections: + # iptables -A INPUT -p --dport -m state --state NEW -j ACCEPT' + check_type: multi_param + eval_expr: "'${1}' != '';" + additional_info: 'Changing firewall settings while connected over network can result in being locked out of the system. + Remediation will only affect the active system firewall, be sure to configure the default policy in your firewall management to apply on boot as well. + The remediation command opens up the port to traffic from all sources. Consult iptables documentation and set any restrictions in compliance with site policy.' + - + name: '3.4.4.3.1 Ensure IPv6 default deny firewall policy (Automated)' + description: A default deny all policy on connections ensures that any unconfigured network usage will be rejected. + profile_applicability: Level 1 + audit: + - 'iptables -L 2> /dev/null |grep Chain |awk -F "Chain INPUT " ''{print $2}''| awk ''FNR <= 3''' + - 'grep "^\s*linux" /boot/grub/grub.cfg 2> /dev/null| grep -v ipv6.disable=1' + remediation: 'Run the following commands to implement a default DROP policy: + # ip6tables -P INPUT DROP + # ip6tables -P OUTPUT DROP + # ip6tables -P FORWARD DROP' + check_type: multi_param + eval_expr: "('${0}' == '(policy DROP)'; || '${1}' == '(policy REJECT)';) && '${1}' == '' " + additional_info: 'Changing firewall settings while connected over network can result in being locked out of the system. + Remediation will only affect the active system firewall, be sure to configure the default policy in your firewall management to apply on boot as well.' + - + name: '3.4.4.3.2 Ensure IPv6 loopback traffic is configured (Automated)' + description: Configure the loopback interface to accept traffic. Configure all other interfaces to deny traffic to the loopback network (::1). + profile_applicability: Level 1 + audit: + - 'ip6tables -L INPUT -v -n |grep ACCEPT |grep -v Chain |awk -F " " ''{print $4}''| awk ''FNR <= 1''' + - 'ip6tables -L INPUT -v -n |grep ACCEPT |grep -v Chain |awk -F " " ''{print $6}''| awk ''FNR <= 1''' + - 'ip6tables -L INPUT -v -n |grep DROP |grep -v Chain |awk -F " " ''{print $6}''| awk ''FNR <= 1''' + - 'ip6tables -L INPUT -v -n |grep DROP |grep -v Chain |awk -F " " ''{print $8}''| awk ''FNR <= 1''' + - 'ip6tables -L OUTPUT -v -n |grep ACCEPT |grep -v Chain |awk -F " " ''{print $4}''| awk ''FNR <= 1''' + - 'ip6tables -L OUTPUT -v -n |grep ACCEPT |grep -v Chain |awk -F " " ''{print $7}''| awk ''FNR <= 1''' + - 'grep "^\s*linux" /boot/grub/grub.cfg 2> /dev/null | grep -v ipv6.disable=1' + remediation: 'Run the following commands to implement the loopback rules: + # ip6tables -A INPUT -i lo -j ACCEPT + # ip6tables -A OUTPUT -o lo -j ACCEPT + # ip6tables -A INPUT -s ::1 -j DROP' + check_type: multi_param + eval_expr: "('${0}' == 'all'; && '${1}' == 'lo'; && '$2' == '*'; && '${3}' == '127.0.0.0/8'; && '${4}' == 'all'; && '${5}' == 'lo';) || '${7}' != ''" + additional_info: 'Changing firewall settings while connected over network can result in being locked out of the system. + Remediation will only affect the active system firewall, be sure to configure the default policy in your firewall + management to apply on boot as well.' + - + name: '3.4.4.3.3 Ensure IPv6 outbound and established connections are configured (Manual)' + description: Configure the firewall rules for new outbound, and established IPv6 connections. + profile_applicability: Level 1 + audit: + - 'grep "^\s*linux" /boot/grub/grub.cfg 2> /dev/null | grep -v ipv6.disable=1' + - '# grep "^\s*linux" /boot/grub/grub.cfg 2> /dev/null | grep -v ipv6.disable=1' + remediation: 'Configure iptables in accordance with site policy. The following commands will implement a policy + to allow all outbound connections and all established connections: + # ip6tables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT + # ip6tables -A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT + # ip6tables -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT + # ip6tables -A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT + # ip6tables -A INPUT -p udp -m state --state ESTABLISHED -j ACCEPT + # ip6tables -A INPUT -p icmp -m state --state ESTABLISHED -j ACCEPT' + check_type: multi_param + additional_info: 'Changing firewall settings while connected over network can result in being locked out of the system. + Remediation will only affect the active system firewall, be sure to configure the default policy in your firewall management to apply on boot as well.' + type: manual + - + name: '3.4.4.3.4 Ensure IPv6 firewall rules exist for all open ports (Manual)' + description: Any ports that have been opened on non-loopback addresses need firewall rules to govern traffic. + profile_applicability: Level 1 + audit: + - 'ss -6tuln' + - 'ip6tables -L INPUT -v -n' + remediation: 'For each port identified in the audit which does not have a firewall + rule establish a proper rule for accepting inbound connections + # ip6tables -A INPUT -p --dport -m state --state NEW -j ACCEPT' + check_type: multi_param + additional_info: 'Changing firewall settings while connected over network can result in being locked out of the system. + Remediation will only affect the active system firewall, be sure to configure the default policy in your firewall management to apply on boot as well. + The remediation command opens up the port to traffic from all sources. Consult iptables documentation and set any restrictions in compliance with site policy.' + type: manual diff --git a/internal/benchmark/lxd/v1.0.0/4.1_configure_logging.yml b/internal/benchmark/lxd/v1.0.0/4.1_configure_logging.yml new file mode 100644 index 0000000..6b63a21 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/4.1_configure_logging.yml @@ -0,0 +1,197 @@ +--- +benchmark_type: lxd +categories: + - + name: Logging and Auditing + sub_category: + name: 4.1 Configure Logging + audit_tests: + - + name: '4.1.1.1 Ensure rsyslog is installed (Automated)' + description: The rsyslog software is a recommended replacement to the original syslogd daemon which provide improvements over syslogd, + such as connection-oriented (i.e. TCP) transmission of logs, the option to log to database formats, + and the encryption of log data en route to a central logging server. + profile_applicability: Level 1 + audit: + - 'dpkg -s rsyslog 2> /dev/null |grep Status |awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'nstall rsyslog: + # apt install rsyslog' + check_type: multi_param + eval_expr: "'${0}' == 'install ok installed';" + - + name: '4.1.1.2 Ensure rsyslog Service is enabled (Automated)' + description: Once the rsyslog package is installed it needs to be activated. + profile_applicability: Level 1 + audit: + - 'systemctl is-enabled rsyslog 2> /dev/null' + remediation: 'Run the following commands to enable rsyslog: + # systemctl --now enable rsyslog' + check_type: multi_param + eval_expr: "'${0}' == 'enabled';" + additional_info: 'Additional methods of enabling a service exist. Consult your distribution documentation for appropriate methods.' + - + name: '4.1.1.3 Ensure logging is configured (Manual)' + description: The /etc/rsyslog.conf and /etc/rsyslog.d/*.conf files specifies rules for logging and which files are to be used to log certain classes of messages. + profile_applicability: Level 1 + audit: + - 'ls -l /var/log/' + remediation: 'Edit the following lines in the /etc/rsyslog.conf and /etc/rsyslog.d/*.conf files as appropriate for your environment: + *.emerg + auth,authpriv.* + mail.* + mail.info + mail.warning + mail.err + news.crit + news.err + news.notice + :omusrmsg:* + /var/log/auth.log + -/var/log/mail + -/var/log/mail.info + -/var/log/mail.warn + /var/log/mail.err + -/var/log/news/news.crit + -/var/log/news/news.err + -/var/log/news/news.notice + *.=warning;*.=err + *.crit + *.*;mail.none;news.none + local0,local1.* + local2,local3.* + local4,local5.* + local6,local7.* + -/var/log/warn + /var/log/warn + -/var/log/messages + -/var/log/localmessages + -/var/log/localmessages + -/var/log/localmessages + -/var/log/localmessages + Run the following command to reload the rsyslog configuration: + # systemctl reload rsyslog' + check_type: multi_param + references: + - See the rsyslog.conf(5) man page for more information. + additional_info: 'On some systems /var/log/secure should be used for authentication data rather than /var/log/auth.log. + Please consult your distribution-specific recommendations for further details.' + type: manual + - + name: '4.1.1.4 Ensure rsyslog default file permissions configured (Automated)' + description: rsyslog will create logfiles that do not already exist on the system. + This setting controls what permissions will be applied to these newly created files. + profile_applicability: Level 1 + audit: + - 'grep ^\$FileCreateMode /etc/rsyslog.conf /etc/rsyslog.d/*.conf |awk -F "FileCreateMode" ''{print $2}'' |awk ''FNR <= 1''' + remediation: 'Edit the /etc/rsyslog.conf and /etc/rsyslog.d/*.conf files and set $FileCreateMode to 0640 or more restrictive: + $FileCreateMode 0640' + check_type: multi_param + eval_expr: "'${0}' == '0640';" + references: + - See the rsyslog.conf(5) man page for more information. + - + name: '4.1.1.5 Ensure rsyslog is configured to send logs to a remote log host (Automated)' + description: The rsyslog utility supports the ability to send logs it gathers to a remote log host running syslogd(8) + or to receive messages from remote hosts, reducing administrative overhead. + profile_applicability: Level 1 + audit: + - 'grep -E "^[^#](\s*\S+\s*)\s*action\(" /etc/rsyslog.conf /etc/rsyslog.d/*.conf | grep "target="' + remediation: 'Edit the /etc/rsyslog.conf and /etc/rsyslog.d/*.conf files and add one of the following lines: + Newer syntax: + action(type="omfwd" target="" port="" protocol="tcp" + action.resumeRetryCount="" queue.size=") + queue.type="linkList" + Example: + *.* action(type="omfwd" target="192.168.2.100" port"514" protocol="tcp" action.resumeRetryCount="100" + queue.type="linkList" queue.size="1000") + Older syntax: + *.* @@ + Example: + *.* @@192.168.2.100 + Run the following command to reload the rsyslog configuration: # systemctl reload rsyslog' + check_type: multi_param + eval_expr: "'${0}' != '';" + additional_info: 'The double "at" sign (@@) directs rsyslog to use TCP to send log messages to the server, which is a more reliable transport mechanism than the default UDP protocol. + *.* sends all logs to the remote loghost. Ensure that the selection of logfiles being sent follows local site policy' + references: + - See the rsyslog.conf(5) man page for more information. + - + name: '4.1.1.6 Ensure remote rsyslog messages are only accepted on designated log hosts. (Manual)' + description: By default, rsyslog does not listen for log messages coming in from remote systems. + The ModLoad tells rsyslog to load the imtcp.so module so it can listen over a network via TCP. + The InputTCPServerRun option instructs rsyslogd to listen on the specified TCP port. + audit: + - '# grep ''$ModLoad imtcp'' /etc/rsyslog.conf /etc/rsyslog.d/*.conf $ModLoad imtcp + # grep ''$InputTCPServerRun'' /etc/rsyslog.conf /etc/rsyslog.d/*.conf $InputTCPServerRun 514' + remedeation: 'For hosts that are designated as log hosts, edit the /etc/rsyslog.conf file and un- comment or add the following lines: + $ModLoad imtcp + $InputTCPServerRun 514 + For hosts that are not designated as log hosts, edit the /etc/rsyslog.conf file and comment or remove the following lines: + # $ModLoad imtcp + # $InputTCPServerRun 514 + Run the following command to reload the rsyslogd configuration: # systemctl restart rsyslog' + check_type: multi_param + additional_info: 'The $ModLoad imtcp line can have the .so extension added to the end of the module, or use the full path to the module.' + references: + - See the rsyslog(8) man page for more information. + type: manual + - + name: '4.1.2.1 Ensure journald is configured to send logs to rsyslog (Automated)' + description: Data from journald may be stored in volatile memory or persisted locally on the server. + Utilities exist to accept remote export of journald logs, however, use of the rsyslog service + provides a consistent means of log collection and export. + audit: + - 'grep -e ForwardToSyslog /etc/systemd/journald.conf' + remedeation: 'Edit the /etc/systemd/journald.conf file and add the following line: + ForwardToSyslog=yes' + check_type: multi_param + eval_expr: "'${0}' == 'ForwardToSyslog=yes';" + additional_info: 'This recommendation assumes that recommendation 4.2.1.5, "Ensure rsyslog is configured to send logs to a remote log host" + has been implemented. As noted in the journald man pages, journald logs may be exported to rsyslog either through the process mentioned here, + or through a facility like systemd-journald.service. + There are trade-offs involved in each implementation, where ForwardToSyslog will immediately capture all events + (and forward to an external log server, if properly configured), but may not capture all boot-up activities. + Mechanisms such as systemd- journald.service, on the other hand, will record bootup events, but may delay sending the information to rsyslog, + leading to the potential for log manipulation prior to export. Be aware of the limitations of all tools employed to secure a system. + The main configuration file /etc/systemd/journald.conf is read before any of the custom *.conf files. + If there are custom configs present, they override the main configuration parameters' + references: + - https://github.com/konstruktoid/hardening/blob/master/systemd.adoc#etcsyste mdjournaldconf + - + name: '4.1.2.2 Ensure journald is configured to compress large log files (Automated)' + description: The journald system includes the capability of compressing overly large + files to avoid filling up the system with logs or making the logs unmanageably large.. + audit: + - 'grep -e Compress /etc/systemd/journald.conf' + remedeation: 'Edit the /etc/systemd/journald.conf file and add the following line: + Compress=yes' + check_type: multi_param + eval_expr: "'${0}' == 'Compress=yes';" + additional_info: 'The main configuration file /etc/systemd/journald.conf is read before any of the custom *.conf files. + If there are custom configs present, they override the main configuration parameters' + references: + - https://github.com/konstruktoid/hardening/blob/master/systemd.adoc#etcsyste mdjournaldconf + - + name: '4.1.2.3 Ensure journald is configured to write logfiles to persistent disk (Automated)' + description: Data from journald may be stored in volatile memory or persisted locally on the server. + Logs in memory will be lost upon a system reboot. By persisting logs to local disk on the server they are protected from loss. + audit: + - 'grep -e Storage /etc/systemd/journald.conf' + remedeation: 'Edit the /etc/systemd/journald.conf file and add the following line: + Storage=persistent' + check_type: multi_param + eval_expr: "'${0}' == 'Storage=persistent';" + additional_info: 'The main configuration file /etc/systemd/journald.conf is read before any of the custom *.conf files. + If there are custom configs present, they override the main configuration parameters' + references: + - https://github.com/konstruktoid/hardening/blob/master/systemd.adoc#etcsyste mdjournaldconf + - + name: '4.1.3 Ensure permissions on all logfiles are configured (Automated)' + description: Log files stored in /var/log/ contain logged information from many services on the system, or on log hosts others as well. + audit: + - 'stat -c %a $( find /var/log -type f)' + remedeation: 'Run the following commands to set permissions on all existing log files: + find /var/log -type f -exec chmod g-wx,o-rwx "{}" + -o -type d -exec chmod g- w,o-rwx "{}" +' + check_type: multi_param + eval_expr: "${0} <= 444;" + additional_info: 'You may also need to change the configuration for your logging software or services for any logs that had incorrect permissions.' \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/4.2_ensure_logrotate_configured.yml b/internal/benchmark/lxd/v1.0.0/4.2_ensure_logrotate_configured.yml new file mode 100644 index 0000000..638e32c --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/4.2_ensure_logrotate_configured.yml @@ -0,0 +1,20 @@ +--- +benchmark_type: lxd +categories: + - + name: Logging and Auditing + sub_category: + name: 4.2 Ensure logrotate is configured + audit_tests: + - + name: '4.2 Ensure logrotate is configured (Manual)' + description: The system includes the capability of rotating log files regularly to avoid filling up the system with logs or making the logs unmanageably large. + The file /etc/logrotate.d/rsyslog is the configuration file used to rotate log files created by rsyslog. + audit: + - 'Review /etc/logrotate.conf and /etc/logrotate.d/rsyslog and verify logs are rotated according to site policy.' + remedeation: 'Edit /etc/logrotate.conf and /etc/logrotate.d/rsyslog to ensure logs are rotated according to site policy.' + check_type: multi_param + additional_info: 'If no maxage setting is set for logrotate a situation can occur where logrotate is interrupted and fails to delete rotated logfiles. + It is recommended to set this to a value greater than the longest any log file should exist on your system to ensure that any such logfile + is removed but standard rotation settings are not overridden.' + type: manual \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/4.3_ensure_logrotate_assigns_appropriate_permissions.yml b/internal/benchmark/lxd/v1.0.0/4.3_ensure_logrotate_assigns_appropriate_permissions.yml new file mode 100644 index 0000000..dc5f582 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/4.3_ensure_logrotate_assigns_appropriate_permissions.yml @@ -0,0 +1,21 @@ +--- +benchmark_type: lxd +categories: + - + name: Logging and Auditing + sub_category: + name: 4.3 Ensure logrotate permissions + audit_tests: + - + name: '4.3 Ensure logrotate assigns appropriate permissions (Automated)' + description: Log files contain logged information from many services on the system, or on log hosts others as well. + audit: + - 'grep -E "^\s*create\s+\S+" /etc/logrotate.conf | grep -E -v ''\s(0)?[0-6][04]0\s''' + remedeation: 'Edit /etc/logrotate.conf and update the create line to read 0640 or more restrictive, following local site policy + Example + create 0640 root utmp' + check_type: multi_param + additional_info: 'If no maxage setting is set for logrotate a situation can occur where logrotate is interrupted and fails to delete rotated logfiles. + It is recommended to set this to a value greater than the longest any log file should exist on your system to ensure that any such logfile + is removed but standard rotation settings are not overridden.' + eval_expr: "'${0}' == '';" \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/5.1_configure_cron.yml b/internal/benchmark/lxd/v1.0.0/5.1_configure_cron.yml new file mode 100644 index 0000000..15ebada --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/5.1_configure_cron.yml @@ -0,0 +1,121 @@ +--- +benchmark_type: lxd +categories: + - + name: Access, Authentication and Authorization + sub_category: + name: 5.1 Configure cron + audit_tests: + - + name: '5.1.1 Ensure cron daemon is enabled (Automated)' + description: The cron daemon is used to execute batch jobs on the system. + audit: + - 'systemctl is-enabled cron 2> /dev/null' + remedeation: 'Based on your system configuration, run the appropriate one of the following commands to enable cron: + # systemctl --now enable cron' + check_type: multi_param + additional_info: 'Additional methods of enabling a service exist. Consult your distribution documentation for appropriate methods.' + eval_expr: "'${0}' == 'enabled';" + - + name: '5.1.2 Ensure permissions on /etc/crontab are configured (Automated)' + description: The /etc/crontab file is used by cron to control its own jobs. + The commands in this item make sure that root is the user and group owner of the file and that only the owner can access the file. + audit: + - 'stat /etc/crontab |grep Access |awk -F "Access:" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Run the following commands to set ownership and permissions on /etc/crontab : + # chown root:root /etc/crontab + # chmod og-rwx /etc/crontab' + check_type: multi_param + eval_expr: "'${0}' == '(0600/-rw-------) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '5.1.3 Ensure permissions on /etc/cron.hourly are configured (Automated)' + description: This directory contains system cron jobs that need to run on an hourly basis. + The files in this directory cannot be manipulated by the crontab command, but are instead edited by system administrators using a text editor. + The commands below restrict read/write and search access to user and group root, preventing regular users from accessing this directory. + audit: + - 'stat /etc/cron.hourly |grep Access |awk -F "Access:" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Run the following commands to set ownership and permissions on /etc/cron.hourly: + # chown root:root /etc/cron.hourly + # chmod og-rwx /etc/cron.hourly' + check_type: multi_param + eval_expr: "'${0}' == '(0700/drwx------) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '5.1.4 Ensure permissions on /etc/cron.daily are configured (Automated)' + description: The /etc/cron.daily directory contains system cron jobs that need to run on a daily basis. + The files in this directory cannot be manipulated by the crontab command, but are instead edited by system administrators + using a text editor. The commands below restrict read/write and search access to user and group root, preventing regular users from accessing this directory. + audit: + - 'stat /etc/cron.daily |grep Access |awk -F "Access:" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Run the following commands to set ownership and permissions on /etc/cron.daily: + # chown root:root /etc/cron.daily + # chmod og-rwx /etc/cron.daily' + check_type: multi_param + eval_expr: "'${0}' == '(0700/drwx------) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '5.1.5 Ensure permissions on /etc/cron.weekly are configured (Automated)' + description: The /etc/cron.weekly directory contains system cron jobs that need to run on a weekly basis. + The files in this directory cannot be manipulated by the crontab command, but are instead edited by system + administrators using a text editor. The commands below restrict read/write and search access to user and group root, preventing + regular users from accessing this directory. + audit: + - 'stat /etc/cron.weekly |grep Access |awk -F "Access:" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Run the following commands to set ownership and permissions on /etc/cron.weekly: + # chown root:root /etc/cron.weekly + # chmod og-rwx /etc/cron.weekly' + check_type: multi_param + eval_expr: "'${0}' == '(0700/drwx------) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '5.1.6 Ensure permissions on /etc/cron.monthly are configured (Automated)' + description: The /etc/cron.monthly directory contains system cron jobs that need to run on a monthly basis. + The files in this directory cannot be manipulated by the crontab command, but are instead edited by system + administrators using a text editor. The commands below restrict read/write and search access to user and group + root, preventing regular users from accessing this directory. + audit: + - 'stat /etc/cron.monthly |grep Access |awk -F "Access:" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Run the following commands to set ownership and permissions on /etc/cron.monthly: + # chown root:root /etc/cron.monthly + # chmod og-rwx /etc/cron.monthly' + check_type: multi_param + eval_expr: "'${0}' == '(0700/drwx------) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '5.1.7 Ensure permissions on /etc/cron.d are configured (Automated)' + description: The /etc/cron.d directory contains system cron jobs that need to run in a similar manner to the hourly, + daily weekly and monthly jobs from /etc/crontab , but require more granular control as to when they run. + The files in this directory cannot be manipulated by the crontab command, but are instead edited by system administrators + using a text editor. The commands below restrict read/write and search access to user and group root, preventing regular + users from accessing this directory. + audit: + - 'stat /etc/cron.d 2> /dev/null |grep Access |awk -F "Access:" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Run the following commands to set ownership and permissions on /etc/cron.d: + # chown root:root /etc/cron.d + # chmod og-rwx /etc/cron.d' + check_type: multi_param + eval_expr: "'${0}' == '(0700/drwx------) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '5.1.8 Ensure at/cron is restricted to authorized users (Automated)' + description: Configure /etc/cron.allow and /etc/at.allow to allow specific users to use these services. + If /etc/cron.allow or /etc/at.allow do not exist, then /etc/at.deny and /etc/cron.deny are checked. + Any user not specifically defined in those files is allowed to use at and cron. By removing the files, + only users in /etc/cron.allow and /etc/at.allow are allowed to use at and cron. Note that even though + a given user is not listed in cron.allow , cron jobs can still be run as that user. + The cron.allow file only controls administrative access to the crontab command for scheduling and modifying cron jobs. + audit: + - 'stat /etc/cron.deny 2> /dev/null' + - 'stat /etc/at.deny 2> /dev/null' + - 'stat /etc/cron.allow 2> /dev/null |grep Access |awk -F "Access:" ''{print $2}'' |awk ''FNR <= 1''' + - 'stat /etc/at.allow 2> /dev/null |grep Access |awk -F "Access:" ''{print $2}'' |awk ''FNR <= 1''' + + remedeation: 'Run the following commands to remove /etc/cron.deny and /etc/at.deny and create and set permissions and ownership for /etc/cron.allow and /etc/at.allow : + # rm /etc/cron.deny + # rm /etc/at.deny + # touch /etc/cron.allow + # touch /etc/at.allow + # chmod o-rwx /etc/cron.allow + # chmod g-wx /etc/cron.allow + # chmod o-rwx /etc/at.allow + # chmod g-wx /etc/at.allow + # chown root:root /etc/cron.allow + # chown root:root /etc/at.allow' + check_type: multi_param + eval_expr: "'${0}' == ''; && '${1}' == ''; && '${2}' == '(0640/-rw-r-----) Uid: ( 0/ root) Gid: ( 0/ root)' && '${3}' == '(0640/-rw-r-----) Uid: ( 0/ root) Gid: ( 0/ root)';" + diff --git a/internal/benchmark/lxd/v1.0.0/5.2_ssh_server_configuration.yml b/internal/benchmark/lxd/v1.0.0/5.2_ssh_server_configuration.yml new file mode 100644 index 0000000..c29872f --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/5.2_ssh_server_configuration.yml @@ -0,0 +1,359 @@ +--- +benchmark_type: lxd +categories: + - + name: Access, Authentication and Authorization + sub_category: + name: 5.2 SSH Server Configuration + audit_tests: + - + name: '5.2.1 Ensure permissions on /etc/ssh/sshd_config are configured (Automated)' + description: The /etc/ssh/sshd_config file contains configuration specifications for sshd. The command below sets the owner and group of the file to root. + audit: + - 'stat /etc/ssh/sshd_config 2> /dev/null |grep Access |awk -F "Access:" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Run the following commands to set ownership and permissions on /etc/ssh/sshd_config: + # chown root:root /etc/ssh/sshd_config + # chmod og-rwx /etc/ssh/sshd_config' + check_type: multi_param + additional_info: 'Additional methods of enabling a service exist. Consult your distribution documentation for appropriate methods.' + eval_expr: "'${0}' == '(0600/-rw-------) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '5.2.2 Ensure permissions on SSH private host key files are configured (Automated)' + description: An SSH private key is one of two files used in SSH public key authentication. + In this authentication method, The possession of the private key is proof of identity. + Only a private key that corresponds to a public key will be able to authenticate successfully. + The private keys need to be stored and handled carefully, and no copies of the private key should be distributed. + audit: + - 'find /etc/ssh -xdev -type f -name ''ssh_host_*_key'' -exec stat {} \; | grep "Access: (" |awk -F "Access:" ''{print $2}''' + remedeation: 'Run the following commands to set ownership and permissions on the private SSH host key files: + # find /etc/ssh -xdev -type f -name ''ssh_host_*_key'' -exec chown root:root {} \; + # find /etc/ssh -xdev -type f -name ''ssh_host_*_key'' -exec chmod 0600 {} \;' + check_type: multi_param + eval_expr: "'${0}' == '(0600/-rw-------) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '5.2.3 Ensure permissions on SSH public host key files are configured (Automated)' + description: An SSH public key is one of two files used in SSH public key authentication. + In this authentication method, a public key is a key that can be used for verifying digital + signatures generated using a corresponding private key. Only a public key that corresponds to a private + key will be able to authenticate successfully. + audit: + - 'find /etc/ssh -xdev -type f -name ''ssh_host_*_key.pub'' -exec stat {} \; | grep "Access: (" |awk -F "Access:" ''{print $2}''' + remedeation: 'Run the following commands to set permissions and ownership on the SSH host public key files: + # find /etc/ssh -xdev -type f -name ''ssh_host_*_key.pub'' -exec chmod go-wx {} \; + # find /etc/ssh -xdev -type f -name ''ssh_host_*_key.pub'' -exec chown root:root {} \;' + check_type: multi_param + eval_expr: "'${0}' == '(0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '5.2.4 Ensure SSH Protocol is not set to 1 (Automated)' + description: Older versions of SSH support two different and incompatible protocols + SSH1 and SSH2. SSH1 was the original protocol and was subject to security issues. + SSH2 is more advanced and secure. + audit: + - 'sshd -T 2> /dev/null | grep -Ei ''^\s*protocol\s+(1|1\s*,\s*2|2\s*,\s*1)\s*''' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: Protocol 2' + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: 'This command not longer exists in newer versions of SSH. + This check is still being included for systems that may be running an older version of SSH. As of + openSSH version 7.4 this parameter will not cause an issue when included.' + - + name: '5.2.5 Ensure SSH LogLevel is appropriate (Automated)' + description: INFO level is the basic level that only records login activity of SSH users. In many situations, + such as Incident Response, it is important to determine when a particular user was active on a system. + The logout record can eliminate those users who disconnected, which helps narrow the field. + VERBOSE level specifies that login and logout activity as well as the key fingerprint for any SSH key used for + login will be logged. This information is important for SSH key management, especially in legacy environments. + audit: + - 'sshd -T 2> /dev/null | grep loglevel' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: LogLevel VERBOSE + OR + LogLevel INFO' + check_type: multi_param + eval_expr: "'${0}' == 'loglevel VERBOSE'; || '${0}' == 'loglevel INFO';" + default_value: LogLevel INFO + references: + - https://www.ssh.com/ssh/sshd_config/ + - + name: '5.2.6 Ensure SSH X11 forwarding is disabled (Automated)' + description: The X11Forwarding parameter provides the ability to tunnel X11 traffic through the connection to enable remote graphic connections. + audit: + - 'sshd -T 2> /dev/null| grep x11forwarding' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: + X11Forwarding no' + check_type: multi_param + eval_expr: "'${0}' == 'x11forwarding no';" + - + name: '5.2.7 Ensure SSH MaxAuthTries is set to 4 or less (Automated)' + description: The MaxAuthTries parameter specifies the maximum number of authentication attempts permitted per connection. + When the login failure count reaches half the number, error messages will be written to the syslog file detailing the login failure. + audit: + - 'sshd -T 2> /dev/null| grep maxauthtries' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: + MaxAuthTries 4' + check_type: multi_param + eval_expr: "'${0}' == 'maxAuthTries 4';" + default_value: MaxAuthTries 6 + - + name: '5.2.8 Ensure SSH IgnoreRhosts is enabled (Automated)' + description: The IgnoreRhosts parameter specifies that .rhosts and .shosts + files will not be used in RhostsRSAAuthentication or HostbasedAuthentication. + audit: + - 'sshd -T 2> /dev/null| grep ignorerhosts' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: + IgnoreRhosts yes' + check_type: multi_param + eval_expr: "'${0}' == 'ignoreRhosts yes';" + default_value: IgnoreRhosts yes + - + name: '5.2.9 Ensure SSH HostbasedAuthentication is disabled (Automated)' + description: The HostbasedAuthentication parameter specifies if authentication is allowed through + trusted hosts via the user of .rhosts, or /etc/hosts.equiv, along with successful public key + client host authentication. This option only applies to SSH Protocol Version 2. + audit: + - 'sshd -T 2> /dev/null| grep hostbasedauthentication' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: + hostbasedauthentication no' + check_type: multi_param + eval_expr: "'${0}' == 'hostbasedauthentication no';" + default_value: hostbasedAuthentication no + - + name: '5.2.10 Ensure SSH root login is disabled (Automated)' + description: The PermitRootLogin parameter specifies if the root user can log in using ssh. The default is no. + audit: + - 'sshd -T 2> /dev/null| grep permitrootlogin' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows:: + permitrootlogin no' + check_type: multi_param + eval_expr: "'${0}' == 'permitrootlogin no';" + default_value: PermitRootLogin without-password + - + name: '5.2.11 Ensure SSH PermitEmptyPasswords is disabled (Automated)' + description: The PermitEmptyPasswords parameter specifies if the SSH server allows login to accounts with empty password strings. + audit: + - 'sshd -T 2> /dev/null| grep permitemptypasswords' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows:: + permitemptypasswords no' + check_type: multi_param + eval_expr: "'${0}' == 'permitemptypasswords no';" + default_value: PermitEmptyPasswords no + - + name: '5.2.12 Ensure SSH PermitUserEnvironment is disabled (Automated)' + description: The PermitUserEnvironment option allows users to present environment options to the ssh daemon. + audit: + - 'sshd -T 2> /dev/null| grep permituserenvironment' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows:: + permituserenvironment no' + check_type: multi_param + eval_expr: "'${0}' == 'permituserenvironment no';" + default_value: permituserenvironment no + - + name: '5.2.13 Ensure only strong Ciphers are used (Automated)' + description: This variable limits the ciphers that SSH can use during communication. + audit: + - 'sshd -T 2> /dev/null| grep ciphers |awk -F "ciphers" ''{print $2}'' |awk ''FNR <= 1'' | sed -e $''s/,/\\\n/g''' + remedeation: 'Edit the /etc/ssh/sshd_config file add/modify the Ciphers line to contain a comma separated list of the site approved ciphers + Example: + Ciphers chacha20-poly1305@openssh.com, + aes256-gcm@openssh.com, + aes128-gcm@openssh.com, + aes256-ctr, + aes192-ctr, + aes128-ctr' + check_type: multi_param + eval_expr: "'${0}' IN ('3des-cbc','aes128-cbc','aes192-cbc','aes256-cbc','arcfour','arcfour128','arcfour256','blowfish-cbc','cast128-cbc','rijndael-cbc@lysator.liu.se');" + default_value: Ciphers chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128- gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256- cbc,blowfish-cbc,cast128-cbc,3des-cbc + references: + - https://nvd.nist.gov/vuln/detail/CVE-2016-2183 2. https://nvd.nist.gov/vuln/detail/CVE-2015-2808 3. https://www.kb.cert.org/vuls/id/565052 + - https://www.openssh.com/txt/cbc.adv + - https://nvd.nist.gov/vuln/detail/CVE-2008-5161 6. https://nvd.nist.gov/vuln/detail/CVE-2013-4548 7. https://www.kb.cert.org/vuls/id/565052 + - https://www.openssh.com/txt/cbc.adv + - SSHD_CONFIG(5) + additional_info: 'Some organizations may have stricter requirements for approved ciphers. Ensure that ciphers used are in compliance with site policy. + The only "strong" ciphers currently FIPS 140-2 compliant are: aes256-ctr,aes192- ctr,aes128-ctr + CVE-2013-4548 referenced above applies to OpenSSH versions 6.2 and 6.3. If running these versions of Open SSH, Please upgrade to version 6.4 or later to fix the vulnerability, or disable AES-GCM in the server configuration. + The Following are the supported ciphers in openSSH: + 3des-cbc + aes128-cbc + aes192-cbc + aes256-cbc + aes128-ctr + aes192-ctr + aes256-ctr + aes128-gcm@openssh.com + aes256-gcm@openssh.com + arcfour + arcfour128 + arcfour256 + blowfish-cbc + cast128-cbc + rijndael-cbc@lysator.liu.se + chacha20-poly1305@openssh.com' + - + name: '5.2.14 Ensure only strong MAC algorithms are used (Automated)' + description: This variable limits the types of MAC algorithms that SSH can use during communication. + audit: + - 'sshd -T | grep -i "MACs" |awk -F "macs" ''{print $2}'' |awk ''FNR <= 1'' | sed -e $''s/,/\\\n/g''' + remedeation: 'Edit the /etc/ssh/sshd_config file and add/modify the MACs line to contain a comma separated list of the site approved MACs + Example: + MACs hmac-sha2-512-etm@openssh.com, + hmac-sha2-256-etm@openssh.com, + hmac-sha2-512, + hmac-sha2-256' + check_type: multi_param + eval_expr: "!('${0}' IN ('hmac-md5','hmac-md5-96','hmac-ripemd160','hmac-sha1','hmac-sha1-96','umac-64@openssh.com','umac-128@openssh.com','hmac-md5-etm@openssh.com','hmac-md5-96-etm@openssh.com','hmac-ripemd160-etm@openssh.com','hmac-sha1-etm@openssh.com','hmac-sha1-96-etm@openssh.com','umac-64-etm@openssh.com','umac-128-etm@openssh.com');)" + default_value: MACs umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256- etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1- etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2- 256,hmac-sha2-512,hmac-sha1,hmac-sha1-etm@openssh.com + references: + - More information on SSH downgrade attacks can be found here http://www.mitls.org/pages/attacks/SLOTH + - SSHD_CONFIG(5) + additional_info: 'Some organizations may have stricter requirements for approved MACs. Ensure that MACs used are in compliance with site policy. + The only "strong" MACs currently FIPS 140-2 approved are hmac-sha2-256 and hmac- sha2-512 + The Supported MACs are: + hmac-md5 + hmac-md5-96 + hmac-ripemd160 + hmac-sha1 + hmac-sha1-96 + hmac-sha2-256 + hmac-sha2-512 + umac-64@openssh.com + umac-128@openssh.com + hmac-md5-etm@openssh.com + hmac-md5-96-etm@openssh.com + hmac-ripemd160-etm@openssh.com + hmac-sha1-etm@openssh.com + hmac-sha1-96-etm@openssh.com + hmac-sha2-256-etm@openssh.com + hmac-sha2-512-etm@openssh.com + umac-64-etm@openssh.com + umac-128-etm@openssh.com' + - + name: '5.2.15 Ensure only strong Key Exchange algorithms are used (Automated)' + description: Key exchange is any method in cryptography by which cryptographic keys are exchanged between two parties, allowing use of + a cryptographic algorithm. If the sender and receiver wish to exchange encrypted messages, + each must be equipped to encrypt messages to be sent and decrypt messages received + audit: + - 'sshd -T | grep -i kexalgorithms |awk -F "kexalgorithms" ''{print $2}'' |awk ''FNR <= 1'' | sed -e $''s/,/\\\n/g''' + remedeation: 'Edit the /etc/ssh/sshd_config file add/modify the KexAlgorithms line to contain a comma separated list of the site approved key exchange algorithms + Example: + KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org, + diffie-hellman-group14-sha256,diffie-hellman-group16-sha512, + diffie-hellman-group18- sha512, + ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256, + diffie- hellman-group-exchange-sha256' + check_type: multi_param + eval_expr: "!('${0}' IN ('diffie-hellman-group1-sha1','diffie-hellman-group14-sha1','diffie-hellman-group-exchange-sha1');)" + default_value: KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2- nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange- sha256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1 + additional_info: 'Kex algorithms have a higher preference the earlier they appear in the list + Some organizations may have stricter requirements for approved Key exchange algorithms. Ensure that Key exchange algorithms used are in compliance with site policy. + The only Key Exchange Algorithms currently FIPS 140-2 approved are: ecdh-sha2- nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange- sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman- group14-sha256 + The Key Exchange algorithms supported by OpenSSH 7 are: + curve25519-sha256 curve25519-sha256@libssh.org diffie-hellman-group1-sha1 diffie-hellman-group14-sha1 diffie-hellman-group-exchange-sha1 + diffie-hellman-group-exchange-sha256 ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521' + - + name: '5.2.16 Ensure SSH Idle Timeout Interval is configured (Automated)' + description: The two options ClientAliveInterval and ClientAliveCountMax control the timeout of ssh sessions. + When the ClientAliveInterval variable is set, ssh sessions that have no activity for the specified length of + time are terminated. When the ClientAliveCountMax variable is set, sshd will send client alive messages at every + ClientAliveInterval interval. When the number of consecutive client alive messages are sent with no response from the client, + the ssh session is terminated. For example, if the ClientAliveInterval is set to 15 seconds and the ClientAliveCountMax is set to 3, + the client ssh session will be terminated after 45 seconds of idle time. + audit: + - 'sshd -T 2> /dev/null| grep clientaliveinterval |awk -F "clientaliveinterval" ''{print $2}'' |awk ''FNR <= 1''' + - 'sshd -T 2> /dev/null| grep clientalivecountmax |awk -F "clientalivecountmax" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameters according to site policy: + ClientAliveInterval 300 + ClientAliveCountMax 0' + check_type: multi_param + eval_expr: "${0} > 1 && ${0} < 300 && ${1} <= 3" + default_value: ClientAliveInterval 300 ClientAliveCountMax 0 + - + name: '5.2.17 Ensure SSH LoginGraceTime is set to one minute or less (Automated)' + description: The LoginGraceTime parameter specifies the time allowed for successful authentication to the SSH server. + The longer the Grace period is the more open unauthenticated connections can exist. + Like other session controls in this session the Grace Period should be limited to appropriate organizational + limits to ensure the service is available for needed access. + audit: + - 'sshd -T 2> /dev/null| grep logingracetime |awk -F "logingracetime" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: LoginGraceTime 60' + check_type: multi_param + eval_expr: "${0} > 1 && ${0} < 60" + default_value: LoginGraceTime 120 + - + name: '5.2.18 Ensure SSH access is limited (Automated)' + description: There are several options available to limit which users and group can access the system via SSH. + It is recommended that at least one of the following options be leveraged + AllowUsers + The AllowUsers variable gives the system administrator the option of allowing specific users to ssh into the system. + The list consists of space separated user names. Numeric user IDs are not recognized with this variable. If a system administrator wants to restrict user access further by only allowing the allowed users to log in from a particular host, the entry can be specified in the form of user@host. + AllowGroups + The AllowGroups variable gives the system administrator the option of allowing specific groups of users to ssh into the system. + The list consists of space separated group names. Numeric group IDs are not recognized with this variable. + DenyUsers + The DenyUsers variable gives the system administrator the option of denying specific users to ssh into the system. + The list consists of space separated user names. Numeric user IDs are not recognized with this variable. If a system administrator wants to restrict user access further by specifically denying a user's access from a particular host, the entry can be specified in the form of user@host. + DenyGroups + The DenyGroups variable gives the system administrator the option of denying specific groups of users to ssh into the system. + The list consists of space separated group names. Numeric group IDs are not recognized with this variable. + audit: + - 'sshd -T 2> /dev/null| grep allowusers |awk -F "allowusers" ''{print $2}'' |awk ''FNR <= 1''' + - 'sshd -T 2> /dev/null| grep allowgroups |awk -F "allowgroups" ''{print $2}'' |awk ''FNR <= 1''' + - 'sshd -T 2> /dev/null| grep denyusers |awk -F "denyusers" ''{print $2}'' |awk ''FNR <= 1''' + - 'sshd -T 2> /dev/null| grep denygroups |awk -F "denygroups" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Edit the /etc/ssh/sshd_config file to set one or more of the parameter as follows: + AllowUsers + AllowGroups + DenyUsers + DenyGroups ' + check_type: multi_param + eval_expr: "'${0}' != ''; && '${1}' != ''; && '$2' != ''; && '${3}' != '';" + - + name: '5.2.19 Ensure SSH warning banner is configured (Automated)' + description: The Banner parameter specifies a file whose contents must be sent to the remote user before authentication is permitted. + By default, no banner is displayed. + audit: + - 'sshd -T 2> /dev/null| grep banner' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: Banner /etc/issue.net' + check_type: multi_param + eval_expr: "'${0}' == 'banner /etc/issue.net';" + - + name: '5.2.20 Ensure SSH PAM is enabled (Automated)' + description: UsePAM Enables the Pluggable Authentication Module interface. + If set to “yes” this will enable PAM authentication using ChallengeResponseAuthentication and PasswordAuthentication + in addition to PAM account and session module processing for all authentication types + audit: + - 'sshd -T 2> /dev/null| grep -i usepam' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: UsePAM yes' + check_type: multi_param + eval_expr: "'${0}' == 'usepam yes';" + default_value: usepam yes + - + name: '5.2.21 Ensure SSH AllowTcpForwarding is disabled (Automated)' + description: SSH port forwarding is a mechanism in SSH for tunneling application ports from the client to the server, + or servers to clients. It can be used for adding encryption to legacy applications, going through firewalls, + and some system administrators and IT professionals use it for opening backdoors into the internal network from their home machines + audit: + - 'sshd -T 2> /dev/null| grep -i allowtcpforwarding' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: + AllowTcpForwarding no' + check_type: multi_param + eval_expr: "'${0}' == 'allowtcpforwarding no';" + default_value: allowTcpForwarding yes + - + name: '5.2.22 Ensure SSH MaxStartups is configured (Automated)' + description: The MaxStartups parameter specifies the maximum number of concurrent unauthenticated connections to the SSH daemon. + audit: + - 'sshd -T 2> /dev/null| grep -i maxstartups' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: maxstartups 10:30:60' + check_type: multi_param + eval_expr: "'${0}' == 'maxstartups 10:30:60';" + additional_info: 'Local site policy may be more restrictive' + - + name: '5.2.23 Ensure SSH MaxSessions is set to 4 or less (Automated)' + description: The MaxSessions parameter specifies the maximum number of open sessions permitted from a given connection. + audit: + - 'sshd -T 2> /dev/null| grep -i maxsessions' + remedeation: 'Edit the /etc/ssh/sshd_config file to set the parameter as follows: MaxSessions 4' + check_type: multi_param + eval_expr: "'${0}' == 'maxsessions 4';" + default_value: MaxSessions 10 + diff --git a/internal/benchmark/lxd/v1.0.0/5.3_configure_pam.yml b/internal/benchmark/lxd/v1.0.0/5.3_configure_pam.yml new file mode 100644 index 0000000..9cd4ce9 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/5.3_configure_pam.yml @@ -0,0 +1,96 @@ +--- +benchmark_type: lxd +categories: + - + name: Access, Authentication and Authorization + sub_category: + name: 5.3 Configure PAM + audit_tests: + - + name: '5.3.1 Ensure password creation requirements are configured (Automated)' + description: The pam_pwquality.so module checks the strength of passwords. It performs checks such as making sure a password is not + a dictionary word, it is a certain length, contains a mix of characters (e.g. alphabet, numeric, other) and more. + The following are definitions of the pam_pwquality.so options. + The following options are set in the /etc/security/pwquality.conf file Password Length + minlen = 14 - password must be 14 characters or more Password complexity + minclass = 4 - The minimum number of required classes of characters for the new password (digits, uppercase, lowercase, others) + OR + dcredit = -1 - provide at least one digit + ucredit = -1 - provide at least one uppercase character + ocredit = -1 - provide at least one special character + lcredit = -1 - provide at least one lowercase character + The following is st in the /etc/pam.d/common-password file + retry=3 - Allow 3 tries before sending back a failure. + The settings shown above are one possible policy. + Alter these values to conform to your own organization's password policies. + audit: + - 'grep ''^\s*minlen\s*'' /etc/security/pwquality.conf 2> /dev/null' + - 'grep ''^\s*minclass\s*'' /etc/security/pwquality.conf 2> /dev/null' + - 'grep -E ''^\s*[duol]credit\s*'' /etc/security/pwquality.conf 2> /dev/null' + - 'grep -E ''^\s*password\s+(requisite|required)\s+pam_pwquality\.so\s+(\S+\s+)*retry=[1-3]\s*(\s+\S+\s*)*(\s+#.*)?$'' /etc/pam.d/common-password |awk -F "pam_pwquality.so" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Run the following command to install the pam_pwquality module: + apt install libpam-pwquality + Edit the file /etc/security/pwquality.conf and add or modify the following line for password length to conform to site policy + minlen = 14 + Edit the file /etc/security/pwquality.conf and add or modify the following line for password complexity to conform to site policy + minclass = 4 + OR + Edit the /etc/pam.d/common-password file to include the appropriate options for pam_pwquality.so and to conform to site policy: + password requisite pam_pwquality.so retry=3' + check_type: multi_param + additional_info: 'Additional module options may be set, recommendation requirements only cover including try_first_pass and minlen set to 14 or more. + Settings in /etc/security/pwquality.conf must use spaces around the = symbol.' + eval_expr: "'${0}' == 'minlen = 14'; && '${1}' == 'minclass = 4'; && '${2}' IN ('dcredit = -1','ucredit = -1','lcredit = -1','ocredit = -1'); && '${3}' == 'retry=3';" + - + name: '5.3.2 Ensure lockout for failed password attempts is configured (Automated)' + description: Lock out users after n unsuccessful consecutive login attempts. The first sets of changes are made to the PAM configuration files. The second set of changes are applied to the program specific PAM configuration file. The second set of changes must be applied to each program that will lock out users. Check the documentation for each secondary program for instructions on how to configure them to work with PAM. + deny=n - n represents the number of failed attempts before the account is locked + unlock_time=n - n represents the number of seconds before the account is unlocked + audit - Will log the user name into the system log if the user is not found. + silent - Don't print informative messages. + Set the lockout number and unlock time in accordance with local site policy. + audit: + - 'grep "pam_tally2" /etc/pam.d/common-auth 2> /dev/null' + - 'grep -E "pam_(tally2|deny)\.so" /etc/pam.d/common-account |awk -F " " ''{print $3}'' 2> /dev/null' + remedeation: 'Edit the /etc/pam.d/common-auth file and add the auth line below: + auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900 Edit + the /etc/pam.d/common-account file and add the account lines bellow: + account requisite pam_deny.so + account required pam_tally2.so + Note: If a user has been locked out because they have reached the maximum consecutive failure count defined + by deny= in the pam_tally2.so module, the user can be unlocked by issuing the command /sbin/pam_tally2 -u + --reset. This command sets the failed count to 0, effectively unlocking the user. +' + check_type: multi_param + additional_info: 'BUG In pam_tally2.so + To work around this issue you have to add pam_tally2 to the account section account required pam_tally2.sofor + the counter to reset to 0 when using sudo + Use of the "audit" keyword may log credentials in the case of user error during authentication. This risk + should be evaluated in the context of the site policies of your organization.' + eval_expr: "'${0}' == 'auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900'; && '${1}' IN ('pam_deny.so','pam_tally2.so');" + - + name: '5.3.3 Ensure password reuse is limited (Automated)' + description: The /etc/security/opasswd file stores the users' old passwords and can be checked to ensure that users are not recycling recent passwords. + audit: + - 'grep -E ''^password\s+required\s+pam_pwhistory.so'' /etc/pam.d/common- password 2> /dev/null' + remedeation: 'Edit the /etc/pam.d/common-password file to include the remember option and conform to site policy as shown: + password required pam_pwhistory.so remember=5' + check_type: multi_param + additional_info: 'Additional module options may be set, recommendation only covers those listed here.' + eval_expr: "'${0}' == 'password required pam_pwhistory.so remember=5';" + - + name: '5.3.4 Ensure password hashing algorithm is SHA-512 (Automated)' + description: The commands below change password encryption from md5 to sha512 (a much stronger hashing algorithm). + All existing accounts will need to perform a password change to upgrade the stored hashes to the new algorithm. + audit: + - 'grep -E ''^\s*password\s+(\S+\s+)+pam_unix\.so\s+(\S+\s+)*sha512\s*(\S+\s*)*(\s+#.*)?$'' /etc/pam.d/common-password |grep sha512 2> /dev/null' + remedeation: 'Edit the /etc/pam.d/common-password file to include the sha512 option for pam_unix.so as shown: + password [success=1 default=ignore] pam_unix.so sha512' + check_type: multi_param + additional_info: 'Consult your documentation for the appropriate PAM file and module. + Additional module options may be set, recommendation only covers those listed here. + If it is determined that the password algorithm being used is not SHA-512, once it is changed, it is recommended that all user ID''s + be immediately expired and forced to change their passwords on next login. + To accomplish that, the following commands can be used. Any system accounts that need to be expired should be + carefully done separately by the system administrator to prevent any potential problems.' + eval_expr: "'${0}' != '';" diff --git a/internal/benchmark/lxd/v1.0.0/5.4_user_accounts_and_environment.yml b/internal/benchmark/lxd/v1.0.0/5.4_user_accounts_and_environment.yml new file mode 100644 index 0000000..4c5f7b8 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/5.4_user_accounts_and_environment.yml @@ -0,0 +1,134 @@ +--- +benchmark_type: lxd +categories: + - + name: Access, Authentication and Authorization + sub_category: + name: 5.4 User Accounts and Environment + audit_tests: + - + name: '5.4.1.1 Ensure password expiration is 365 days or less (Automated)' + description: The PASS_MAX_DAYS parameter in /etc/login.defs allows an administrator to force passwords to expire once they reach a defined age. + It is recommended that the PASS_MAX_DAYS parameter be set to less than or equal to 365 days. + audit: + - 'grep PASS_MAX_DAYS /etc/login.defs 2> /dev/null|grep -v ''#'' | awk -F "PASS_MAX_DAYS" ''{print $2}'' |awk ''FNR <= 1''' + - 'grep -E ''^[^:]+:[^!*]'' /etc/shadow 2> /dev/null| cut -d: -f1,5 | awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Set the PASS_MAX_DAYS parameter to conform to site policy in /etc/login.defs : PASS_MAX_DAYS 365 + Modify user parameters for all users with a password set to match: + # chage --maxdays 365 ' + check_type: multi_param + additional_info: 'You can also check this setting in /etc/shadow directly. The 5th field should be 365 or less for all users with a password. + Note: A value of -1 will disable password expiration. Additionally the password expiration must be + greater than the minimum days between password changes or users will be unable to change their password.' + eval_expr: "${0} <= 365; && ${1} <= 365" + - + name: '5.4.1.2 Ensure minimum days between password changes is configured (Automated)' + description: The PASS_MIN_DAYS parameter in /etc/login.defs allows an administrator to prevent users from changing + their password until a minimum number of days have passed since the last time the user changed their password. + It is recommended that PASS_MIN_DAYS parameter be set to 1 or more days. + audit: + - 'grep PASS_MIN_DAYS /etc/login.defs 2> /dev/null|grep -v ''#'' | awk -F "PASS_MIN_DAYS" ''{print $2}'' |awk ''FNR <= 1''' + - 'grep -E ''^[^:]+:[^!*]'' /etc/shadow 2> /dev/null| cut -d: -f1,4 | awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Set the PASS_MIN_DAYS parameter to 1 in /etc/login.defs : PASS_MIN_DAYS 1 + Modify user parameters for all users with a password set to match: # chage --mindays 1 ' + check_type: multi_param + additional_info: 'You can also check this setting in /etc/shadow directly. The 4th field should be 1 or more for all users with a password.' + eval_expr: "${0} >= 1 && ${1} >= 1" + - + name: '5.4.1.3 Ensure password expiration warning days is 7 or more (Automated)' + description: The PASS_WARN_AGE parameter in /etc/login.defs allows an administrator to notify users + that their password will expire in a defined number of days. It is recommended that the + PASS_WARN_AGE parameter be set to 7 or more days. + audit: + - 'grep PASS_WARN_AGE /etc/login.defs 2> /dev/null|grep -v ''#'' | awk -F "PASS_WARN_AGE" ''{print $2}'' |awk ''FNR <= 1''' + - 'grep -E ''^[^:]+:[^!*]'' /etc/shadow 2> /dev/null| cut -d: -f1,6 | awk -F ":" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Set the PASS_WARN_AGE parameter to 7 in /etc/login.defs : PASS_WARN_AGE 7 + Modify user parameters for all users with a password set to match: + # chage --warndays 7 ' + check_type: multi_param + additional_info: 'You can also check this setting in /etc/shadow directly. The 6th field should be 7 or more for all users with a password.' + eval_expr: "${0} >= 7 && ${1} >= 7" + - + name: '5.4.1.4 Ensure inactive password lock is 30 days or less (Automated)' + description: User accounts that have been inactive for over a given period of time can be automatically disabled. + It is recommended that accounts that are inactive for 30 days after password expiration be disabled. + audit: + - 'useradd -D 2> /dev/null| grep INACTIVE | awk -F "INACTIVE=" ''{print $2}'' |awk ''FNR <= 1''' + - 'grep -E ''^[^:]+:[^]'' /etc/shadow 2> /dev/null| cut -d: -f1,7 | awk -F ":" ''{print $2}'' |awk ''FNR <= 1'' |sed ''/^$/d''' + remedeation: 'Run the following command to set the default password inactivity period to 30 days: + # useradd -D -f 30 + Modify user parameters for all users with a password set to match: + # chage --inactive 30 ' + check_type: multi_param + additional_info: 'You can also check this setting in /etc/shadow directly. The 7th field should be 30 or less for all users with a password. + Note: A value of -1 would disable this setting.' + eval_expr: "${0} <= 30 && ${1} == 30" + - + name: '5.4.1.5 Ensure all users last password change date is in the past (Automated)' + description: All users should have a password change date in the past. + audit: + - 'for usr in $(cut -d: -f1 /etc/shadow); do [[ $(chage --list $usr | grep ''^Last password change'' | cut -d: -f2) > $(date) ]] && echo "$usr :$(chage -- list $usr | grep ''^Last password change'' | cut -d: -f2)"; done' + remedeation: 'Investigate any users with a password change date in the future and correct them. Locking the account, expiring the password, or resetting the password manually may be appropriate.' + check_type: multi_param + eval_expr: "'${0}' == ''" + - + name: '5.4.2 Ensure system accounts are secured (Automated)' + description: There are a number of accounts provided with most distributions that are used to manage applications and are not intended to provide an interactive shell. + audit: + - 'awk -F: ''($1!="root" && $1!="sync" && $1!="shutdown" && $1!="halt" && $1!~/^\+/ && $3<''"$(awk ''/^\s*UID_MIN/{print $2}'' /etc/login.defs)"'' && $7!="''"$(which nologin)"''" && $7!="/bin/false") {print}'' /etc/passwd' + - 'awk -F: ''($1!="root" && $1!~/^\+/ && $3<''"$(awk ''/^\s*UID_MIN/{print $2}'' /etc/login.defs)"'') {print $1}'' /etc/passwd | xargs -I ''{}'' passwd -S ''{}'' | awk ''($2!="L" && $2!="LK") {print $1}''' + remedeation: 'Run the commands appropriate for your distribution: + Set the shell for any accounts returned by the audit to nologin: + # usermod -s $(which nologin) + Lock any non root accounts returned by the audit: + # usermod -L + The following command will set all system accounts to a non login shell: + awk -F: ''($1!="root" && $1!="sync" && $1!="shutdown" && $1!="halt" && $1!~/^\+/ && $3<''"$(awk ''/^\s*UID_MIN/{print $2}'' /etc/login.defs)"'' && $7!="''"$(which nologin)"''" && $7!="/bin/false") {print $1}'' /etc/passwd | while read -r user; do usermod -s "$(which nologin)" "$user"; done + The following command will automatically lock not root system accounts: + awk -F: ''($1!="root" && $1!~/^\+/ && $3<''"$(awk ''/^\s*UID_MIN/{print $2}'' /etc/login.defs)"'') {print $1}'' /etc/passwd | xargs -I ''{}'' passwd -S ''{}'' | awk ''($2!="L" && $2!="LK") {print $1}'' | while read -r user; do usermod -L "$user"; done' + check_type: multi_param + eval_expr: "'${0}' == '' && '${1}' == ''" + additional_info: 'The root, sync, shutdown, and halt users are exempted from requiring a non-login shell.' + - + name: '5.4.3 Ensure default group for the root account is GID 0 (Automated)' + description: The usermod command can be used to specify which group the root user belongs to. This affects permissions of files that are created by the root user. + audit: + - 'grep "^root:" /etc/passwd 2> /dev/null| cut -f4 -d:' + remedeation: 'Run the following command to set the root user default group to GID 0 : + # usermod -g 0 root' + check_type: multi_param + eval_expr: "'${0}' == '0'" + - + name: '5.4.4 Ensure default user umask is 027 or more restrictive (Automated)' + description: The default umask determines the permissions of files created by users. + The user creating the file has the discretion of making their files and directories readable + by others via the chmod command. Users who wish to allow their files and directories to be readable by + others by default may choose a different default umask by inserting the umask command into the standard shell + configuration files ( .profile , .bashrc , etc.) in their home directories. + audit: + - 'grep "umask" /etc/bash.bashrc 2> /dev/null |awk -F "umask" ''{print $2}'' |awk ''FNR <= 1''' + - 'grep "umask" /etc/profile /etc/profile.d/*.sh 2> /dev/null |awk -F "umask" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Edit the /etc/bash.bashrc, /etc/profile and /etc/profile.d/*.sh files (and the appropriate files for any other shell supported on your system) and add or edit any umask parameters as follows: + umask 027' + check_type: multi_param + eval_expr: "${0} >= 27 && ${1} >= 27" + additional_info: 'The audit and remediation in this recommendation apply to bash and shell. If other shells are supported on the system, + it is recommended that their configuration files also are checked. + Other methods of setting a default user umask exist however the shell configuration files + are the last run and will override other settings if they exist therefor our recommendation is to configure + in the shell configuration files. If other methods are in use in your environment they should be audited and the + shell configs should be verified to not override.' + - + name: '5.4.5 Ensure default user shell timeout is 900 seconds or less (Automated)' + description: The default TMOUT determines the shell timeout for users. The TMOUT value is measured in seconds. + audit: + - 'grep "TMOUT" /etc/bash.bashrc | awk -F ";" ''{print $1}'' |awk ''FNR <= 1'' | awk -F "TMOUT=" ''{print $2}'' |awk ''FNR <= 1''' + - 'grep "TMOUT" /etc/profile /etc/profile.d/*.sh | awk -F ";" ''{print $1}'' |awk ''FNR <= 1'' | awk -F "TMOUT=" ''{print $2}'' |awk ''FNR <= 1''' + remedeation: 'Edit the /etc/bashrc, /etc/profile and /etc/profile.d/*.sh files (and the appropriate files for any other shell supported on your system) and add or edit any TMOUT parameters in accordance with site policy: + readonly TMOUT=900 ; export TMOUT + Note: setting the value to readonly prevents unwanted modification during runtime.' + check_type: multi_param + eval_expr: "${0} <= 900 && ${1} <= 900" + additional_info: 'The audit and remediation in this recommendation apply to bash and shell. If other shells are supported on the system, it is recommended that their configuration files also are checked. Other methods of setting a timeout exist for other shells not covered here. + Ensure that the timeout conforms to your local policy.' + diff --git a/internal/benchmark/lxd/v1.0.0/5.5_root_login_restricted_system_console.yml b/internal/benchmark/lxd/v1.0.0/5.5_root_login_restricted_system_console.yml new file mode 100644 index 0000000..b8752a3 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/5.5_root_login_restricted_system_console.yml @@ -0,0 +1,16 @@ +--- +benchmark_type: lxd +categories: + - + name: Access, Authentication and Authorization + sub_category: + name: 5.5 root login is restricted + audit_tests: + - + name: '5.5 Ensure root login is restricted to system console (Manual)' + description: The file /etc/securetty contains a list of valid terminals that may be logged in directly as root. + audit: + - '# cat /etc/securetty' + remedeation: 'Remove entries for any consoles that are not in a physically secure location.' + check_type: multi_param + type: manual \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/5.6_ensure_access_su_command_restricted.yml b/internal/benchmark/lxd/v1.0.0/5.6_ensure_access_su_command_restricted.yml new file mode 100644 index 0000000..08f1a88 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/5.6_ensure_access_su_command_restricted.yml @@ -0,0 +1,27 @@ +--- +benchmark_type: lxd +categories: + - + name: Access, Authentication and Authorization + sub_category: + name: 5.6 access su command restricted + audit_tests: + - + name: '5.6 Ensure access to the su command is restricted (Automated)' + description: The su command allows a user to run a command or shell as another user. The program has been superseded by sudo , + which allows for more granular control over privileged access. Normally, the su command can be executed by any user. + By uncommenting the pam_wheel.so statement in /etc/pam.d/su , the su command will only allow users in a specific groups to execute su. + This group should be empty to reinforce the use of sudo for privileged access. + audit: + - 'grep pam_wheel.so /etc/pam.d/su 2> /dev/null |awk -F " " ''{print $1}'' |awk ''FNR <= 1''' + - 'grep pam_wheel.so /etc/pam.d/su 2> /dev/null |awk -F " " ''{print $2}'' |awk ''FNR <= 1''' + - 'grep pam_wheel.so /etc/pam.d/su 2> /dev/null |awk -F " " ''{print $3}'' |awk ''FNR <= 1''' + - 'grep pam_wheel.so /etc/pam.d/su 2> /dev/null |awk -F " " ''{print $4}'' |awk ''FNR <= 1''' + - 'grep pam_wheel.so /etc/pam.d/su 2> /dev/null |awk -F "group=" ''{print $2}'' |awk ''FNR <= 1''' + - 'grep ${1} /etc/group 2> /dev/null |awk -F ":" ''{print $4}'' |awk ''FNR <= 1''' + remedeation: 'Create an empty group that will be specified for use of the su command. The group should be named according to site policy. + Example: + # groupadd sugroup + Add the following line to the /etc/pam.d/su file, specifying the empty group: auth required pam_wheel.so use_uid group=sugroup' + check_type: multi_param + eval_expr: "'${0}' == 'auth'; && '${1}' == 'required'; && '${2}' == 'pam_wheel.so'; && '${3}' == 'use_uid'; && '${4}' != ''; && '${5}' == '';" \ No newline at end of file diff --git a/internal/benchmark/lxd/v1.0.0/6.1_system_file_permissions.yml b/internal/benchmark/lxd/v1.0.0/6.1_system_file_permissions.yml new file mode 100644 index 0000000..d091bc7 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/6.1_system_file_permissions.yml @@ -0,0 +1,175 @@ +--- +benchmark_type: lxd +categories: + - + name: System Maintenance + sub_category: + name: 6.1 System File Permissions + audit_tests: + - + name: '6.1.1 Audit system file permissions (Manual)' + description: 'The Debian package manager has a number of useful options. One of these, the --verify option, can be used to verify that system packages are correctly installed. The --verify option can be used to verify a particular package or to verify all system packages. If no output is returned, the package is installed correctly. The following table describes the meaning of output from the verify option: + Code Meaning + S File size differs. + M File mode differs (includes permissions and file type). + 5 The MD5 checksum differs. + D The major and minor version numbers differ on a device file. L A mismatch occurs in a link. + U The file ownership differs. + G The file group owner differs. + T The file time (mtime) differs. + The dpkg -S command can be used to determine which package a particular file belongs to. For example the following command determines which package the /bin/bash file belongs to: + To verify the settings for the package that controls the /bin/bash file, run the following: + # dpkg -S /bin/bash + bash: /bin/bash + # dpkg --verify bash + ??5?????? c /etc/bash.bashrc' + audit: + - 'dpkg --verify ' + remedeation: 'Correct any discrepancies found and rerun the audit until output is clean or risk is mitigated or accepted.' + additional_info: 'Since packages and important files may change with new updates and releases, it is recommended to verify everything, not just a finite list of files. + This can be a time consuming task and results may depend on site policy therefore it is not a scorable benchmark item, but is provided for those interested in additional security measures. + Some of the recommendations of this benchmark alter the state of files audited by this recommendation. + The audit command will alert for all changes to a file permissions even if the new state is more secure than the default.' + check_type: multi_param + type: manual + - + name: '6.1.2 Ensure permissions on /etc/passwd are configured (Automated)' + description: 'The /etc/passwd file contains user account information that is used by many + system utilities and therefore must be readable for these utilities to operate.' + audit: + - 'stat /etc/passwd 2> /dev/null| grep "Access: ("' + remedeation: 'Run the following command to set permissions on /etc/passwd: + # chown root:root /etc/passwd + # chmod 644 /etc/passwd' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '6.1.3 Ensure permissions on /etc/gshadow- are configured (Automated)' + description: 'The /etc/gshadow- file is used to store backup information about groups that is critical + to the security of those accounts, such as the hashed password and other security information.' + audit: + - 'stat /etc/gshadow- 2> /dev/null| grep "Access: ("' + remedeation: 'Run one of the following chown commands as appropriate and the chmod to set permissions on /etc/gshadow- : + # chown root:root /etc/gshadow- + # chown root:shadow /etc/gshadow- + # chmod o-rwx,g-wx /etc/gshadow-' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0640/-rw-r-----) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '6.1.4 Ensure permissions on /etc/shadow are configured (Automated)' + description: 'The /etc/shadow file is used to store the information about user accounts that is + critical to the security of those accounts, such as the hashed password and other security information.' + audit: + - 'stat /etc/shadow 2> /dev/null| grep "Access: ("' + remedeation: 'Run one of the following chown commands as appropriate and the chmod to set permissions on /etc/shadow : + # chown root:root /etc/shadow + # chown root:shadow /etc/shadow + # chmod o-rwx,g-wx /etc/shadow' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0640/-rw-r-----) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '6.1.5 Ensure permissions on /etc/group are configured (Automated)' + description: 'The /etc/group file contains a list of all the valid groups defined in the system. + The command below allows read/write access for root and read access for everyone else.' + audit: + - 'stat /etc/group 2> /dev/null | grep "Access: ("' + remedeation: 'Run the following command to set permissions on /etc/group : + # chown root:root /etc/group + # chmod u-x,go-wx /etc/group' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '6.1.6 Ensure permissions on /etc/passwd- are configured (Automated)' + description: 'The /etc/passwd- file contains backup user account information.' + audit: + - 'stat /etc/passwd- 2> /dev/null | grep "Access: ("' + remedeation: 'Run the following command to set permissions on /etc/passwd- : + # chown root:root /etc/passwd- + # chmod u-x,go-rwx /etc/passwd-' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '6.1.7 Ensure permissions on /etc/shadow- are configured (Automated)' + description: 'The /etc/shadow- file is used to store backup information about user accounts that is critical + to the security of those accounts, such as the hashed password and other security information.' + audit: + - 'stat /etc/shadow- 2> /dev/null | grep "Access: ("' + remedeation: 'Run the following commands to set permissions on /etc/shadow-: + # chown root:shadow /etc/shadow- + # chmod u-x,go-rwx /etc/shadow-' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0600/-rw-------) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '6.1.8 Ensure permissions on /etc/group- are configured (Automated)' + description: 'The /etc/group- file contains a backup list of all the valid groups defined in the system.' + audit: + - 'stat stat /etc/group- 2> /dev/null | grep "Access: ("' + remedeation: 'Run the following command to set permissions on /etc/group- : + # chown root:root /etc/group- + # chmod u-x,go-rwx /etc/group-' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0600/-rw-------) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '6.1.9 Ensure permissions on /etc/gshadow are configured (Automated)' + description: 'The /etc/gshadow file is used to store the information about groups that is critical to the security of those + accounts, such as the hashed password and other security information.' + audit: + - 'stat stat /etc/gshadow 2> /dev/null | grep "Access: ("' + remedeation: 'Run one of the following chown commands as appropriate and the chmod to set permissions on /etc/gshadow : + # chown root:root /etc/gshadow + # chown root:shadow /etc/gshadow + # chmod u-x,g-wx,o-rwx /etc/gshadow' + check_type: multi_param + eval_expr: "'${0}' == 'Access: (0640/-rw-r-----) Uid: ( 0/ root) Gid: ( 0/ root)';" + - + name: '6.1.10 Ensure no world writable files exist (Automated)' + description: 'Unix-based systems support variable settings to control access to files. World writable + files are the least secure. See the chmod(2) man page for more information.' + audit: + - 'df --local -P | awk ''{if (NR!=1) print $6}'' | xargs -I ''{}'' find ''{}'' 2>/dev/null -xdev -type f -perm -0002 |awk ''FNR <= 1''' + remedeation: 'Removing write access for the "other" category ( chmod o-w ) + is advisable, but always consult relevant vendor documentation to avoid breaking + any application dependencies on a given file.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.1.11 Ensure no unowned files or directories exist (Automated)' + description: 'Sometimes when administrators delete users from the password file they neglect to remove all files owned by those users from the system.' + audit: + - 'df --local -P | awk {''if (NR!=1) print $6''} | xargs -I ''{}'' find ''{}'' 2>/dev/null -xdev -nouser |awk ''FNR <= 1''' + remedeation: 'Locate files that are owned by users or groups not listed in the system configuration + files, and reset the ownership of these files to some active user on the system as appropriate.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.1.12 Ensure no ungrouped files or directories exist (Automated)' + description: 'Sometimes when administrators delete users or groups from the system they neglect to remove all files owned by those users or groups.' + audit: + - 'df --local -P | awk ''{if (NR!=1) print $6}'' | xargs -I ''{}'' find ''{}'' 2>/dev/null -xdev -nogroup |awk ''FNR <= 1''' + remedeation: 'Locate files that are owned by users or groups not listed in the system configuration files, and reset the ownership of these files to some active user on the system as appropriate.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.1.13 Audit SUID executables (Manual)' + description: 'The owner of a file can set the files permissions to run with the owners or groups permissions, even if + the user running the program is not the owner or a member of the group. The most common reason for a SUID program + is to enable users to perform functions (such as changing their password) that require root privileges.' + audit: + - '# df --local -P| awk ''{if (NR!=1) print $6}'' | xargs -I ''{}'' find ''{}'' 2>/dev/null -xdev -type f -perm -4000' + - '# find -xdev -type f -perm -4000' + remedeation: 'Ensure that no rogue SUID programs have been introduced into the system. Review the files returned + by the action in the Audit section and confirm the integrity of these binaries.' + check_type: multi_param + type: manual + - + name: '6.1.14 Audit SGID executables (Manual)' + description: 'The owner of a file can set the files permissions to run with the owners or groups permissions, even if + the user running the program is not the owner or a member of the group. The most common reason for a SGID program + is to enable users to perform functions (such as changing their password) that require root privileges.' + audit: + - ' # df --local -P | awk ''{if (NR!=1) print $6}'' | xargs -I ''{}'' find ''{}'' -xdev -type f -perm -2000' + - '# find -xdev -type f -perm -2000' + remedeation: 'Ensure that no rogue SGID programs have been introduced into the system. + Review the files returned by the action in the Audit section and confirm the integrity of these binaries.' + check_type: multi_param + type: manual diff --git a/internal/benchmark/lxd/v1.0.0/6.2_user_and_group_settings.yml b/internal/benchmark/lxd/v1.0.0/6.2_user_and_group_settings.yml new file mode 100644 index 0000000..7ef2da3 --- /dev/null +++ b/internal/benchmark/lxd/v1.0.0/6.2_user_and_group_settings.yml @@ -0,0 +1,316 @@ +--- +benchmark_type: lxd +categories: + - + name: System Maintenance + sub_category: + name: 6.2 User and Group Settings + audit_tests: + - + name: '6.2.1 Ensure password fields are not empty (Automated)' + description: 'An account with an empty password field means that anybody may log in as that user without providing a password.' + audit: + - 'awk -F: ''($2 == "" ) { print $1 " does not have a password "}'' /etc/shadow 2> /dev/null' + remedeation: 'If any accounts in the /etc/shadow file do not have a password, run the following command to lock the account until it can be determined why it does not have a password: + # passwd -l + Also, check to see if the account is logged in and investigate what it is being used for to determine if it needs to be forced off.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.2.2 Ensure no legacy "+" entries exist in /etc/passwd (Automated)' + description: 'The character + in various files used to be markers for systems to insert data from NIS maps at + a certain point in a system configuration file. These entries are no longer required on most + systems, but may exist in files that have been imported from other platforms.' + audit: + - 'grep ''^\+:'' /etc/passwd 2> /dev/null' + remedeation: 'Remove any legacy entries from /etc/passwd if they exist.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.2.3 Ensure all users'' home directories exist (Automated)' + description: 'The character + in various files used to be markers for systems to insert data + from NIS maps at a certain point in a system configuration file. These entries are no longer + required on most systems, but may exist in files that have been imported from other platforms.' + audit: + - '#!/bin/bash grep -E -v ''^(halt|sync|shutdown)'' /etc/passwd | awk -F: ''($7 != "''"$(which nologin)"''" && $7 != "/bin/false") { print $1 " " $6 }'' | while read -r user dir; do + if [ ! -d "$dir" ]; then + echo "The home directory ($dir) of user $user does not exist." + fi done > tf | awk ''{ print $3 }'' tf' + remedeation: 'If any users home directories do not exist, create them and make sure the respective user owns the directory. + Users without an assigned home directory should be removed or assigned a home directory as appropriate.' + additional_info: 'The audit script checks all users with interactive shells except halt, sync, shutdown, and nfsnobody.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.2.4 Ensure no legacy "+" entries exist in /etc/shadow (Automated)' + description: 'The character + in various files used to be markers for systems to insert data from NIS maps at a certain point in a system configuration file. + These entries are no longer required on most systems, but may exist in files that have been imported from other platforms.' + audit: + - 'grep ''^\+:'' /etc/shadow 2> /dev/null' + remedeation: 'Remove any legacy entries from /etc/shadow if they exist.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.2.5 Ensure no legacy "+" entries exist in /etc/group (Automated)' + description: 'The character + in various files used to be markers for systems to insert data from NIS maps at a certain point + in a system configuration file. These entries are no longer required on most systems, but may exist in files that + have been imported from other platforms.' + audit: + - 'grep ''^\+:'' /etc/group 2> /dev/null' + remedeation: 'Remove any legacy entries from /etc/group if they exist.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.2.6 Ensure root is the only UID 0 account (Automated)' + description: 'Any account with UID 0 has superuser privileges on the system.' + audit: + - 'awk -F: ''($3 == 0) { print $1 }'' /etc/passwd 2> /dev/null' + remedeation: 'Remove any users other than root with UID 0 or assign them a new UID if appropriate.' + check_type: multi_param + eval_expr: "'${0}' == 'root';" + - + name: '6.2.7 Ensure root PATH Integrity (Automated)' + description: 'The root user can execute any command on the system and could be fooled into executing programs unintentionally if the PATH is not set correctly.' + audit: + - '#!/bin/bash + if echo $PATH | grep -q "::" ; then + echo "Empty Directory in PATH (::)" + fi + if echo $PATH | grep -q ":$" ; then + echo "Trailing : in PATH" + fi + for x in $(echo $PATH | tr ":" " ") ; do + if [ -d "$x" ] ; then + ls -ldH "$x" | awk '' + $9 == "." {print "PATH contains current working directory (.)"} $3 != "root" {print $9, "is not owned by root"} + substr($1,6,1) != "-" {print $9, "is group writable"} substr($1,9,1) != "-" {print $9, "is world writable"}'' + else + echo "$x is not a directory" + fi done > tf | awk ''{ print $3 }'' tf' + remedeation: 'Correct or justify any items discovered in the Audit step.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.2.8 Ensure users home directories permissions are 750 or more restrictive (Automated)' + description: 'While the system administrator can establish secure permissions for users home directories, the users can easily override these.' + audit: + - '#!/bin/bash grep -E -v ''^(halt|sync|shutdown)'' /etc/passwd | awk -F: ''($7 != "''"$(which nologin)"''" && $7 != "/bin/false") { print $1 " " $6 }'' | while read user dir; do + if [ ! -d "$dir" ]; then + echo "The home directory ($dir) of user $user does not exist." + else + dirperm=$(ls -ld $dir | cut -f1 -d" ") + if [ $(echo $dirperm | cut -c6) != "-" ]; then + echo "Group Write permission set on the home directory ($dir) of user $user" + fi + if [ $(echo $dirperm | cut -c8) != "-" ]; then + echo "Other Read permission set on the home directory ($dir) of user $user" + fi + if [ $(echo $dirperm | cut -c9) != "-" ]; then + echo "Other Write permission set on the home directory ($dir) of user $user" + fi + if [ $(echo $dirperm | cut -c10) != "-" ]; then + echo "Other Execute permission set on the home directory ($dir) of user $user" + fi fi + done > tf | awk ''{ print $3 }'' tf' + remedeation: 'Making global modifications to user home directories without alerting the user community + can result in unexpected outages and unhappy users. Therefore, it is recommended that a monitoring + policy be established to report user file permissions and determine the action to be taken in accordance with site policy.' + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: 'On some distributions the /sbin/nologin should be replaced with /usr/sbin/nologin.' + - + name: '6.2.9 Ensure users own their home directories (Automated)' + description: 'The user home directory is space defined for the particular user to set local environment variables and to store personal files.' + audit: + - '#!/bin/bash grep -E -v ''^(halt|sync|shutdown)'' /etc/passwd | awk -F: ''($7 != "''"$(which nologin)"''" && $7 != "/bin/false") { print $1 " " $6 }'' | while read user dir; do + if [ ! -d "$dir" ]; then + echo "The home directory ($dir) of user $user does not exist." + else + owner=$(stat -L -c "%U" "$dir") + if [ "$owner" != "$user" ]; then + echo "The home directory ($dir) of user $user is owned by $owner." fi + fi done > tf | awk ''{ print $3 }'' tf' + remedeation: 'Change the ownership of any home directories that are not owned by the defined user to the correct user.' + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: 'On some distributions the /sbin/nologin should be replaced with /usr/sbin/nologin.' + - + name: '6.2.10 Ensure users dot files are not group or world writable (Automated)' + description: 'While the system administrator can establish secure permissions for users "dot" files, the users can easily override these.' + audit: + - '#!/bin/bash grep -E -v ''^(halt|sync|shutdown)'' /etc/passwd | awk -F: ''($7 != "''"$(which nologin)"''" && $7 != "/bin/false") { print $1 " " $6 }'' | while read user dir; do + if [ ! -d "$dir" ]; then + echo "The home directory ($dir) of user $user does not exist." + else + for file in $dir/.[A-Za-z0-9]*; do + if [ ! -h "$file" -a -f "$file" ]; then + fileperm=$(ls -ld $file | cut -f1 -d" ") + if [ $(echo $fileperm | cut -c6) != "-" ]; then echo "Group Write permission set on file $file" + fi + if [ $(echo $fileperm | cut -c9) != "-" ]; then + echo "Other Write permission set on file $file" fi + fi + done fi + done > tf | awk ''{ print $3 }'' tf' + remedeation: 'Making global modifications to users files without alerting the user community can result in unexpected outages and unhappy users. + Therefore, it is recommended that a monitoring policy be established to report user dot + file permissions and determine the action to be taken in accordance with site policy.' + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: 'On some distributions the /sbin/nologin should be replaced with /usr/sbin/nologin.' + - + name: '6.2.11 Ensure no users have .forward files (Automated)' + description: 'The .forward file specifies an email address to forward the users mail to.' + audit: + - '#!/bin/bash grep -E -v ''^(root|halt|sync|shutdown)'' /etc/passwd | awk -F: ''($7 != "''"$(which nologin)"''" && $7 != "/bin/false") { print $1 " " $6 }'' | while read user dir; do + if [ ! -d "$dir" ]; then + echo "The home directory ($dir) of user $user does not exist." + else + if [ ! -h "$dir/.forward" -a -f "$dir/.forward" ]; then + echo ".forward file $dir/.forward exists" fi + fi done > tf | awk ''{ print $3 }'' tf' + remedeation: 'Making global modifications to users + files without alerting the user community can result in unexpected outages and unhappy users. + Therefore, it is recommended that a monitoring policy be established to report user. + forward files and determine the action to be taken in accordance with site policy.' + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: 'On some distributions the /sbin/nologin should be replaced with /usr/sbin/nologin.' + - + name: '6.2.12 Ensure no users have .netrc files (Automated)' + description: 'The .netrc file contains data for logging into a remote host for file transfers via FTP.' + audit: + - '#!/bin/bash + grep -E -v ''^(root|halt|sync|shutdown)'' /etc/passwd | awk -F: ''($7 != "''"$(which nologin)"''" && $7 != "/bin/false") { print $1 " " $6 }'' | while read user dir; do + if [ ! -d "$dir" ]; then + echo "The home directory ($dir) of user $user does not exist." + else + if [ ! -h "$dir/.netrc" -a -f "$dir/.netrc" ]; then + echo ".netrc file $dir/.netrc exists" + fi + fi done > tf | awk ''{ print $3 }'' tf' + remedeation: 'Making global modifications to users files without alerting the user community can result + in unexpected outages and unhappy users. Therefore, it is recommended that a monitoring policy + be established to report user .netrc files and determine the action to be taken in accordance with site policy.' + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: 'On some distributions the /sbin/nologin should be replaced with /usr/sbin/nologin.' + - + name: '6.2.13 Ensure users .netrc Files are not group or world accessible (Automated)' + description: 'While the system administrator can establish secure permissions for users .netrc files, the users can easily override these.' + audit: + - '#!/bin/bash + grep -E -v ''^(root|halt|sync|shutdown)'' /etc/passwd | awk -F: ''($7 != "''"$(which nologin)"''" && $7 != "/bin/false") { print $1 " " $6 }'' | while read user dir; do + if [ ! -d "$dir" ]; then + echo "The home directory ($dir) of user $user does not exist." + else + for file in $dir/.netrc; do + if [ ! -h "$file" -a -f "$file" ]; then + fileperm=$(ls -ld $file | cut -f1 -d" ") + if [ $(echo $fileperm | cut -c5) != "-" ]; then + echo "Group Read set on $file" + fi + if [ $(echo $fileperm | cut -c6) != "-" ]; then + echo "Group Write set on $file" + fi + if [ $(echo $fileperm | cut -c7) != "-" ]; then + echo "Group Execute set on $file" + fi + if [ $(echo $fileperm | cut -c8) != "-" ]; then + echo "Other Read set on $file" + fi + if [ $(echo $fileperm | cut -c9) != "-" ]; then + echo "Other Write set on $file" + fi + if [ $(echo $fileperm | cut -c10) != "-" ]; then + echo "Other Execute set on $file" + fi + fi done + fi done 2> /dev/null > tf | awk ''{ print $3 }'' tf' + remedeation: 'Making global modifications to users files without alerting the user community can result in unexpected outages + and unhappy users. Therefore, it is recommended that a monitoring policy be established to report user + .netrc file permissions and determine the action to be taken in accordance with site policy' + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: 'While the complete removal of .netrc files is recommended if any are required on the system secure permissions must be applied.' + - + name: '6.2.14 Ensure no users have .rhosts files (Automated)' + description: 'While no .rhosts files are shipped by default, users can easily create them.' + audit: + - '#!/bin/bash grep -E -v ''^(root|halt|sync|shutdown)'' /etc/passwd | awk -F: ''($7 != "''"$(which nologin)"''" && $7 != "/bin/false") { print $1 " " $6 }'' | while read user dir; do + if [ ! -d "$dir" ]; then + echo "The home directory ($dir) of user $user does not exist." + else + for file in $dir/.rhosts; do + if [ ! -h "$file" -a -f "$file" ]; then + echo ".rhosts file in $dir" + fi done + fi done > tf | awk ''{ print $3 }'' tf' + remedeation: 'Making global modifications to users files without alerting the user community can result in unexpected outages and unhappy users. Therefore, it is recommended that a monitoring policy be established to report user .rhosts files and determine the action to be taken in accordance with site policy.' + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: 'On some distributions the /sbin/nologin should be replaced with /usr/sbin/nologin.' + - + name: '6.2.15 Ensure all groups in /etc/passwd exist in /etc/group (Automated)' + description: 'Over time, system administration errors and changes can lead to groups being defined in /etc/passwd but not in /etc/group' + audit: + - '#!/bin/bash for i in $(cut -s -d: -f4 /etc/passwd | sort -u ); do grep -q -P "^.*?:[^:]*:$i:" /etc/group + if [ $? -ne 0 ]; then + echo "Group $i is referenced by /etc/passwd but does not exist in /etc/group" + fi done > tf | awk ''{ print $3 }'' tf' + remedeation: 'Analyze the output of the Audit step above and perform the appropriate action to correct any discrepancies found.' + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: 'On some distributions the /sbin/nologin should be replaced with /usr/sbin/nologin.' + - + name: '6.2.16 Ensure no duplicate UIDs exist (Automated)' + description: 'Although the useradd program will not let you create a duplicate User ID (UID), + it is possible for an administrator to manually edit the /etc/passwd file and change the UID field.' + audit: + - '#!/bin/bash cut -f3 -d":" /etc/passwd | sort -n | uniq -c | while read x ; do [ -z "$x" ] && break + set - $x + if [ $1 -gt 1 ]; then + users=$(awk -F: ''($3 == n) { print $1 }'' n=$2 /etc/passwd | xargs) + echo "Duplicate UID ($2): $users" + fi + done > tf | awk ''{ print $3 }'' tf' + remedeation: 'Based on the results of the audit script, establish unique UIDs and review all files owned by the shared UIDs to determine which UID they are supposed to belong to.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.2.17 Ensure no duplicate GIDs exist (Automated)' + description: 'Although the groupadd program will not let you create a duplicate Group ID (GID), it is possible for an administrator to manually edit the /etc/group file and change the GID field.' + audit: + - '#!/bin/bash cut -d: -f3 /etc/group | sort | uniq -d | while read x ; do echo "Duplicate GID ($x) in /etc/group" + done > tf | awk ''{ print $2 }'' tf' + remedeation: 'Based on the results of the audit script, establish unique GIDs and review all files owned by the shared GID to determine which group they are supposed to belong to.' + check_type: multi_param + eval_expr: "'${0}' == '';" + additional_info: 'You can also use the grpck command to check for other inconsistencies in the /etc/group file.' + - + name: '6.2.18 Ensure no duplicate user names exist (Automated)' + description: 'Although the useradd program will not let you create a duplicate user name, it is possible for an administrator to manually edit the /etc/passwd file and change the user name.' + audit: + - '#!/bin/bash cut -d: -f1 /etc/passwd | sort | uniq -d | while read x do echo "Duplicate login name ${x} in /etc/passwd" + done > tf | awk ''{ print $2 }'' tf' + remedeation: 'Based on the results of the audit script, establish unique user names for the users. File ownerships will automatically reflect the change as long as the users have unique UIDs.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.2.19 Ensure no duplicate group names exist (Automated)' + description: 'Although the groupadd program will not let you create a duplicate group name, it is possible for an administrator to manually edit the /etc/group file and change the group name.' + audit: + - '#!/bin/bash cut -d: -f1 /etc/group | sort | uniq -d | while read x do echo "Duplicate group name ${x} in /etc/group" + done > tf | awk ''{ print $2 }'' tf' + remedeation: 'Based on the results of the audit script, establish unique names for the user groups. File group ownerships will automatically reflect the change as long as the groups have unique GIDs.' + check_type: multi_param + eval_expr: "'${0}' == '';" + - + name: '6.2.20 Ensure shadow group is empty (Automated)' + description: 'The shadow group allows system programs which require access the ability to read the /etc/shadow file. No users should be assigned to the shadow group.' + audit: + - 'grep ^shadow:[^:]*:[^:]*:[^:]+ /etc/group' + - 'awk -F: ''($4 == "") { print }'' /etc/passwd' + remedeation: 'Remove all users from the shadow group, and change the primary group of any users with shadow as their primary group.' + check_type: multi_param + eval_expr: "'${0}' == ''; && '${1}' == '';" \ No newline at end of file diff --git a/internal/cli/cli.go b/internal/cli/cli.go new file mode 100644 index 0000000..7cfffca --- /dev/null +++ b/internal/cli/cli.go @@ -0,0 +1,257 @@ +package cli + +import ( + "bytes" + "context" + "fmt" + "github.com/chen-keinan/go-command-eval/eval" + "github.com/chen-keinan/go-user-plugins/uplugin" + "github.com/chen-keinan/kube-mesh-kridik/internal/cli/commands" + "github.com/chen-keinan/kube-mesh-kridik/internal/common" + "github.com/chen-keinan/kube-mesh-kridik/internal/hooks" + "github.com/chen-keinan/kube-mesh-kridik/internal/logger" + "github.com/chen-keinan/kube-mesh-kridik/internal/startup" + "github.com/chen-keinan/kube-mesh-kridik/pkg/models" + "github.com/chen-keinan/kube-mesh-kridik/pkg/utils" + "github.com/mitchellh/cli" + "go.uber.org/fx" + "go.uber.org/zap" + "os" + "plugin" + "strings" +) + +// StartCLI start ldx-prob audit tester +func StartCLI() { + app := fx.New( + // dependency injection + fx.NopLogger, + fx.Provide(NewLxdResultChan), + fx.Provide(NewCompletionChan), + fx.Provide(NewArgFunc), + fx.Provide(NewCliArgs), + fx.Provide(utils.NewKFolder), + fx.Provide(initBenchmarkSpecData), + fx.Provide(NewCliCommands), + fx.Provide(NewCommandArgs), + fx.Provide(createCliBuilderData), + fx.Provide(logger.GetLog), + fx.Invoke(StartCLICommand), + ) + if err := app.Start(context.Background()); err != nil { + panic(err) + } +} + +//initBenchmarkSpecData initialize benchmark spec file and save if to file system +func initBenchmarkSpecData(fm utils.FolderMgr, ad ArgsData) []utils.FilesInfo { + err := utils.CreateHomeFolderIfNotExist(fm) + if err != nil { + panic(err) + } + err = utils.CreateBenchmarkFolderIfNotExist(ad.SpecType, ad.SpecVersion, fm) + if err != nil { + panic(err) + } + var filesData []utils.FilesInfo + switch ad.SpecType { + case "lxd": + if ad.SpecVersion == "v1.0.0" { + filesData, err = startup.GenerateLxdBenchmarkFiles() + } + } + if err != nil { + panic(err) + } + err = startup.SaveBenchmarkFilesIfNotExist(ad.SpecType, ad.SpecVersion, filesData) + if err != nil { + panic(err) + } + return filesData +} + +//initBenchmarkSpecData initialize benchmark spec file and save if to file system +func initPluginFolders(fm utils.FolderMgr) { + err := utils.CreatePluginsSourceFolderIfNotExist(fm) + if err != nil { + panic(err) + } + err = utils.CreatePluginsCompiledFolderIfNotExist(fm) + if err != nil { + panic(err) + } +} + +//loadAuditBenchPluginSymbols load API call plugin symbols +func loadAuditBenchPluginSymbols(log *zap.Logger) hooks.LxdBenchAuditResultHook { + fm := utils.NewKFolder() + sourceFolder, err := utils.GetPluginSourceSubFolder(fm) + if err != nil { + panic(fmt.Sprintf("failed tpo get plugin source sourceFolder %s", err.Error())) + } + compliledFolder, err := utils.GetCompilePluginSubFolder(fm) + if err != nil { + panic(fmt.Sprintf("failed to get plugin compiled sourceFolder %s", err.Error())) + } + + pl := uplugin.NewPluginLoader(sourceFolder, compliledFolder) + names, err := pl.Plugins(uplugin.CompiledExt) + if err != nil { + panic(fmt.Sprintf("failed to get plugin compiled plugins %s", err.Error())) + } + apiPlugin := hooks.LxdBenchAuditResultHook{Plugins: make([]plugin.Symbol, 0), Plug: pl} + for _, name := range names { + sym, err := pl.Load(name, common.LxdBenchAuditResultHook) + if err != nil { + log.Error(fmt.Sprintf("failed to load sym %s error %s", name, err.Error())) + continue + } + apiPlugin.Plugins = append(apiPlugin.Plugins, sym) + } + return apiPlugin +} + +// init new plugin worker , accept audit result chan and audit result plugin hooks +func initPluginWorker(plChan chan models.MeshKridikSecurityResults, completedChan chan bool) { + log, err := zap.NewProduction() + if err != nil { + panic(err) + } + lxdHooks := loadAuditBenchPluginSymbols(log) + pluginData := hooks.NewPluginWorkerData(plChan, lxdHooks, completedChan) + worker := hooks.NewPluginWorker(pluginData, log) + worker.Invoke() +} + +//StartCLICommand invoke cli lxd command kube-mesh-kridik cli +func StartCLICommand(fm utils.FolderMgr, plChan chan models.MeshKridikSecurityResults, completedChan chan bool, ad ArgsData, cmdArgs []string, commands map[string]cli.CommandFactory, log *logger.MeshKridikLogger) { + // init plugin folders + initPluginFolders(fm) + // init plugin worker + initPluginWorker(plChan, completedChan) + if ad.Help { + cmdArgs = cmdArgs[1:] + } + status, err := invokeCommandCli(cmdArgs, commands) + if err != nil { + log.Console(err.Error()) + } + os.Exit(status) +} + +//NewCommandArgs return new cli command args +// accept cli args and return command args +func NewCommandArgs(ad ArgsData) []string { + cmdArgs := []string{"a"} + cmdArgs = append(cmdArgs, ad.Filters...) + return cmdArgs +} + +//NewCliCommands return cli lxd obj commands +// accept cli args data , completion chan , result chan , spec files and return artay of cli commands +func NewCliCommands(ad ArgsData, plChan chan models.MeshKridikSecurityResults, completedChan chan bool, fi []utils.FilesInfo) []cli.Command { + cmds := make([]cli.Command, 0) + // invoke cli + evaluator := eval.NewEvalCmd() + cmds = append(cmds, commands.NewLxdAudit(ad.Filters, plChan, completedChan, fi, evaluator)) + return cmds +} + +//NewArgFunc return args func +func NewArgFunc() SanitizeArgs { + return ArgsSanitizer +} + +//NewCliArgs return cli args +func NewCliArgs(sa SanitizeArgs) ArgsData { + ad := sa(os.Args[1:]) + return ad +} + +//NewCompletionChan return plugin Completion chan +func NewCompletionChan() chan bool { + completedChan := make(chan bool) + return completedChan +} + +//NewLxdResultChan return plugin test result chan +func NewLxdResultChan() chan models.MeshKridikSecurityResults { + plChan := make(chan models.MeshKridikSecurityResults) + return plChan +} + +//createCliBuilderData return cli params and commands +func createCliBuilderData(ca []string, cmd []cli.Command) map[string]cli.CommandFactory { + // read cli args + cmdFactory := make(map[string]cli.CommandFactory) + // build cli commands + for index, a := range cmd { + cmdFactory[ca[index]] = func() (cli.Command, error) { + return a, nil + } + } + return cmdFactory +} + +// invokeCommandCli invoke cli command with params +func invokeCommandCli(args []string, commands map[string]cli.CommandFactory) (int, error) { + app := cli.NewCLI(common.LdxProbeCli, common.LdxProbeVersion) + app.Args = append(app.Args, args...) + app.Commands = commands + app.HelpFunc = LxdProbeHelpFunc(common.LdxProbeCli) + status, err := app.Run() + return status, err +} + +//ArgsSanitizer sanitize CLI arguments +var ArgsSanitizer SanitizeArgs = func(str []string) ArgsData { + ad := ArgsData{SpecType: "lxd"} + args := make([]string, 0) + if len(str) == 0 { + args = append(args, "") + } + for _, arg := range str { + arg = strings.Replace(arg, "--", "", -1) + arg = strings.Replace(arg, "-", "", -1) + switch { + case arg == "help", arg == "h": + ad.Help = true + args = append(args, arg) + case strings.HasPrefix(arg, "s="): + ad.SpecType = arg[len("s="):] + case strings.HasPrefix(arg, "spec="): + ad.SpecType = arg[len("spec="):] + case strings.HasPrefix(arg, "v="): + ad.SpecVersion = fmt.Sprintf("v%s", arg[len("v="):]) + case strings.HasPrefix(arg, "version="): + ad.SpecVersion = fmt.Sprintf("v%s", arg[len("version="):]) + default: + args = append(args, arg) + } + } + if ad.SpecType == "lxd" && len(ad.SpecVersion) == 0 { + ad.SpecVersion = "v1.0.0" + } + ad.Filters = args + return ad +} + +//ArgsData hold cli args data +type ArgsData struct { + Filters []string + Help bool + SpecType string + SpecVersion string +} + +//SanitizeArgs sanitizer func +type SanitizeArgs func(str []string) ArgsData + +// LxdProbeHelpFunc kube-mesh-kridik Help function with all supported commands +func LxdProbeHelpFunc(app string) cli.HelpFunc { + return func(commands map[string]cli.CommandFactory) string { + var buf bytes.Buffer + buf.WriteString(fmt.Sprintf(startup.GetHelpSynopsis(), app)) + return buf.String() + } +} diff --git a/internal/cli/commands/command-helper.go b/internal/cli/commands/command-helper.go new file mode 100644 index 0000000..0692089 --- /dev/null +++ b/internal/cli/commands/command-helper.go @@ -0,0 +1,218 @@ +package commands + +import ( + "fmt" + "github.com/cheggaaa/pb" + "github.com/chen-keinan/kube-mesh-kridik/internal/common" + "github.com/chen-keinan/kube-mesh-kridik/internal/logger" + "github.com/chen-keinan/kube-mesh-kridik/internal/models" + "github.com/chen-keinan/kube-mesh-kridik/pkg/filters" + "github.com/chen-keinan/kube-mesh-kridik/pkg/utils" + "github.com/chen-keinan/kube-mesh-kridik/ui" + "github.com/mitchellh/colorstring" + "github.com/olekukonko/tablewriter" + "gopkg.in/yaml.v2" + "strings" + "time" +) + +func printTestResults(at []*models.CheckSpec, table *tablewriter.Table, category string) models.SecCheckTotals { + var ( + warnCounter int + passCounter int + failCounter int + ) + for _, a := range at { + var testType string + if a.NonApplicable { + testType = "Manual" + } else { + testType = "Automated" + } + if a.NonApplicable { + warnTest := colorstring.Color("[yellow][Warn]") + warnCounter++ + table.Append([]string{category, warnTest, testType, a.Name}) + continue + } + if a.TestSucceed { + passTest := colorstring.Color("[green][Pass]") + table.Append([]string{category, passTest, testType, a.Name}) + + passCounter++ + } else { + failTest := colorstring.Color("[red][Fail]") + table.Append([]string{category, failTest, testType, a.Name}) + failCounter++ + } + } + return models.SecCheckTotals{Fail: failCounter, Pass: passCounter, Warn: warnCounter} +} + +func printClassicTestResults(at []*models.CheckSpec, log *logger.MeshKridikLogger) models.SecCheckTotals { + var ( + warnCounter int + passCounter int + failCounter int + ) + for _, a := range at { + if a.NonApplicable { + warnTest := colorstring.Color("[yellow][Warn]") + log.Console(fmt.Sprintf("%s %s\n", warnTest, a.Name)) + warnCounter++ + continue + } + if a.TestSucceed { + passTest := colorstring.Color("[green][Pass]") + log.Console(fmt.Sprintf("%s %s\n", passTest, a.Name)) + passCounter++ + } else { + failTest := colorstring.Color("[red][Fail]") + log.Console(fmt.Sprintf("%s %s\n", failTest, a.Name)) + failCounter++ + } + } + return models.SecCheckTotals{Fail: failCounter, Pass: passCounter, Warn: warnCounter} +} + +//AddFailedMessages add failed audit test to report data +func AddFailedMessages(at *models.CheckSpec, isSucceeded bool) []*models.CheckSpec { + av := make([]*models.CheckSpec, 0) + at.TestSucceed = isSucceeded + if !isSucceeded || at.NonApplicable { + av = append(av, at) + } + return av +} + +//AddAllMessages add all audit test to report data +func AddAllMessages(at *models.CheckSpec, isSucceeded bool) []*models.CheckSpec { + av := make([]*models.CheckSpec, 0) + at.TestSucceed = isSucceeded + av = append(av, at) + return av +} + +//TestLoader load tests from filesystem +//command-helper.go +//go:generate mockgen -destination=../../mocks/mock_TestLoader.go -package=mocks . TestLoader +type TestLoader interface { + LoadAuditTests(fi []utils.FilesInfo) []*models.SubCategory +} + +//AuditTestLoader object +type AuditTestLoader struct { +} + +//NewFileLoader create new file loader +func NewFileLoader() TestLoader { + return &AuditTestLoader{} +} + +//LoadAuditTests load audit test from benchmark folder +func (tl AuditTestLoader) LoadAuditTests(auditFiles []utils.FilesInfo) []*models.SubCategory { + auditTests := make([]*models.SubCategory, 0) + audit := models.SecCheck{} + for _, auditFile := range auditFiles { + err := yaml.Unmarshal([]byte(auditFile.Data), &audit) + if err != nil { + panic("Failed to unmarshal audit test yaml file") + } + auditTests = append(auditTests, audit.Categories[0].SubCategory) + } + return auditTests +} + +//FilterAuditTests filter audit tests by predicate chain +func FilterAuditTests(predicates []filters.Predicate, predicateParams []string, at *models.SubCategory) *models.SubCategory { + return RunPredicateChain(predicates, predicateParams, len(predicates), at) +} + +//RunPredicateChain call every predicate in chain and filter tests +func RunPredicateChain(predicates []filters.Predicate, predicateParams []string, size int, at *models.SubCategory) *models.SubCategory { + if size == 0 { + return at + } + return RunPredicateChain(predicates[1:size], predicateParams[1:size], size-1, predicates[size-1](at, predicateParams[size-1])) +} + +// check weather are exist in array of specificTests +func isArgsExist(args []string, name string) bool { + for _, n := range args { + if n == name { + return true + } + } + return false +} + +//GetResultProcessingFunction return processing function by specificTests +func GetResultProcessingFunction(args []string) ResultProcessor { + if isArgsExist(args, common.Report) || isArgsExist(args, common.ReportFull) { + return reportResultProcessor + } + return simpleResultProcessor +} + +//getOutPutGeneratorFunction return output generator function +func getOutputGeneratorFunction(args []string) ui.OutputGenerator { + switch { + case isArgsExist(args, common.Report) || isArgsExist(args, common.ReportFull): + return ReportOutputGenerator + case isArgsExist(args, common.Classic) || isArgsExist(args, common.ClassicFull): + return ClassicOutputGenerator + default: + return ConsoleOutputGenerator + } +} + +//buildPredicateChain build chain of filters based on command criteria +func buildPredicateChain(args []string) []filters.Predicate { + pc := make([]filters.Predicate, 0) + for _, n := range args { + switch { + case strings.HasPrefix(n, common.IncludeParam): + pc = append(pc, filters.IncludeAudit) + case strings.HasPrefix(n, common.ExcludeParam): + pc = append(pc, filters.ExcludeAudit) + case strings.HasPrefix(n, common.NodeParam): + pc = append(pc, filters.NodeAudit) + case n == "a": + pc = append(pc, filters.Basic) + } + } + return pc +} + +//buildPredicateParams build chain of filters params based on command criteria +func buildPredicateChainParams(args []string) []string { + pp := make([]string, 0) + pp = append(pp, args...) + return pp +} + +func filteredAuditBenchTests(auditTests []*models.SubCategory, pc []filters.Predicate, pp []string) []*models.SubCategory { + ft := make([]*models.SubCategory, 0) + for _, adt := range auditTests { + filteredAudit := FilterAuditTests(pc, pp, adt) + if len(filteredAudit.AuditTests) == 0 { + continue + } + ft = append(ft, filteredAudit) + } + return ft +} + +func executeTests(ft []*models.SubCategory, execTestFunc func(ad *models.CheckSpec) []*models.CheckSpec, log *logger.MeshKridikLogger) []*models.SubCategory { + completedTest := make([]*models.SubCategory, 0) + log.Console(ui.LxdAuditTest) + bar := pb.StartNew(len(ft)).Prefix("Executing LXD specs:") + for _, f := range ft { + tr := ui.ExecuteSpecs(f, execTestFunc) + completedTest = append(completedTest, tr) + bar.Increment() + time.Sleep(time.Millisecond * 50) + } + bar.Finish() + return completedTest +} diff --git a/internal/cli/commands/fixtures/CheckInClause4.2.13.yml b/internal/cli/commands/fixtures/CheckInClause4.2.13.yml new file mode 100644 index 0000000..8be3cc1 --- /dev/null +++ b/internal/cli/commands/fixtures/CheckInClause4.2.13.yml @@ -0,0 +1,39 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: 4.2.13 Ensure that the Kubelet only makes use of Strong Cryptographic + Ciphers + description: Ensure that the Kubelet is configured to only use strong cryptographic + ciphers. + profile_applicability: Level 1 - Worker Node + audit: + - ps -ef | grep kubelet |grep ' --config' | grep -o ' --config=[^"]\S*' | awk + -F "=" '{print $2}' |awk 'FNR <= 1' + - 'sudo grep ''TLSCipherSuites'' ${0} |grep ''TLSCipherSuites:[^"]\S*''| awk -F + ":" ''{print $2}'' |awk ''FNR <= 1''' + - 'echo ${1} > tmp && sed ''s/,/\n/g'' tmp' + - ps -ef | grep kubelet |grep 'TLSCipherSuites' | grep -o 'TLSCipherSuites=[^"]\S*' + | awk -F "=" '{print $2}' |awk 'FNR <= 1' + - 'echo ${3} > tmp && sed ''s/,/\n/g'' tmp' + remediation: |- + If using a Kubelet config file, edit the file to set TLSCipherSuites: to TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + ,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256 or to a subset of these values. + If using executable arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the --tls-cipher-suites parameter as follows, or to a subset of these values. + --tls-cipher- suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM _SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM _SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM _SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256 + check_type: multi_param + impact: Kubelet clients that cannot support modern cryptographic ciphers will + not be able to make connections to the Kubelet API. + eval_expr: "'${2}'; IN ('TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256','TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' + ,'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305','TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384' + ,'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305','TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384','TLS_RSA_WITH_AES_256_GCM_SHA384','TLS_RSA_WITH_AES_128_GCM_SHA256'); + || '${4}'; IN ('TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256','TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' + ,'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305','TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384','TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305','TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384','TLS_RSA_WITH_AES_256_GCM_SHA384','TLS_RSA_WITH_AES_128_GCM_SHA256');" + default_value: By default the Kubernetes API server supports a wide range of + TLS ciphers + references: + - https://github.com/kubernetes/kubernetes/pull/45059 + - https://kubernetes.io/docs/admin/kubelet-tls-bootstrapping/#kubelet-configuration diff --git a/internal/cli/commands/fixtures/CheckInClauseOpposite.yml b/internal/cli/commands/fixtures/CheckInClauseOpposite.yml new file mode 100644 index 0000000..162a70b --- /dev/null +++ b/internal/cli/commands/fixtures/CheckInClauseOpposite.yml @@ -0,0 +1,25 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: 1.2.34 Ensure that encryption providers are appropriately configured + description: Where etcd encryption is used, appropriate providers should be + configured. + profile_applicability: Level 1 - Master Node + audit: + - aaa + remediation: Follow the Kubernetes documentation and configure a EncryptionConfig + file. In this file, choose aescbc, kms or secretbox as the encryption provider. + check_type: multi_param + impact: None + eval_expr: "'${0}'; IN ('a','b','c');" + default_value: By default, no encryption provider is set. + references: + - https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/ + - https://acotten.com/post/kube17-security + - https://kubernetes.io/docs/admin/kube-apiserver/ + - https://github.com/kubernetes/features/issues/92 + - https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/#providers diff --git a/internal/cli/commands/fixtures/CheckInClauseOppositeEmptyReturn.yml b/internal/cli/commands/fixtures/CheckInClauseOppositeEmptyReturn.yml new file mode 100644 index 0000000..738a425 --- /dev/null +++ b/internal/cli/commands/fixtures/CheckInClauseOppositeEmptyReturn.yml @@ -0,0 +1,26 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: 1.2.34 Ensure that encryption providers are appropriately configured + description: Where etcd encryption is used, appropriate providers should be + configured. + profile_applicability: Level 1 - Master Node + audit: + - aaa + - 'bbb ${0}' + remediation: Follow the Kubernetes documentation and configure a EncryptionConfig + file. In this file, choose aescbc, kms or secretbox as the encryption provider. + check_type: multi_param + impact: None + eval_expr: "${0}; IN ('a','b','c'); || ${1}; IN ('a','b','c')" + default_value: By default, no encryption provider is set. + references: + - https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/ + - https://acotten.com/post/kube17-security + - https://kubernetes.io/docs/admin/kube-apiserver/ + - https://github.com/kubernetes/features/issues/92 + - https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/#providers diff --git a/internal/cli/commands/fixtures/CheckInClauseOppositeWithNum.yml b/internal/cli/commands/fixtures/CheckInClauseOppositeWithNum.yml new file mode 100644 index 0000000..eed7989 --- /dev/null +++ b/internal/cli/commands/fixtures/CheckInClauseOppositeWithNum.yml @@ -0,0 +1,25 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: 4.1.3 If proxy kubeconfig file exists ensure permissions are set to 644 + or more restrictive + description: If kube-proxy is running, and if it is using a file-based kubeconfig + file, ensure that the proxy kubeconfig file has permissions of 644 or more + restrictive. + profile_applicability: Level 1 - Worker Node + audit: + - aaa + - 'bbb ${0}' + remediation: |- + Run the below command (based on the file location on your system) on the each worker node. For example, + chmod 644 + check_type: multi_param + impact: None + eval_expr: "${1} <= 644;" + default_value: By default, proxy file has permissions of 640. + references: + - https://kubernetes.io/docs/admin/kube-proxy/ diff --git a/internal/cli/commands/fixtures/CheckMultiParamComplex.yml b/internal/cli/commands/fixtures/CheckMultiParamComplex.yml new file mode 100644 index 0000000..ba59a77 --- /dev/null +++ b/internal/cli/commands/fixtures/CheckMultiParamComplex.yml @@ -0,0 +1,30 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: 1.2.34 Ensure that encryption providers are appropriately configured + description: Where etcd encryption is used, appropriate providers should be + configured. + profile_applicability: Level 1 - Master Node + audit: + - aaa + - bbb + - ccc + - ddd + - eee + remediation: Follow the Kubernetes documentation and configure a EncryptionConfig + file. In this file, choose aescbc, kms or secretbox as the encryption provider. + check_type: multi_param + impact: None + eval_expr: "'${0}' == '${1}'; && (('${2}' == 'aescbc:'; && '${3}' == 'kms';) || '${4}' + == 'secretbox';)" + default_value: By default, no encryption provider is set. + references: + - https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/ + - https://acotten.com/post/kube17-security + - https://kubernetes.io/docs/admin/kube-apiserver/ + - https://github.com/kubernetes/features/issues/92 + - https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/#providers diff --git a/internal/cli/commands/fixtures/CheckMultiParamNOK.yml b/internal/cli/commands/fixtures/CheckMultiParamNOK.yml new file mode 100644 index 0000000..5136a27 --- /dev/null +++ b/internal/cli/commands/fixtures/CheckMultiParamNOK.yml @@ -0,0 +1,24 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: Ensure that the --authorization-mode argument includes RBAC (Automated) + description: Turn on Role Based Access Control. + profile_applicability: Level 1 - Master Node + audit: + - aaa + - 'bbb ${0}' + remediation: Edit the API server pod specification file /etc/kubernetes/manifests/kube- + apiserver.yaml on the master node and set the --authorization-mode parameter + to a value that includes RBAC, for example:--authorization-mode=Node,RBAC + check_type: multi_param + impact: When RBAC is enabled you will need to ensure that appropriate RBAC settings + (including Roles, RoleBindings and ClusterRoleBindings) are configured to + allow appropriate access. + eval_expr: "'${0}' != '${1}';" + default_value: By default, RBAC authorization is not enabled. + references: + - https://kubernetes.io/docs/reference/access-authn-authz/rbac/ diff --git a/internal/cli/commands/fixtures/CheckMultiParamNOKWithIN.yml b/internal/cli/commands/fixtures/CheckMultiParamNOKWithIN.yml new file mode 100644 index 0000000..f7cd379 --- /dev/null +++ b/internal/cli/commands/fixtures/CheckMultiParamNOKWithIN.yml @@ -0,0 +1,24 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: Ensure that the --authorization-mode argument includes RBAC (Automated) + description: Turn on Role Based Access Control. + profile_applicability: Level 1 - Master Node + audit: + - aaa + - 'bbb ${0}' + remediation: Edit the API server pod specification file /etc/kubernetes/manifests/kube- + apiserver.yaml on the master node and set the --authorization-mode parameter + to a value that includes RBAC, for example:--authorization-mode=Node,RBAC + check_type: multi_param + impact: When RBAC is enabled you will need to ensure that appropriate RBAC settings + (including Roles, RoleBindings and ClusterRoleBindings) are configured to + allow appropriate access. + eval_expr: "!('${0}' IN (${1}));" + default_value: By default, RBAC authorization is not enabled. + references: + - https://kubernetes.io/docs/reference/access-authn-authz/rbac/ diff --git a/internal/cli/commands/fixtures/CheckMultiParamOK.yml b/internal/cli/commands/fixtures/CheckMultiParamOK.yml new file mode 100644 index 0000000..dfa8c3b --- /dev/null +++ b/internal/cli/commands/fixtures/CheckMultiParamOK.yml @@ -0,0 +1,24 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: Ensure that the --authorization-mode argument includes RBAC (Automated) + description: Turn on Role Based Access Control. + profile_applicability: Level 1 - Master Node + audit: + - aaa + - 'bbb ${0}' + remediation: Edit the API server pod specification file /etc/kubernetes/manifests/kube- + apiserver.yaml on the master node and set the --authorization-mode parameter + to a value that includes RBAC, for example:--authorization-mode=Node,RBAC + check_type: multi_param + impact: When RBAC is enabled you will need to ensure that appropriate RBAC settings + (including Roles, RoleBindings and ClusterRoleBindings) are configured to + allow appropriate access. + eval_expr: "'${0}' == '${1}';" + default_value: By default, RBAC authorization is not enabled. + references: + - https://kubernetes.io/docs/reference/access-authn-authz/rbac/ diff --git a/internal/cli/commands/fixtures/CheckMultiParamOKWithIN.yml b/internal/cli/commands/fixtures/CheckMultiParamOKWithIN.yml new file mode 100644 index 0000000..35430a5 --- /dev/null +++ b/internal/cli/commands/fixtures/CheckMultiParamOKWithIN.yml @@ -0,0 +1,24 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: Ensure that the --authorization-mode argument includes RBAC (Automated) + description: Turn on Role Based Access Control. + profile_applicability: Level 1 - Master Node + audit: + - aaa + - 'bbb ${0}' + remediation: Edit the API server pod specification file /etc/kubernetes/manifests/kube- + apiserver.yaml on the master node and set the --authorization-mode parameter + to a value that includes RBAC, for example:--authorization-mode=Node,RBAC + check_type: multi_param + impact: When RBAC is enabled you will need to ensure that appropriate RBAC settings + (including Roles, RoleBindings and ClusterRoleBindings) are configured to + allow appropriate access. + eval_expr: "'${0}' IN (${1});" + default_value: By default, RBAC authorization is not enabled. + references: + - https://kubernetes.io/docs/reference/access-authn-authz/rbac/ diff --git a/internal/cli/commands/fixtures/CheckMultiParamPass1stResultToNext.yml b/internal/cli/commands/fixtures/CheckMultiParamPass1stResultToNext.yml new file mode 100644 index 0000000..4c5652c --- /dev/null +++ b/internal/cli/commands/fixtures/CheckMultiParamPass1stResultToNext.yml @@ -0,0 +1,26 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: 1.2.34 Ensure that encryption providers are appropriately configured + description: Where etcd encryption is used, appropriate providers should be + configured. + profile_applicability: Level 1 - Master Node + audit: + - aaa + - bbb + - 'ccc ${1}' + remediation: Follow the Kubernetes documentation and configure a EncryptionConfig + file. In this file, choose aescbc, kms or secretbox as the encryption provider. + check_type: multi_param + impact: None + eval_expr: "'${0}' == '${1}'; && (('${2}' == '- aescbc:'; && ${3} == '- kms:';) || + ${4} == '- secretbox:';)" + default_value: By default, no encryption provider is set. + references: + - aaa + - bbb + - 'ccc ${1}' diff --git a/internal/cli/commands/fixtures/CheckTypeComparator.yml b/internal/cli/commands/fixtures/CheckTypeComparator.yml new file mode 100644 index 0000000..a016df2 --- /dev/null +++ b/internal/cli/commands/fixtures/CheckTypeComparator.yml @@ -0,0 +1,24 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: 1.2.20 Ensure that the --secure-port argument is not set to 0 + description: Do not disable the secure port. + profile_applicability: Level 1 - Master Node + audit: + - ps -ef | grep kube-apiserver |grep 'secure-port' | grep -o 'secure-port=[^"]\S*' + | awk -F "=" '{print $2}' |awk 'FNR <= 1' + remediation: 'Edit the API server pod specification file /etc/kubernetes/manifests/kube- + apiserver.yaml on the master node and either remove the --secure-port parameter + or set it to a different (non-zero) desired port. + +' + check_type: multi_param + impact: You need to set the API Server up with the right TLS certificates. + eval_expr: "${0} > 0; && ${0} < 65535;" + default_value: By default, port 6443 is used as the secure port. + references: + - https://kubernetes.io/docs/admin/kube-apiserver/ diff --git a/internal/cli/commands/fixtures/CheckTypeMultiExprEmptyProcessParam.yml b/internal/cli/commands/fixtures/CheckTypeMultiExprEmptyProcessParam.yml new file mode 100644 index 0000000..fd14309 --- /dev/null +++ b/internal/cli/commands/fixtures/CheckTypeMultiExprEmptyProcessParam.yml @@ -0,0 +1,26 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: 1.2.14 Ensure that the admission control plugin ServiceAccount is set + description: Automate service accounts management. + profile_applicability: Level 1 - Master Node + audit: + - ps -ef | grep kube-apiserver |grep 'disable-admission-plugins' | grep -o 'disable-admission-plugins=[^"]\S*' + | awk -F "=" '{print $2}' |awk 'FNR <= 1' + remediation: Follow the documentation and create ServiceAccount objects as per + your environment. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- + apiserver.yaml on the master node and ensure that the --disable-admission-plugins + parameter is set to a value that does not include ServiceAccount. + check_type: multi_param + impact: None + eval_expr: "'${0}' != ''; && !('ServiceAccount' IN (${0}));" + default_value: By default, ServiceAccount is set. + references: + - https://kubernetes.io/docs/admin/kube-apiserver/ + - https://kubernetes.io/docs/admin/admission-controllers/#serviceaccount + - https://kubernetes.io/docs/tasks/configure-pod-container/configure-service- + account/ diff --git a/internal/cli/commands/fixtures/CheckTypeMultiExprProcessParam.yml b/internal/cli/commands/fixtures/CheckTypeMultiExprProcessParam.yml new file mode 100644 index 0000000..05566be --- /dev/null +++ b/internal/cli/commands/fixtures/CheckTypeMultiExprProcessParam.yml @@ -0,0 +1,24 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: 1.2.11 Ensure that the admission control plugin AlwaysAdmit is not set + description: Do not allow all requests. + profile_applicability: Level 1 - Master Node + audit: + - ps -ef | grep kube-apiserver |grep 'enable-admission-plugins' | grep -o 'enable-admission-plugins=[^"]\S*' + | awk -F "=" '{print $2}' |awk 'FNR <= 1' + remediation: Edit the API server pod specification file /etc/kubernetes/manifests/kube- + apiserver.yaml on the master node and either remove the --enable-admission-plugins + parameter, or set it to a value that does not include AlwaysAdmit. + check_type: multi_param + impact: Only requests explicitly allowed by the admissions control plugins would + be served. + eval_expr: "'${0}' != ''; && !('AlwaysAdmit' IN (${0}));" + default_value: AlwaysAdmit is not in the list of default admission plugins. + references: + - https://kubernetes.io/docs/admin/kube-apiserver/ + - https://kubernetes.io/docs/admin/admission-controllers/#alwaysadmit diff --git a/internal/cli/commands/fixtures/CheckTypeMultiProcessInClause.yml b/internal/cli/commands/fixtures/CheckTypeMultiProcessInClause.yml new file mode 100644 index 0000000..f90c9a1 --- /dev/null +++ b/internal/cli/commands/fixtures/CheckTypeMultiProcessInClause.yml @@ -0,0 +1,24 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: Ensure that the --authorization-mode argument includes RBAC (Automated) + description: Turn on Role Based Access Control. + profile_applicability: Level 1 - Master Node + audit: + - ps -ef | grep kube-apiserver |grep 'authorization-mode' | grep -o 'authorization-mode=[^"]\S*' + | awk -F "=" '{print $2}' |awk 'FNR <= 1' + remediation: Edit the API server pod specification file /etc/kubernetes/manifests/kube- + apiserver.yaml on the master node and set the --authorization-mode parameter + to a value that includes RBAC, for example:--authorization-mode=Node,RBAC + check_type: multi_param + impact: When RBAC is enabled you will need to ensure that appropriate RBAC settings + (including Roles, RoleBindings and ClusterRoleBindings) are configured to + allow appropriate access. + eval_expr: "!('RBAC' IN (${0}));" + default_value: By default, RBAC authorization is not enabled. + references: + - https://kubernetes.io/docs/reference/access-authn-authz/rbac/ diff --git a/internal/cli/commands/help/synopsis b/internal/cli/commands/help/synopsis new file mode 100644 index 0000000..e8c2524 --- /dev/null +++ b/internal/cli/commands/help/synopsis @@ -0,0 +1,7 @@ +Usage: %s [--version] [--help] [] + +Available commands are: + -r , --report : run audit tests and generate failure/warn report + -i , --include: execute only specific audit test, example -i=1.2.3,1.4.5 + -e , --exclude, ignore specific audit tests, example -e=1.2.3,1.4.5 + -c , --classic: test report in classic view diff --git a/internal/cli/commands/kube-mesh-kridik.go b/internal/cli/commands/kube-mesh-kridik.go new file mode 100644 index 0000000..131243c --- /dev/null +++ b/internal/cli/commands/kube-mesh-kridik.go @@ -0,0 +1,179 @@ +package commands + +import ( + "fmt" + "github.com/chen-keinan/go-command-eval/eval" + "github.com/chen-keinan/kube-mesh-kridik/internal/logger" + "github.com/chen-keinan/kube-mesh-kridik/internal/models" + "github.com/chen-keinan/kube-mesh-kridik/internal/reports" + "github.com/chen-keinan/kube-mesh-kridik/internal/startup" + "github.com/chen-keinan/kube-mesh-kridik/pkg/filters" + m2 "github.com/chen-keinan/kube-mesh-kridik/pkg/models" + "github.com/chen-keinan/kube-mesh-kridik/pkg/utils" + "github.com/chen-keinan/kube-mesh-kridik/ui" + "github.com/mitchellh/colorstring" + "github.com/olekukonko/tablewriter" + "os" +) + +//LxdAudit lxd benchmark object +type LxdAudit struct { + ResultProcessor ResultProcessor + OutputGenerator ui.OutputGenerator + FileLoader TestLoader + PredicateChain []filters.Predicate + PredicateParams []string + PlChan chan m2.MeshKridikSecurityResults + CompletedChan chan bool + FilesInfo []utils.FilesInfo + Evaluator eval.CmdEvaluator + log *logger.MeshKridikLogger +} + +// ResultProcessor process audit results +type ResultProcessor func(at *models.CheckSpec, isSucceeded bool) []*models.CheckSpec + +// ConsoleOutputGenerator print audit tests to stdout +var ConsoleOutputGenerator ui.OutputGenerator = func(at []*models.SubCategory, log *logger.MeshKridikLogger) { + grandTotal := make([]models.SecCheckTotals, 0) + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Category", "Status", "Type", "SecCheck Test Description"}) + table.SetAutoWrapText(false) + table.SetBorder(true) // Set + for _, a := range at { + categoryTotal := printTestResults(a.AuditTests, table, a.Name) + grandTotal = append(grandTotal, categoryTotal) + } + table.SetAutoMergeCellsByColumnIndex([]int{0}) + table.SetRowLine(true) + table.Render() + log.Console(printFinalResults(grandTotal)) +} + +// ClassicOutputGenerator print audit tests to stdout in classic view +var ClassicOutputGenerator ui.OutputGenerator = func(at []*models.SubCategory, log *logger.MeshKridikLogger) { + grandTotal := make([]models.SecCheckTotals, 0) + for _, a := range at { + log.Console(fmt.Sprintf("%s %s\n", "[Category]", a.Name)) + categoryTotal := printClassicTestResults(a.AuditTests, log) + grandTotal = append(grandTotal, categoryTotal) + } + log.Console(printFinalResults(grandTotal)) +} + +func printFinalResults(grandTotal []models.SecCheckTotals) string { + finalTotal := calculateFinalTotal(grandTotal) + passTest := colorstring.Color("[green]Pass:") + failTest := colorstring.Color("[red]Fail:") + warnTest := colorstring.Color("[yellow]Warn:") + title := "Test Result Total: " + return fmt.Sprintf("%s %s %d , %s %d , %s %d ", title, passTest, finalTotal.Pass, warnTest, finalTotal.Warn, failTest, finalTotal.Fail) +} + +func calculateFinalTotal(granTotal []models.SecCheckTotals) models.SecCheckTotals { + var ( + warn int + fail int + pass int + ) + for _, total := range granTotal { + warn = warn + total.Warn + fail = fail + total.Fail + pass = pass + total.Pass + } + return models.SecCheckTotals{Pass: pass, Fail: fail, Warn: warn} +} + +// ReportOutputGenerator print failed audit test to human report +var ReportOutputGenerator ui.OutputGenerator = func(at []*models.SubCategory, log *logger.MeshKridikLogger) { + for _, a := range at { + log.Table(reports.GenerateAuditReport(a.AuditTests)) + } +} + +// simpleResultProcessor process audit results to stdout print only +var simpleResultProcessor ResultProcessor = func(at *models.CheckSpec, isSucceeded bool) []*models.CheckSpec { + return AddAllMessages(at, isSucceeded) +} + +// ResultProcessor process audit results to std out and failure results +var reportResultProcessor ResultProcessor = func(at *models.CheckSpec, isSucceeded bool) []*models.CheckSpec { + // append failed messages + return AddFailedMessages(at, isSucceeded) +} + +//CmdEvaluator interface expose one method to evaluate command with evalExpr +//lxd-seccheck.go +//go:generate mockgen -destination=../mocks/mock_CmdEvaluator.go -package=mocks . CmdEvaluator +type CmdEvaluator interface { + EvalCommand(commands []string, evalExpr string) eval.CmdEvalResult +} + +//NewLxdAudit new audit object +func NewLxdAudit(filters []string, plChan chan m2.MeshKridikSecurityResults, completedChan chan bool, fi []utils.FilesInfo, evaluator CmdEvaluator) *LxdAudit { + return &LxdAudit{ + PredicateChain: buildPredicateChain(filters), + PredicateParams: buildPredicateChainParams(filters), + ResultProcessor: GetResultProcessingFunction(filters), + OutputGenerator: getOutputGeneratorFunction(filters), + FileLoader: NewFileLoader(), + PlChan: plChan, + FilesInfo: fi, + Evaluator: evaluator, + CompletedChan: completedChan} +} + +//Help return benchmark command help +func (ldx LxdAudit) Help() string { + return startup.GetHelpSynopsis() +} + +//Run execute the full lxd benchmark +func (ldx *LxdAudit) Run(args []string) int { + // load audit tests fro benchmark folder + auditTests := ldx.FileLoader.LoadAuditTests(ldx.FilesInfo) + // filter tests by cmd criteria + ft := filteredAuditBenchTests(auditTests, ldx.PredicateChain, ldx.PredicateParams) + //execute audit tests and show it in progress bar + completedTest := executeTests(ft, ldx.runAuditTest, ldx.log) + // generate output data + ui.PrintOutput(completedTest, ldx.OutputGenerator, ldx.log) + // send test results to plugin + sendResultToPlugin(ldx.PlChan, ldx.CompletedChan, completedTest) + return 0 +} + +func sendResultToPlugin(plChan chan m2.MeshKridikSecurityResults, completedChan chan bool, auditTests []*models.SubCategory) { + ka := m2.MeshKridikSecurityResults{BenchmarkType: "lxd", Categories: make([]m2.AuditBenchResult, 0)} + for _, at := range auditTests { + for _, ab := range at.AuditTests { + var testResult = "FAIL" + if ab.TestSucceed { + testResult = "PASS" + } + abr := m2.AuditBenchResult{Category: at.Name, ProfileApplicability: ab.ProfileApplicability, Description: ab.Description, AuditCommand: ab.AuditCommand, Remediation: ab.Remediation, Impact: ab.Impact, AdditionalInfo: ab.AdditionalInfo, References: ab.References, TestResult: testResult} + ka.Categories = append(ka.Categories, abr) + } + } + plChan <- ka + <-completedChan +} + +// runAuditTest execute category of audit tests +func (ldx *LxdAudit) runAuditTest(at *models.CheckSpec) []*models.CheckSpec { + auditRes := make([]*models.CheckSpec, 0) + if at.NonApplicable { + auditRes = append(auditRes, at) + return auditRes + } + // execute audit test command + cmdEvalResult := ldx.Evaluator.EvalCommand(at.AuditCommand, at.EvalExpr) + // continue with result processing + auditRes = append(auditRes, ldx.ResultProcessor(at, cmdEvalResult.Match)...) + return auditRes +} + +//Synopsis for help +func (ldx *LxdAudit) Synopsis() string { + return ldx.Help() +} diff --git a/internal/common/globalconsts.go b/internal/common/globalconsts.go new file mode 100644 index 0000000..599314b --- /dev/null +++ b/internal/common/globalconsts.go @@ -0,0 +1,100 @@ +package common + +const ( + //FilesystemConfiguration file name + FilesystemConfiguration = "1.1_filesystem_configuration.yml" + //ConfigureSoftwareUpdates file name + ConfigureSoftwareUpdates = "1.2_configure_software_updates.yml" + //ConfigureSudo file name + ConfigureSudo = "1.3_configure_sudo.yml" + //FilesystemIntegrityChecking file name + FilesystemIntegrityChecking = "1.4_filesystem_integrity_checking.yml" + //AdditionalProcessHardening file name + AdditionalProcessHardening = "1.5_additional_process_hardening.yml" + //MandatoryAccessControl file name + MandatoryAccessControl = "1.6_mandatory_access_control.yml" + //WarningBanners file name + WarningBanners = "1.7_warning_banners.yml" + //EnsureUpdates file name + EnsureUpdates = "1.8_ensure_updates.yml" + //InetdServices file name + InetdServices = "2.1_inetd_services.yml" + //SpecialPurposeServices file name + SpecialPurposeServices = "2.2_special_purpose_services.yml" + //ServiceClients file name + ServiceClients = "2.3_service_clients.yml" + //NonessentialServices file name + NonessentialServices = "2.4_nonessential_services.yml" + //NetworkParameters file name + NetworkParameters = "3.1_network_parameters.yml" + //NetworkParametersHost file name + NetworkParametersHost = "3.2_network_parameters_host.yml" + //TCPWrappers file name + TCPWrappers = "3.3_tcp_wrappers.yml" + //FirewallConfiguration file name + FirewallConfiguration = "3.4_firewall_configuration.yml" + //ConfigureLogging file name + ConfigureLogging = "4.1_configure_logging.yml" + //EnsureLogrotateConfigured file name + EnsureLogrotateConfigured = "4.2_ensure_logrotate_configured.yml" + //EnsureLogrotateAssignsAppropriatePermissions file name + EnsureLogrotateAssignsAppropriatePermissions = "4.3_ensure_logrotate_assigns_appropriate_permissions.yml" + //ConfigureCron file name + ConfigureCron = "5.1_configure_cron.yml" + //SSHServerConfiguration file name + SSHServerConfiguration = "5.2_ssh_server_configuration.yml" + //ConfigurePam file name + ConfigurePam = "5.3_configure_pam.yml" + //UserAccountsAndEnvironment file name + UserAccountsAndEnvironment = "5.4_user_accounts_and_environment.yml" + //RootLoginRestrictedSystemConsole file name + RootLoginRestrictedSystemConsole = "5.5_root_login_restricted_system_console.yml" + //EnsureAccessSuCommandRestricted file name + EnsureAccessSuCommandRestricted = "5.6_ensure_access_su_command_restricted.yml" + //SystemFilePermissions file name + SystemFilePermissions = "6.1_system_file_permissions.yml" + //UserAndGroupSettings file name + UserAndGroupSettings = "6.2_user_and_group_settings.yml" + //GrepRegex for tests + GrepRegex = "[^\"]\\S*'" + //MultiValue for tests + MultiValue = "MultiValue" + //SingleValue for tests + SingleValue = "SingleValue" + //EmptyValue for test + EmptyValue = "EmptyValue" + //NotValidNumber value + NotValidNumber = "10000" + //Report arg + Report = "r" + //ReportFull arg + ReportFull = "report" + //Classic arg + Classic = "c" + //ClassicFull arg + ClassicFull = "classic" + //Synopsis help + Synopsis = "synopsis" + //LdxProbeCli Name + LdxProbeCli = "ldx-probe" + //LdxProbeVersion version + LdxProbeVersion = "0.1" + //IncludeParam param + IncludeParam = "i=" + //ExcludeParam param + ExcludeParam = "e=" + //NodeParam param + NodeParam = "n=" + //LxdProbeHomeEnvVar ldx probe Home env var + LxdProbeHomeEnvVar = "LXD_PROBE_HOME" + //LxdProbe binary name + LxdProbe = "kube-mesh-kridik" + //RootUser process user owner + RootUser = "root" + //NonApplicableTest test is not applicable + NonApplicableTest = "non_applicable" + //ManualTest test can only be manual executed + ManualTest = "manual" + //LxdBenchAuditResultHook hook name + LxdBenchAuditResultHook = "LxdBenchAuditResultHook" +) diff --git a/internal/hooks/worker.go b/internal/hooks/worker.go new file mode 100644 index 0000000..469f5ed --- /dev/null +++ b/internal/hooks/worker.go @@ -0,0 +1,54 @@ +package hooks + +import ( + "fmt" + "github.com/chen-keinan/go-user-plugins/uplugin" + "github.com/chen-keinan/kube-mesh-kridik/pkg/models" + "go.uber.org/zap" + "plugin" +) + +//PluginWorker instance which match command data to specific pattern +type PluginWorker struct { + cmd *PluginWorkerData + log *zap.Logger +} + +//LxdBenchAuditResultHook hold the plugin symbol for Lxd bench audit result Hook +type LxdBenchAuditResultHook struct { + Plugins []plugin.Symbol + Plug *uplugin.PluginLoader +} + +//NewPluginWorker return new plugin worker instance +func NewPluginWorker(commandMatchData *PluginWorkerData, log *zap.Logger) *PluginWorker { + return &PluginWorker{cmd: commandMatchData, log: log} +} + +//NewPluginWorkerData return new plugin worker instance +func NewPluginWorkerData(plChan chan models.MeshKridikSecurityResults, hook LxdBenchAuditResultHook, completedChan chan bool) *PluginWorkerData { + return &PluginWorkerData{plChan: plChan, plugins: hook, completedChan: completedChan} +} + +//PluginWorkerData encapsulate plugin worker properties +type PluginWorkerData struct { + plChan chan models.MeshKridikSecurityResults + completedChan chan bool + plugins LxdBenchAuditResultHook +} + +//Invoke invoke plugin accept audit bench results +func (pm *PluginWorker) Invoke() { + go func() { + ae := <-pm.cmd.plChan + if len(pm.cmd.plugins.Plugins) > 0 { + for _, pl := range pm.cmd.plugins.Plugins { + _, err := pm.cmd.plugins.Plug.Invoke(pl, ae) + if err != nil { + pm.log.Error(fmt.Sprintf("failed to execute plugins %s", err.Error())) + } + } + } + pm.cmd.completedChan <- true + }() +} diff --git a/internal/hooks/worker_test.go b/internal/hooks/worker_test.go new file mode 100644 index 0000000..d823026 --- /dev/null +++ b/internal/hooks/worker_test.go @@ -0,0 +1,18 @@ +package hooks + +import ( + m2 "github.com/chen-keinan/kube-mesh-kridik/pkg/models" + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + "testing" +) + +func Test_NewPluginWorker(t *testing.T) { + production, err := zap.NewProduction() + assert.NoError(t, err) + completedChan := make(chan bool) + plChan := make(chan m2.LxdAuditResults) + pw := NewPluginWorker(NewPluginWorkerData(plChan, LxdBenchAuditResultHook{}, completedChan), production) + assert.True(t, len(pw.cmd.plugins.Plugins) == 0) + +} diff --git a/internal/logger/ldxlogger.go b/internal/logger/ldxlogger.go new file mode 100644 index 0000000..f143e6d --- /dev/null +++ b/internal/logger/ldxlogger.go @@ -0,0 +1,26 @@ +package logger + +import ( + "log" +) + +//MeshKridikLogger Object +type MeshKridikLogger struct { +} + +//GetLog return native logger +func GetLog() *MeshKridikLogger { + return &MeshKridikLogger{} +} + +//Console print to console +func (BLogger *MeshKridikLogger) Console(str string) { + log.SetFlags(0) + log.Print(str) +} + +//Table print to console +func (BLogger *MeshKridikLogger) Table(v interface{}) { + log.SetFlags(0) + log.Print(v) +} diff --git a/internal/models/fixtures/manual.yml b/internal/models/fixtures/manual.yml new file mode 100644 index 0000000..17670cc --- /dev/null +++ b/internal/models/fixtures/manual.yml @@ -0,0 +1,25 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: Ensure that the --authorization-mode argument includes RBAC (Automated) + description: Turn on Role Based Access Control. + profile_applicability: Level 1 - Master Node + audit: + - ps -ef | grep kube-apiserver |grep 'authorization-mode' | grep -o 'authorization-mode=[^"]\S*' + | awk -F "=" '{print $2}' |awk 'FNR <= 1' + remediation: Edit the API server pod specification file /etc/kubernetes/manifests/kube- + apiserver.yaml on the master node and set the --authorization-mode parameter + to a value that includes RBAC, for example:--authorization-mode=Node,RBAC + check_type: multi_param + impact: When RBAC is enabled you will need to ensure that appropriate RBAC settings + (including Roles, RoleBindings and ClusterRoleBindings) are configured to + allow appropriate access. + type: manual + eval_expr: "'RBAC' IN ($1)" + default_value: By default, RBAC authorization is not enabled. + references: + - https://kubernetes.io/docs/reference/access-authn-authz/rbac/ diff --git a/internal/models/fixtures/no_applicable.yml b/internal/models/fixtures/no_applicable.yml new file mode 100644 index 0000000..3205825 --- /dev/null +++ b/internal/models/fixtures/no_applicable.yml @@ -0,0 +1,25 @@ +--- +benchmark_type: lxd +categories: + - name: Control Plane Components + sub_category: + name: API Server + audit_tests: + - name: Ensure that the --authorization-mode argument includes RBAC (Automated) + description: Turn on Role Based Access Control. + profile_applicability: Level 1 - Master Node + audit: + - ps -ef | grep kube-apiserver |grep 'authorization-mode' | grep -o 'authorization-mode=[^"]\S*' + | awk -F "=" '{print $2}' |awk 'FNR <= 1' + remediation: Edit the API server pod specification file /etc/kubernetes/manifests/kube- + apiserver.yaml on the master node and set the --authorization-mode parameter + to a value that includes RBAC, for example:--authorization-mode=Node,RBAC + check_type: multi_param + impact: When RBAC is enabled you will need to ensure that appropriate RBAC settings + (including Roles, RoleBindings and ClusterRoleBindings) are configured to + allow appropriate access. + type: non_applicable + eval_expr: "'RBAC' IN ($1)" + default_value: By default, RBAC authorization is not enabled. + references: + - https://kubernetes.io/docs/reference/access-authn-authz/rbac/ diff --git a/internal/models/seccheck.go b/internal/models/seccheck.go new file mode 100644 index 0000000..8daff6d --- /dev/null +++ b/internal/models/seccheck.go @@ -0,0 +1,72 @@ +package models + +import ( + "github.com/chen-keinan/kube-mesh-kridik/internal/common" + "github.com/mitchellh/mapstructure" +) + +//SecCheck data model +type SecCheck struct { + BenchmarkType string `yaml:"benchmark_type"` + Categories []Category `yaml:"categories"` +} + +//SecCheckTotals model +type SecCheckTotals struct { + Warn int + Pass int + Fail int +} + +//Category data model +type Category struct { + Name string `yaml:"name"` + SubCategory *SubCategory `yaml:"sub_category"` +} + +//SubCategory data model +type SubCategory struct { + Name string `yaml:"name"` + AuditTests []*CheckSpec `yaml:"audit_tests"` +} + +//CheckSpec data model +type CheckSpec struct { + Name string `mapstructure:"name" yaml:"name"` + ProfileApplicability string `mapstructure:"profile_applicability" yaml:"profile_applicability"` + Description string `mapstructure:"description" yaml:"description"` + AuditCommand []string `mapstructure:"audit" json:"audit"` + CheckType string `mapstructure:"check_type" yaml:"check_type"` + Remediation string `mapstructure:"remediation" yaml:"remediation"` + Impact string `mapstructure:"impact" yaml:"impact"` + AdditionalInfo string `mapstructure:"additional_info" yaml:"additional_info"` + References []string `mapstructure:"references" yaml:"references"` + EvalExpr string `mapstructure:"eval_expr" yaml:"eval_expr"` + TestSucceed bool + CommandParams map[int][]string + Category string + NonApplicable bool + TestType string `mapstructure:"type" yaml:"type"` +} + +//AuditResult data +type AuditResult struct { + NumOfExec int + NumOfSuccess int +} + +//UnmarshalYAML over unmarshall to add logic +func (at *CheckSpec) UnmarshalYAML(unmarshal func(interface{}) error) error { + var res map[string]interface{} + if err := unmarshal(&res); err != nil { + return err + } + err := mapstructure.Decode(res, &at) + if err != nil { + return err + } + if at.TestType == common.NonApplicableTest || at.TestType == common.ManualTest { + at.NonApplicable = true + } + return nil +} diff --git a/internal/models/seccheck_test.go b/internal/models/seccheck_test.go new file mode 100644 index 0000000..a909e6d --- /dev/null +++ b/internal/models/seccheck_test.go @@ -0,0 +1,47 @@ +package models + +import ( + "fmt" + "github.com/chen-keinan/kube-mesh-kridik/internal/common" + "gopkg.in/yaml.v2" + "io/ioutil" + "os" + "testing" +) + +func TestAuditBench_UnmarshalYAML(t *testing.T) { + tests := []struct { + name string + fileName string + want string + }{ + {name: "non applicable test", fileName: "no_applicable.yml", want: common.NonApplicableTest}, + {name: "manual test", fileName: "manual.yml", want: common.ManualTest}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ab := SecCheck{} + err := yaml.Unmarshal(readTestData(tt.fileName, t), &ab) + if err != nil { + t.Errorf("TestAuditBench_UnmarshalYAML failed to unmarshal json %v", err) + } + got := ab.Categories[0].SubCategory.AuditTests[0].TestType + if tt.want != got { + t.Errorf("TestAuditBench_UnmarshalYAML want %v got %v", tt.want, got) + } + }) + } +} + +func readTestData(fileName string, t *testing.T) []byte { + f, err := os.Open(fmt.Sprintf("./fixtures/%s", fileName)) + if err != nil { + t.Fatal(err) + } + b, err := ioutil.ReadAll(f) + if err != nil { + t.Fatal(err) + } + f.Close() + return b +} diff --git a/internal/reports/processor.go b/internal/reports/processor.go new file mode 100644 index 0000000..1ab6e9c --- /dev/null +++ b/internal/reports/processor.go @@ -0,0 +1,28 @@ +package reports + +import ( + "github.com/chen-keinan/kube-mesh-kridik/internal/models" + "github.com/gosuri/uitable" +) + +//GenerateAuditReport generate failed audit report +func GenerateAuditReport(adtsReport []*models.CheckSpec) *uitable.Table { + table := uitable.New() + for _, failedAudit := range adtsReport { + table.MaxColWidth = 100 + status := "Failed" + if failedAudit.NonApplicable { + status = "Warn" + } + table.Wrap = true // wrap columns + table.AddRow("--------------", "-------------------------------------------------------------------------------------------") + table.AddRow("Status:", status) + table.AddRow("Name:", failedAudit.Name) + table.AddRow("Description:", failedAudit.Description) + table.AddRow("SecCheck:", failedAudit.AuditCommand) + table.AddRow("Remediation:", failedAudit.Remediation) + table.AddRow("References:", failedAudit.References) + table.AddRow("") // blank + } + return table +} diff --git a/internal/reports/processor_test.go b/internal/reports/processor_test.go new file mode 100644 index 0000000..a7b93e5 --- /dev/null +++ b/internal/reports/processor_test.go @@ -0,0 +1,16 @@ +package reports + +import ( + "github.com/chen-keinan/kube-mesh-kridik/internal/models" + "github.com/magiconair/properties/assert" + "testing" +) + +//Test_GenerateAuditReport test +func Test_GenerateAuditReport(t *testing.T) { + ab := make([]*models.CheckSpec, 0) + ab = append(ab, &models.CheckSpec{Name: "aaa", Description: "bbb", Impact: "ccc", Remediation: "ddd"}) + tb := GenerateAuditReport(ab) + s := tb.String() + assert.Equal(t, s, "--------------\t-------------------------------------------------------------------------------------------\nStatus: \tFailed \nName: \taaa \nDescription: \tbbb \nAudit: \t[] \nRemediation: \tddd \nReferences: \t[] \n ") +} diff --git a/internal/startup/templates.go b/internal/startup/templates.go new file mode 100644 index 0000000..e0f0296 --- /dev/null +++ b/internal/startup/templates.go @@ -0,0 +1,219 @@ +package startup + +import ( + "fmt" + "github.com/chen-keinan/kube-mesh-kridik/internal/common" + "github.com/chen-keinan/kube-mesh-kridik/pkg/utils" + "github.com/gobuffalo/packr" + "os" + "path/filepath" +) + +//GenerateLxdBenchmarkFiles use packr to load benchmark audit test yaml +//nolint:gocyclo +func GenerateLxdBenchmarkFiles() ([]utils.FilesInfo, error) { + fileInfo := make([]utils.FilesInfo, 0) + box := packr.NewBox("./../benchmark/lxd/v1.0.0/") + // Add Master Node Configuration tests + //1 + mnc, err := box.FindString(common.FilesystemConfiguration) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.FilesystemConfiguration, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.FilesystemConfiguration, Data: mnc}) + //2 + su, err := box.FindString(common.ConfigureSoftwareUpdates) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.ConfigureSoftwareUpdates, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.ConfigureSoftwareUpdates, Data: su}) + //3 + cs, err := box.FindString(common.ConfigureSudo) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.ConfigureSudo, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.ConfigureSudo, Data: cs}) + //4 + ic, err := box.FindString(common.FilesystemIntegrityChecking) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.FilesystemIntegrityChecking, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.FilesystemIntegrityChecking, Data: ic}) + //5 + ah, err := box.FindString(common.AdditionalProcessHardening) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.AdditionalProcessHardening, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.AdditionalProcessHardening, Data: ah}) + //6 + mac, err := box.FindString(common.MandatoryAccessControl) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.MandatoryAccessControl, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.MandatoryAccessControl, Data: mac}) + //7 + wb, err := box.FindString(common.WarningBanners) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.WarningBanners, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.WarningBanners, Data: wb}) + //8 + eu, err := box.FindString(common.EnsureUpdates) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.EnsureUpdates, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.EnsureUpdates, Data: eu}) + //9 + is, err := box.FindString(common.InetdServices) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.InetdServices, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.InetdServices, Data: is}) + //10 + sps, err := box.FindString(common.SpecialPurposeServices) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.SpecialPurposeServices, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.SpecialPurposeServices, Data: sps}) + //11 + sci, err := box.FindString(common.ServiceClients) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.ServiceClients, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.ServiceClients, Data: sci}) + //12 + nes, err := box.FindString(common.NonessentialServices) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.NonessentialServices, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.NonessentialServices, Data: nes}) + //13 + np, err := box.FindString(common.NetworkParameters) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.NetworkParameters, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.NetworkParameters, Data: np}) + //14 + nps, err := box.FindString(common.NetworkParametersHost) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.NetworkParametersHost, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.NetworkParametersHost, Data: nps}) + //15 + tw, err := box.FindString(common.TCPWrappers) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.TCPWrappers, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.TCPWrappers, Data: tw}) + //15 + fc, err := box.FindString(common.FirewallConfiguration) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.FirewallConfiguration, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.FirewallConfiguration, Data: fc}) + //16 + cf, err := box.FindString(common.ConfigureLogging) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.ConfigureLogging, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.ConfigureLogging, Data: cf}) + //16 + elc, err := box.FindString(common.EnsureLogrotateConfigured) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.EnsureLogrotateConfigured, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.EnsureLogrotateConfigured, Data: elc}) + //17 + elap, err := box.FindString(common.EnsureLogrotateAssignsAppropriatePermissions) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.EnsureLogrotateAssignsAppropriatePermissions, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.EnsureLogrotateAssignsAppropriatePermissions, Data: elap}) + //18 + cc, err := box.FindString(common.ConfigureCron) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.ConfigureCron, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.ConfigureCron, Data: cc}) + //19 + ssc, err := box.FindString(common.SSHServerConfiguration) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.SSHServerConfiguration, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.SSHServerConfiguration, Data: ssc}) + //20 + cp, err := box.FindString(common.ConfigurePam) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.ConfigurePam, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.ConfigurePam, Data: cp}) + //21 + uaae, err := box.FindString(common.UserAccountsAndEnvironment) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.UserAccountsAndEnvironment, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.UserAccountsAndEnvironment, Data: uaae}) + //22 + rrs, err := box.FindString(common.RootLoginRestrictedSystemConsole) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.RootLoginRestrictedSystemConsole, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.RootLoginRestrictedSystemConsole, Data: rrs}) + //23 + easc, err := box.FindString(common.EnsureAccessSuCommandRestricted) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.EnsureAccessSuCommandRestricted, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.EnsureAccessSuCommandRestricted, Data: easc}) + //24 + sfp, err := box.FindString(common.SystemFilePermissions) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.SystemFilePermissions, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.SystemFilePermissions, Data: sfp}) + //25 + ugs, err := box.FindString(common.UserAndGroupSettings) + if err != nil { + return []utils.FilesInfo{}, fmt.Errorf("faild to load lxd benchmarks audit tests %s %s", common.UserAndGroupSettings, err.Error()) + } + fileInfo = append(fileInfo, utils.FilesInfo{Name: common.UserAndGroupSettings, Data: ugs}) + return fileInfo, nil +} + +//GetHelpSynopsis get help synopsis file +func GetHelpSynopsis() string { + box := packr.NewBox("./../cli/commands/help/") + // Add Master Node Configuration tests + hs, err := box.FindString(common.Synopsis) + if err != nil { + panic(fmt.Sprintf("faild to load cli help synopsis %s", err.Error())) + } + return hs +} + +//SaveBenchmarkFilesIfNotExist create benchmark audit file if not exist +func SaveBenchmarkFilesIfNotExist(spec, version string, filesData []utils.FilesInfo) error { + fm := utils.NewKFolder() + folder, err := utils.GetBenchmarkFolder(spec, version, fm) + if err != nil { + return err + } + for _, fileData := range filesData { + filePath := filepath.Join(folder, fileData.Name) + if _, err := os.Stat(filePath); os.IsNotExist(err) { + f, err := os.Create(filePath) + if err != nil { + return fmt.Errorf(err.Error()) + } + _, err = f.WriteString(fileData.Data) + if err != nil { + return fmt.Errorf("failed to write benchmark file") + } + err = f.Close() + if err != nil { + return fmt.Errorf("faild to close file %s", filePath) + } + } + } + return nil +} diff --git a/internal/startup/templates_test.go b/internal/startup/templates_test.go new file mode 100644 index 0000000..635ee33 --- /dev/null +++ b/internal/startup/templates_test.go @@ -0,0 +1,100 @@ +package startup + +import ( + "github.com/chen-keinan/kube-mesh-kridik/internal/common" + "github.com/chen-keinan/kube-mesh-kridik/pkg/utils" + "github.com/stretchr/testify/assert" + "os" + "testing" +) + +//Test_CreateLxdBenchmarkFilesIfNotExist test +func Test_CreateLxdBenchmarkFilesIfNotExist(t *testing.T) { + bFiles, err := GenerateLxdBenchmarkFiles() + if err != nil { + t.Fatal(err) + } + // generate test with packr + assert.Equal(t, bFiles[0].Name, common.FilesystemConfiguration) + assert.Equal(t, bFiles[1].Name, common.ConfigureSoftwareUpdates) + assert.Equal(t, bFiles[2].Name, common.ConfigureSudo) + assert.Equal(t, bFiles[3].Name, common.FilesystemIntegrityChecking) + assert.Equal(t, bFiles[4].Name, common.AdditionalProcessHardening) + assert.Equal(t, bFiles[5].Name, common.MandatoryAccessControl) + assert.Equal(t, bFiles[6].Name, common.WarningBanners) + assert.Equal(t, bFiles[7].Name, common.EnsureUpdates) + assert.Equal(t, bFiles[8].Name, common.InetdServices) + assert.Equal(t, bFiles[9].Name, common.SpecialPurposeServices) + assert.Equal(t, bFiles[10].Name, common.ServiceClients) + assert.Equal(t, bFiles[11].Name, common.NonessentialServices) + assert.Equal(t, bFiles[12].Name, common.NetworkParameters) + assert.Equal(t, bFiles[13].Name, common.NetworkParametersHost) + assert.Equal(t, bFiles[14].Name, common.TCPWrappers) + assert.Equal(t, bFiles[15].Name, common.FirewallConfiguration) + assert.Equal(t, bFiles[16].Name, common.ConfigureLogging) + assert.Equal(t, bFiles[17].Name, common.EnsureLogrotateConfigured) + assert.Equal(t, bFiles[18].Name, common.EnsureLogrotateAssignsAppropriatePermissions) + assert.Equal(t, bFiles[19].Name, common.ConfigureCron) + assert.Equal(t, bFiles[20].Name, common.SSHServerConfiguration) + assert.Equal(t, bFiles[21].Name, common.ConfigurePam) + assert.Equal(t, bFiles[22].Name, common.UserAccountsAndEnvironment) + assert.Equal(t, bFiles[23].Name, common.RootLoginRestrictedSystemConsole) + assert.Equal(t, bFiles[24].Name, common.EnsureAccessSuCommandRestricted) + assert.Equal(t, bFiles[25].Name, common.SystemFilePermissions) + assert.Equal(t, bFiles[26].Name, common.UserAndGroupSettings) + fm := utils.NewKFolder() + err = utils.CreateBenchmarkFolderIfNotExist("lxd", "v1.0.0", fm) + assert.NoError(t, err) + // save benchmark files to folder + err = SaveBenchmarkFilesIfNotExist("lxd", "v1.0.0", bFiles) + assert.NoError(t, err) + // fetch files from benchmark folder + bFiles, err = utils.GetLxdBenchAuditFiles("lxd", "v1.0.0", fm) + assert.Equal(t, bFiles[0].Name, common.FilesystemConfiguration) + assert.Equal(t, bFiles[1].Name, common.ConfigureSoftwareUpdates) + assert.Equal(t, bFiles[2].Name, common.ConfigureSudo) + assert.Equal(t, bFiles[3].Name, common.FilesystemIntegrityChecking) + assert.Equal(t, bFiles[4].Name, common.AdditionalProcessHardening) + assert.Equal(t, bFiles[5].Name, common.MandatoryAccessControl) + assert.Equal(t, bFiles[6].Name, common.WarningBanners) + assert.Equal(t, bFiles[7].Name, common.EnsureUpdates) + assert.Equal(t, bFiles[8].Name, common.InetdServices) + assert.Equal(t, bFiles[9].Name, common.SpecialPurposeServices) + assert.Equal(t, bFiles[10].Name, common.ServiceClients) + assert.Equal(t, bFiles[11].Name, common.NonessentialServices) + assert.Equal(t, bFiles[12].Name, common.NetworkParameters) + assert.Equal(t, bFiles[13].Name, common.NetworkParametersHost) + assert.Equal(t, bFiles[14].Name, common.TCPWrappers) + assert.Equal(t, bFiles[15].Name, common.FirewallConfiguration) + assert.Equal(t, bFiles[16].Name, common.ConfigureLogging) + assert.Equal(t, bFiles[17].Name, common.EnsureLogrotateConfigured) + assert.Equal(t, bFiles[18].Name, common.EnsureLogrotateAssignsAppropriatePermissions) + assert.Equal(t, bFiles[19].Name, common.ConfigureCron) + assert.Equal(t, bFiles[20].Name, common.SSHServerConfiguration) + assert.Equal(t, bFiles[21].Name, common.ConfigurePam) + assert.Equal(t, bFiles[22].Name, common.UserAccountsAndEnvironment) + assert.Equal(t, bFiles[23].Name, common.RootLoginRestrictedSystemConsole) + assert.Equal(t, bFiles[24].Name, common.EnsureAccessSuCommandRestricted) + assert.Equal(t, bFiles[25].Name, common.SystemFilePermissions) + assert.Equal(t, bFiles[26].Name, common.UserAndGroupSettings) + assert.NoError(t, err) + err = os.RemoveAll(utils.GetHomeFolder()) + assert.NoError(t, err) +} + +//Test_GetHelpSynopsis test +func Test_GetHelpSynopsis(t *testing.T) { + hs := GetHelpSynopsis() + assert.True(t, len(hs) != 0) +} + +//Test_SaveBenchmarkFilesIfNotExist test +func Test_SaveBenchmarkFilesIfNotExist(t *testing.T) { + fm := utils.NewKFolder() + folder, err2 := utils.GetBenchmarkFolder("lxd", "v1.6.0", fm) + assert.NoError(t, err2) + err := os.RemoveAll(folder) + assert.NoError(t, err) + err = os.RemoveAll(utils.GetHomeFolder()) + assert.NoError(t, err) +} diff --git a/jobs/lxd-probe.yaml b/jobs/lxd-probe.yaml new file mode 100644 index 0000000..6eaf0bb --- /dev/null +++ b/jobs/lxd-probe.yaml @@ -0,0 +1,50 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: kube-mesh-kridik +spec: + template: + metadata: + labels: + app: kube-mesh-kridik + spec: + hostPID: true + containers: + - name: kube-mesh-kridik + image: chenkeinan/kube-mesh-kridik:latest + command: ["./kube-mesh-kridik"] + volumeMounts: + - name: var-lib-etcd + mountPath: /var/lib/etcd + readOnly: true + - name: var-lib-kubelet + mountPath: /var/lib/kubelet + readOnly: true + - name: etc-systemd + mountPath: /etc/systemd + readOnly: true + - name: etc-kubernetes + mountPath: /etc/kubernetes + readOnly: true + - name: usr-bin + mountPath: /usr/bin + readOnly: true + restartPolicy: Never + volumes: + - name: var-lib-etcd + hostPath: + path: "/var/lib/etcd" + - name: var-lib-kubelet + hostPath: + path: "/var/lib/kubelet" + - name: etc-systemd + hostPath: + path: "/etc/systemd" + - name: etc-kubernetes + hostPath: + path: "/etc/kubernetes" + - name: usr-bin + hostPath: + path: "/usr/bin" + tolerations: + - operator: "Exists" \ No newline at end of file diff --git a/pkg/README.md b/pkg/README.md new file mode 100644 index 0000000..ea5aa4c --- /dev/null +++ b/pkg/README.md @@ -0,0 +1,3 @@ +# `/pkg` + +expose lib functions \ No newline at end of file diff --git a/pkg/filters/predicate.go b/pkg/filters/predicate.go new file mode 100644 index 0000000..e92892d --- /dev/null +++ b/pkg/filters/predicate.go @@ -0,0 +1,82 @@ +package filters + +import ( + "github.com/chen-keinan/kube-mesh-kridik/internal/models" + "github.com/chen-keinan/kube-mesh-kridik/pkg/utils" + "strings" +) + +// Predicate filter audit tests cmd criteria +type Predicate func(tests *models.SubCategory, params string) *models.SubCategory + +// IncludeAudit include audit tests , only included tests will be executed +var IncludeAudit Predicate = func(tests *models.SubCategory, params string) *models.SubCategory { + sat := make([]*models.CheckSpec, 0) + spt := utils.GetAuditTestsList("i", params) + // check if param include category + for _, sp := range spt { + if strings.HasPrefix(tests.Name, sp) { + return tests + } + } + // check tests + for _, at := range tests.AuditTests { + for _, sp := range spt { + if strings.HasPrefix(at.Name, sp) { + sat = append(sat, at) + } + } + } + if len(sat) == 0 { + return &models.SubCategory{Name: tests.Name, AuditTests: make([]*models.CheckSpec, 0)} + } + return &models.SubCategory{Name: tests.Name, AuditTests: sat} +} + +// ExcludeAudit audit test from been executed +var ExcludeAudit Predicate = func(tests *models.SubCategory, params string) *models.SubCategory { + sat := make([]*models.CheckSpec, 0) + spt := utils.GetAuditTestsList("e", params) + // if exclude category + for _, sp := range spt { + if strings.HasPrefix(tests.Name, sp) { + return &models.SubCategory{Name: tests.Name, AuditTests: []*models.CheckSpec{}} + } + } + for _, at := range tests.AuditTests { + var skipTest bool + for _, sp := range spt { + if strings.HasPrefix(at.Name, sp) { + skipTest = true + } + } + if skipTest { + continue + } + sat = append(sat, at) + } + return &models.SubCategory{Name: tests.Name, AuditTests: sat} +} + +// NodeAudit audit test from been executed +var NodeAudit Predicate = func(tests *models.SubCategory, params string) *models.SubCategory { + sat := make([]*models.CheckSpec, 0) + spt := utils.GetAuditTestsList("n", params) + // check tests + for _, at := range tests.AuditTests { + for _, sp := range spt { + if strings.ToLower(at.ProfileApplicability) == sp { + sat = append(sat, at) + } + } + } + if len(sat) == 0 { + return &models.SubCategory{Name: tests.Name, AuditTests: make([]*models.CheckSpec, 0)} + } + return &models.SubCategory{Name: tests.Name, AuditTests: sat} +} + +// Basic filter by specific audit tests as set in command +var Basic Predicate = func(tests *models.SubCategory, params string) *models.SubCategory { + return tests +} diff --git a/pkg/filters/predicate_test.go b/pkg/filters/predicate_test.go new file mode 100644 index 0000000..db5d6fe --- /dev/null +++ b/pkg/filters/predicate_test.go @@ -0,0 +1,71 @@ +package filters + +import ( + "github.com/chen-keinan/kube-mesh-kridik/internal/models" + "github.com/stretchr/testify/assert" + "testing" +) + +//Test_IncludeTestPredict text +func Test_IncludeTestPredict(t *testing.T) { + ab := &models.SubCategory{AuditTests: []*models.CheckSpec{{Name: "1.2.1 abc"}, {Name: "1.2.3 eft"}}} + abp := IncludeAudit(ab, "1.2.1") + assert.Equal(t, abp.AuditTests[0].Name, "1.2.1 abc") + assert.True(t, len(abp.AuditTests) == 1) +} + +//Test_IncludeTestPredicateNoValidArg text +func Test_IncludeTestPredicateNoValidArg(t *testing.T) { + ab := &models.SubCategory{AuditTests: []*models.CheckSpec{{Name: "1.2.1 abc"}, {Name: "1.2.3 eft"}}} + abp := IncludeAudit(ab, "1.2.5") + assert.True(t, len(abp.AuditTests) == 0) +} + +//Test_ExcludeTestPredict text +func Test_ExcludeTestPredict(t *testing.T) { + ab := &models.SubCategory{AuditTests: []*models.CheckSpec{{Name: "1.2.1 abc"}, {Name: "1.2.3 eft"}}} + abp := ExcludeAudit(ab, "1.2.1") + assert.Equal(t, abp.AuditTests[0].Name, "1.2.3 eft") + assert.True(t, len(abp.AuditTests) == 1) +} + +//Test_ExcludeTestPredicateNoValidArg text +func Test_ExcludeTestPredicateNoValidArg(t *testing.T) { + ab := &models.SubCategory{AuditTests: []*models.CheckSpec{{Name: "1.2.1 abc"}, {Name: "1.2.3 eft"}}} + abp := ExcludeAudit(ab, "1.2.5") + assert.Equal(t, abp.AuditTests[0].Name, "1.2.1 abc") + assert.Equal(t, abp.AuditTests[1].Name, "1.2.3 eft") + assert.True(t, len(abp.AuditTests) == 2) +} + +//Test_BasicPredicate text +func Test_BasicPredicate(t *testing.T) { + ab := &models.SubCategory{AuditTests: []*models.CheckSpec{{Name: "1.2.1 abc"}, {Name: "1.2.3 eft"}}} + abp := Basic(ab, "") + assert.Equal(t, abp.AuditTests[0].Name, "1.2.1 abc") + assert.Equal(t, abp.AuditTests[1].Name, "1.2.3 eft") + assert.True(t, len(abp.AuditTests) == 2) +} + +//Test_NodePredicateMaster text +func Test_NodePredicateMaster(t *testing.T) { + ab := &models.SubCategory{AuditTests: []*models.CheckSpec{{Name: "1.2.1 abc", ProfileApplicability: "Master"}, {Name: "1.2.3 eft", ProfileApplicability: "Worker"}}} + abp := NodeAudit(ab, "n=master") + assert.Equal(t, abp.AuditTests[0].Name, "1.2.1 abc") + assert.True(t, len(abp.AuditTests) == 1) +} + +//Test_NodePredicateWorker text +func Test_NodePredicateWorker(t *testing.T) { + ab := &models.SubCategory{AuditTests: []*models.CheckSpec{{Name: "1.2.1 abc", ProfileApplicability: "Master"}, {Name: "1.2.3 eft", ProfileApplicability: "Worker"}}} + abp := NodeAudit(ab, "n=worker") + assert.Equal(t, abp.AuditTests[0].Name, "1.2.3 eft") + assert.True(t, len(abp.AuditTests) == 1) +} + +//Test_NodePredicateNone text +func Test_NodePredicateNone(t *testing.T) { + ab := &models.SubCategory{AuditTests: []*models.CheckSpec{{Name: "1.2.1 abc", ProfileApplicability: "Master"}, {Name: "1.2.3 eft", ProfileApplicability: "Worker"}}} + abp := NodeAudit(ab, "n=abd") + assert.Equal(t, len(abp.AuditTests), 0) +} diff --git a/pkg/img/coverage_badge.png b/pkg/img/coverage_badge.png new file mode 100644 index 0000000000000000000000000000000000000000..9b0cba22723f3b2abf8f0b7e6a9ef65ecaf34160 GIT binary patch literal 2265 zcmV;~2qyQ5P)Px-lSxEDRA_evKVThdySG&UM_ywJok(-=wrs6qfiWgX5HYyBk%hgS z{$bgOvJl(OfD@mY@1L{Zd7k%upYOcqJLjzM?6c24sMG1*5CmZ+VBtRQ8rRGJIimUj zv`zu-(;I#63RzKpEDDn&Wf{mG>45HajF$Qd0@<>rX~vNb zUF%%7>JZgfuhcTLJc;C?f14dH~hcr}@Byw|e$;!$iIy#!p&Q6XWKhFOB`|0iN zy(=L}lE}-;BP%Nlv)Rn$%a^ICsiCf}?tjf;#4%V6AB&kwN#aVzgvE2k)5gv(H}P55 z!2xrgj(?uT<6q`?pXcLnHUJU1nZQ3-7i;MAky_ifU zJRT4G_U%KGB=mYcQ>RX)xVV^@m>61GTBxe3qNAhZ2XS?Gce8QhMvO)yk3Rb7pgj5c z`4|ias;jF3Fc=JM-MW?X@^TUr6Dch%B_Sb!&dyGD?b^keGiLzUyLT_UcI{%$oH^9i z*0OKkK6dQb5zL{fsfq2|x8rm=Nl#CwsHg}L9^}@I>aGcyx326`xrZRENyLV`2BtqML`e*BuTriS$NbOb>_(=;+NGB|eZ7@{arR#wKQO`DiK zdp7IVtz*fOB`As#Ojf7UQCL{WyYIe>rfJNdKcB3uEauOjPh(>vPd@o1CXi5tw*Dm% zJok9}C+HOe?`M9_bk&*1)y_;vAc?MNg@pwD~xcq+q0IpkMwOT{+xZQ3pUc5+ZYAPpB zo@B<18NB`W+axC^Gk*Mds;a66a9J!CzW(}a0QT(JLu6!Ra532Jc4p3;iP>yM6h#^u z8kjh7BBxKErnR+|h=>TPtE-ticP^TyVYAtW)#%6VIfY9RY{{+WwHiBh7mhI9HjB#K z_gLJJL2TGKeiAl~-(Frsc&rpWzn?=e`FOFW0IyR+7bUVh`&ITd?BL;)G=4w%Ei^PX zH!b6A_u#j@kcPIjv=AR3PgGPC*REaT+_`gPW@b`QP=L*5!{_rM2m-3A0yo=Xzj?QF zHa9m9;JOt<@ra_x;lqcSF=GZD9UX*+htty1LUeRAr%s*1Znxi2Y(-Ikn~SHvST>uD z^z?LIc;N-w+uKP`PiN7hML`XnP6vQquMeK%^ZAC==*R8(#;aDmeO?*@hlorQIo@4^ z&%1#H)kTRRx9JijYHEk91aI5DJi6;rlP7U z3l}cri!Z*Qr>AF7uA@hfQc+RCgb5Q+6orI@1j@_Hxpe8$kUS?&oM7_g$;_KKk3)wJ zp(qLthl7a|CsI^YL}FqhadC0P#l<1Z^7kuU_`W>}f`HfSMW@q|oSaNaNeKXrjg3s1 zGKG|sl%RIMLBnYbHNNU<#S|9B<4JST$zeQUn@6N-;!;;De{Fb^)b-}zxY%`pUsUI? z|LpENc$Q9BL*>zzP-8>_ePBqGh)9(2_lDLM^7HdU-eFxX7sbWJ%$hZen3x#4y1Hm+ zXkh2gop`-ol9G~GzI-_ri-q&&&$D^+=8%swE|-hvo_mg*oE*$%Gi_~c?A^PU`ucj3 zlaoX8XqrY@Ss8QY%%P;Dgr1%r0)YS)i-i>{R$#SSgKfU3s0e@$KKOtI3l;>m`}+E@ z+wDxBKAo#quToc6hs|bV?b@|WnKA{t-Ht5FeE8vqwE=f#&ITn*!I&UcVhfl1CR z*5v#d4S4m?QZAVOHE5lMyu7@ShH9FI+wBe(Q4~c~RmEU1AW0Ivy}dY{&fsRpWHKSk z@(<#YWtoVG2*Sg|hvm6`{W>>p++fU@F-VdWG|A<1;q`ihS7B^yECB88?Zm~!4bboI z?#AQsAW0Ics^atch>nh?r>6&(%Y|OAr?j+`haP%}%F4=NHEzXVUt4;w1-S8*AHPRK z3KP(el~AL_JLY|RrVqme8O1p8H&2J3fFJY^{wLq=0PdEX`x=8)MrXQ{3qZ)t%^f|j zIYt00SFR)@BLk1egTvuq%a$#7Z0d%?NPj-N6+ik{f2&rlqPMpfK@d#X=U*0#LFh@=iS00000NkvXXu0mjfw3J@Q literal 0 HcmV?d00001 diff --git a/pkg/models/audit_results.go b/pkg/models/audit_results.go new file mode 100644 index 0000000..9b4bd39 --- /dev/null +++ b/pkg/models/audit_results.go @@ -0,0 +1,21 @@ +package models + +//MeshKridikSecurityResults encapsulate security check results to be consumed by user plugin +type MeshKridikSecurityResults struct { + BenchmarkType string `yaml:"benchmark_type"` + Categories []AuditBenchResult `yaml:"audit_bench_result"` +} + +//AuditBenchResult data model +type AuditBenchResult struct { + Name string `yaml:"name"` + ProfileApplicability string `yaml:"profile_applicability"` + Category string `yaml:"category"` + Description string `yaml:"description"` + AuditCommand []string `json:"audit_command"` + Remediation string `yaml:"remediation"` + Impact string `yaml:"impact"` + AdditionalInfo string `yaml:"additional_info"` + References []string `yaml:"references"` + TestResult string `yaml:"test_result"` +} diff --git a/pkg/utils/fileutil.go b/pkg/utils/fileutil.go new file mode 100644 index 0000000..14721a6 --- /dev/null +++ b/pkg/utils/fileutil.go @@ -0,0 +1,174 @@ +package utils + +import ( + "fmt" + "github.com/chen-keinan/kube-mesh-kridik/internal/common" + "io/ioutil" + "os" + "os/user" + "path" + "path/filepath" +) + +//PluginSourceSubFolder plugin source folder +const PluginSourceSubFolder = "plugins/source" + +//CompilePluginSubFolder plugins complied folder +const CompilePluginSubFolder = "plugins/compile" + +//FolderMgr defines the interface for kube-knark folder +//fileutil.go +//go:generate mockgen -destination=./mocks/mock_FolderMgr.go -package=mocks . FolderMgr +type FolderMgr interface { + CreateFolder(folderName string) error + GetHomeFolder() (string, error) +} + +//bFolder kube-mesh-kridik folder object +type bFolder struct { +} + +//NewKFolder return bFolder instance +func NewKFolder() FolderMgr { + return &bFolder{} +} + +//CreateFolder create new kube-mesh-kridik folder +func (lxdf bFolder) CreateFolder(folderName string) error { + _, err := os.Stat(folderName) + if os.IsNotExist(err) { + errDir := os.MkdirAll(folderName, 0750) + if errDir != nil { + return err + } + } + return nil +} + +//GetHomeFolder return kube-mesh-kridik home folder +func (lxdf bFolder) GetHomeFolder() (string, error) { + usr, err := user.Current() + if err != nil { + return "", err + } + // User can set a custom KUBE_KNARK_HOME from environment variable + usrHome := GetEnv(common.LxdProbeHomeEnvVar, usr.HomeDir) + return path.Join(usrHome, ".kube-mesh-kridik"), nil +} + +//GetPluginSourceSubFolder return plugins source folder path +func GetPluginSourceSubFolder(fm FolderMgr) (string, error) { + folder, err := fm.GetHomeFolder() + if err != nil { + return "", err + } + return path.Join(folder, PluginSourceSubFolder), nil +} + +//GetCompilePluginSubFolder return plugin compiled folder path +func GetCompilePluginSubFolder(fm FolderMgr) (string, error) { + folder, err := fm.GetHomeFolder() + if err != nil { + return "", err + } + return path.Join(folder, CompilePluginSubFolder), nil +} + +//CreatePluginsCompiledFolderIfNotExist create plugins compiled folder if not exist +func CreatePluginsCompiledFolderIfNotExist(fm FolderMgr) error { + ebpfFolder, err := GetCompilePluginSubFolder(fm) + if err != nil { + return err + } + return fm.CreateFolder(ebpfFolder) +} + +//CreatePluginsSourceFolderIfNotExist plugins source folder if not exist +func CreatePluginsSourceFolderIfNotExist(fm FolderMgr) error { + pluginfFolder, err := GetPluginSourceSubFolder(fm) + if err != nil { + return err + } + return fm.CreateFolder(pluginfFolder) +} + +//GetHomeFolder return kube-mesh-kridik home folder +func GetHomeFolder() string { + usr, err := user.Current() + if err != nil { + panic("Failed to fetch user home folder") + } + // User can set a custom LXD_PROBE_HOME from environment variable + usrHome := GetEnv(common.LxdProbeHomeEnvVar, usr.HomeDir) + return path.Join(usrHome, ".kube-mesh-kridik") +} + +//CreateHomeFolderIfNotExist create kube-mesh-kridik home folder if not exist +func CreateHomeFolderIfNotExist(fm FolderMgr) error { + lxdProbeFolder, err := fm.GetHomeFolder() + if err != nil { + return err + } + _, err = os.Stat(lxdProbeFolder) + if os.IsNotExist(err) { + errDir := os.MkdirAll(lxdProbeFolder, 0750) + if errDir != nil { + return fmt.Errorf("failed to create kube-mesh-kridik home folder at %s", lxdProbeFolder) + } + } + return nil +} + +//GetBenchmarkFolder return benchmark folder +func GetBenchmarkFolder(spec, version string, fm FolderMgr) (string, error) { + folder, err := fm.GetHomeFolder() + if err != nil { + return "", err + } + return filepath.Join(folder, fmt.Sprintf("benchmarks/%s/%s/", spec, version)), nil +} + +//CreateBenchmarkFolderIfNotExist create kube-mesh-kridik benchmark folder if not exist +func CreateBenchmarkFolderIfNotExist(spec, version string, fm FolderMgr) error { + benchmarkFolder, err := GetBenchmarkFolder(spec, version, fm) + if err != nil { + return err + } + return fm.CreateFolder(benchmarkFolder) +} + +//GetLxdBenchAuditFiles return lxd benchmark file +func GetLxdBenchAuditFiles(spec, version string, fm FolderMgr) ([]FilesInfo, error) { + filesData := make([]FilesInfo, 0) + folder, err := GetBenchmarkFolder(spec, version, fm) + if err != nil { + return filesData, err + } + filesInfo, err := ioutil.ReadDir(filepath.Join(folder)) + if err != nil { + return nil, err + } + for _, fileInfo := range filesInfo { + filePath := filepath.Join(folder, filepath.Clean(fileInfo.Name())) + fData, err := ioutil.ReadFile(filepath.Clean(filePath)) + if err != nil { + return nil, err + } + filesData = append(filesData, FilesInfo{fileInfo.Name(), string(fData)}) + } + return filesData, nil +} + +//FilesInfo file data +type FilesInfo struct { + Name string + Data string +} + +//GetEnv Get Environment Variable value or return default +func GetEnv(key, fallback string) string { + if value, ok := os.LookupEnv(key); ok { + return value + } + return fallback +} diff --git a/pkg/utils/fileutil_test.go b/pkg/utils/fileutil_test.go new file mode 100644 index 0000000..4106583 --- /dev/null +++ b/pkg/utils/fileutil_test.go @@ -0,0 +1,223 @@ +package utils + +import ( + "fmt" + "github.com/chen-keinan/kube-mesh-kridik/internal/common" + "github.com/chen-keinan/kube-mesh-kridik/pkg/utils/mocks" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "os" + "path/filepath" + "strings" + "testing" +) + +//Test_GetHomeFolder test +func Test_GetHomeFolder(t *testing.T) { + a := GetHomeFolder() + assert.True(t, strings.HasSuffix(a, ".kube-mesh-kridik")) +} + +//Test_CreateHomeFolderIfNotExist test +func Test_CreateHomeFolderIfNotExist(t *testing.T) { + fm := NewKFolder() + err := CreateHomeFolderIfNotExist(fm) + assert.NoError(t, err) + _, err = os.Stat(GetHomeFolder()) + if os.IsNotExist(err) { + t.Fatal() + } + err = os.RemoveAll(GetHomeFolder()) + assert.NoError(t, err) +} + +//Test_GetBenchmarkFolder test +func Test_GetBenchmarkFolder(t *testing.T) { + fm := NewKFolder() + err := CreateHomeFolderIfNotExist(fm) + assert.NoError(t, err) + a, err := GetBenchmarkFolder("lxd", "v1.0.0", fm) + assert.NoError(t, err) + assert.True(t, strings.HasSuffix(a, ".kube-mesh-kridik/benchmarks/lxd/v1.0.0")) +} + +//Test_CreateBenchmarkFolderIfNotExist test +func Test_CreateBenchmarkFolderIfNotExist(t *testing.T) { + fm := NewKFolder() + err := CreateBenchmarkFolderIfNotExist("lxd", "v1.0.0", fm) + assert.NoError(t, err) + folder, err := GetBenchmarkFolder("lxd", "v1.0.0", fm) + assert.NoError(t, err) + _, err = os.Stat(folder) + if os.IsNotExist(err) { + t.Fatal() + } + err = os.RemoveAll(folder) + assert.NoError(t, err) +} + +//Test_GetLxdBenchAuditFiles test +func Test_GetLxdBenchAuditFiles(t *testing.T) { + fm := NewKFolder() + err := CreateHomeFolderIfNotExist(fm) + if err != nil { + t.Fatal(err) + } + err = CreateBenchmarkFolderIfNotExist("lxd", "v1.0.0", fm) + if err != nil { + t.Fatal(err) + } + err = saveFilesIfNotExist([]FilesInfo{{Name: "aaa", Data: "bbb"}, {Name: "ddd", Data: "ccc"}}) + if err != nil { + t.Fatal(err) + } + f, err := GetLxdBenchAuditFiles("lxd", "v1.0.0", fm) + if err != nil { + t.Fatal(err) + } + folder, err := GetBenchmarkFolder("lxd", "v1.0.0", fm) + assert.NoError(t, err) + err = os.RemoveAll(folder) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, f[0].Name, "aaa") + assert.Equal(t, f[1].Name, "ddd") + +} + +//Test_GetLxdBenchAuditNoFolder test +func Test_GetLxdBenchAuditNoFolder(t *testing.T) { + fm := NewKFolder() + _, err := GetLxdBenchAuditFiles("lxd", "v1.1.0", fm) + assert.True(t, err != nil) +} + +func saveFilesIfNotExist(filesData []FilesInfo) error { + fm := NewKFolder() + folder, err := GetBenchmarkFolder("lxd", "v1.0.0", fm) + if err != nil { + return err + } + for _, fileData := range filesData { + filePath := filepath.Join(folder, fileData.Name) + if _, err := os.Stat(filePath); os.IsNotExist(err) { + f, err := os.Create(filePath) + if err != nil { + panic(err) + } + _, err = f.WriteString(fileData.Data) + if err != nil { + return fmt.Errorf("failed to write benchmark file") + } + err = f.Close() + if err != nil { + return fmt.Errorf("faild to close file %s", filePath) + } + } + } + return nil +} + +//Test_GetEnv test getting home kube-mesh-kridik folder +func Test_GetEnv(t *testing.T) { + os.Setenv(common.LxdProbeHomeEnvVar, "/home/kube-mesh-kridik") + homeFolder := GetEnv(common.LxdProbeHomeEnvVar, "/home/user") + assert.Equal(t, homeFolder, "/home/kube-mesh-kridik") + os.Unsetenv(common.LxdProbeHomeEnvVar) + homeFolder = GetEnv(common.LxdProbeHomeEnvVar, "/home/user") + assert.Equal(t, homeFolder, "/home/user") +} + +//Test_PluginsSourceFolder test +func Test_PluginsSourceFolder(t *testing.T) { + fm := NewKFolder() + err := CreatePluginsSourceFolderIfNotExist(fm) + assert.NoError(t, err) + a, err := GetPluginSourceSubFolder(fm) + assert.NoError(t, err) + assert.True(t, strings.HasSuffix(a, PluginSourceSubFolder)) +} + +//Test_PluginsCompiledFolder test +func Test_PluginsCompiledFolder(t *testing.T) { + fm := NewKFolder() + err := CreatePluginsCompiledFolderIfNotExist(fm) + assert.NoError(t, err) + a, err := GetCompilePluginSubFolder(fm) + assert.NoError(t, err) + assert.True(t, strings.HasSuffix(a, CompilePluginSubFolder)) +} + +func TestCreateBenchmarkFoldersErrorHomeFolder(t *testing.T) { + ctl := gomock.NewController(t) + fm := mocks.NewMockFolderMgr(ctl) + fm.EXPECT().GetHomeFolder().Return("homePath", fmt.Errorf("error")).Times(1) + err := CreateBenchmarkFolderIfNotExist("lxd", "v1.0.0", fm) + assert.Error(t, err) + fmr := NewKFolder() + path, err := GetBenchmarkFolder("lxd", "v1.0.0", fmr) + assert.NoError(t, err) + rhfp := GetHomeFolder() + fm2 := mocks.NewMockFolderMgr(ctl) + fm2.EXPECT().GetHomeFolder().Return(rhfp, nil).Times(1) + fm2.EXPECT().CreateFolder(path).Return(fmt.Errorf("error")).Times(1) + err = CreateBenchmarkFolderIfNotExist("lxd", "v1.0.0", fm2) + assert.Error(t, err) +} + +func TestCreatePluginsCompiledFolderIfNotExist(t *testing.T) { + ctl := gomock.NewController(t) + fm := mocks.NewMockFolderMgr(ctl) + fm.EXPECT().GetHomeFolder().Return("homePath", fmt.Errorf("error")).Times(1) + err := CreatePluginsCompiledFolderIfNotExist(fm) + assert.Error(t, err) + fmr := NewKFolder() + path, err := GetCompilePluginSubFolder(fmr) + assert.NoError(t, err) + rhfp := GetHomeFolder() + fm2 := mocks.NewMockFolderMgr(ctl) + fm2.EXPECT().GetHomeFolder().Return(rhfp, nil).Times(1) + fm2.EXPECT().CreateFolder(path).Return(fmt.Errorf("error")).Times(1) + err = CreatePluginsCompiledFolderIfNotExist(fm2) + assert.Error(t, err) +} + +func TestCreatePluginsSourcesFolderIfNotExist(t *testing.T) { + ctl := gomock.NewController(t) + fm := mocks.NewMockFolderMgr(ctl) + fm.EXPECT().GetHomeFolder().Return("homePath", fmt.Errorf("error")).Times(1) + err := CreatePluginsSourceFolderIfNotExist(fm) + assert.Error(t, err) + fmr := NewKFolder() + path, err := GetPluginSourceSubFolder(fmr) + assert.NoError(t, err) + rhfp := GetHomeFolder() + fm2 := mocks.NewMockFolderMgr(ctl) + fm2.EXPECT().GetHomeFolder().Return(rhfp, nil).Times(1) + fm2.EXPECT().CreateFolder(path).Return(fmt.Errorf("error")).Times(1) + err = CreatePluginsSourceFolderIfNotExist(fm2) + assert.Error(t, err) +} + +func TestGetBenchmarkFoldersErrorHomeFolder(t *testing.T) { + ctl := gomock.NewController(t) + fm := mocks.NewMockFolderMgr(ctl) + fm.EXPECT().GetHomeFolder().Return("homePath", fmt.Errorf("error")).Times(1) + _, err := GetBenchmarkFolder("lxd", "v1.0.0", fm) + assert.Error(t, err) +} +func TestGetSourcePluginFoldersErrorHomeFolder(t *testing.T) { + ctl := gomock.NewController(t) + fm := mocks.NewMockFolderMgr(ctl) + fm.EXPECT().GetHomeFolder().Return("homePath", fmt.Errorf("error")).Times(1) + _, err := GetPluginSourceSubFolder(fm) + assert.Error(t, err) +} +func TestGetCompiledPluginFoldersErrorHomeFolder(t *testing.T) { + ctl := gomock.NewController(t) + fm := mocks.NewMockFolderMgr(ctl) + fm.EXPECT().GetHomeFolder().Return("homePath", fmt.Errorf("error")).Times(1) + _, err := GetCompilePluginSubFolder(fm) + assert.Error(t, err) +} diff --git a/pkg/utils/stringutil.go b/pkg/utils/stringutil.go new file mode 100644 index 0000000..009d5b7 --- /dev/null +++ b/pkg/utils/stringutil.go @@ -0,0 +1,12 @@ +package utils + +import ( + "fmt" + "strings" +) + +//GetAuditTestsList return processing function by specificTests +func GetAuditTestsList(key, arg string) []string { + values := strings.ReplaceAll(arg, fmt.Sprintf("%s=", key), "") + return strings.Split(strings.ToLower(values), ",") +} diff --git a/pkg/utils/stringutil_test.go b/pkg/utils/stringutil_test.go new file mode 100644 index 0000000..1ce8686 --- /dev/null +++ b/pkg/utils/stringutil_test.go @@ -0,0 +1,15 @@ +package utils + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +//Test_GetSpecificTestsToExecute test +func Test_GetSpecificTestsToExecute(t *testing.T) { + l := GetAuditTestsList("i", "i=1.2.3,1.4.5") + assert.Equal(t, l[0], "1.2.3") + assert.Equal(t, l[1], "1.4.5") + l = GetAuditTestsList("e", "") + assert.Equal(t, l[0], "") +} diff --git a/scripts/lint.sh b/scripts/lint.sh new file mode 100755 index 0000000..b81bb0f --- /dev/null +++ b/scripts/lint.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.27.0 +## need to generate mock before lint +go get github.com/golang/mock/mockgen@latest +go install -v github.com/golang/mock/mockgen +export PATH=$GOPATH/bin:$PATH +export PATH=$PATH:/root/go/bin +go generate ./... +golangci-lint run -v > lint.xml \ No newline at end of file diff --git a/ui/banners.go b/ui/banners.go new file mode 100644 index 0000000..f01aa14 --- /dev/null +++ b/ui/banners.go @@ -0,0 +1,24 @@ +package ui + +//LxdAuditTest banner +const LxdAuditTest = ` + + + _ _____ __ __ _ _ __ _ _ _ _ + | |/ / _ \ | \/ | | | | |/ / (_) | (_) | + | ' / (_) |___ | \ / | ___ ___| |__ | ' / _ __ _ __| |_| | __ + | < > _