mirror of
https://github.com/aquasecurity/kube-bench.git
synced 2026-02-19 20:40:17 +00:00
Compare commits
160 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77481e8739 | ||
|
|
48489637c5 | ||
|
|
15537cb42b | ||
|
|
9988503223 | ||
|
|
5f254de415 | ||
|
|
64f4f638e9 | ||
|
|
97623aea05 | ||
|
|
ed21839464 | ||
|
|
277ec9c823 | ||
|
|
b1369832bc | ||
|
|
934b4aef96 | ||
|
|
e85de9e8af | ||
|
|
ded5aff482 | ||
|
|
b3a115963b | ||
|
|
e5c05a97f7 | ||
|
|
ba5ec8d4be | ||
|
|
d56afd4104 | ||
|
|
8894b1dc4f | ||
|
|
ff59938f94 | ||
|
|
cc43fcbb7e | ||
|
|
2f4f55a363 | ||
|
|
e9076233dd | ||
|
|
b1e41d345f | ||
|
|
ccc2b6c9ae | ||
|
|
668a9e10ce | ||
|
|
8c3bb62dd4 | ||
|
|
9d0141871a | ||
|
|
344d2bfd24 | ||
|
|
ecd14ed682 | ||
|
|
223ac14642 | ||
|
|
c44e0db97b | ||
|
|
0bc004468b | ||
|
|
83704a7d89 | ||
|
|
024b7ed396 | ||
|
|
c5e04677cf | ||
|
|
2073e08363 | ||
|
|
db096c9f51 | ||
|
|
d736d10f90 | ||
|
|
50a3725ff2 | ||
|
|
468f5fac6e | ||
|
|
3408e0f865 | ||
|
|
182e9b5e01 | ||
|
|
e4100a4435 | ||
|
|
b502d09f8b | ||
|
|
6c7422a938 | ||
|
|
82b1e05a32 | ||
|
|
97e5bc9b97 | ||
|
|
c0d80b4669 | ||
|
|
7b61cf60fe | ||
|
|
c4e7487ba7 | ||
|
|
6d237607fb | ||
|
|
b4b3ebe99c | ||
|
|
609335510a | ||
|
|
5da707b8d6 | ||
|
|
b10b2bd22e | ||
|
|
aa9da13226 | ||
|
|
c13632318e | ||
|
|
b649cef047 | ||
|
|
056da1b28d | ||
|
|
9810bafabe | ||
|
|
5eb4ab7479 | ||
|
|
9f5c856206 | ||
|
|
39d94df81b | ||
|
|
7823ca388c | ||
|
|
b3fc84277d | ||
|
|
863a643adb | ||
|
|
1935c952d6 | ||
|
|
5be0a9fbdf | ||
|
|
b26b23e573 | ||
|
|
3ee43235b5 | ||
|
|
7460037528 | ||
|
|
479469b3ec | ||
|
|
0c52ace48f | ||
|
|
3eb8a08a9d | ||
|
|
1cff0c4da1 | ||
|
|
0714683371 | ||
|
|
3560bbbbfa | ||
|
|
67786fd3ef | ||
|
|
033245f71c | ||
|
|
cb4bec9120 | ||
|
|
f065893f52 | ||
|
|
5ee7c1b0db | ||
|
|
ec51a4eabb | ||
|
|
0b4872104d | ||
|
|
46bbcdd9bc | ||
|
|
9469b1c124 | ||
|
|
ade064006e | ||
|
|
ef6c017f54 | ||
|
|
b587e7a996 | ||
|
|
bad3508ba3 | ||
|
|
0d84dc4d42 | ||
|
|
51212b861f | ||
|
|
728cb0765f | ||
|
|
d846b221e5 | ||
|
|
f091c8adea | ||
|
|
d6c16f7563 | ||
|
|
c86d0ff81b | ||
|
|
c808d9527d | ||
|
|
95769cae83 | ||
|
|
1f52a13400 | ||
|
|
7f41564a62 | ||
|
|
8c56ca650a | ||
|
|
58b6358a02 | ||
|
|
731fcb4437 | ||
|
|
fe23f8140a | ||
|
|
d464ab5639 | ||
|
|
165444df60 | ||
|
|
18032b22eb | ||
|
|
c389d6ecf2 | ||
|
|
4f07b01ead | ||
|
|
e0a032dfbb | ||
|
|
0c309bc1d4 | ||
|
|
4b1b2b8762 | ||
|
|
4f90a1361c | ||
|
|
fc4fe38bc2 | ||
|
|
961dbeb2b5 | ||
|
|
8fc6904093 | ||
|
|
be0134de95 | ||
|
|
7fcfb0cf30 | ||
|
|
c9227c0eea | ||
|
|
850cde23e9 | ||
|
|
cbe02e1d5e | ||
|
|
f63cd11807 | ||
|
|
94a1f3c41f | ||
|
|
3dd5db693d | ||
|
|
e7152265eb | ||
|
|
1e25e089d0 | ||
|
|
b42f2ba39e | ||
|
|
22e46990db | ||
|
|
216b1d497a | ||
|
|
033ab5638c | ||
|
|
94b960cfad | ||
|
|
017a9836ce | ||
|
|
a863cf87ca | ||
|
|
64aaef7997 | ||
|
|
53eb720952 | ||
|
|
04f044e3b9 | ||
|
|
7b538ed6e4 | ||
|
|
778c662055 | ||
|
|
97485419e2 | ||
|
|
730871f330 | ||
|
|
471c02f4d7 | ||
|
|
c93c94b3f6 | ||
|
|
1d7df75f57 | ||
|
|
c60c459bc4 | ||
|
|
4907843b7b | ||
|
|
d52e326147 | ||
|
|
42a1068964 | ||
|
|
f90dd925b8 | ||
|
|
31b5910a7f | ||
|
|
85fb818e41 | ||
|
|
2eb261b94f | ||
|
|
732b987d6d | ||
|
|
909e6cc874 | ||
|
|
1b13375ff7 | ||
|
|
bdb5ccf982 | ||
|
|
83e58b86db | ||
|
|
1faeb55b67 | ||
|
|
f7d4f03f48 | ||
|
|
d79a2a5478 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
kube-bench
|
||||
*.swp
|
||||
vendor
|
||||
dist
|
||||
|
||||
19
.goreleaser.yml
Normal file
19
.goreleaser.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
builds:
|
||||
- main: main.go
|
||||
binary: kube-bench
|
||||
goos:
|
||||
- darwin
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
# Archive customization
|
||||
archive:
|
||||
format: tar.gz
|
||||
nfpm:
|
||||
vendor: Aqua Security
|
||||
description: "The Kubernetes Bench for Security is a Go application that checks whether Kubernetes is deployed according to security best practices"
|
||||
license: Apache-2.0
|
||||
homepage: https://github.com/aquasecurity/kube-bench
|
||||
formats:
|
||||
- deb
|
||||
- rpm
|
||||
33
.travis.yml
33
.travis.yml
@@ -1,6 +1,33 @@
|
||||
---
|
||||
language: go
|
||||
install:
|
||||
- go get github.com/aquasecurity/kube-bench
|
||||
|
||||
sudo: required
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
before_install:
|
||||
- sudo apt-get -qq update
|
||||
- sudo apt-get install -y rpm
|
||||
- gem install --no-ri --no-rdoc fpm
|
||||
|
||||
install:
|
||||
- go get -v github.com/golang/dep/cmd/dep
|
||||
- dep ensure -v -vendor-only
|
||||
|
||||
script:
|
||||
- go test ./...
|
||||
- go build -o kube-bench .
|
||||
- docker build --tag kube-bench .
|
||||
- docker run -v `pwd`:/host kube-bench install
|
||||
- test -d cfg
|
||||
- test -f kube-bench
|
||||
|
||||
after_success:
|
||||
- test -n "$TRAVIS_TAG" && curl -sL https://git.io/goreleaser | bash
|
||||
|
||||
env:
|
||||
global:
|
||||
secure: mb8AYZKDo6hkKN+2F9ldXcw27Yn2AfxpXvKlD8GD7NdGOI+TaiSFbE0I+qqTa/1DqcRekCQwqN7OG/17s9JDkgzUXYuYUGlVUOM4WbeJoSlzJFIOh9r9R/JddluYJohypgkE20IBHIrEHq5sY0Nn1Pl9WgSQFaVcQjxkX009AOuVjN0o5HcoXsb5hAzvHrpoSPkcSSqq7VWab60TgUttVaRlZSGwGdSYQEqk5TdO0hWHuXyxaaEPybgFIyZLLbxPS4JmMz8n3Sngetpw9Jgc+V9Fc7wKXpjvZZ33SpArG5p5ZFFu2YQOXFLZth9qtQOjduQ2gU1kHN6WjWnJ8QX2s8vmU38Tk19kd5i+mz9dvc87IdBvmTIqVYSpM6AAYa2osBGP3f97Rj2S68lTad4ecSVyHdsjz56vdE3ZH4wskswmogbKkVdvO4biPHxT6odszBxYLEJuRJyZ7ckXd52MCzqAUPrw7YUuH8N1mLIlf7V5bW5R+q4DlKw774zxnHiWrymXGvlINSrB0qxBn8Fii6ib+Pacl3PuqSumCcgIHlVjqrzIXaqcTMn2/ABZYC99mralGvwA/EgNa8CBKB5evMCEwWa5Ntvcs2I2DFcO5Q2WzN4H0YScyAzzCzK7/3hWJE/rUIJntwiSXkV3MSa1yxWSGGH8F1lcz+lzgTBm/MU=
|
||||
|
||||
27
Dockerfile
27
Dockerfile
@@ -1,13 +1,22 @@
|
||||
FROM golang:1.8
|
||||
WORKDIR /kube-bench
|
||||
RUN go get github.com/aquasecurity/kube-bench
|
||||
RUN cp /go/bin/kube-bench /kube-bench/ && chmod +x /kube-bench/kube-bench
|
||||
RUN cp -r /go/src/github.com/aquasecurity/kube-bench/cfg cfg
|
||||
FROM golang:1.9 AS build
|
||||
WORKDIR /go/src/github.com/aquasecurity/kube-bench/
|
||||
ADD Gopkg.toml Gopkg.lock ./
|
||||
RUN go get -v github.com/golang/dep/cmd/dep && dep ensure -v -vendor-only
|
||||
ADD main.go .
|
||||
ADD check/ check/
|
||||
ADD cmd/ cmd/
|
||||
RUN CGO_ENABLED=0 go install -a -ldflags '-w'
|
||||
|
||||
# When Docker Hub supports it, we would split this into a multi-stage build with the second part based on, say, alpine for size
|
||||
WORKDIR /
|
||||
ADD entrypoint.sh /entrypoint.sh
|
||||
ENTRYPOINT /entrypoint.sh
|
||||
FROM alpine:3.7 AS run
|
||||
WORKDIR /opt/kube-bench/
|
||||
# add GNU ps for -C, -o cmd, and --no-headers support
|
||||
# https://github.com/aquasecurity/kube-bench/issues/109
|
||||
RUN apk --no-cache add procps
|
||||
COPY --from=build /go/bin/kube-bench /usr/local/bin/kube-bench
|
||||
ADD entrypoint.sh .
|
||||
ADD cfg/ cfg/
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
CMD ["install"]
|
||||
|
||||
# Build-time metadata as defined at http://label-schema.org
|
||||
ARG BUILD_DATE
|
||||
|
||||
153
Gopkg.lock
generated
Normal file
153
Gopkg.lock
generated
Normal file
@@ -0,0 +1,153 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fatih/color"
|
||||
packages = ["."]
|
||||
revision = "570b54cabe6b8eb0bc2dfce68d964677d63b5260"
|
||||
version = "v1.5.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
revision = "4da3e2cfbabc9f751898f250b49f2439785783a1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/golang/glog"
|
||||
packages = ["."]
|
||||
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
"hcl/ast",
|
||||
"hcl/parser",
|
||||
"hcl/scanner",
|
||||
"hcl/strconv",
|
||||
"hcl/token",
|
||||
"json/parser",
|
||||
"json/scanner",
|
||||
"json/token"
|
||||
]
|
||||
revision = "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/jinzhu/gorm"
|
||||
packages = [
|
||||
".",
|
||||
"dialects/postgres"
|
||||
]
|
||||
revision = "5174cc5c242a728b435ea2be8a2f7f998e15429b"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/jinzhu/inflection"
|
||||
packages = ["."]
|
||||
revision = "1c35d901db3da928c72a72d8458480cc9ade058f"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/lib/pq"
|
||||
packages = [
|
||||
".",
|
||||
"hstore",
|
||||
"oid"
|
||||
]
|
||||
revision = "83612a56d3dd153a94a629cd64925371c9adad78"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
revision = "49d762b9817ba1c2e9d0c69183c2b4a8b8f1d934"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
revision = "5411d3eea5978e6cdc258b30de592b60df6aba96"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
revision = "57fdcb988a5c543893cc61bce354a6e24ab70022"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
revision = "06020f85339e21b2478f756a78e295255ffa4d6a"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
revision = "0131db6d737cfbbfb678f8b7d92e55e27ce46224"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem"
|
||||
]
|
||||
revision = "57afd63c68602b63ed976de00dd066ccb3c319db"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
revision = "acbeb36b902d72a7a4c18e8f3241075e7ab763e4"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b"
|
||||
version = "v0.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
revision = "12bd96e66386c1960ab0f74ced1362f66f552f7b"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
revision = "4c012f6dcd9546820e378d0bdda4d8fc772cdfea"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/viper"
|
||||
packages = ["."]
|
||||
revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "e24f485414aeafb646f6fca458b0bf869c0880a1"
|
||||
|
||||
[[projects]]
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"internal/gen",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"transform",
|
||||
"unicode/cldr",
|
||||
"unicode/norm"
|
||||
]
|
||||
revision = "e19ae1496984b1c655b8044a65c0300a3c878dd3"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "c95af922eae69f190717a0b7148960af8c55a072"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "8d9a1b665b338530deef434f168913ba1184f835aa5bfed3a213a14c613bc17e"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
23
Gopkg.toml
Normal file
23
Gopkg.toml
Normal file
@@ -0,0 +1,23 @@
|
||||
[[constraint]]
|
||||
name = "github.com/fatih/color"
|
||||
version = "1.5.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/golang/glog"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/jinzhu/gorm"
|
||||
version = "1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/spf13/cobra"
|
||||
version = "0.0.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/spf13/viper"
|
||||
version = "1.0.0"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
104
README.md
104
README.md
@@ -3,54 +3,92 @@
|
||||
[](https://microbadger.com/images/aquasec/kube-bench "Get your own image badge on microbadger.com")
|
||||
[](https://microbadger.com/images/aquasec/kube-bench)
|
||||
|
||||
# kube-bench
|
||||
<img src="images/kube-bench.png" width="200" alt="kube-bench logo">
|
||||
|
||||
The Kubernetes Bench for Security is a Go application that checks whether Kubernetes is deployed securely by running the checks documented in the CIS Kubernetes Benchmark.
|
||||
kube-bench is a Go application that checks whether Kubernetes is deployed securely by running the checks documented in the [CIS Kubernetes Benchmark](https://www.cisecurity.org/benchmark/kubernetes/).
|
||||
|
||||
Tests are configured with YAML files, making this tool easy to update as test specifications evolve.
|
||||
Tests are configured with YAML files, making this tool easy to update as test specifications evolve.
|
||||
|
||||

|
||||
|
||||
## CIS Kubernetes Benchmark support
|
||||
|
||||
kube-bench supports the tests for multiple versions of Kubernetes (1.6, 1.7, 1.8, and 1.11) as defined in the CIS Benchmarks 1.0.0, 1.1.0, 1.2.0, and 1.30 respectively. It will determine the test set to run based on the Kubernetes version running on the machine.
|
||||
|
||||
## Installation
|
||||
|
||||
You can either install kube-bench through a dedicated container, or compile it from source:
|
||||
You can choose to
|
||||
* run kube-bench from inside a container (sharing PID namespace with the host)
|
||||
* run a container that installs kube-bench on the host, and then run kube-bench directly on the host
|
||||
* install the latest binaries from the [Releases page](https://github.com/aquasecurity/kube-bench/releases),
|
||||
* compile it from source.
|
||||
|
||||
1. Container installation:
|
||||
Run ```docker run --rm -v `pwd`:/host aquasec/kube-bench:latest```. This will copy the kube-bench binary and configuration to you host. You can then run ```./kube-bench <master|node>```.
|
||||
### Running inside a container
|
||||
|
||||
2. Install from sources:
|
||||
If Go is installed on the target machines, you can simply clone this repository and run as follows:
|
||||
```go get github.com/aquasecurity/kube-bench```
|
||||
```cp $GOROOT/bin/kube-bench .```
|
||||
```./kube-bench <master|node>```
|
||||
|
||||
## Usage
|
||||
```./kube-bench [command]```
|
||||
You can avoid installing kube-bench on the host by running it inside a container using the host PID namespace.
|
||||
|
||||
```
|
||||
Available Commands:
|
||||
federated Run benchmark checks for a Kubernetes federated deployment.
|
||||
help Help about any command
|
||||
master Run benchmark checks for a Kubernetes master node.
|
||||
node Run benchmark checks for a Kubernetes node.
|
||||
docker run --pid=host -t aquasec/kube-bench:latest <master|node>
|
||||
```
|
||||
|
||||
You can even use your own configs by mounting them over the default ones in `/opt/kube-bench/cfg/`
|
||||
|
||||
```
|
||||
docker run --pid=host -t -v path/to/my-config.yaml:/opt/kube-bench/cfg/config.yaml aquasec/kube-bench:latest <master|node>
|
||||
```
|
||||
|
||||
> Note: the tests require either the kubelet or kubectl binary in the path in order to know the Kubernetes version. You can pass `-v $(which kubectl):/usr/bin/kubectl` to the above invocations to resolve this.
|
||||
|
||||
### Running in a kubernetes cluster
|
||||
Run the master check
|
||||
|
||||
```
|
||||
kubectl run --rm -i -t kube-bench-master --image=aquasec/kube-bench:latest --restart=Never --overrides="{ \"apiVersion\": \"v1\", \"spec\": { \"hostPID\": true, \"nodeSelector\": { \"kubernetes.io/role\": \"master\" }, \"tolerations\": [ { \"key\": \"node-role.kubernetes.io/master\", \"operator\": \"Exists\", \"effect\": \"NoSchedule\" } ] } }" -- master --version 1.11
|
||||
```
|
||||
|
||||
Run the node check
|
||||
|
||||
```
|
||||
kubectl run --rm -i -t kube-bench-node --image=aquasec/kube-bench:latest --restart=Never --overrides="{ \"apiVersion\": \"v1\", \"spec\": { \"hostPID\": true } }" -- node --version 1.11
|
||||
```
|
||||
|
||||
### Installing from a container
|
||||
|
||||
This command copies the kube-bench binary and configuration files to your host from the Docker container:
|
||||
```
|
||||
docker run --rm -v `pwd`:/host aquasec/kube-bench:latest install
|
||||
```
|
||||
|
||||
You can then run `./kube-bench <master|node>`.
|
||||
|
||||
### Installing from sources
|
||||
|
||||
If Go is installed on the target machines, you can simply clone this repository and run as follows (assuming your [$GOPATH is set](https://github.com/golang/go/wiki/GOPATH)):
|
||||
|
||||
```shell
|
||||
go get github.com/aquasecurity/kube-bench
|
||||
go get github.com/golang/dep/cmd/dep
|
||||
cd $GOPATH/src/github.com/aquasecurity/kube-bench
|
||||
$GOPATH/bin/dep ensure -vendor-only
|
||||
go build -o kube-bench .
|
||||
|
||||
# See all supported options
|
||||
./kube-bench --help
|
||||
|
||||
# Run the all checks on a master node
|
||||
./kube-bench master
|
||||
|
||||
Flags:
|
||||
-c, --check string A comma-delimited list of checks to run as specified in CIS document. Example --check="1.1.1,1.1.2"
|
||||
--config string config file (default is ./cfg/config.yaml)
|
||||
-g, --group string Run all the checks under this comma-delimited list of groups. Example --group="1.1"
|
||||
--installation string Specify how kubernetes cluster was installed. Possible values are default,hyperkube,kops,kubeadm (default "default")
|
||||
--json Prints the results as JSON
|
||||
-v, --verbose verbose output (default false)
|
||||
```
|
||||
|
||||
## Configuration
|
||||
Kubernetes config and binary file locations and names can vary from installation to installation, so these are configurable in the `cfg/config.yaml` file.
|
||||
Kubernetes config and binary file locations and names can vary from installation to installation, so these are configurable in the `cfg/config.yaml` file.
|
||||
|
||||
For each type of node (*master*, *node* or *federated*) there is a list of components, and for each component there is a set of binaries (*bins*) and config files (*confs*) that kube-bench will look for (in the order they are listed). If your installation uses a different binary name or config file location for a Kubernetes component, you can add it to `cfg/config.yaml`.
|
||||
For each type of node (*master*, *node* or *federated*) there is a list of components, and for each component there is a set of binaries (*bins*) and config files (*confs*) that kube-bench will look for (in the order they are listed). If your installation uses a different binary name or config file location for a Kubernetes component, you can add it to `cfg/config.yaml`.
|
||||
|
||||
* **bins** - If there is a *bins* list for a component, at least one of these binaries must be running. The tests will consider the parameters for the first binary in the list found to be running.
|
||||
* **confs** - If one of the listed config files is found, this will be considered for the test. Tests can continue even if no config file is found. If no file is found at any of the listed locations, and a *defaultconf* location is given for the component, the test will give remediation advice using the *defaultconf* location.
|
||||
* **bins** - If there is a *bins* list for a component, at least one of these binaries must be running. The tests will consider the parameters for the first binary in the list found to be running.
|
||||
* **podspecs** - From version 1.2.0 of the benchmark (tests for Kubernetes 1.8), the remediation instructions were updated to assume that the configuration for several kubernetes components is defined in a pod YAML file, and podspec settings define where to look for that configuration.
|
||||
* **confs** - If one of the listed config files is found, this will be considered for the test. Tests can continue even if no config file is found. If no file is found at any of the listed locations, and a *defaultconf* location is given for the component, the test will give remediation advice using the *defaultconf* location.
|
||||
* **unitfiles** - From version 1.2.0 of the benchmark (tests for Kubernetes 1.8), the remediation instructions were updated to assume that kubelet configuration is defined in a service file, and this setting defines where to look for that configuration.
|
||||
|
||||
## Test config YAML representation
|
||||
The tests are represented as YAML documents (installed by default into ./cfg).
|
||||
@@ -109,5 +147,7 @@ These operations are:
|
||||
- `has`: tests if the flag value contains the compared value.
|
||||
- `nothave`: tests if the flag value does not contain the compared value.
|
||||
|
||||
# Roadmap
|
||||
The tests are up-to-date with the CIS Benchmark 1.1.0, which refers to Kubernetes 1.7. Going forward we should release updates to kube-bench to reflect new releases of the Benchmark, which in turn we can anticipate being made for each new Kubernetes release.
|
||||
# Roadmap
|
||||
Going forward we plan to release updates to kube-bench to add support for new releases of the Benchmark, which in turn we can anticipate being made for each new Kubernetes release.
|
||||
|
||||
We welcome PRs and issue reports.
|
||||
|
||||
29
cfg/1.11/config.yaml
Normal file
29
cfg/1.11/config.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
## Controls Files.
|
||||
# These are YAML files that hold all the details for running checks.
|
||||
#
|
||||
## Uncomment to use different control file paths.
|
||||
# masterControls: ./cfg/master.yaml
|
||||
# nodeControls: ./cfg/node.yaml
|
||||
# federatedControls: ./cfg/federated.yaml
|
||||
|
||||
master:
|
||||
apiserver:
|
||||
defaultconf: /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||
|
||||
scheduler:
|
||||
defaultconf: /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||
|
||||
controllermanager:
|
||||
defaultconf: /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||
|
||||
etcd:
|
||||
defaultconf: /etc/kubernetes/manifests/etcd.yaml
|
||||
|
||||
node:
|
||||
kubelet:
|
||||
defaultconf: /etc/kubernetes/kubelet.conf
|
||||
defaultsvc: /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
|
||||
|
||||
proxy:
|
||||
defaultconf: /etc/kubernetes/addons/kube-proxy-daemonset.yaml
|
||||
1443
cfg/1.11/master.yaml
Normal file
1443
cfg/1.11/master.yaml
Normal file
File diff suppressed because it is too large
Load Diff
497
cfg/1.11/node.yaml
Normal file
497
cfg/1.11/node.yaml
Normal file
@@ -0,0 +1,497 @@
|
||||
---
|
||||
controls:
|
||||
version: 1.11
|
||||
id: 2
|
||||
text: "Worker Node Security Configuration"
|
||||
type: "node"
|
||||
groups:
|
||||
- id: 2.1
|
||||
text: "Kubelet"
|
||||
checks:
|
||||
- id: 2.1.1
|
||||
text: "Ensure that the --allow-privileged argument is set to false (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--allow-privileged"
|
||||
compare:
|
||||
op: eq
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--allow-privileged=false
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.2
|
||||
text: "Ensure that the --anonymous-auth argument is set to false (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--anonymous-auth"
|
||||
compare:
|
||||
op: eq
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set authentication: anonymous: enabled to
|
||||
false .
|
||||
If using executable arguments, edit the kubelet service file
|
||||
$kubeletconf on each worker node and
|
||||
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--anonymous-auth=false
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.3
|
||||
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--authorization-mode"
|
||||
compare:
|
||||
op: nothave
|
||||
value: "AlwaysAllow"
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set authorization: mode to Webhook.
|
||||
If using executable arguments, edit the kubelet service file
|
||||
$kubeletconf on each worker node and
|
||||
set the below parameter in KUBELET_AUTHZ_ARGS variable.
|
||||
--authorization-mode=Webhook
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.4
|
||||
text: "Ensure that the --client-ca-file argument is set as appropriate (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--client-ca-file"
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set authentication: x509: clientCAFile to
|
||||
the location of the client CA file.
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletconf on each worker node and
|
||||
set the below parameter in KUBELET_AUTHZ_ARGS variable.
|
||||
--client-ca-file=<path/to/client-ca-file>
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.5
|
||||
text: "Ensure that the --read-only-port argument is set to 0 (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--read-only-port"
|
||||
compare:
|
||||
op: eq
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set readOnlyPort to 0 .
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletconf on each worker node and
|
||||
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--read-only-port=0
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.6
|
||||
text: "Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--streaming-connection-idle-timeout"
|
||||
compare:
|
||||
op: noteq
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set streamingConnectionIdleTimeout to a
|
||||
value other than 0.
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletconf on each worker node and
|
||||
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--streaming-connection-idle-timeout=5m
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.7
|
||||
text: "Ensure that the --protect-kernel-defaults argument is set to true (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--protect-kernel-defaults"
|
||||
compare:
|
||||
op: eq
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set protectKernelDefaults: true .
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletconf on each worker node and
|
||||
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--protect-kernel-defaults=true
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.8
|
||||
text: "Ensure that the --make-iptables-util-chains argument is set to true (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "--make-iptables-util-chains"
|
||||
compare:
|
||||
op: eq
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set makeIPTablesUtilChains: true .
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletconf on each worker node and
|
||||
remove the --make-iptables-util-chains argument from the
|
||||
KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.9
|
||||
text: "Ensure that the --hostname-override argument is not set (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--hostname-override"
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and remove the --hostname-override argument from the
|
||||
KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.10
|
||||
text: "Ensure that the --event-qps argument is set to 0 (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--event-qps"
|
||||
compare:
|
||||
op: eq
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set eventRecordQPS: 0 .
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletconf on each worker node and
|
||||
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--event-qps=0
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.11
|
||||
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
bin_op: and
|
||||
test_items:
|
||||
- flag: "--tls-cert-file"
|
||||
set: true
|
||||
- flag: "--tls-private-key-file"
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to set tlsCertFile to the location of the certificate
|
||||
file to use to identify this Kubelet, and tlsPrivateKeyFile to the location of the
|
||||
corresponding private key file.
|
||||
If using command line arguments, edit the kubelet service file
|
||||
$kubeletconf on each worker node and
|
||||
set the below parameters in KUBELET_CERTIFICATE_ARGS variable.
|
||||
--tls-cert-file=<path/to/tls-certificate-file>
|
||||
file=<path/to/tls-key-file>
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.12
|
||||
text: "Ensure that the --cadvisor-port argument is set to 0 (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "--cadvisor-port"
|
||||
compare:
|
||||
op: eq
|
||||
value: 0
|
||||
set: true
|
||||
- flag: "--cadvisor-port"
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_CADVISOR_ARGS variable.
|
||||
--cadvisor-port=0
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.13
|
||||
text: "Ensure that the --rotate-certificates argument is not set to false (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--rotate-certificates"
|
||||
compare:
|
||||
op: eq
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
If using a Kubelet config file, edit the file to add the line rotateCertificates: true.
|
||||
If using command line arguments, edit the kubelet service file $kubeletconf
|
||||
on each worker node and add --rotate-certificates=true argument to the KUBELET_CERTIFICATE_ARGS variable.
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.14
|
||||
text: "Ensure that the RotateKubeletServerCertificate argument is set to true (Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "RotateKubeletServerCertificate"
|
||||
compare:
|
||||
op: eq
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_CERTIFICATE_ARGS variable.
|
||||
--feature-gates=RotateKubeletServerCertificate=true
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
systemctl daemon-reload
|
||||
systemctl restart kubelet.service
|
||||
scored: true
|
||||
|
||||
- id: 2.1.15
|
||||
text: "Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Not Scored)"
|
||||
audit: "ps -ef | grep $kubeletbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "--tls-cipher-suites"
|
||||
compare:
|
||||
op: eq
|
||||
value: "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"
|
||||
set: true
|
||||
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
|
||||
If using executable arguments, edit the kubelet service file $kubeletconf on each worker node and set the below parameter.
|
||||
--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
|
||||
scored: false
|
||||
|
||||
- id: 2.2
|
||||
text: "Configuration Files"
|
||||
checks:
|
||||
- id: 2.2.1
|
||||
text: "Ensure that the kubelet.conf file permissions are set to 644 or
|
||||
more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletconf; then stat -c %a $kubeletconf; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "640"
|
||||
compare:
|
||||
op: eq
|
||||
value: "640"
|
||||
set: true
|
||||
- flag: "600"
|
||||
compare:
|
||||
op: eq
|
||||
value: "600"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chmod 644 $kubeletconf
|
||||
scored: true
|
||||
|
||||
- id: 2.2.2
|
||||
text: "Ensure that the kubelet.conf file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletconf; then stat -c %U:%G $kubeletconf; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
compare:
|
||||
op: eq
|
||||
value: root:root
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chown root:root $kubeletconf
|
||||
scored: true
|
||||
|
||||
- id: 2.2.3
|
||||
text: "Ensure that the kubelet service file permissions are set to 644 or
|
||||
more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletsvc; then stat -c %a $kubeletsvc; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: 644
|
||||
set: true
|
||||
- flag: "640"
|
||||
compare:
|
||||
op: eq
|
||||
value: "640"
|
||||
set: true
|
||||
- flag: "600"
|
||||
compare:
|
||||
op: eq
|
||||
value: "600"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chmod 755 $kubeletsvc
|
||||
scored: true
|
||||
|
||||
- id: 2.2.4
|
||||
text: "Ensure that the kubelet service file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletsvc; then stat -c %U:%G $kubeletsvc; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chown root:root $kubeletsvc
|
||||
scored: true
|
||||
|
||||
- id: 2.2.5
|
||||
text: "Ensure that the proxy kubeconfig file permissions are set to 644 or more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $proxyconf; then stat -c %a $proxyconf; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "640"
|
||||
compare:
|
||||
op: eq
|
||||
value: "640"
|
||||
set: true
|
||||
- flag: "600"
|
||||
compare:
|
||||
op: eq
|
||||
value: "600"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chmod 644 $proxyconf
|
||||
scored: true
|
||||
|
||||
- id: 2.2.6
|
||||
text: "Ensure that the proxy kubeconfig file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $proxyconf; then stat -c %U:%G $proxyconf; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chown root:root $proxyconf
|
||||
scored: true
|
||||
|
||||
- id: 2.2.7
|
||||
text: "Ensure that the certificate authorities file permissions are set to
|
||||
644 or more restrictive (Scored)"
|
||||
type: manual
|
||||
remediation: |
|
||||
Run the following command to modify the file permissions of the --client-ca-file
|
||||
chmod 644 <filename>
|
||||
scored: true
|
||||
|
||||
- id: 2.2.8
|
||||
text: "Ensure that the client certificate authorities file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $ca-file; then stat -c %U:%G $ca-file; fi'"
|
||||
type: manual
|
||||
remediation: |
|
||||
Run the following command to modify the ownership of the --client-ca-file .
|
||||
chown root:root <filename>
|
||||
scored: true
|
||||
|
||||
- id: 2.2.9
|
||||
text: "Ensure that the kubelet configuration file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e /var/lib/kubelet/config.yaml; then stat -c %U:%G /var/lib/kubelet/config.yaml; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the following command (using the config file location identied in the Audit step)
|
||||
chown root:root /etc/kubernetes/kubelet.conf
|
||||
scored: true
|
||||
|
||||
- id: 2.2.10
|
||||
text: "Ensure that the kubelet configuration file has permissions set to 644 or more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e /var/lib/kubelet/config.yaml; then stat -c %a /var/lib/kubelet/config.yaml; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "640"
|
||||
compare:
|
||||
op: eq
|
||||
value: "640"
|
||||
set: true
|
||||
- flag: "600"
|
||||
compare:
|
||||
op: eq
|
||||
value: "600"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the following command (using the config file location identied in the Audit step)
|
||||
chmod 644 /var/lib/kubelet/config.yaml
|
||||
scored: true
|
||||
@@ -731,7 +731,7 @@ groups:
|
||||
|
||||
- id: 1.4.11
|
||||
text: "Ensure that the etcd data directory permissions are set to 700 or more restrictive (Scored)"
|
||||
audit: "ps -ef | grep $etcdbin | grep -v grep | grep -o data-dir=.* | cut -d= -f2 | xargs stat -c %a"
|
||||
audit: ps -ef | grep $etcdbin | grep -v grep | sed 's%.*data-dir[= ]\(\S*\)%\1%' | xargs stat -c %a
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "700"
|
||||
@@ -748,7 +748,7 @@ groups:
|
||||
|
||||
- id: 1.4.12
|
||||
text: "Ensure that the etcd data directory ownership is set to etcd:etcd (Scored)"
|
||||
audit: "ps -ef | grep $etcdbin | grep -v grep | grep -o data-dir=.* | cut -d= -f2 | xargs stat -c %U:%G"
|
||||
audit: ps -ef | grep $etcdbin | grep -v grep | sed 's%.*data-dir[= ]\(\S*\)%\1%' | xargs stat -c %U:%G
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "etcd:etcd"
|
||||
|
||||
@@ -793,7 +793,7 @@ groups:
|
||||
|
||||
- id: 1.4.11
|
||||
text: "Ensure that the etcd data directory permissions are set to 700 or more restrictive (Scored)"
|
||||
audit: "ps -ef | grep $etcdbin | grep -v grep | grep -o data-dir=.* | cut -d= -f2 | xargs stat -c %a"
|
||||
audit: ps -ef | grep $etcdbin | grep -v grep | sed 's%.*data-dir[= ]\(\S*\)%\1%' | xargs stat -c %a
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "700"
|
||||
@@ -810,7 +810,7 @@ groups:
|
||||
|
||||
- id: 1.4.12
|
||||
text: "Ensure that the etcd data directory ownership is set to etcd:etcd (Scored)"
|
||||
audit: "ps -ef | grep $etcdbin | grep -v grep | grep -o data-dir=.* | cut -d= -f2 | xargs stat -c %U:%G"
|
||||
audit: ps -ef | grep $etcdbin | grep -v grep | ed 's%.*data-dir[= ]\(\S*\)%\1%' | xargs stat -c %U:%G
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "etcd:etcd"
|
||||
|
||||
44
cfg/1.8/config.yaml
Normal file
44
cfg/1.8/config.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
## Controls Files.
|
||||
# These are YAML files that hold all the details for running checks.
|
||||
#
|
||||
## Uncomment to use different control file paths.
|
||||
# masterControls: ./cfg/master.yaml
|
||||
# nodeControls: ./cfg/node.yaml
|
||||
# federatedControls: ./cfg/federated.yaml
|
||||
|
||||
master:
|
||||
apiserver:
|
||||
confs:
|
||||
- /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||
- /etc/kubernetes/manifests/kube-apiserver.manifest
|
||||
defaultconf: /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||
|
||||
scheduler:
|
||||
confs:
|
||||
- /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||
- /etc/kubernetes/manifests/kube-scheduler.manifest
|
||||
defaultconf: /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||
|
||||
controllermanager:
|
||||
confs:
|
||||
- /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||
- /etc/kubernetes/manifests/kube-controller-manager.manifest
|
||||
defaultconf: /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||
|
||||
etcd:
|
||||
confs:
|
||||
- /etc/kubernetes/manifests/etcd.yaml
|
||||
- /etc/kubernetes/manifests/etcd.manifest
|
||||
defaultconf: /etc/kubernetes/manifests/etcd.yaml
|
||||
|
||||
node:
|
||||
kubelet:
|
||||
confs:
|
||||
- /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
|
||||
defaultconf: /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
|
||||
|
||||
proxy:
|
||||
confs:
|
||||
- /etc/kubernetes/addons/kube-proxy-daemonset.yaml
|
||||
defaultconf: /etc/kubernetes/addons/kube-proxy-daemonset.yaml
|
||||
@@ -19,9 +19,8 @@ groups:
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the deployment specs and set --anonymous-auth=false .
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
Edit the deployment specs and set --anonymous-auth=false.
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.2
|
||||
@@ -33,9 +32,8 @@ groups:
|
||||
set: false
|
||||
remediation: |
|
||||
Follow the documentation and configure alternate mechanisms for authentication. Then,
|
||||
edit the deployment specs and remove "--basic-auth-file=<filename>" .
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
edit the deployment specs and remove "--basic-auth-file=<filename>".
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.3
|
||||
@@ -46,9 +44,8 @@ groups:
|
||||
- flag: "--insecure-allow-any-token"
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the deployment specs and remove --insecure-allow-any-token .
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
Edit the deployment specs and remove --insecure-allow-any-token.
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.4
|
||||
@@ -59,9 +56,8 @@ groups:
|
||||
- flag: "--insecure-bind-address"
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the deployment specs and remove --insecure-bind-address .
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
Edit the deployment specs and remove --insecure-bind-address.
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.5
|
||||
@@ -75,9 +71,8 @@ groups:
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the deployment specs and set --insecure-port=0 .
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
Edit the deployment specs and set --insecure-port=0.
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.6
|
||||
@@ -95,8 +90,7 @@ groups:
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the deployment specs and set the --secure-port argument to the desired port.
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.7
|
||||
@@ -110,9 +104,8 @@ groups:
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the deployment specs and set "--profiling=false" :
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
Edit the deployment specs and set "--profiling=false":
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
score: true
|
||||
|
||||
- id: 3.1.8
|
||||
@@ -128,8 +121,7 @@ groups:
|
||||
remediation: |
|
||||
Edit the deployment specs and set --admission-control argument to a value that does not
|
||||
include AlwaysAdmit .
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.9
|
||||
@@ -144,9 +136,8 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the deployment specs and set --admission-control argument to a value that includes
|
||||
NamespaceLifecycle .
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
NamespaceLifecycle.
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.10
|
||||
@@ -172,8 +163,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the deployment specs and set --audit-log-maxage to 30 or as appropriate.
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.12
|
||||
@@ -188,8 +178,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the deployment specs and set --audit-log-maxbackup to 10 or as appropriate.
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.13
|
||||
@@ -204,8 +193,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the deployment specs and set --audit-log-maxsize=100 to 100 or as appropriate.
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.14
|
||||
@@ -221,8 +209,7 @@ groups:
|
||||
remediation: |
|
||||
Edit the deployment specs and set --authorization-mode argument to a value other than
|
||||
AlwaysAllow
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.15
|
||||
@@ -235,8 +222,7 @@ groups:
|
||||
remediation: |
|
||||
Follow the documentation and configure alternate mechanisms for authentication. Then,
|
||||
edit the deployment specs and remove the --token-auth-file=<filename> argument.
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.16
|
||||
@@ -251,8 +237,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the deployment specs and set "--service-account-lookup=true" .
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.17
|
||||
@@ -264,8 +249,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the deployment specs and set --service-account-key-file argument as appropriate.
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.18
|
||||
@@ -281,11 +265,10 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and set up the TLS connection between the
|
||||
federation apiserver and etcd. Then, edit the deployment specs and set "--etcd-
|
||||
certfile=<path/to/client-certificate-file>" and "--etcd-
|
||||
keyfile=<path/to/client-key-file>" arguments.
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
federation apiserver and etcd. Then, edit the deployment specs and set
|
||||
"--etcd-certfile=<path/to/client-certificate-file>" and
|
||||
"--etcd-keyfile=<path/to/client-key-file>" arguments.
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.1.19
|
||||
@@ -301,10 +284,10 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and set up the TLS connection on the federation
|
||||
apiserver. Then, edit the deployment specs and set "--tls-cert-file=<path/to/tls-
|
||||
certificate-file>" and "--tls-private-key-file=<path/to/tls-key-file>" :
|
||||
kubectl edit deployments federation-apiserver-deployment --
|
||||
namespace=federation-system
|
||||
apiserver. Then, edit the deployment specs and set
|
||||
"--tls-cert-file=<path/to/tls-certificate-file>" and
|
||||
"--tls-private-key-file=<path/to/tls-key-file>":
|
||||
kubectl edit deployments federation-apiserver-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
- id: 3.2
|
||||
@@ -321,7 +304,6 @@ groups:
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the deployment specs and set "--profiling=false" :
|
||||
kubectl edit deployments federation-controller-manager-deployment --
|
||||
namespace=federation-system
|
||||
Edit the deployment specs and set "--profiling=false":
|
||||
kubectl edit deployments federation-controller-manager-deployment --namespace=federation-system
|
||||
scored: true
|
||||
|
||||
@@ -19,7 +19,7 @@ groups:
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the below parameter.
|
||||
--anonymous-auth=false
|
||||
|
||||
@@ -34,7 +34,7 @@ groups:
|
||||
set: false
|
||||
remediation: |
|
||||
Follow the documentation and configure alternate mechanisms for authentication. Then,
|
||||
edit the API server pod specification file $apiserverpodspec
|
||||
edit the API server pod specification file $apiserverconf
|
||||
on the master node and remove the --basic-auth-file=<filename>
|
||||
parameter.
|
||||
scored: true
|
||||
@@ -47,7 +47,7 @@ groups:
|
||||
- flag: "--insecure-allow-any-token"
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and remove the --insecure-allow-any-token
|
||||
parameter.
|
||||
scored: true
|
||||
@@ -66,7 +66,7 @@ groups:
|
||||
- flag: "--kubelet-https"
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and remove the --kubelet-https parameter.
|
||||
scored: true
|
||||
|
||||
@@ -78,7 +78,7 @@ groups:
|
||||
- flag: "--insecure-bind-address"
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and remove the --insecure-bind-address
|
||||
parameter.
|
||||
scored: true
|
||||
@@ -94,7 +94,7 @@ groups:
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
apiserver.yaml on the master node and set the below parameter.
|
||||
--insecure-port=0
|
||||
scored: true
|
||||
@@ -113,7 +113,7 @@ groups:
|
||||
- flag: "--secure-port"
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and either remove the --secure-port parameter or
|
||||
set it to a different (non-zero) desired port.
|
||||
scored: true
|
||||
@@ -129,7 +129,7 @@ groups:
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the below parameter.
|
||||
--profiling=false
|
||||
scored: true
|
||||
@@ -145,7 +145,7 @@ groups:
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the below parameter.
|
||||
--repair-malformed-updates=false
|
||||
scored: true
|
||||
@@ -161,9 +161,9 @@ groups:
|
||||
value: AlwaysAdmit
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --admission-control parameter to a
|
||||
value that does not include AlwaysAdmit .
|
||||
value that does not include AlwaysAdmit.
|
||||
scored: true
|
||||
|
||||
- id: 1.1.11
|
||||
@@ -177,9 +177,9 @@ groups:
|
||||
value: "AlwaysPullImages"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --admission-control parameter to
|
||||
include AlwaysPullImages .
|
||||
include AlwaysPullImages.
|
||||
--admission-control=...,AlwaysPullImages,...
|
||||
scored: true
|
||||
|
||||
@@ -194,9 +194,9 @@ groups:
|
||||
value: "DenyEscalatingExec"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --admission-control parameter to a
|
||||
value that includes DenyEscalatingExec .
|
||||
value that includes DenyEscalatingExec.
|
||||
--admission-control=...,DenyEscalatingExec,...
|
||||
scored: true
|
||||
|
||||
@@ -211,9 +211,9 @@ groups:
|
||||
value: "SecurityContextDeny"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --admission-control parameter to
|
||||
include SecurityContextDeny .
|
||||
include SecurityContextDeny.
|
||||
--admission-control=...,SecurityContextDeny,...
|
||||
scored: true
|
||||
|
||||
@@ -228,9 +228,9 @@ groups:
|
||||
value: "NamespaceLifecycle"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --admission-control parameter to
|
||||
include NamespaceLifecycle .
|
||||
include NamespaceLifecycle.
|
||||
--admission-control=...,NamespaceLifecycle,...
|
||||
scored: true
|
||||
|
||||
@@ -242,7 +242,7 @@ groups:
|
||||
- flag: "--audit-log-path"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --audit-log-path parameter to a suitable
|
||||
path and file where you would like audit logs to be written, for example:
|
||||
--audit-log-path=/var/log/apiserver/audit.log
|
||||
@@ -259,7 +259,7 @@ groups:
|
||||
value: 30
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --audit-log-maxage parameter to 30 or
|
||||
as an appropriate number of days:
|
||||
--audit-log-maxage=30
|
||||
@@ -276,7 +276,7 @@ groups:
|
||||
value: 10
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --audit-log-maxbackup parameter to 10
|
||||
or to an appropriate value.
|
||||
--audit-log-maxbackup=10
|
||||
@@ -293,7 +293,7 @@ groups:
|
||||
value: 100
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --audit-log-maxsize parameter to an
|
||||
appropriate size in MB. For example, to set it as 100 MB:
|
||||
--audit-log-maxsize=100
|
||||
@@ -310,9 +310,9 @@ groups:
|
||||
value: "AlwaysAllow"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --authorization-mode parameter to
|
||||
values other than AlwaysAllow . One such example could be as below.
|
||||
values other than AlwaysAllow. One such example could be as below.
|
||||
--authorization-mode=RBAC
|
||||
scored: true
|
||||
|
||||
@@ -325,7 +325,7 @@ groups:
|
||||
set: false
|
||||
remediation: |
|
||||
Follow the documentation and configure alternate mechanisms for authentication. Then,
|
||||
edit the API server pod specification file $apiserverpodspec
|
||||
edit the API server pod specification file $apiserverconf
|
||||
on the master node and remove the --token-auth-file=<filename>
|
||||
parameter.
|
||||
scored: true
|
||||
@@ -340,7 +340,7 @@ groups:
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and setup the TLS connection between the apiserver
|
||||
and kubelets. Then, edit the API server pod specification file
|
||||
$apiserverpodspec on the master node and set the --
|
||||
$apiserverconf on the master node and set the --
|
||||
kubelet-certificate-authority parameter to the path to the cert file for the certificate
|
||||
authority.
|
||||
--kubelet-certificate-authority=<ca-string>
|
||||
@@ -360,7 +360,7 @@ groups:
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and set up the TLS connection between the
|
||||
apiserver and kubelets. Then, edit API server pod specification file
|
||||
$apiserverpodspec on the master node and set the
|
||||
$apiserverconf on the master node and set the
|
||||
kubelet client certificate and key parameters as below.
|
||||
--kubelet-client-certificate=<path/to/client-certificate-file>
|
||||
--kubelet-client-key=<path/to/client-key-file>
|
||||
@@ -377,7 +377,7 @@ groups:
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the below parameter.
|
||||
--service-account-lookup=true
|
||||
scored: true
|
||||
@@ -394,7 +394,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Follow the documentation and create Pod Security Policy objects as per your environment.
|
||||
Then, edit the API server pod specification file $apiserverpodspec
|
||||
Then, edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --admission-control parameter to a
|
||||
value that includes PodSecurityPolicy :
|
||||
--admission-control=...,PodSecurityPolicy,...
|
||||
@@ -410,7 +410,7 @@ groups:
|
||||
- flag: "--service-account-key-file"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --service-account-key-file parameter
|
||||
to the public key file for service accounts:
|
||||
--service-account-key-file=<filename>
|
||||
@@ -418,7 +418,7 @@ groups:
|
||||
|
||||
- id: 1.1.26
|
||||
text: "Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as
|
||||
appropriate (Scored"
|
||||
appropriate (Scored)"
|
||||
audit: "ps -ef | grep $apiserverbin | grep -v grep"
|
||||
tests:
|
||||
bin_op: and
|
||||
@@ -430,7 +430,7 @@ groups:
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and set up the TLS connection between the
|
||||
apiserver and etcd. Then, edit the API server pod specification file
|
||||
$apiserverpodspec on the master node and set the etcd
|
||||
$apiserverconf on the master node and set the etcd
|
||||
certificate and key file parameters.
|
||||
--etcd-certfile=<path/to/client-certificate-file>
|
||||
--etcd-keyfile=<path/to/client-key-file>
|
||||
@@ -448,9 +448,9 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Follow the documentation and create ServiceAccount objects as per your environment.
|
||||
Then, edit the API server pod specification file $apiserverpodspec
|
||||
Then, edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --admission-control parameter to a
|
||||
value that includes ServiceAccount .
|
||||
value that includes ServiceAccount.
|
||||
--admission-control=...,ServiceAccount,...
|
||||
scored: true
|
||||
|
||||
@@ -467,7 +467,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and set up the TLS connection on the apiserver.
|
||||
Then, edit the API server pod specification file $apiserverpodspec
|
||||
Then, edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the TLS certificate and private key file
|
||||
parameters.
|
||||
--tls-cert-file=<path/to/tls-certificate-file>
|
||||
@@ -483,7 +483,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and set up the TLS connection on the apiserver.
|
||||
Then, edit the API server pod specification file $apiserverpodspec
|
||||
Then, edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the client certificate authority file.
|
||||
--client-ca-file=<path/to/client-ca-file>
|
||||
scored: true
|
||||
@@ -498,7 +498,7 @@ groups:
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and set up the TLS connection between the
|
||||
apiserver and etcd. Then, edit the API server pod specification file
|
||||
$apiserverpodspec on the master node and set the etcd
|
||||
$apiserverconf on the master node and set the etcd
|
||||
certificate authority file parameter.
|
||||
--etcd-cafile=<path/to/ca-file>
|
||||
scored: true
|
||||
@@ -514,9 +514,9 @@ groups:
|
||||
value: "Node"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --authorization-mode parameter to a
|
||||
value that includes Node .
|
||||
value that includes Node.
|
||||
--authorization-mode=Node,RBAC
|
||||
scored: true
|
||||
|
||||
@@ -532,14 +532,14 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and configure NodeRestriction plug-in on kubelets.
|
||||
Then, edit the API server pod specification file $apiserverpodspec
|
||||
Then, edit the API server pod specification file $apiserverconf
|
||||
on the master node and set the --admission-control parameter to a
|
||||
value that includes NodeRestriction.
|
||||
--admission-control=...,NodeRestriction,...
|
||||
scored: true
|
||||
|
||||
- id: 1.1.33
|
||||
text: "1.1.34 Ensure that the --experimental-encryption-provider-config argument is
|
||||
text: "Ensure that the --experimental-encryption-provider-config argument is
|
||||
set as appropriate (Scored)"
|
||||
audit: "ps -ef | grep $apiserverbin | grep -v grep"
|
||||
tests:
|
||||
@@ -548,7 +548,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and configure a EncryptionConfig file. Then, edit
|
||||
the API server pod specification file $apiserverpodspec
|
||||
the API server pod specification file $apiserverconf
|
||||
on the master node and set the --experimental-encryption-provider-config parameter
|
||||
to the path of that file:
|
||||
--experimental-encryption-provider-config=</path/to/EncryptionConfig/File>
|
||||
@@ -586,7 +586,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and set the desired limits in a configuration file.
|
||||
Then, edit the API server pod specification file $apiserverpodspec
|
||||
Then, edit the API server pod specification file $apiserverconf
|
||||
and set the below parameters.
|
||||
--admission-control=EventRateLimit
|
||||
--admission-control-config-file=<path/to/configuration/file>
|
||||
@@ -598,8 +598,7 @@ groups:
|
||||
type: "manual"
|
||||
remediation: |
|
||||
Follow the Kubernetes documentation and set the desired audit policy in the
|
||||
/etc/kubernetes/audit-policy.yaml file.
|
||||
Then, edit the API server pod specification file $apiserverpodspec
|
||||
/etc/kubernetes/audit-policy.yaml file. Then, edit the API server pod specification file $apiserverconf
|
||||
and set the below parameters.
|
||||
--audit-policy-file=/etc/kubernetes/audit-policy.yaml
|
||||
scored: true
|
||||
@@ -609,9 +608,9 @@ groups:
|
||||
audit: "ps -ef | grep $apiserverbin | grep -v grep"
|
||||
type: "manual"
|
||||
remediation: |
|
||||
Edit the API server pod specification file $apiserverpodspec
|
||||
Edit the API server pod specification file $apiserverconf
|
||||
and set the below parameter as appropriate and if needed. For example,
|
||||
--request-timeout=300
|
||||
--request-timeout=300s
|
||||
scored: true
|
||||
|
||||
- id: 1.2
|
||||
@@ -629,7 +628,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Remediation:
|
||||
Edit the Scheduler pod specification file $apiserverpodspec
|
||||
Edit the Scheduler pod specification file $schedulerconf
|
||||
file on the master node and set the below parameter.
|
||||
--profiling=false
|
||||
scored: true
|
||||
@@ -645,9 +644,8 @@ groups:
|
||||
- flag: "--terminated-pod-gc-threshold"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the Controller Manager pod specification file $apiserverpodspec
|
||||
on the master node and set the --terminated-pod-gc-
|
||||
threshold to an appropriate threshold, for example:
|
||||
Edit the Controller Manager pod specification file $controllermanagerconf
|
||||
on the master node and set the --terminated-pod-gc-threshold to an appropriate threshold, for example:
|
||||
--terminated-pod-gc-threshold=10
|
||||
scored: true
|
||||
|
||||
@@ -662,13 +660,13 @@ groups:
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the Controller Manager pod specification file $apiserverpodspec
|
||||
Edit the Controller Manager pod specification file $apiserverconf
|
||||
on the master node and set the below parameter.
|
||||
--profiling=false
|
||||
scored: true
|
||||
|
||||
- id: 1.3.3
|
||||
text: "Ensure that the --use-service-account-credentials argument is set"
|
||||
text: "Ensure that the --use-service-account-credentials argument is set (Scored)"
|
||||
audit: "ps -ef | grep $controllermanagerbin | grep -v grep"
|
||||
tests:
|
||||
test_items:
|
||||
@@ -678,7 +676,7 @@ groups:
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the Controller Manager pod specification file $apiserverpodspec
|
||||
Edit the Controller Manager pod specification file $apiserverconf
|
||||
on the master node to set the below parameter.
|
||||
--use-service-account-credentials=true
|
||||
scored: true
|
||||
@@ -691,7 +689,7 @@ groups:
|
||||
- flag: "--service-account-private-key-file"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the Controller Manager pod specification file $apiserverpodspec
|
||||
Edit the Controller Manager pod specification file $apiserverconf
|
||||
on the master node and set the --service-account-private-
|
||||
key-file parameter to the private key file for service accounts.
|
||||
--service-account-private-key-file=<filename>
|
||||
@@ -705,9 +703,9 @@ groups:
|
||||
- flag: "--root-ca-file"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the Controller Manager pod specification file $apiserverpodspec
|
||||
Edit the Controller Manager pod specification file $apiserverconf
|
||||
on the master node and set the --root-ca-file parameter to
|
||||
the certificate bundle file`.
|
||||
the certificate bundle file.
|
||||
--root-ca-file=<path/to/file>
|
||||
scored: true
|
||||
|
||||
@@ -731,7 +729,7 @@ groups:
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the Controller Manager pod specification file $apiserverpodspec
|
||||
Edit the Controller Manager pod specification file $apiserverconf
|
||||
controller-manager.yaml on the master node and set the --feature-gates parameter to
|
||||
include RotateKubeletServerCertificate=true.
|
||||
--feature-gates=RotateKubeletServerCertificate=true
|
||||
@@ -743,7 +741,7 @@ groups:
|
||||
- id: 1.4.1
|
||||
text: "Ensure that the API server pod specification file permissions are
|
||||
set to 644 or more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $apiserverpodspec; then stat -c %a $apiserverpodspec; fi'"
|
||||
audit: "/bin/sh -c 'if test -e $apiserverconf; then stat -c %a $apiserverconf; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
@@ -765,13 +763,13 @@ groups:
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the master node.
|
||||
For example,
|
||||
chmod 644 $apiserverpodspec
|
||||
chmod 644 $apiserverconf
|
||||
scored: true
|
||||
|
||||
- id: 1.4.2
|
||||
text: "Ensure that the API server pod specification file ownership is set to
|
||||
root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $apiserverpodspec; then stat -c %U:%G $apiserverpodspec; fi'"
|
||||
audit: "/bin/sh -c 'if test -e $apiserverconf; then stat -c %U:%G $apiserverconf; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
@@ -782,13 +780,13 @@ groups:
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the master node.
|
||||
For example,
|
||||
chown root:root $apiserverpodspec
|
||||
chown root:root $apiserverconf
|
||||
scored: true
|
||||
|
||||
- id: 1.4.3
|
||||
text: "Ensure that the controller manager pod specification file
|
||||
permissions are set to 644 or more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $controllermanagerpodspec; then stat -c %a $controllermanagerpodspec; fi'"
|
||||
audit: "/bin/sh -c 'if test -e $controllermanagerconf; then stat -c %a $controllermanagerconf; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
@@ -810,13 +808,13 @@ groups:
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the master node.
|
||||
For example,
|
||||
chmod 644 $controllermanagerpodspec
|
||||
chmod 644 $controllermanagerconf
|
||||
scored: true
|
||||
|
||||
- id: 1.4.4
|
||||
text: "Ensure that the controller manager pod specification file
|
||||
ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $controllermanagerpodspec; then stat -c %U:%G $controllermanagerpodspec; fi'"
|
||||
audit: "/bin/sh -c 'if test -e $controllermanagerconf; then stat -c %U:%G $controllermanagerconf; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
@@ -827,13 +825,13 @@ groups:
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the master node.
|
||||
For example,
|
||||
chown root:root $controllermanagerpodspec
|
||||
chown root:root $controllermanagerconf
|
||||
scored: true
|
||||
|
||||
- id: 1.4.5
|
||||
text: "Ensure that the scheduler pod specification file permissions are set
|
||||
to 644 or more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $schedulerpodspec; then stat -c %a $schedulerpodspec; fi'"
|
||||
audit: "/bin/sh -c 'if test -e $schedulerconf; then stat -c %a $schedulerconf; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
@@ -855,13 +853,13 @@ groups:
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the master node.
|
||||
For example,
|
||||
chmod 644 $schedulerpodspec
|
||||
chmod 644 $schedulerconf
|
||||
scored: true
|
||||
|
||||
- id: 1.4.6
|
||||
text: "Ensure that the scheduler pod specification file ownership is set to
|
||||
root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $schedulerpodspec; then stat -c %U:%G $schedulerpodspec; fi'"
|
||||
audit: "/bin/sh -c 'if test -e $schedulerconf; then stat -c %U:%G $schedulerconf; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
@@ -872,13 +870,13 @@ groups:
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the master node.
|
||||
For example,
|
||||
chown root:root $schedulerpodspec
|
||||
chown root:root $schedulerconf
|
||||
scored: true
|
||||
|
||||
- id: 1.4.7
|
||||
text: "Ensure that the etcd pod specification file permissions are set to
|
||||
644 or more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $etcdpodspec; then stat -c %a $etcdpodspec; fi'"
|
||||
audit: "/bin/sh -c 'if test -e $etcdconf; then stat -c %a $etcdconf; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
@@ -900,13 +898,13 @@ groups:
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the master node.
|
||||
For example,
|
||||
chmod 644 $etcdpodspec
|
||||
chmod 644 $etcdconf
|
||||
scored: true
|
||||
|
||||
- id: 1.4.8
|
||||
text: "Ensure that the etcd pod specification file ownership is set to
|
||||
root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $etcdpodspec; then stat -c %U:%G $etcdpodspec; fi'"
|
||||
audit: "/bin/sh -c 'if test -e $etcdconf; then stat -c %U:%G $etcdconf; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
@@ -917,7 +915,7 @@ groups:
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the master node.
|
||||
For example,
|
||||
chown root:root $etcdpodspec
|
||||
chown root:root $etcdconf
|
||||
scored: true
|
||||
|
||||
- id: 1.4.9
|
||||
@@ -944,7 +942,7 @@ groups:
|
||||
|
||||
- id: 1.4.11
|
||||
text: "Ensure that the etcd data directory permissions are set to 700 or more restrictive (Scored)"
|
||||
audit: "ps -ef | grep $etcdbin | grep -v grep | grep -o data-dir=.* | cut -d= -f2 | xargs stat -c %a"
|
||||
audit: ps -ef | grep $etcdbin | grep -- --data-dir | sed 's%.*data-dir[= ]\([^ ]*\).*%\1%' | xargs stat -c %a
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "700"
|
||||
@@ -962,7 +960,7 @@ groups:
|
||||
|
||||
- id: 1.4.12
|
||||
text: "Ensure that the etcd data directory ownership is set to etcd:etcd (Scored)"
|
||||
audit: "ps -ef | grep $etcdbin | grep -v grep | grep -o data-dir=.* | cut -d= -f2 | xargs stat -c %U:%G"
|
||||
audit: ps -ef | grep $etcdbin | grep -- --data-dir | sed 's%.*data-dir[= ]\([^ ]*\).*%\1%' | xargs stat -c %U:%G
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "etcd:etcd"
|
||||
@@ -980,12 +978,23 @@ groups:
|
||||
more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e /etc/kubernetes/admin.conf; then stat -c %a /etc/kubernetes/admin.conf; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "640"
|
||||
compare:
|
||||
op: eq
|
||||
value: "640"
|
||||
set: true
|
||||
- flag: "600"
|
||||
compare:
|
||||
op: eq
|
||||
value: "600"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the master node.
|
||||
For example,
|
||||
@@ -1011,14 +1020,25 @@ groups:
|
||||
- id: 1.4.15
|
||||
text: "Ensure that the scheduler.conf file permissions are set to 644 or
|
||||
more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $schedulerconf then stat -c %a $schedulerconf; fi'"
|
||||
audit: "/bin/sh -c 'if test -e $schedulerconf; then stat -c %a $schedulerconf; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "640"
|
||||
compare:
|
||||
op: eq
|
||||
value: "640"
|
||||
set: true
|
||||
- flag: "600"
|
||||
compare:
|
||||
op: eq
|
||||
value: "600"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the master node.
|
||||
For example,
|
||||
@@ -1044,14 +1064,25 @@ groups:
|
||||
- id: 1.4.17
|
||||
text: "Ensure that the controller-manager.conf file permissions are set
|
||||
to 644 or more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $controllermanagerconf then stat -c %a $controllermanagerconf; fi'"
|
||||
audit: "/bin/sh -c 'if test -e $controllermanagerconf; then stat -c %a $controllermanagerconf; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "644"
|
||||
compare:
|
||||
op: eq
|
||||
value: "644"
|
||||
set: true
|
||||
- flag: "640"
|
||||
compare:
|
||||
op: eq
|
||||
value: "640"
|
||||
set: true
|
||||
- flag: "600"
|
||||
compare:
|
||||
op: eq
|
||||
value: "600"
|
||||
set: true
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the master node.
|
||||
For example,
|
||||
@@ -1088,7 +1119,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Follow the etcd service documentation and configure TLS encryption.
|
||||
Then, edit the etcd pod specification file $etcdpodspec on the
|
||||
Then, edit the etcd pod specification file $etcdconf on the
|
||||
master node and set the below parameters.
|
||||
--ca-file=</path/to/ca-file>
|
||||
--key-file=</path/to/key-file>
|
||||
@@ -1105,7 +1136,7 @@ groups:
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the etcd pod specification file $etcdpodspec on the master
|
||||
Edit the etcd pod specification file $etcdconf on the master
|
||||
node and set the below parameter.
|
||||
--client-cert-auth="true"
|
||||
scored: true
|
||||
@@ -1123,8 +1154,8 @@ groups:
|
||||
op: neq
|
||||
value: true
|
||||
remediation: |
|
||||
Edit the etcd pod specification file $etcdpodspec on the master
|
||||
node and either remove the --auto-tls parameter or set it to false .
|
||||
Edit the etcd pod specification file $etcdconf on the master
|
||||
node and either remove the --auto-tls parameter or set it to false.
|
||||
--auto-tls=false
|
||||
scored: true
|
||||
|
||||
@@ -1140,8 +1171,7 @@ groups:
|
||||
set: true
|
||||
remediation: |
|
||||
Follow the etcd service documentation and configure peer TLS encryption as appropriate
|
||||
for your etcd cluster.
|
||||
Then, edit the etcd pod specification file $etcdpodspec on the
|
||||
for your etcd cluster. Then, edit the etcd pod specification file $etcdconf on the
|
||||
master node and set the below parameters.
|
||||
--peer-client-file=</path/to/peer-cert-file>
|
||||
--peer-key-file=</path/to/peer-key-file>
|
||||
@@ -1158,7 +1188,7 @@ groups:
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the etcd pod specification file $etcdpodspec on the master
|
||||
Edit the etcd pod specification file $etcdconf on the master
|
||||
node and set the below parameter.
|
||||
--peer-client-cert-auth=true
|
||||
scored: true
|
||||
@@ -1177,8 +1207,8 @@ groups:
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the etcd pod specification file $etcdpodspec on the master
|
||||
node and either remove the --peer-auto-tls parameter or set it to false .
|
||||
Edit the etcd pod specification file $etcdconf on the master
|
||||
node and either remove the --peer-auto-tls parameter or set it to false.
|
||||
--peer-auto-tls=false
|
||||
scored: true
|
||||
|
||||
@@ -1190,7 +1220,7 @@ groups:
|
||||
- flag: "--wal-dir"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the etcd pod specification file $etcdpodspec on the master
|
||||
Edit the etcd pod specification file $etcdconf on the master
|
||||
node and set the below parameter.
|
||||
--wal-dir=</path/to/log/dir>
|
||||
scored: true
|
||||
@@ -1206,7 +1236,7 @@ groups:
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the etcd pod specification file $etcdpodspec on the master
|
||||
Edit the etcd pod specification file $etcdconf on the master
|
||||
node and set the below parameter.
|
||||
--max-wals=0
|
||||
scored: true
|
||||
@@ -1221,7 +1251,7 @@ groups:
|
||||
remediation: |
|
||||
Follow the etcd documentation and create a dedicated certificate authority setup for the
|
||||
etcd service.
|
||||
Then, edit the etcd pod specification file $etcdpodspec on the
|
||||
Then, edit the etcd pod specification file $etcdconf on the
|
||||
master node and set the below parameter.
|
||||
--trusted-ca-file=</path/to/ca-file>
|
||||
scored: false
|
||||
|
||||
@@ -19,7 +19,7 @@ groups:
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--allow-privileged=false
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -38,7 +38,7 @@ groups:
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--anonymous-auth=false
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -57,7 +57,7 @@ groups:
|
||||
value: "AlwaysAllow"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_AUTHZ_ARGS variable.
|
||||
--authorization-mode=Webhook
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -73,7 +73,7 @@ groups:
|
||||
- flag: "--client-ca-file"
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_AUTHZ_ARGS variable.
|
||||
--client-ca-file=<path/to/client-ca-file>
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -92,7 +92,7 @@ groups:
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--read-only-port=0
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -111,7 +111,7 @@ groups:
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--streaming-connection-idle-timeout=5m
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -130,7 +130,7 @@ groups:
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--protect-kernel-defaults=true
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -150,7 +150,7 @@ groups:
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and remove the --make-iptables-util-chains argument from the
|
||||
KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -169,7 +169,7 @@ groups:
|
||||
value: false
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--keep-terminated-pod-volumes=false
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -185,7 +185,7 @@ groups:
|
||||
- flag: "--hostname-override"
|
||||
set: false
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and remove the --hostname-override argument from the
|
||||
KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -204,7 +204,7 @@ groups:
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
|
||||
--event-qps=0
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -245,7 +245,7 @@ groups:
|
||||
value: 0
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_CADVISOR_ARGS variable.
|
||||
--cadvisor-port=0
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -264,7 +264,7 @@ groups:
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and remove the --feature-
|
||||
gates=RotateKubeletClientCertificate=false argument from the
|
||||
KUBELET_CERTIFICATE_ARGS variable.
|
||||
@@ -284,7 +284,7 @@ groups:
|
||||
value: true
|
||||
set: true
|
||||
remediation: |
|
||||
Edit the kubelet service file $kubeletunitfile
|
||||
Edit the kubelet service file $kubeletconf
|
||||
on each worker node and set the below parameter in KUBELET_CERTIFICATE_ARGS variable.
|
||||
--feature-gates=RotateKubeletServerCertificate=true
|
||||
Based on your system, restart the kubelet service. For example:
|
||||
@@ -342,7 +342,7 @@ groups:
|
||||
- id: 2.2.3
|
||||
text: "Ensure that the kubelet service file permissions are set to 644 or
|
||||
more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletunitfile; then stat -c %a $kubeletunitfile; fi'"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletconf; then stat -c %a $kubeletconf; fi'"
|
||||
tests:
|
||||
bin_op: or
|
||||
test_items:
|
||||
@@ -364,13 +364,12 @@ groups:
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chmod 755 $kubeletunitfile
|
||||
chmod 755 $kubeletconf
|
||||
scored: true
|
||||
|
||||
- id: 2.2.4
|
||||
text: "Ensure that the kubelet service file permissions are set to 644 or
|
||||
more restrictive (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletunitfile; then stat -c %U:%G $kubeletunitfile; fi'"
|
||||
text: "2.2.4 Ensure that the kubelet service file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $kubeletconf; then stat -c %U:%G $kubeletconf; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
@@ -378,7 +377,7 @@ groups:
|
||||
remediation: |
|
||||
Run the below command (based on the file location on your system) on the each worker
|
||||
node. For example,
|
||||
chown root:root $kubeletunitfile
|
||||
chown root:root $kubeletconf
|
||||
scored: true
|
||||
|
||||
- id: 2.2.5
|
||||
@@ -411,6 +410,7 @@ groups:
|
||||
|
||||
- id: 2.2.6
|
||||
text: "Ensure that the proxy kubeconfig file ownership is set to root:root (Scored)"
|
||||
audit: "/bin/sh -c 'if test -e $proxyconf; then stat -c %U:%G $proxyconf; fi'"
|
||||
tests:
|
||||
test_items:
|
||||
- flag: "root:root"
|
||||
|
||||
@@ -30,10 +30,6 @@ master:
|
||||
- /etc/kubernetes/apiserver
|
||||
defaultconf: /etc/kubernetes/apiserver
|
||||
|
||||
podspecs:
|
||||
- /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||
defaultpodspec: /etc/kubernetes/manifests/kube-apiserver.yaml
|
||||
|
||||
scheduler:
|
||||
bins:
|
||||
- "kube-scheduler"
|
||||
@@ -44,10 +40,6 @@ master:
|
||||
- /etc/kubernetes/scheduler
|
||||
defaultconf: /etc/kubernetes/scheduler
|
||||
|
||||
podspecs:
|
||||
- /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||
defaultpodspec: /etc/kubernetes/manifests/kube-scheduler.yaml
|
||||
|
||||
controllermanager:
|
||||
bins:
|
||||
- "kube-controller-manager"
|
||||
@@ -58,10 +50,6 @@ master:
|
||||
- /etc/kubernetes/controller-manager
|
||||
defaultconf: /etc/kubernetes/controller-manager
|
||||
|
||||
podspecs:
|
||||
- /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||
defaultpodspec: /etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||
|
||||
etcd:
|
||||
optional: true
|
||||
bins:
|
||||
@@ -70,17 +58,12 @@ master:
|
||||
- /etc/etcd/etcd.conf
|
||||
defaultconf: /etc/etcd/etcd.conf
|
||||
|
||||
podspecs:
|
||||
- /etc/kubernetes/manifests/etcd.yaml
|
||||
defaultpodspec: /etc/kubernetes/manifests/etcd.yaml
|
||||
|
||||
flanneld:
|
||||
optional: true
|
||||
bins:
|
||||
- flanneld
|
||||
defaultconf: /etc/sysconfig/flanneld
|
||||
|
||||
|
||||
node:
|
||||
components:
|
||||
- kubelet
|
||||
@@ -100,10 +83,6 @@ node:
|
||||
- /etc/kubernetes/kubelet
|
||||
defaultconf: "/etc/kubernetes/kubelet.conf"
|
||||
|
||||
unitfiles:
|
||||
- /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
|
||||
defaultunitfile: /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
|
||||
|
||||
proxy:
|
||||
bins:
|
||||
- "kube-proxy"
|
||||
@@ -130,5 +109,3 @@ federated:
|
||||
- "hyperkube federation-controller-manager"
|
||||
- "kube-federation-controller-manager"
|
||||
- "federation-controller-manager"
|
||||
|
||||
|
||||
|
||||
@@ -60,15 +60,17 @@ func handleError(err error, context string) (errmsg string) {
|
||||
// Check contains information about a recommendation in the
|
||||
// CIS Kubernetes 1.6+ document.
|
||||
type Check struct {
|
||||
ID string `yaml:"id" json:"id"`
|
||||
Text string
|
||||
ID string `yaml:"id" json:"test_number"`
|
||||
Text string `json:"test_desc"`
|
||||
Audit string `json:"omit"`
|
||||
Type string `json:"type"`
|
||||
Commands []*exec.Cmd `json:"omit"`
|
||||
Tests *tests `json:"omit"`
|
||||
Set bool `json:"omit"`
|
||||
Remediation string
|
||||
State
|
||||
Remediation string `json:"-"`
|
||||
TestInfo []string `json:"test_info"`
|
||||
State `json:"status"`
|
||||
ActualValue string `json:"actual_value"`
|
||||
}
|
||||
|
||||
// Run executes the audit commands specified in a check and outputs
|
||||
@@ -156,15 +158,25 @@ func (c *Check) Run() {
|
||||
i++
|
||||
}
|
||||
|
||||
if errmsgs != "" {
|
||||
glog.V(2).Info(errmsgs)
|
||||
finalOutput := c.Tests.execute(out.String())
|
||||
if finalOutput != nil {
|
||||
c.ActualValue = finalOutput.actualResult
|
||||
if finalOutput.testResult {
|
||||
c.State = PASS
|
||||
} else {
|
||||
c.State = FAIL
|
||||
}
|
||||
} else {
|
||||
errmsgs += handleError(
|
||||
fmt.Errorf("final output is nil"),
|
||||
fmt.Sprintf("failed to run: %s\n",
|
||||
c.Audit,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
res := c.Tests.execute(out.String())
|
||||
if res {
|
||||
c.State = PASS
|
||||
} else {
|
||||
c.State = FAIL
|
||||
if errmsgs != "" {
|
||||
glog.V(2).Info(errmsgs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,26 +23,29 @@ import (
|
||||
|
||||
// Controls holds all controls to check for master nodes.
|
||||
type Controls struct {
|
||||
ID string `yaml:"id"`
|
||||
Version string
|
||||
Text string
|
||||
Type NodeType
|
||||
Groups []*Group
|
||||
ID string `yaml:"id" json:"id"`
|
||||
Version string `json:"version"`
|
||||
Text string `json:"text"`
|
||||
Type NodeType `json:"node_type"`
|
||||
Groups []*Group `json:"tests"`
|
||||
Summary
|
||||
}
|
||||
|
||||
// Group is a collection of similar checks.
|
||||
type Group struct {
|
||||
ID string `yaml:"id"`
|
||||
Text string
|
||||
Checks []*Check
|
||||
ID string `yaml:"id" json:"section"`
|
||||
Pass int `json:"pass"`
|
||||
Fail int `json:"fail"`
|
||||
Warn int `json:"warn"`
|
||||
Text string `json:"desc"`
|
||||
Checks []*Check `json:"results"`
|
||||
}
|
||||
|
||||
// Summary is a summary of the results of control checks run.
|
||||
type Summary struct {
|
||||
Pass int
|
||||
Fail int
|
||||
Warn int
|
||||
Pass int `json:"total_pass"`
|
||||
Fail int `json:"total_fail"`
|
||||
Warn int `json:"total_warn"`
|
||||
}
|
||||
|
||||
// NewControls instantiates a new master Controls object.
|
||||
@@ -84,7 +87,9 @@ func (controls *Controls) RunGroup(gids ...string) Summary {
|
||||
if gid == group.ID {
|
||||
for _, check := range group.Checks {
|
||||
check.Run()
|
||||
check.TestInfo = append(check.TestInfo, check.Remediation)
|
||||
summarize(controls, check)
|
||||
summarizeGroup(group, check)
|
||||
}
|
||||
|
||||
g = append(g, group)
|
||||
@@ -112,6 +117,7 @@ func (controls *Controls) RunChecks(ids ...string) Summary {
|
||||
for _, id := range ids {
|
||||
if id == check.ID {
|
||||
check.Run()
|
||||
check.TestInfo = append(check.TestInfo, check.Remediation)
|
||||
summarize(controls, check)
|
||||
|
||||
// Check if we have already added this checks group.
|
||||
@@ -178,3 +184,14 @@ func summarize(controls *Controls, check *Check) {
|
||||
controls.Summary.Warn++
|
||||
}
|
||||
}
|
||||
|
||||
func summarizeGroup(group *Group, check *Check) {
|
||||
switch check.State {
|
||||
case PASS:
|
||||
group.Pass++
|
||||
case FAIL:
|
||||
group.Fail++
|
||||
case WARN:
|
||||
group.Warn++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ groups:
|
||||
- id: 1
|
||||
text: "flag is not set"
|
||||
tests:
|
||||
test_item:
|
||||
test_items:
|
||||
- flag: "--basic-auth"
|
||||
set: false
|
||||
|
||||
|
||||
@@ -49,8 +49,13 @@ type compare struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func (t *testItem) execute(s string) (result bool) {
|
||||
result = false
|
||||
type testOutput struct {
|
||||
testResult bool
|
||||
actualResult string
|
||||
}
|
||||
|
||||
func (t *testItem) execute(s string) *testOutput {
|
||||
result := &testOutput{}
|
||||
match := strings.Contains(s, t.Flag)
|
||||
|
||||
if t.Set {
|
||||
@@ -78,45 +83,57 @@ func (t *testItem) execute(s string) (result bool) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
result.actualResult = strings.ToLower(flagVal)
|
||||
switch t.Compare.Op {
|
||||
case "eq":
|
||||
result = flagVal == t.Compare.Value
|
||||
value := strings.ToLower(flagVal)
|
||||
// Do case insensitive comparaison for booleans ...
|
||||
if value == "false" || value == "true" {
|
||||
result.testResult = value == t.Compare.Value
|
||||
} else {
|
||||
result.testResult = flagVal == t.Compare.Value
|
||||
}
|
||||
|
||||
case "noteq":
|
||||
result = !(flagVal == t.Compare.Value)
|
||||
value := strings.ToLower(flagVal)
|
||||
// Do case insensitive comparaison for booleans ...
|
||||
if value == "false" || value == "true" {
|
||||
result.testResult = !(value == t.Compare.Value)
|
||||
} else {
|
||||
result.testResult = !(flagVal == t.Compare.Value)
|
||||
}
|
||||
|
||||
case "gt":
|
||||
a, b := toNumeric(flagVal, t.Compare.Value)
|
||||
result = a > b
|
||||
result.testResult = a > b
|
||||
|
||||
case "gte":
|
||||
a, b := toNumeric(flagVal, t.Compare.Value)
|
||||
result = a >= b
|
||||
result.testResult = a >= b
|
||||
|
||||
case "lt":
|
||||
a, b := toNumeric(flagVal, t.Compare.Value)
|
||||
result = a < b
|
||||
result.testResult = a < b
|
||||
|
||||
case "lte":
|
||||
a, b := toNumeric(flagVal, t.Compare.Value)
|
||||
result = a <= b
|
||||
result.testResult = a <= b
|
||||
|
||||
case "has":
|
||||
result = strings.Contains(flagVal, t.Compare.Value)
|
||||
result.testResult = strings.Contains(flagVal, t.Compare.Value)
|
||||
|
||||
case "nothave":
|
||||
result = !strings.Contains(flagVal, t.Compare.Value)
|
||||
result.testResult = !strings.Contains(flagVal, t.Compare.Value)
|
||||
}
|
||||
} else {
|
||||
result = isset
|
||||
result.testResult = isset
|
||||
}
|
||||
|
||||
} else {
|
||||
notset := !match
|
||||
result = notset
|
||||
result.testResult = notset
|
||||
}
|
||||
|
||||
return
|
||||
return result
|
||||
}
|
||||
|
||||
type tests struct {
|
||||
@@ -124,13 +141,19 @@ type tests struct {
|
||||
BinOp binOp `yaml:"bin_op"`
|
||||
}
|
||||
|
||||
func (ts *tests) execute(s string) (result bool) {
|
||||
res := make([]bool, len(ts.TestItems))
|
||||
func (ts *tests) execute(s string) *testOutput {
|
||||
finalOutput := &testOutput{}
|
||||
|
||||
for i, t := range ts.TestItems {
|
||||
res[i] = t.execute(s)
|
||||
res := make([]testOutput, len(ts.TestItems))
|
||||
if len(res) == 0 {
|
||||
return finalOutput
|
||||
}
|
||||
|
||||
for i, t := range ts.TestItems {
|
||||
res[i] = *(t.execute(s))
|
||||
}
|
||||
|
||||
var result bool
|
||||
// If no binary operation is specified, default to AND
|
||||
switch ts.BinOp {
|
||||
default:
|
||||
@@ -139,16 +162,19 @@ func (ts *tests) execute(s string) (result bool) {
|
||||
case and, "":
|
||||
result = true
|
||||
for i := range res {
|
||||
result = result && res[i]
|
||||
result = result && res[i].testResult
|
||||
}
|
||||
case or:
|
||||
result = false
|
||||
for i := range res {
|
||||
result = result || res[i]
|
||||
result = result || res[i].testResult
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
finalOutput.testResult = result
|
||||
finalOutput.actualResult = res[0].actualResult
|
||||
|
||||
return finalOutput
|
||||
}
|
||||
|
||||
func toNumeric(a, b string) (c, d int) {
|
||||
|
||||
@@ -113,7 +113,7 @@ func TestTestExecute(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
res := c.Tests.execute(c.str)
|
||||
res := c.Tests.execute(c.str).testResult
|
||||
if !res {
|
||||
t.Errorf("%s, expected:%v, got:%v\n", c.Text, true, res)
|
||||
}
|
||||
|
||||
146
cmd/common.go
146
cmd/common.go
@@ -17,6 +17,8 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/aquasecurity/kube-bench/check"
|
||||
"github.com/golang/glog"
|
||||
@@ -27,60 +29,67 @@ var (
|
||||
errmsgs string
|
||||
)
|
||||
|
||||
func runChecks(t check.NodeType) {
|
||||
func runChecks(nodetype check.NodeType) {
|
||||
var summary check.Summary
|
||||
var file string
|
||||
var err error
|
||||
var typeConf *viper.Viper
|
||||
|
||||
switch t {
|
||||
switch nodetype {
|
||||
case check.MASTER:
|
||||
file = masterFile
|
||||
typeConf = viper.Sub("master")
|
||||
case check.NODE:
|
||||
file = nodeFile
|
||||
typeConf = viper.Sub("node")
|
||||
case check.FEDERATED:
|
||||
file = federatedFile
|
||||
typeConf = viper.Sub("federated")
|
||||
}
|
||||
|
||||
runningVersion, err := getKubeVersion()
|
||||
if err != nil && kubeVersion == "" {
|
||||
exitWithError(fmt.Errorf("Version check failed: %s\nAlternatively, you can specify the version with --version", err))
|
||||
}
|
||||
path, err := getConfigFilePath(kubeVersion, runningVersion, file)
|
||||
if err != nil {
|
||||
exitWithError(fmt.Errorf("can't find %s controls file in %s: %v", nodetype, cfgDir, err))
|
||||
}
|
||||
|
||||
def := filepath.Join(path, file)
|
||||
in, err := ioutil.ReadFile(def)
|
||||
if err != nil {
|
||||
exitWithError(fmt.Errorf("error opening %s controls file: %v", nodetype, err))
|
||||
}
|
||||
|
||||
glog.V(1).Info(fmt.Sprintf("Using benchmark file: %s\n", def))
|
||||
|
||||
// Merge kubernetes version specific config if any.
|
||||
viper.SetConfigFile(path + "/config.yaml")
|
||||
err = viper.MergeInConfig()
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
glog.V(2).Info(fmt.Sprintf("No version-specific config.yaml file in %s", path))
|
||||
} else {
|
||||
exitWithError(fmt.Errorf("couldn't read config file %s: %v", path+"/config.yaml", err))
|
||||
}
|
||||
} else {
|
||||
glog.V(1).Info(fmt.Sprintf("Using config file: %s\n", viper.ConfigFileUsed()))
|
||||
}
|
||||
|
||||
// Get the set of exectuables and config files we care about on this type of node. This also
|
||||
// checks that the executables we need for the node type are running.
|
||||
typeConf = viper.Sub(string(nodetype))
|
||||
binmap := getBinaries(typeConf)
|
||||
confmap := getConfigFiles(typeConf, "conf")
|
||||
podspecmap := getConfigFiles(typeConf, "podspec")
|
||||
unitfilemap := getConfigFiles(typeConf, "unitfile")
|
||||
|
||||
switch t {
|
||||
case check.MASTER:
|
||||
file = masterFile
|
||||
case check.NODE:
|
||||
file = nodeFile
|
||||
case check.FEDERATED:
|
||||
file = federatedFile
|
||||
}
|
||||
|
||||
ver := getKubeVersion()
|
||||
path := fmt.Sprintf("%s/%s/%s", cfgDir, ver.Server, file)
|
||||
in, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
exitWithError(fmt.Errorf("error opening %s controls file: %v", t, err))
|
||||
}
|
||||
confmap := getConfigFiles(typeConf)
|
||||
svcmap := getServiceFiles(typeConf)
|
||||
|
||||
// Variable substitutions. Replace all occurrences of variables in controls files.
|
||||
s := string(in)
|
||||
s = makeSubstitutions(s, "bin", binmap)
|
||||
s = makeSubstitutions(s, "conf", confmap)
|
||||
s = makeSubstitutions(s, "podspec", podspecmap)
|
||||
s = makeSubstitutions(s, "unitfile", unitfilemap)
|
||||
s = makeSubstitutions(s, "svc", svcmap)
|
||||
|
||||
glog.V(1).Info(fmt.Sprintf("Using config file: %s\n", viper.ConfigFileUsed()))
|
||||
glog.V(1).Info(fmt.Sprintf("Using benchmark file: %s\n", path))
|
||||
|
||||
controls, err := check.NewControls(t, []byte(s))
|
||||
controls, err := check.NewControls(nodetype, []byte(s))
|
||||
if err != nil {
|
||||
exitWithError(fmt.Errorf("error setting up %s controls: %v", t, err))
|
||||
exitWithError(fmt.Errorf("error setting up %s controls: %v", nodetype, err))
|
||||
}
|
||||
|
||||
if groupList != "" && checkList == "" {
|
||||
@@ -104,7 +113,17 @@ func runChecks(t check.NodeType) {
|
||||
|
||||
fmt.Println(string(out))
|
||||
} else {
|
||||
prettyPrint(controls, summary)
|
||||
// if we want to store in PostgreSQL, convert to JSON and save it
|
||||
if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0) && pgSQL {
|
||||
out, err := controls.JSON()
|
||||
if err != nil {
|
||||
exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
|
||||
}
|
||||
|
||||
savePgsql(string(out))
|
||||
} else {
|
||||
prettyPrint(controls, summary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,41 +135,48 @@ func colorPrint(state check.State, s string) {
|
||||
|
||||
// prettyPrint outputs the results to stdout in human-readable format
|
||||
func prettyPrint(r *check.Controls, summary check.Summary) {
|
||||
colorPrint(check.INFO, fmt.Sprintf("%s %s\n", r.ID, r.Text))
|
||||
for _, g := range r.Groups {
|
||||
colorPrint(check.INFO, fmt.Sprintf("%s %s\n", g.ID, g.Text))
|
||||
for _, c := range g.Checks {
|
||||
colorPrint(c.State, fmt.Sprintf("%s %s\n", c.ID, c.Text))
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// Print remediations.
|
||||
if summary.Fail > 0 || summary.Warn > 0 {
|
||||
colors[check.WARN].Printf("== Remediations ==\n")
|
||||
// Print check results.
|
||||
if !noResults {
|
||||
colorPrint(check.INFO, fmt.Sprintf("%s %s\n", r.ID, r.Text))
|
||||
for _, g := range r.Groups {
|
||||
colorPrint(check.INFO, fmt.Sprintf("%s %s\n", g.ID, g.Text))
|
||||
for _, c := range g.Checks {
|
||||
if c.State != check.PASS {
|
||||
fmt.Printf("%s %s\n", c.ID, c.Remediation)
|
||||
}
|
||||
colorPrint(c.State, fmt.Sprintf("%s %s\n", c.ID, c.Text))
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// Print summary setting output color to highest severity.
|
||||
var res check.State
|
||||
if summary.Fail > 0 {
|
||||
res = check.FAIL
|
||||
} else if summary.Warn > 0 {
|
||||
res = check.WARN
|
||||
} else {
|
||||
res = check.PASS
|
||||
// Print remediations.
|
||||
if !noRemediations {
|
||||
if summary.Fail > 0 || summary.Warn > 0 {
|
||||
colors[check.WARN].Printf("== Remediations ==\n")
|
||||
for _, g := range r.Groups {
|
||||
for _, c := range g.Checks {
|
||||
if c.State != check.PASS {
|
||||
fmt.Printf("%s %s\n", c.ID, c.Remediation)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
colors[res].Printf("== Summary ==\n")
|
||||
fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n",
|
||||
summary.Pass, summary.Fail, summary.Warn,
|
||||
)
|
||||
// Print summary setting output color to highest severity.
|
||||
if !noSummary {
|
||||
var res check.State
|
||||
if summary.Fail > 0 {
|
||||
res = check.FAIL
|
||||
} else if summary.Warn > 0 {
|
||||
res = check.WARN
|
||||
} else {
|
||||
res = check.PASS
|
||||
}
|
||||
|
||||
colors[res].Printf("== Summary ==\n")
|
||||
fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n",
|
||||
summary.Pass, summary.Fail, summary.Warn,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
60
cmd/database.go
Normal file
60
cmd/database.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/postgres" // database packages get blank imports
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func savePgsql(jsonInfo string) {
|
||||
envVars := map[string]string{
|
||||
"PGSQL_HOST": viper.GetString("PGSQL_HOST"),
|
||||
"PGSQL_USER": viper.GetString("PGSQL_USER"),
|
||||
"PGSQL_DBNAME": viper.GetString("PGSQL_DBNAME"),
|
||||
"PGSQL_SSLMODE": viper.GetString("PGSQL_SSLMODE"),
|
||||
"PGSQL_PASSWORD": viper.GetString("PGSQL_PASSWORD"),
|
||||
}
|
||||
|
||||
for k, v := range envVars {
|
||||
if v == "" {
|
||||
exitWithError(fmt.Errorf("environment variable %s is missing", envVarsPrefix+"_"+k))
|
||||
}
|
||||
}
|
||||
|
||||
connInfo := fmt.Sprintf("host=%s user=%s dbname=%s sslmode=%s password=%s",
|
||||
envVars["PGSQL_HOST"],
|
||||
envVars["PGSQL_USER"],
|
||||
envVars["PGSQL_DBNAME"],
|
||||
envVars["PGSQL_SSLMODE"],
|
||||
envVars["PGSQL_PASSWORD"],
|
||||
)
|
||||
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
exitWithError(fmt.Errorf("received error looking up hostname: %s", err))
|
||||
}
|
||||
|
||||
timestamp := time.Now()
|
||||
|
||||
type ScanResult struct {
|
||||
gorm.Model
|
||||
ScanHost string `gorm:"type:varchar(63) not null"` // https://www.ietf.org/rfc/rfc1035.txt
|
||||
ScanTime time.Time `gorm:"not null"`
|
||||
ScanInfo string `gorm:"type:jsonb not null"`
|
||||
}
|
||||
|
||||
db, err := gorm.Open("postgres", connInfo)
|
||||
defer db.Close()
|
||||
if err != nil {
|
||||
exitWithError(fmt.Errorf("received error connecting to database: %s", err))
|
||||
}
|
||||
|
||||
db.Debug().AutoMigrate(&ScanResult{})
|
||||
db.Save(&ScanResult{ScanHost: hostname, ScanTime: timestamp, ScanInfo: jsonInfo})
|
||||
glog.V(2).Info(fmt.Sprintf("successfully stored result to: %s", envVars["PGSQL_HOST"]))
|
||||
}
|
||||
36
cmd/root.go
36
cmd/root.go
@@ -25,22 +25,28 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
cfgDir = "./cfg"
|
||||
cfgFile string
|
||||
|
||||
jsonFmt bool
|
||||
checkList string
|
||||
groupList string
|
||||
masterFile string
|
||||
nodeFile string
|
||||
federatedFile string
|
||||
envVarsPrefix = "KUBE_BENCH"
|
||||
defaultKubeVersion = "1.6"
|
||||
kubeVersion string
|
||||
cfgFile string
|
||||
cfgDir string
|
||||
jsonFmt bool
|
||||
pgSQL bool
|
||||
checkList string
|
||||
groupList string
|
||||
masterFile string
|
||||
nodeFile string
|
||||
federatedFile string
|
||||
noResults bool
|
||||
noSummary bool
|
||||
noRemediations bool
|
||||
)
|
||||
|
||||
// RootCmd represents the base command when called without any subcommands
|
||||
var RootCmd = &cobra.Command{
|
||||
Use: os.Args[0],
|
||||
Short: "Run CIS Benchmarks checks against a Kubernetes deployment",
|
||||
Long: `This tool runs the CIS Kubernetes 1.6 Benchmark v1.0.0 checks.`,
|
||||
Long: `This tool runs the CIS Kubernetes Benchmark (https://www.cisecurity.org/benchmark/kubernetes/)`,
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command sets flags appropriately.
|
||||
@@ -58,7 +64,13 @@ func Execute() {
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
|
||||
// Output control
|
||||
RootCmd.PersistentFlags().BoolVar(&noResults, "noresults", false, "Disable printing of results section")
|
||||
RootCmd.PersistentFlags().BoolVar(&noSummary, "nosummary", false, "Disable printing of summary section")
|
||||
RootCmd.PersistentFlags().BoolVar(&noRemediations, "noremediations", false, "Disable printing of remediations section")
|
||||
RootCmd.PersistentFlags().BoolVar(&jsonFmt, "json", false, "Prints the results as JSON")
|
||||
RootCmd.PersistentFlags().BoolVar(&pgSQL, "pgsql", false, "Save the results to PostgreSQL")
|
||||
|
||||
RootCmd.PersistentFlags().StringVarP(
|
||||
&checkList,
|
||||
"check",
|
||||
@@ -74,6 +86,8 @@ func init() {
|
||||
`Run all the checks under this comma-delimited list of groups. Example --group="1.1"`,
|
||||
)
|
||||
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is ./cfg/config.yaml)")
|
||||
RootCmd.PersistentFlags().StringVarP(&cfgDir, "config-dir", "D", "./cfg/", "config directory")
|
||||
RootCmd.PersistentFlags().StringVar(&kubeVersion, "version", "", "Manually specify Kubernetes version, automatically detected if unset")
|
||||
|
||||
goflag.CommandLine.VisitAll(func(goflag *goflag.Flag) {
|
||||
RootCmd.PersistentFlags().AddGoFlag(goflag)
|
||||
@@ -90,7 +104,7 @@ func initConfig() {
|
||||
viper.AddConfigPath(cfgDir) // adding ./cfg as first search path
|
||||
}
|
||||
|
||||
viper.SetEnvPrefix("KUBE_BENCH")
|
||||
viper.SetEnvPrefix(envVarsPrefix)
|
||||
viper.AutomaticEnv() // read in environment variables that match
|
||||
|
||||
// If a config file is found, read it in.
|
||||
|
||||
168
cmd/util.go
168
cmd/util.go
@@ -4,7 +4,9 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/aquasecurity/kube-bench/check"
|
||||
@@ -116,10 +118,61 @@ func getBinaries(v *viper.Viper) map[string]string {
|
||||
return binmap
|
||||
}
|
||||
|
||||
// getConfigFilePath locates the config files we should be using based on either the specified
|
||||
// version, or the running version of kubernetes if not specified
|
||||
func getConfigFilePath(specifiedVersion string, runningVersion string, filename string) (path string, err error) {
|
||||
var fileVersion string
|
||||
|
||||
if specifiedVersion != "" {
|
||||
fileVersion = specifiedVersion
|
||||
} else {
|
||||
fileVersion = runningVersion
|
||||
}
|
||||
|
||||
glog.V(2).Info(fmt.Sprintf("Looking for config for version %s", fileVersion))
|
||||
|
||||
for {
|
||||
path = filepath.Join(cfgDir, fileVersion)
|
||||
file := filepath.Join(path, string(filename))
|
||||
glog.V(2).Info(fmt.Sprintf("Looking for config file: %s\n", file))
|
||||
|
||||
if _, err = os.Stat(file); !os.IsNotExist(err) {
|
||||
if specifiedVersion == "" && fileVersion != runningVersion {
|
||||
glog.V(1).Info(fmt.Sprintf("No test file found for %s - using tests for Kubernetes %s\n", runningVersion, fileVersion))
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// If we were given an explicit version to look for, don't look for any others
|
||||
if specifiedVersion != "" {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fileVersion = decrementVersion(fileVersion)
|
||||
if fileVersion == "" {
|
||||
return "", fmt.Errorf("no test files found <= runningVersion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decrementVersion decrements the version number
|
||||
// We want to decrement individually even through versions where we don't supply test files
|
||||
// just in case someone wants to specify their own test files for that version
|
||||
func decrementVersion(version string) string {
|
||||
split := strings.Split(version, ".")
|
||||
minor, err := strconv.Atoi(split[1])
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if minor <= 1 {
|
||||
return ""
|
||||
}
|
||||
split[1] = strconv.Itoa(minor - 1)
|
||||
return strings.Join(split, ".")
|
||||
}
|
||||
|
||||
// getConfigFiles finds which of the set of candidate config files exist
|
||||
// accepts a string 't' which indicates the type of config file, conf,
|
||||
// podspec or untifile.
|
||||
func getConfigFiles(v *viper.Viper, t string) map[string]string {
|
||||
func getConfigFiles(v *viper.Viper) map[string]string {
|
||||
confmap := make(map[string]string)
|
||||
|
||||
for _, component := range v.GetStringSlice("components") {
|
||||
@@ -129,14 +182,14 @@ func getConfigFiles(v *viper.Viper, t string) map[string]string {
|
||||
}
|
||||
|
||||
// See if any of the candidate config files exist
|
||||
conf := findConfigFile(s.GetStringSlice(t + "s"))
|
||||
conf := findConfigFile(s.GetStringSlice("confs"))
|
||||
if conf == "" {
|
||||
if s.IsSet("default" + t) {
|
||||
conf = s.GetString("default" + t)
|
||||
if s.IsSet("defaultconf") {
|
||||
conf = s.GetString("defaultconf")
|
||||
glog.V(2).Info(fmt.Sprintf("Using default config file name '%s' for component %s", conf, component))
|
||||
} else {
|
||||
// Default the config file name that we'll substitute to the name of the component
|
||||
printlnWarn(fmt.Sprintf("Missing config file for %s", component))
|
||||
glog.V(2).Info(fmt.Sprintf("Missing config file for %s", component))
|
||||
conf = component
|
||||
}
|
||||
} else {
|
||||
@@ -149,6 +202,37 @@ func getConfigFiles(v *viper.Viper, t string) map[string]string {
|
||||
return confmap
|
||||
}
|
||||
|
||||
// getServiceFiles finds which of the set of candidate service files exist
|
||||
func getServiceFiles(v *viper.Viper) map[string]string {
|
||||
svcmap := make(map[string]string)
|
||||
|
||||
for _, component := range v.GetStringSlice("components") {
|
||||
s := v.Sub(component)
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// See if any of the candidate config files exist
|
||||
svc := findConfigFile(s.GetStringSlice("svc"))
|
||||
if svc == "" {
|
||||
if s.IsSet("defaultsvc") {
|
||||
svc = s.GetString("defaultsvc")
|
||||
glog.V(2).Info(fmt.Sprintf("Using default service file name '%s' for component %s", svc, component))
|
||||
} else {
|
||||
// Default the service file name that we'll substitute to the name of the component
|
||||
glog.V(2).Info(fmt.Sprintf("Missing service file for %s", component))
|
||||
svc = component
|
||||
}
|
||||
} else {
|
||||
glog.V(2).Info(fmt.Sprintf("Component %s uses service file '%s'", component, svc))
|
||||
}
|
||||
|
||||
svcmap[component] = svc
|
||||
}
|
||||
|
||||
return svcmap
|
||||
}
|
||||
|
||||
// verifyBin checks that the binary specified is running
|
||||
func verifyBin(bin string) bool {
|
||||
|
||||
@@ -196,9 +280,8 @@ func findExecutable(candidates []string) (string, error) {
|
||||
for _, c := range candidates {
|
||||
if verifyBin(c) {
|
||||
return c, nil
|
||||
} else {
|
||||
glog.V(1).Info(fmt.Sprintf("executable '%s' not running", c))
|
||||
}
|
||||
glog.V(1).Info(fmt.Sprintf("executable '%s' not running", c))
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("no candidates running")
|
||||
@@ -213,39 +296,60 @@ func multiWordReplace(s string, subname string, sub string) string {
|
||||
return strings.Replace(s, subname, sub, -1)
|
||||
}
|
||||
|
||||
type version struct {
|
||||
Server string
|
||||
Client string
|
||||
}
|
||||
|
||||
func getKubeVersion() *version {
|
||||
ver := new(version)
|
||||
func getKubeVersion() (string, error) {
|
||||
// These executables might not be on the user's path.
|
||||
_, err := exec.LookPath("kubectl")
|
||||
|
||||
if err != nil {
|
||||
s := fmt.Sprintf("Kubernetes version check skipped with error %v", err)
|
||||
continueWithError(err, sprintlnWarn(s))
|
||||
return nil
|
||||
_, err = exec.LookPath("kubelet")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("need kubectl or kubelet binaries to get kubernetes version")
|
||||
}
|
||||
return getKubeVersionFromKubelet(), nil
|
||||
}
|
||||
|
||||
cmd := exec.Command("kubectl", "version")
|
||||
out, err := cmd.Output()
|
||||
return getKubeVersionFromKubectl(), nil
|
||||
}
|
||||
|
||||
func getKubeVersionFromKubectl() string {
|
||||
cmd := exec.Command("kubectl", "version", "--short")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
s := fmt.Sprintf("Kubernetes version check skipped, with error getting kubectl version")
|
||||
continueWithError(err, sprintlnWarn(s))
|
||||
return nil
|
||||
continueWithError(fmt.Errorf("%s", out), "")
|
||||
}
|
||||
|
||||
clientVerRe := regexp.MustCompile(`Client.*Major:"(\d+)".*Minor:"(\d+)"`)
|
||||
svrVerRe := regexp.MustCompile(`Server.*Major:"(\d+)".*Minor:"(\d+)"`)
|
||||
return getVersionFromKubectlOutput(string(out))
|
||||
}
|
||||
|
||||
sub := clientVerRe.FindStringSubmatch(string(out))
|
||||
ver.Client = sub[1] + "." + sub[2]
|
||||
func getKubeVersionFromKubelet() string {
|
||||
cmd := exec.Command("kubelet", "--version")
|
||||
out, err := cmd.CombinedOutput()
|
||||
|
||||
sub = svrVerRe.FindStringSubmatch(string(out))
|
||||
ver.Server = sub[1] + "." + sub[2]
|
||||
if err != nil {
|
||||
continueWithError(fmt.Errorf("%s", out), "")
|
||||
}
|
||||
|
||||
return ver
|
||||
return getVersionFromKubeletOutput(string(out))
|
||||
}
|
||||
|
||||
func getVersionFromKubectlOutput(s string) string {
|
||||
serverVersionRe := regexp.MustCompile(`Server Version: v(\d+.\d+)`)
|
||||
subs := serverVersionRe.FindStringSubmatch(s)
|
||||
if len(subs) < 2 {
|
||||
printlnWarn(fmt.Sprintf("Unable to get kubectl version, using default version: %s", defaultKubeVersion))
|
||||
return defaultKubeVersion
|
||||
}
|
||||
return subs[1]
|
||||
}
|
||||
|
||||
func getVersionFromKubeletOutput(s string) string {
|
||||
serverVersionRe := regexp.MustCompile(`Kubernetes v(\d+.\d+)`)
|
||||
subs := serverVersionRe.FindStringSubmatch(s)
|
||||
if len(subs) < 2 {
|
||||
printlnWarn(fmt.Sprintf("Unable to get kubelet version, using default version: %s", defaultKubeVersion))
|
||||
return defaultKubeVersion
|
||||
}
|
||||
return subs[1]
|
||||
}
|
||||
|
||||
func makeSubstitutions(s string, ext string, m map[string]string) string {
|
||||
@@ -255,7 +359,7 @@ func makeSubstitutions(s string, ext string, m map[string]string) string {
|
||||
glog.V(2).Info(fmt.Sprintf("No subsitution for '%s'\n", subst))
|
||||
continue
|
||||
}
|
||||
glog.V(1).Info(fmt.Sprintf("Substituting %s with '%s'\n", subst, v))
|
||||
glog.V(2).Info(fmt.Sprintf("Substituting %s with '%s'\n", subst, v))
|
||||
s = multiWordReplace(s, subst, v)
|
||||
}
|
||||
|
||||
|
||||
144
cmd/util_test.go
144
cmd/util_test.go
@@ -15,9 +15,10 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
@@ -182,19 +183,17 @@ func TestMultiWordReplace(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetKubeVersion(t *testing.T) {
|
||||
ver := getKubeVersion()
|
||||
if ver == nil {
|
||||
t.Log("Expected non nil version info.")
|
||||
} else {
|
||||
if ok, err := regexp.MatchString(`\d+.\d+`, ver.Client); !ok && err != nil {
|
||||
t.Logf("Expected:%v got %v\n", "n.m", ver.Client)
|
||||
}
|
||||
|
||||
if ok, err := regexp.MatchString(`\d+.\d+`, ver.Server); !ok && err != nil {
|
||||
t.Logf("Expected:%v got %v\n", "n.m", ver.Server)
|
||||
}
|
||||
func TestKubeVersionRegex(t *testing.T) {
|
||||
ver := getVersionFromKubectlOutput(`Client Version: v1.8.0
|
||||
Server Version: v1.8.12
|
||||
`)
|
||||
if ver != "1.8" {
|
||||
t.Fatalf("Expected 1.8 got %s", ver)
|
||||
}
|
||||
|
||||
ver = getVersionFromKubectlOutput("Something completely different")
|
||||
if ver != "1.6" {
|
||||
t.Fatalf("Expected 1.6 got %s", ver)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +281,82 @@ func TestGetConfigFiles(t *testing.T) {
|
||||
e = c.statResults
|
||||
eIndex = 0
|
||||
|
||||
m := getConfigFiles(v, "conf")
|
||||
m := getConfigFiles(v)
|
||||
if !reflect.DeepEqual(m, c.exp) {
|
||||
t.Fatalf("Got %v\nExpected %v", m, c.exp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServiceFiles(t *testing.T) {
|
||||
cases := []struct {
|
||||
config map[string]interface{}
|
||||
exp map[string]string
|
||||
statResults []error
|
||||
}{
|
||||
{
|
||||
config: map[string]interface{}{
|
||||
"components": []string{"kubelet"},
|
||||
"kubelet": map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
|
||||
},
|
||||
statResults: []error{os.ErrNotExist, nil},
|
||||
exp: map[string]string{"kubelet": "10-kubeadm.conf"},
|
||||
},
|
||||
{
|
||||
// Component "thing" isn't included in the list of components
|
||||
config: map[string]interface{}{
|
||||
"components": []string{"kubelet"},
|
||||
"kubelet": map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
|
||||
"thing": map[string]interface{}{"svc": []string{"/my/file/thing"}},
|
||||
},
|
||||
statResults: []error{os.ErrNotExist, nil},
|
||||
exp: map[string]string{"kubelet": "10-kubeadm.conf"},
|
||||
},
|
||||
{
|
||||
// More than one component
|
||||
config: map[string]interface{}{
|
||||
"components": []string{"kubelet", "thing"},
|
||||
"kubelet": map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
|
||||
"thing": map[string]interface{}{"svc": []string{"/my/file/thing"}},
|
||||
},
|
||||
statResults: []error{os.ErrNotExist, nil, nil},
|
||||
exp: map[string]string{"kubelet": "10-kubeadm.conf", "thing": "/my/file/thing"},
|
||||
},
|
||||
{
|
||||
// Default thing to specified default service
|
||||
config: map[string]interface{}{
|
||||
"components": []string{"kubelet", "thing"},
|
||||
"kubelet": map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
|
||||
"thing": map[string]interface{}{"svc": []string{"/my/file/thing"}, "defaultsvc": "another/thing"},
|
||||
},
|
||||
statResults: []error{os.ErrNotExist, nil, os.ErrNotExist},
|
||||
exp: map[string]string{"kubelet": "10-kubeadm.conf", "thing": "another/thing"},
|
||||
},
|
||||
{
|
||||
// Default thing to component name
|
||||
config: map[string]interface{}{
|
||||
"components": []string{"kubelet", "thing"},
|
||||
"kubelet": map[string]interface{}{"svc": []string{"kubelet", "10-kubeadm.conf"}},
|
||||
"thing": map[string]interface{}{"svc": []string{"/my/file/thing"}},
|
||||
},
|
||||
statResults: []error{os.ErrNotExist, nil, os.ErrNotExist},
|
||||
exp: map[string]string{"kubelet": "10-kubeadm.conf", "thing": "thing"},
|
||||
},
|
||||
}
|
||||
|
||||
v := viper.New()
|
||||
statFunc = fakestat
|
||||
|
||||
for id, c := range cases {
|
||||
t.Run(strconv.Itoa(id), func(t *testing.T) {
|
||||
for k, val := range c.config {
|
||||
v.Set(k, val)
|
||||
}
|
||||
e = c.statResults
|
||||
eIndex = 0
|
||||
|
||||
m := getServiceFiles(v)
|
||||
if !reflect.DeepEqual(m, c.exp) {
|
||||
t.Fatalf("Got %v\nExpected %v", m, c.exp)
|
||||
}
|
||||
@@ -309,3 +383,45 @@ func TestMakeSubsitutions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConfigFilePath(t *testing.T) {
|
||||
var err error
|
||||
cfgDir, err = ioutil.TempDir("", "kube-bench-test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp directory")
|
||||
}
|
||||
defer os.RemoveAll(cfgDir)
|
||||
d := filepath.Join(cfgDir, "1.8")
|
||||
err = os.Mkdir(d, 0666)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp file")
|
||||
}
|
||||
ioutil.WriteFile(filepath.Join(d, "master.yaml"), []byte("hello world"), 0666)
|
||||
|
||||
cases := []struct {
|
||||
specifiedVersion string
|
||||
runningVersion string
|
||||
succeed bool
|
||||
exp string
|
||||
}{
|
||||
{runningVersion: "1.8", succeed: true, exp: d},
|
||||
{runningVersion: "1.9", succeed: true, exp: d},
|
||||
{runningVersion: "1.10", succeed: true, exp: d},
|
||||
{runningVersion: "1.1", succeed: false},
|
||||
{specifiedVersion: "1.8", succeed: true, exp: d},
|
||||
{specifiedVersion: "1.9", succeed: false},
|
||||
{specifiedVersion: "1.10", succeed: false},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.specifiedVersion+"-"+c.runningVersion, func(t *testing.T) {
|
||||
path, err := getConfigFilePath(c.specifiedVersion, c.runningVersion, "/master.yaml")
|
||||
if err != nil && c.succeed {
|
||||
t.Fatalf("Error %v", err)
|
||||
}
|
||||
if path != c.exp {
|
||||
t.Fatalf("Got %s expected %s", path, c.exp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
#!/bin/sh
|
||||
if [ -d /host ]; then
|
||||
mkdir -p /host/cfg/
|
||||
yes | cp -rf ./kube-bench/cfg/* /host/cfg/
|
||||
yes | cp -rf ./kube-bench/kube-bench /host/
|
||||
echo "==============================================="
|
||||
echo "kube-bench is now installed on your host "
|
||||
echo "Run ./kube-bench to perform a security check "
|
||||
echo "==============================================="
|
||||
#!/bin/sh -e
|
||||
if [ "$1" == "install" ]; then
|
||||
if [ -d /host ]; then
|
||||
mkdir -p /host/cfg/
|
||||
yes | cp -rf cfg/* /host/cfg/
|
||||
yes | cp -rf /usr/local/bin/kube-bench /host/
|
||||
echo "==============================================="
|
||||
echo "kube-bench is now installed on your host "
|
||||
echo "Run ./kube-bench to perform a security check "
|
||||
echo "==============================================="
|
||||
else
|
||||
echo "Usage:"
|
||||
echo " install: docker run --rm -v \`pwd\`:/host aquasec/kube-bench install"
|
||||
echo " run: docker run --rm --pid=host aquasec/kube-bench [command]"
|
||||
exit
|
||||
fi
|
||||
else
|
||||
echo "Usage:"
|
||||
echo " docker run --rm -v \`pwd\`:/host aquasec/kube-bench"
|
||||
exit
|
||||
exec kube-bench "$@"
|
||||
fi
|
||||
|
||||
0
hooks/build
Normal file → Executable file
0
hooks/build
Normal file → Executable file
BIN
images/kube-bench.png
Normal file
BIN
images/kube-bench.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
121
images/kube-bench.svg
Normal file
121
images/kube-bench.svg
Normal file
@@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 831.49597 755.90533"
|
||||
height="755.90533"
|
||||
width="831.49597"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath22"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path20"
|
||||
d="M 0,566.929 H 623.622 V 0 H 0 Z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,755.90533)"
|
||||
id="g10"><g
|
||||
transform="translate(314.8111,521.959)"
|
||||
id="g12"><path
|
||||
id="path14"
|
||||
style="fill:#0ab1d5;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 0,0 -106.784,-145.31 0,-280.384 105.477,-147.025 Z" /></g><g
|
||||
id="g16"><g
|
||||
clip-path="url(#clipPath22)"
|
||||
id="g18"><g
|
||||
transform="translate(51.8912,72.061)"
|
||||
id="g24"><path
|
||||
id="path26"
|
||||
style="fill:#464648;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 v 71.061 c 0,3.629 2.86,6.6 6.6,6.6 3.74,0 6.6,-2.971 6.6,-6.6 V 32.45 h 2.97 c 1.32,0 2.42,0.551 3.52,1.981 L 33.44,52.69 c 1.43,1.981 3.081,3.3 5.72,3.3 3.63,0 6.271,-2.969 6.271,-6.599 0,-1.87 -0.881,-3.411 -1.981,-4.731 L 29.59,27.5 44.44,3.96 C 45.32,2.641 45.76,1.21 45.76,0 c 0,-3.63 -2.97,-6.6 -6.6,-6.6 -2.309,0 -4.4,1.54 -5.5,3.411 L 19.8,19.25 c -0.88,1.431 -1.98,2.091 -3.52,2.091 H 13.2 L 13.2,0 C 13.2,-3.63 10.34,-6.6 6.6,-6.6 2.86,-6.6 0,-3.63 0,0" /></g><g
|
||||
transform="translate(104.9547,86.8013)"
|
||||
id="g28"><path
|
||||
id="path30"
|
||||
style="fill:#464648;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 v 34.65 c 0,3.63 2.97,6.6 6.6,6.6 3.629,0 6.6,-2.97 6.6,-6.6 V 2.86 c 0,-8.47 3.409,-11.44 9.57,-11.44 4.73,0 9.24,2.86 11.33,4.95 v 38.28 c 0,3.63 2.97,6.6 6.6,6.6 3.63,0 6.6,-2.97 6.6,-6.6 v -50.16 c 0,-3.3 -2.53,-5.83 -5.72,-5.83 -2.97,0 -5.06,2.09 -5.72,4.95 l -0.55,2.42 C 32.12,-17.16 26.18,-21.34 18.149,-21.34 5.06,-21.34 0,-11.99 0,0" /></g><g
|
||||
transform="translate(197.5084,90.4312)"
|
||||
id="g32"><path
|
||||
id="path34"
|
||||
style="fill:#464648;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 v 12.65 c 0,8.47 -2.971,12.54 -10.341,12.54 -4.069,0 -8.029,-2.2 -10.559,-4.839 V -7.59 c 2.53,-2.639 6.49,-4.95 10.559,-4.95 C -2.971,-12.54 0,-8.47 0,0 m -34.101,-19.14 v 71.83 c 0,3.63 2.861,6.601 6.6,6.601 3.74,0 6.601,-2.971 6.601,-6.601 V 31.57 c 3.08,3.191 8.359,6.05 14.299,6.05 13.09,0 19.8,-8.8 19.8,-23.54 V -1.319 c 0,-14.741 -6.819,-23.651 -20.13,-23.651 -6.16,0 -11.88,2.97 -14.96,6.491 l -0.66,-2.201 c -0.769,-2.53 -3.08,-4.29 -5.72,-4.29 -3.299,0 -5.83,2.75 -5.83,5.83" /></g><g
|
||||
transform="translate(251.7047,102.311)"
|
||||
id="g36"><path
|
||||
id="path38"
|
||||
style="fill:#464648;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0,9.57 -1.87,14.301 -9.9,14.301 -7.92,0 -9.9,-4.181 -9.9,-14.301 z M -33,-15.069 V 2.2 c 0,14.521 7.479,23.54 23.1,23.54 15.95,0 22.77,-8.689 22.77,-23.54 v -7.37 c 0,-2.859 -2.309,-5.17 -5.17,-5.17 h -27.5 v -5.939 c 0,-4.62 2.86,-9.13 10.89,-9.13 5.72,0 8.8,0.88 13.09,2.97 0.66,0.33 1.54,0.66 2.42,0.66 2.97,0 5.39,-2.42 5.39,-5.391 0,-2.309 -1.429,-3.96 -3.52,-5.17 -5.17,-2.97 -10.23,-4.51 -17.93,-4.51 -15.73,0 -23.54,8.25 -23.54,21.781" /></g><g
|
||||
transform="translate(271.7564,99.4517)"
|
||||
id="g40"><path
|
||||
id="path42"
|
||||
style="fill:#464648;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0,3.3 2.53,5.83 5.721,5.83 h 19.91 c 3.3,0 5.83,-2.53 5.83,-5.83 0,-3.19 -2.53,-5.72 -5.83,-5.72 H 5.721 C 2.53,-5.72 0,-3.19 0,0" /></g><g
|
||||
transform="translate(345.776,90.4312)"
|
||||
id="g44"><path
|
||||
id="path46"
|
||||
style="fill:#464648;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 v 12.65 c 0,8.47 -2.971,12.54 -10.341,12.54 -4.069,0 -8.029,-2.2 -10.559,-4.839 V -7.59 c 2.53,-2.639 6.49,-4.95 10.559,-4.95 C -2.971,-12.54 0,-8.47 0,0 m -34.101,-19.14 v 71.83 c 0,3.63 2.861,6.601 6.6,6.601 3.74,0 6.601,-2.971 6.601,-6.601 V 31.57 c 3.08,3.191 8.359,6.05 14.299,6.05 13.09,0 19.8,-8.8 19.8,-23.54 V -1.319 c 0,-14.741 -6.819,-23.651 -20.13,-23.651 -6.16,0 -11.88,2.97 -14.96,6.491 l -0.66,-2.201 c -0.769,-2.53 -3.08,-4.29 -5.72,-4.29 -3.299,0 -5.83,2.75 -5.83,5.83" /></g><g
|
||||
transform="translate(399.9723,102.311)"
|
||||
id="g48"><path
|
||||
id="path50"
|
||||
style="fill:#464648;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0,9.57 -1.87,14.301 -9.9,14.301 -7.92,0 -9.9,-4.181 -9.9,-14.301 z M -33,-15.069 V 2.2 c 0,14.521 7.479,23.54 23.1,23.54 15.95,0 22.77,-8.689 22.77,-23.54 v -7.37 c 0,-2.859 -2.309,-5.17 -5.17,-5.17 h -27.5 v -5.939 c 0,-4.62 2.86,-9.13 10.89,-9.13 5.72,0 8.8,0.88 13.09,2.97 0.66,0.33 1.54,0.66 2.42,0.66 2.97,0 5.39,-2.42 5.39,-5.391 0,-2.309 -1.429,-3.96 -3.52,-5.17 -5.17,-2.97 -10.23,-4.51 -17.93,-4.51 -15.73,0 -23.54,8.25 -23.54,21.781" /></g><g
|
||||
transform="translate(421.8512,72.061)"
|
||||
id="g52"><path
|
||||
id="path54"
|
||||
style="fill:#464648;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 v 50.16 c 0,3.301 2.53,5.83 5.72,5.83 2.97,0 5.06,-2.09 5.72,-4.949 l 0.55,-2.421 c 3.19,3.191 9.13,7.37 17.16,7.37 13.09,0 18.15,-9.349 18.15,-21.34 V 0 c 0,-3.63 -2.97,-6.6 -6.6,-6.6 -3.63,0 -6.599,2.97 -6.599,6.6 v 31.79 c 0,8.471 -3.411,11.44 -9.571,11.44 -4.73,0 -9.24,-2.86 -11.33,-4.95 L 13.2,0 C 13.2,-3.63 10.23,-6.6 6.6,-6.6 2.97,-6.6 0,-3.63 0,0" /></g><g
|
||||
transform="translate(478.358,89.1118)"
|
||||
id="g56"><path
|
||||
id="path58"
|
||||
style="fill:#464648;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 v 15.29 c 0,14.52 8.36,23.649 24.31,23.649 8.36,0 14.08,-3.08 18.15,-8.029 1.21,-1.54 1.87,-2.75 1.87,-4.511 0,-3.299 -2.53,-5.83 -5.83,-5.83 -1.76,0 -3.08,0.66 -4.4,1.981 -2.75,2.75 -5.39,4.62 -9.79,4.62 -8.69,0 -11.11,-5.83 -11.11,-12.981 L 13.2,1.1 c 0,-7.151 2.75,-12.981 11.44,-12.981 4.4,0 7.04,1.87 9.79,4.62 1.32,1.321 2.31,1.981 4.29,1.981 3.3,0 5.94,-2.531 5.94,-5.83 0,-1.76 -0.66,-2.97 -1.87,-4.51 C 38.72,-20.57 33,-23.65 24.64,-23.65 8.689,-23.65 0,-14.521 0,0" /></g><g
|
||||
transform="translate(530.5396,72.061)"
|
||||
id="g60"><path
|
||||
id="path62"
|
||||
style="fill:#464648;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 v 71.061 c 0,3.629 2.86,6.6 6.6,6.6 3.74,0 6.6,-2.971 6.6,-6.6 v -21.34 c 3.41,2.969 9.02,6.269 16.17,6.269 13.09,0 18.26,-9.349 18.26,-21.34 V 0 c 0,-3.63 -2.859,-6.6 -6.6,-6.6 -3.74,0 -6.6,2.97 -6.6,6.6 v 31.79 c 0,8.471 -3.52,11.44 -9.68,11.44 -4.729,0 -9.46,-2.86 -11.55,-4.95 V 0 C 13.2,-3.63 10.34,-6.6 6.6,-6.6 2.86,-6.6 0,-3.63 0,0" /></g><g
|
||||
transform="translate(249.2096,192.0259)"
|
||||
id="g64"><path
|
||||
id="path66"
|
||||
style="fill:#f1df36;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 h 0.008 l 131.211,0.031 h 0.013 c 3.063,0 6.107,0.66 8.916,1.863 L 65.602,49.549 -8.531,1.7 C -5.83,0.6 -2.923,0 0,0" /></g><g
|
||||
transform="translate(420.2877,374.9341)"
|
||||
id="g68"><path
|
||||
id="path70"
|
||||
style="fill:#faaf42;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 -105.477,-133.359 74.547,-47.655 c 3.392,1.452 6.439,3.697 8.747,6.559 l 75.104,93.431 6.686,8.317 c 1.38,1.714 2.479,3.637 3.289,5.675 0.384,0.965 0.701,1.954 0.95,2.962 z" /></g><g
|
||||
transform="translate(145.3785,311.2251)"
|
||||
id="g72"><path
|
||||
id="path74"
|
||||
style="fill:#faaf42;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 0.583,-2.568 1.609,-5.036 3.054,-7.245 0.401,-0.614 0.83,-1.209 1.285,-1.783 l 81.823,-101.735 c 2.396,-2.975 5.588,-5.289 9.138,-6.736 L 169.433,-69.65 62.648,65.424 Z" /></g><g
|
||||
transform="translate(179.4977,457.7324)"
|
||||
id="g76"><path
|
||||
id="path78"
|
||||
style="fill:#9ad7ec;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -2.408,-2.762 -4.144,-6.1 -4.985,-9.762 l -29.149,-126.8 c -0.65,-2.826 -0.715,-5.774 -0.239,-8.633 0.073,-0.44 0.155,-0.878 0.254,-1.312 l 62.648,65.424 z" /></g><g
|
||||
transform="translate(484.1334,310.8643)"
|
||||
id="g80"><path
|
||||
id="path82"
|
||||
style="fill:#9ad7ec;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 0,0 C 0.837,3.378 0.913,6.943 0.131,10.337 L -29.076,137.21 c -0.791,3.437 -2.374,6.586 -4.566,9.236 L -63.846,64.07 Z" /></g><g
|
||||
transform="translate(317.7506,366.4487)"
|
||||
id="g84"><path
|
||||
id="path86"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 0,0 40.622,41.329 H 14.038 L -18.791,6.272 V 77.598 H -39.47 V -56.101 h 20.679 v 40.069 l 3.269,3.181 33.46,-43.25 h 27.03 z" /></g><g
|
||||
transform="translate(275.7818,468.8486)"
|
||||
id="g88"><path
|
||||
id="path90"
|
||||
style="fill:#1280c4;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 39.028,53.109 c -0.01,0 -0.022,10e-4 -0.033,10e-4 -0.047,0 -0.094,-0.003 -0.141,-0.003 C 38.521,53.105 38.187,53.099 37.853,53.082 37.814,53.08 37.776,53.072 37.738,53.07 34.783,52.909 31.86,52.166 29.192,50.889 L -89.022,-5.593 c -2.809,-1.342 -5.266,-3.235 -7.262,-5.523 L -67.755,-92.199 0,0.03 Z" /></g><g
|
||||
transform="translate(442.8853,463.2578)"
|
||||
id="g92"><path
|
||||
id="path94"
|
||||
style="fill:#1280c4;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 -118.288,56.48 c -3.039,1.455 -6.412,2.215 -9.785,2.22 L -22.598,-88.324 7.606,-5.947 C 5.558,-3.467 2.978,-1.422 0,0" /></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
Reference in New Issue
Block a user