Compare commits

...

111 Commits

Author SHA1 Message Date
Yoav Rotem
0e6184186f Update release.yml (#1014) 2021-10-03 15:32:27 +03:00
Yoav Rotem
04292261a2 Update release.yml (#1013)
* Update release.yml

* Update release.yml
2021-10-03 14:53:37 +03:00
Lennard Klein
5f7fb350a7 Add a trailing slash to find directory path (#1006)
This transplants #687 to cis-1.6 and cis-1.20. Fixes #686 for cis-1.6 and cis-1.20.
2021-10-03 13:08:28 +03:00
Huang Huang
e50de8145c Fix status of cis-1.20 1.2.25 should be Manual (#1010)
* fix status of cis-1.20 1.2.25 should be Manual

* Fix tests

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-10-03 13:00:58 +03:00
Huang Huang
bfd67496d9 fix integration test not testing latest code and can't run test on local (#1011) 2021-10-03 11:43:43 +03:00
dependabot[bot]
36056797df Bump github.com/aws/aws-sdk-go from 1.40.45 to 1.40.51 (#1005)
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.45 to 1.40.51.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.45...v1.40.51)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-29 16:51:51 +03:00
Jeff Robertson
37581e45ca fix typo in readme (#917)
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-09-29 15:06:23 +03:00
dependabot[bot]
0aea4ca909 Bump github.com/fatih/color from 1.12.0 to 1.13.0 (#1004)
Bumps [github.com/fatih/color](https://github.com/fatih/color) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/fatih/color/releases)
- [Commits](https://github.com/fatih/color/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: github.com/fatih/color
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-09-29 14:54:27 +03:00
dependabot[bot]
5b2051f5b1 Bump k8s.io/client-go from 0.22.1 to 0.22.2 (#999)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.22.1 to 0.22.2.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.22.1...v0.22.2)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-09-29 14:44:44 +03:00
dependabot[bot]
25744cd892 Bump github.com/spf13/viper from 1.8.1 to 1.9.0 (#998)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.8.1 to 1.9.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.8.1...v1.9.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/viper
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-09-29 13:52:41 +03:00
dependabot[bot]
d0a4ac86f7 Bump github.com/aws/aws-sdk-go from 1.40.37 to 1.40.45 (#997)
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.37 to 1.40.45.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.37...v1.40.45)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-22 14:46:43 +03:00
dependabot[bot]
01afd27cb3 Bump gorm.io/driver/postgres from 1.1.0 to 1.1.1 (#989)
Bumps [gorm.io/driver/postgres](https://github.com/go-gorm/postgres) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/go-gorm/postgres/releases)
- [Commits](https://github.com/go-gorm/postgres/compare/v1.1.0...v1.1.1)

---
updated-dependencies:
- dependency-name: gorm.io/driver/postgres
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-09-19 15:54:27 +03:00
dependabot[bot]
2662c07e2b Bump golang from 1.17.0 to 1.17.1 (#988)
Bumps golang from 1.17.0 to 1.17.1.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-19 15:26:10 +03:00
Yoav Rotem
2bbdf8ceac Remove make integration-testing (#986)
Use a different logic now
2021-09-13 01:15:28 +03:00
dependabot[bot]
10ba0adb2d Bump gorm.io/gorm from 1.21.13 to 1.21.14 (#979)
Bumps [gorm.io/gorm](https://github.com/go-gorm/gorm) from 1.21.13 to 1.21.14.
- [Release notes](https://github.com/go-gorm/gorm/releases)
- [Commits](https://github.com/go-gorm/gorm/compare/v1.21.13...v1.21.14)

---
updated-dependencies:
- dependency-name: gorm.io/gorm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-09-09 18:16:45 +03:00
dependabot[bot]
9863f21984 Bump github.com/aws/aws-sdk-go from 1.40.33 to 1.40.37 (#982)
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.33 to 1.40.37.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.33...v1.40.37)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-09 17:29:40 +03:00
Dave Hay
6d758d2011 Update/upgrade Alpine before installing openssl (#981)
Mitigating CVE-2021-3711 and CVE-2021-3712

Signed-off-by: Dave Hay <david_hay@uk.ibm.com>

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-09-05 17:48:33 +03:00
dependabot[bot]
b238a18aaa Bump github.com/aws/aws-sdk-go from 1.40.28 to 1.40.33 (#978)
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.28 to 1.40.33.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.28...v1.40.33)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-09-02 17:21:27 +03:00
dependabot[bot]
2b6d21a652 Bump alpine from 3.14.1 to 3.14.2 (#977)
Bumps alpine from 3.14.1 to 3.14.2.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-01 10:00:35 +03:00
brainfair
548b021340 Add node kubelet config path (#961)
In kubespray tool we have another path for kubelet config, add them to kube-bench config on top

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-08-30 16:02:26 +03:00
Nick Keenan
946a48ca74 Fix 4.1.9, skip irremediable checks, add /home/kubernetes mount (#976)
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-08-30 15:33:59 +03:00
dependabot[bot]
ed484cae83 Bump github.com/aws/aws-sdk-go from 1.40.18 to 1.40.28 (#975)
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.18 to 1.40.28.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.18...v1.40.28)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-08-30 14:58:58 +03:00
dependabot[bot]
a985e6bdf6 Bump k8s.io/client-go from 0.22.0 to 0.22.1 (#974)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.22.0 to 0.22.1.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.22.0...v0.22.1)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-08-30 13:56:32 +03:00
dependabot[bot]
89a7e7a82d Bump golang from 1.16 to 1.17.0 (#973)
Bumps golang from 1.16 to 1.17.0.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-08-30 11:47:18 +03:00
dependabot[bot]
f20539930e Bump gorm.io/gorm from 1.21.12 to 1.21.13 (#966)
Bumps [gorm.io/gorm](https://github.com/go-gorm/gorm) from 1.21.12 to 1.21.13.
- [Release notes](https://github.com/go-gorm/gorm/releases)
- [Commits](https://github.com/go-gorm/gorm/compare/v1.21.12...v1.21.13)

---
updated-dependencies:
- dependency-name: gorm.io/gorm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-30 11:38:07 +03:00
dependabot[bot]
e2e1566a35 Bump github.com/aws/aws-sdk-go from 1.40.14 to 1.40.18 (#957)
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.14 to 1.40.18.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.14...v1.40.18)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-08-11 12:45:13 +03:00
dependabot[bot]
ee1fd825a7 Bump alpine from 3.14.0 to 3.14.1 (#956)
Bumps alpine from 3.14.0 to 3.14.1.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-10 12:04:15 +03:00
Matthieu MOREL
b1119f588e chore(ci) update k8s.io/client-go and github.com/spf13/cobra to latest (#955)
* Update github.com/spf13/cobra

* chore(ci) update k8s.io/client-go and github.com/spf13/cobra to latest
2021-08-09 17:40:21 +03:00
Matthieu MOREL
c91a9434c0 Update Gorm (#950)
* Migrate from github.com/jinzhu/gorm to gorm.io/gorm

* apply gofmt

* github.com/aws/aws-sdk-go

* fix
2021-08-09 11:40:01 +03:00
dependabot[bot]
42da8c681c Bump github.com/aws/aws-sdk-go from 1.40.13 to 1.40.14 (#949)
Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.13 to 1.40.14.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.13...v1.40.14)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-04 17:07:56 +03:00
Matthieu MOREL
8ac8ebfc2a Update Dependencies (#941)
* Create dependabot.yml

* Bump crazy-max/ghaction-docker-meta from 1 to 3.4.0 (#1)

Bumps [crazy-max/ghaction-docker-meta](https://github.com/crazy-max/ghaction-docker-meta) from 1 to 3.4.0.
- [Release notes](https://github.com/crazy-max/ghaction-docker-meta/releases)
- [Upgrade guide](https://github.com/docker/metadata-action/blob/master/UPGRADE.md)
- [Commits](https://github.com/crazy-max/ghaction-docker-meta/compare/v1...v3.4.0)

---
updated-dependencies:
- dependency-name: crazy-max/ghaction-docker-meta
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update .yamllint.yaml

* Update .yamllint.yaml

* Update dependabot.yml

* Update dependabot.yml

* Bump github.com/onsi/ginkgo from 1.10.1 to 1.16.4 (#2)

Bumps [github.com/onsi/ginkgo](https://github.com/onsi/ginkgo) from 1.10.1 to 1.16.4.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v1.10.1...v1.16.4)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump github.com/stretchr/testify from 1.4.0 to 1.7.0 (#4)

Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.4.0 to 1.7.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.4.0...v1.7.0)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump github.com/fatih/color from 1.5.0 to 1.12.0 (#6)

Bumps [github.com/fatih/color](https://github.com/fatih/color) from 1.5.0 to 1.12.0.
- [Release notes](https://github.com/fatih/color/releases)
- [Commits](https://github.com/fatih/color/compare/v1.5.0...v1.12.0)

---
updated-dependencies:
- dependency-name: github.com/fatih/color
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump github.com/magiconair/properties from 1.8.0 to 1.8.5 (#3)

Bumps [github.com/magiconair/properties](https://github.com/magiconair/properties) from 1.8.0 to 1.8.5.
- [Release notes](https://github.com/magiconair/properties/releases)
- [Changelog](https://github.com/magiconair/properties/blob/main/CHANGELOG.md)
- [Commits](https://github.com/magiconair/properties/compare/v1.8.0...v1.8.5)

---
updated-dependencies:
- dependency-name: github.com/magiconair/properties
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump github.com/aws/aws-sdk-go from 1.35.28 to 1.39.6 (#7)

Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.35.28 to 1.39.6.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.35.28...v1.39.6)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump gopkg.in/yaml.v2 from 2.3.0 to 2.4.0 (#8)

Bumps [gopkg.in/yaml.v2](https://github.com/go-yaml/yaml) from 2.3.0 to 2.4.0.
- [Release notes](https://github.com/go-yaml/yaml/releases)
- [Commits](https://github.com/go-yaml/yaml/compare/v2.3.0...v2.4.0)

---
updated-dependencies:
- dependency-name: gopkg.in/yaml.v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump github.com/spf13/viper from 1.4.0 to 1.8.1 (#9)

Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.4.0 to 1.8.1.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.4.0...v1.8.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/viper
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump github.com/spf13/cobra from 0.0.3 to 0.0.7 (#10)

Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 0.0.3 to 0.0.7.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Changelog](https://github.com/spf13/cobra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/spf13/cobra/compare/v0.0.3...0.0.7)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump github.com/aws/aws-sdk-go from 1.39.6 to 1.40.0 (#11)

Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.39.6 to 1.40.0.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.39.6...v1.40.0)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump crazy-max/ghaction-docker-meta from 3.4.0 to 3.4.1 (#12)

Bumps [crazy-max/ghaction-docker-meta](https://github.com/crazy-max/ghaction-docker-meta) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/crazy-max/ghaction-docker-meta/releases)
- [Commits](https://github.com/crazy-max/ghaction-docker-meta/compare/v3.4.0...v3.4.1)

---
updated-dependencies:
- dependency-name: crazy-max/ghaction-docker-meta
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump github.com/aws/aws-sdk-go from 1.40.0 to 1.40.1 (#13)

Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.0 to 1.40.1.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.0...v1.40.1)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump github.com/aws/aws-sdk-go from 1.40.1 to 1.40.7 (#21)

Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.1 to 1.40.7.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.1...v1.40.7)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump codecov/codecov-action from 1 to 2.0.2 (#20)

Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1 to 2.0.2.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v1...v2.0.2)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update build.yml

* Update mkdocs-deploy.yaml

* Update publish.yml

* Update mkdocs-deploy.yaml

* Bump github.com/aws/aws-sdk-go from 1.40.7 to 1.40.9 (#23)

Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.7 to 1.40.9.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.7...v1.40.9)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update .github/workflows/publish.yml

* Update .github/workflows/build.yml

* Update mkdocs-deploy.yaml

* Update build.yml

* Update dependabot.yml

* Update dependabot.yml

* Bump alpine from 3.13 to 3.14.0 (#27)

Bumps alpine from 3.13 to 3.14.0.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump github.com/aws/aws-sdk-go from 1.40.9 to 1.40.13 (#28)

Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.40.9 to 1.40.13.
- [Release notes](https://github.com/aws/aws-sdk-go/releases)
- [Changelog](https://github.com/aws/aws-sdk-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-go/compare/v1.40.9...v1.40.13)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-04 11:38:18 +03:00
Dave Hay
222e696934 Upgrading apk-tools (#944)
Upgrading apk-tools to remediate CVE-2021-36159
( https://snyk.io/vuln/SNYK-ALPINE314-APKTOOLS-1533752 )

Fixes #943

Signed-off-by: Dave Hay <david_hay@uk.ibm.com>

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-08-03 17:21:24 +03:00
Yoav Rotem
25ba9e2fad New integration testing (#947)
* Fix Junit missing testsuites 

Fix issue https://github.com/aquasecurity/kube-bench/issues/883 but also bug with overriding output when --outputfile is effective and only write the last controls

* test new integration

* Update build.yml

* add wait for job to be ready

* Update build.yml

* Update build.yml

* Update build.yml

* test

* Update job.yaml

* Add wait

* test for logs

* Update job.yaml

* Create Expected_output.data

* Update build.yml

* Update build.yml

* remove empty line

* Add new line at the end

* add ---

* Delete docker.go

* Delete integration.go

* Delete integration_test.go

* Delete integration/testdata/cis-1.20 directory

* Delete integration/testdata/cis-1.6 directory

* Update integration testing

* Remove integration tests

Removed integration testing to github action

* Update build.yml
2021-08-03 17:10:50 +03:00
Yoav Rotem
f74149d4ab Update goreleaser (#929)
* Fix Junit missing testsuites 

Fix issue https://github.com/aquasecurity/kube-bench/issues/883 but also bug with overriding output when --outputfile is effective and only write the last controls

* Deprecated files command

* Update .goreleaser.yml

Remove deprecated files, and fix https://github.com/aquasecurity/kube-bench/issues/925
2021-07-14 15:50:12 +03:00
Nick
cb7ee765a3 K8s Job Command Clean (#923)
* Update commands

* oopsy on run command

* update reference version for iks to be 120

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-07-07 18:21:30 +03:00
Hacks4Snacks
016d67bade cis-1.20 section 1.1.10 command revision. (#922)
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-07-07 18:06:50 +03:00
Dave Hay
42f479596c doc(install): Adding detail and example for build (#928)
- Added to the `Installing from sources`
- Includes `git clone` etc.
- Also includes comments

Signed-off-by: Dave Hay <david_hay@uk.ibm.com>
2021-07-07 10:56:33 +03:00
Yoav Rotem
14aef408e8 Fix Junit missing testsuites (#920)
Fix issue https://github.com/aquasecurity/kube-bench/issues/883 but also bug with overriding output when --outputfile is effective and only write the last controls
2021-06-23 18:01:24 +03:00
Yoav Rotem
aedc2942bd Check string size (#915)
ASFF ProductFields[] string can't be longer than 1024 characters, could explain https://github.com/aquasecurity/kube-bench/issues/903
`Message:Finding does not adhere to Amazon Finding Format. data.Remediation.Recommendation.Text should NOT be longer than 512 characters.
Error Code:InvalidInput`
2021-06-20 14:28:22 +03:00
Huang Huang
1173667622 Add docs for cis v1.20 (#914)
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-06-20 12:56:56 +03:00
Huang Huang
e5e2804dfa Fix values of version field in cfg/cis-1.20 were wrong (#913) 2021-06-20 11:23:24 +03:00
Yoav Rotem
2d033edc96 New cis v1.20 (#912)
* Add files via upload

* Add new cis support v1.20!

* Fix issue with 1.1.9 and 1.1.10 tests

Tests in some cases stat empty path which will return error.

* Add tests for kubernetes 1.20 and retire 1.15 tests

kubernetes 1.15 is not supported anymore and we shouldn't keep testing it.

* Kubernetes 1.15 is not supported anymore

* Tests for kubernetes 1.20

* Fix yamllint errors

Removed trailing spaces (trailing-spaces)

* Add tests for v1.20

* Remove extra spaces

* Change cis test functions names
2021-06-16 20:55:04 +03:00
Yoav Rotem
6ca3ce6754 Update go modules 1.16 (#910)
* Update to go 1.16

* Update go modules to 1.16
2021-06-16 17:26:51 +03:00
Yoav Rotem
7bbcaeba04 Fix issue tests 1.1.9 and 1.1.10 (#911)
Issue https://github.com/aquasecurity/kube-bench/issues/909
2021-06-16 17:14:20 +03:00
Yoav Rotem
53752487b6 Add git config user (#901)
* Add git config user

* Create mkdocs-deploy.yaml

* Delete mkdocs-latest.yaml

* Delete mkdocs-dev.yaml
2021-06-14 12:13:48 +03:00
Yoav Rotem
75fe5d0048 Fix ocp job issues (#893)
* Fix openshift missing glibc

Fixing issues #891  #890

* Update goreleaser

Change release to build, no need to release while building (when pushed to main) but only when publishing (release new version)

* Update goreleaser version to 0.169.0

* Change from release to build

* Try day run on release

It used to be released to docker hub each push, the issue was that docker hub had a automation for it, now test if its not releasing every git push.
2021-06-09 15:34:39 +03:00
Yoav Rotem
fdf0bbd960 Fixing typos (#899) 2021-06-09 15:11:05 +03:00
Yoav Rotem
dd68e8f000 Change files names to start with lowercase (#898) 2021-06-09 14:55:28 +03:00
Yoav Rotem
0d1bd2bbd9 mkdocs support and update docs (#884)
* Delete README.md

* Edit readme and separate into different files

* Update README.md

* Update Running.md

* Update CONTRIBUTING.md

* Create Contributing.md

* Add files via upload

* Update Index.md

* Rename Flags and Commands.md to Flags_and_commands.md

* Rename Index.md to index.md

* Create mkdocs.yml

* Delete images directory

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Create mkdocs-dev.yaml

* Create mkdocs-latest.yaml

* Update mkdocs.yml

* Update mkdocs.yml

* Update mkdocs.yml

Add yamllint ---

* Make it yamllint comply

* Make Yamllint comply

* Make Yamllint comply

* Change description

Co-authored-by: Itay Shakury <itay@itaysk.com>

* Fix syntax

Co-authored-by: Itay Shakury <itay@itaysk.com>

* Update docs/Architecture.md

Co-authored-by: Itay Shakury <itay@itaysk.com>

* Update docs/Architecture.md

Co-authored-by: Itay Shakury <itay@itaysk.com>

* Update example for test files

* Update contributing

* Delete Contributing.md

* Update Flags_and_commands.md

* Change syntax and add source

* Update Platforms.md

* lower case file names

* lower case file names

* Lower case file names

* Lower case file names

* Lower case file names

* Lower case file names

* Add note about inspect master in some platforms

* Add quick start

* Lower case files names

* Lower case files names

* Fixing typo

* Remove section about old ocp

* Fix typos

Co-authored-by: Itay Shakury <itay@itaysk.com>
2021-06-09 11:17:16 +03:00
Ed Robinson
4b28c84b97 Allow kube-bench to scan Bottlerocket OS (#889) 2021-06-08 12:23:43 +03:00
tonyqui
6605ff8844 False positive when running rh-0.7 benchmarks (#886) 2021-06-07 12:18:59 +03:00
Dave Hay
fb92680702 Issue 867: Updating CIS 1.1.9 and 1.1.10 (#877)
Mitigating "No such file or directory" related to CNI config directory

Signed-off by: Dave Hay <david_hay@uk.ibm.com>
2021-05-23 11:46:36 +03:00
Yoav Rotem
62d9045ec6 Fix issue with missing 'Maintainer' field (#875)
Issue #840 missing 'Maintainer' field in package
2021-05-20 11:21:04 +03:00
Yoav Rotem
1f4b941c51 Fix test request timeout (#874)
* Test 1.2.24 should be manual

* Test 1.2.26 should be manual

* Test 1.2.26 should be manual

* Change test 1.2.26

* Change test 1.2.26

* Change test 1.2.26

* Change test 1.2.26

* Change test 1.2.26
2021-05-18 16:53:50 +03:00
Yoav Rotem
9820da9579 Update gke-1.0 (#873)
* Create controlplane.yaml

* Update and tidy yaml

* Update and tidy yaml

* Update and tidy yaml
2021-05-18 16:37:55 +03:00
hbc
e4d9455820 cfg: add /etc/default/kubeletconfig.json for AKS (#865)
* cfg: add `/etc/default/kubeletconfig.json`

* fix(cfg): search kubeletconfig.json first

* feat: mount `/etc/default` from host for AKS cluster

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-05-11 12:37:25 +03:00
Huang Huang
47c2494728 Support CIS ACK 1.0.0 benchmark (#841)
* Support CIS ACK 1.0.0 benchmark

* fix yaml lint

* Fix TestMakeSubsitutions may failed when order of map changed

* Support auto-detect platform when running on ACK

* Apply suggestions from code review

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-05-11 11:52:24 +03:00
Yoav Rotem
887965d31f Add detected kubernetes version (#869)
* Add detected kubernetes version to controls

* Refactore NewControls function

Now new Control function is expecting detected version argument.

* Refactore NewControls function

Now new Control function is expecting detected version argument.

* Refactore NewControls function

New Control function is expecting detected version argument.

* Add detected kube version

* add detecetedKubeVersion

* Add detecetedKubeVersion

* Add detectedKubeVersion

* Add detecetedKubeVersion

* Fix missing version

* Change version

Change version from 3.10 to rh-0.7

* fix version: "cis-1.5"

* fix version: "cis-1.5"

* fix version: "cis-1.5"

* Fix version: "cis-1.5"

* Fix version: "cis-1.5"

* Fix version: "cis-1.6"

* Fix version: "cis-1.6"

* Fix version: "cis-1.6"

* Fix version: "cis-1.6"

* Fix version: "cis-1.6"
2021-05-09 14:48:34 +03:00
Huang Huang
182e64753e mount /etc/passwd and /etc/group for etcd ownership related checks (#868) 2021-05-09 14:25:14 +03:00
Yoav Rotem
a1bd51db99 Add rh-1.0 (#863) 2021-05-02 19:31:03 +03:00
Gábor Lipták
af4999ac0e Bring Go to 1.16 (#859)
* Bring Go to 1.16

* Bring Go to 1.16

* Bump actions/setup-go to v2

* Bump actions/setup-go to v2
2021-05-02 12:47:30 +03:00
Yoav Rotem
68c2ee2ebf Add support for Redhat openshift 4.0 cis 1.1.0 (#860) 2021-04-29 17:08:41 +03:00
Dmytro Oboznyi
d528400881 Fix file permissions false positive (#800)
* Fix file permissions false positive

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Added kops files to config path list

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Automated CNI files checks

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Fixed linting

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Fixed to right folder CNI test

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Changed Automated to manual

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Removed changes from remediation

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Added path to config files

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Update cfg/cis-1.6/master.yaml

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Fix

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Fix to job.yaml

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Add extra mountpoints

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Revert audit scripts changes

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2021-04-08 17:02:27 +03:00
Yoav Rotem
f2386c0386 Update ocp 3.11 (#849)
* Add OCP auto-detection

* Add test for openshift

* update and fix bugs

update file to match with new kube-bench features and fix bugs

* Update file and fix bugs

update file to match with new kube-bench features and fix bugs

* Remove specific configs

Those configs could be set in main config.yaml

* Update to include openshift files

* fix typos

* fix typo

* Remove trailing spaces

* Update util.go

* Add tests for getOcpValidVersion
2021-03-24 18:06:54 +02:00
Yoav Rotem
0cb302761c Add logging (#822)
* Add more logging

The old logging could was lacking and in some cases misleading

* Add Logging

Add more logs and change some old messages, the important part is make each test log more readable by adding ------ test id ------ section in logs

* Fix typos

* more info

add more info in comment about the function and it use cases

Co-authored-by: Liz Rice <liz@lizrice.com>

* Use switch case

Change the logic from if to switch and tidy up the code
2021-03-22 17:33:53 +02:00
Neha Viswanathan
9030532263 upgrade base image versions in Dockerfile (#831) 2021-03-21 22:53:39 +02:00
Yoav Rotem
50fce51da7 Fix fallback to default version (#834)
* Fix fallback to default version

In some cases kube-bench will crush instead of fallback to default version. 
Fix it to only log that couldn't auto-detect version and used default.

* Fix case with fallback to default version
2021-03-02 16:27:34 +02:00
Yoav Rotem
e308bc1eba Add version logging (#817)
* Add more logging

issue #816  add more logging for better debug and information about version auto-detection and fix typo

* Fix typo

* Add more logging

issue #816  add more logging for better debug and information about version auto-detection and fix typo

* tidy logging output

Co-authored-by: Liz Rice <liz@lizrice.com>

* tidy logging output

Co-authored-by: Liz Rice <liz@lizrice.com>

* tidy logging output

Co-authored-by: Liz Rice <liz@lizrice.com>

* tidy logging output

Co-authored-by: Liz Rice <liz@lizrice.com>

* tidy logging output

Co-authored-by: Liz Rice <liz@lizrice.com>

* tidy logging output

Co-authored-by: Liz Rice <liz@lizrice.com>

* tidy logging output

Co-authored-by: Liz Rice <liz@lizrice.com>

* Remove extra logging

Co-authored-by: Liz Rice <liz@lizrice.com>
2021-02-23 14:24:14 +00:00
Neha Viswanathan
b2d481812f deprecate master and node subcommands (#812)
* deprecate master and node subcommands

* deprecate master and node subcommands
2021-02-23 14:23:55 +00:00
Naoki Oketani
bc21212980 chore: fix an invalid markdown syntax (#815) 2021-02-23 14:23:38 +00:00
Takahiro Tsuruda
4d6de1e2a5 chore: fix defer func in for-loop (#825)
* chore: call defer func for each iteration

Signed-off-by: TakahiroTsuruda <isrgnoe@gmail.com>

* chore: error check
2021-02-23 14:22:15 +00:00
Liz Rice
baf05eca3b docs: remove deprecated subcommands master / node (#827)
* docs: remove references to deprecated subcommands

Removing master / node since it's better to autodetect, or to use
--target

Signed-off-by: Liz Rice <liz@lizrice.com>

* docs: specifying kubernetes or benchmark version

Signed-off-by: Liz Rice <liz@lizrice.com>
2021-02-23 14:05:34 +00:00
Liz Rice
92ebc493ac chore: fix YAML lint errors (#826)
* chore: fix YAML lint

* chore: fix YAML lint
2021-02-23 14:04:45 +00:00
Michael Kandelaars
3e9b5a7b49 Refactor of EKS and ASFF integration Job and instructions (#794)
* Refactor to use Configmap for EKS and ASFF integration

* newline

* markdown fix

* formatting fix

* Update docs/asff.md

Co-authored-by: Liz Rice <liz@lizrice.com>

* typo

* docs: remove section about rebuilding

* docs: reminder to specify kube-bench image for ASFF

Co-authored-by: Liz Rice <liz@lizrice.com>
2021-02-22 14:28:36 +00:00
Liz Rice
ade7fb0759 chore: improve bug report template (#821)
Ask for more details that we usually need to request anyway, like the
list of currently running processes

Signed-off-by: Liz Rice <liz@lizrice.com>
2021-02-22 11:00:59 +02:00
Thorsten Schifferdecker
2b3f036959 (fix) add config.yaml to releases, see #811 (#813)
Signed-off-by: Thorsten Schifferdecker <ts@systs.org>
2021-02-11 12:56:49 +02:00
Dmytro Oboznyi
6262bc79ec Automated testing 1.2.34 (#801)
* Automated testing 1.2.34

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Changed automation status in test

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Changed one more test

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>

* Changed Automated to manual

Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>
2021-02-11 11:54:41 +02:00
Felipe Augusto de Castro
ed53e56356 Allow kube-bench to scan Bottlerocket OS (#809) 2021-02-10 16:56:11 +02:00
Giuseppe Ingoglia
773b3e6f79 add new proxy path (#820)
Solving issue raised in #819
2021-02-10 12:14:25 +02:00
Liz Rice
95905fb5c2 Publish to aquasec org on Docker Hub 2021-01-21 10:27:46 +00:00
Liz Rice
a96ffc2e16 Publish to the aquasec org on Docker Hub (#805)
* Publish to the aquasec org on Docker Hub

* chore: remove spaces
2021-01-21 10:22:28 +00:00
Liz Rice
5ae42ebd82 Add manual workflow dispatch to Publish (#804)
So we can trigger publish manually
2021-01-21 11:48:48 +02:00
Dmytro Oboznyi
ebcb742931 Fix 1.1.7 1.1.8 (#798)
Signed-off-by: Dmytro Oboznyi <dmytro.oboznyi@syncier.com>
2021-01-20 14:42:57 +02:00
Huang Huang
9782bee80c Remove Travis CI related contents (#792) 2021-01-18 10:29:50 +00:00
Dmytro Oboznyi
58c614cf6c Update master.yaml (#797) 2021-01-13 12:43:40 +02:00
Liz Rice
06ab5dfc80 Rename master branch to main (#778) 2021-01-04 10:31:57 +00:00
Carol Valencia
888c912847 chore: build and push action for ecr and docker (#790)
Co-authored-by: Carol Valencia <krol3@users.noreply.github.com>
2020-12-27 09:43:30 +02:00
Liz Rice
6452df7c7f Expected result pattern not always shows (#784)
* Add expectedResultPattern to invalid test

when testing and try convert to numeric we didn't set expectedResultPattern value.

* check for auditconfig before using it

The current state is that when ever audit output is not what we search for we check for auditConfig output which is sometime empty and therefore create empty expected result as described in #694

* Fix issue about expectedResultPattern

expectedResultPattern not always shown and wasn't accurate enough 
Issue #705

* Add tests for ExpectedResult and fixes

Add tests for ExpectedResult with the new output and the verify that the fix is working

* Add missing flags

In some cases not having audit or audit_config flag would fail the test.
So added just a simple commands like echo something to solve this issue 
Also add bitmask checks

* Add example IAM policy

* Pass RotateKubeletServerCertificate related checks if it's not found (#767)

* Allow for environment variables to be checked in tests (#755)

* Initial commit for checking environment variables for etcd

* Revert config changes

* Remove redundant struct data

* Fix issues with failing tests

* Initial changes based on code review

* Add option to disable envTesting + Update docs

* Initial tests

* Finished testing

* Fix broken tests

* Add a total summary and always show all tests. (#759)

Whether the total summary is shown can be specified with an option.

Fixes #528

Signed-off-by: Christian Zunker <christian.zunker@codecentric.cloud>

* Update Readme.md file with link to Contribution guide (#754)

* Update License with the year and the owner name

Please add this to make your license agreement strong

* Updated Readme.md file with license and proper documentation links

I have added a proper license agreement to the documentation. Also shortened the links to the issues so that it does not break in any on the forks.

* Update LICENSE

* Update README.md

* Update README.md

* Remove erroneous license info

Co-authored-by: Liz Rice <liz@lizrice.com>

* Support auto-detect platform when running on EKS or GKE (#683)

* Support auto-detect platform when running on EKS or GKE

* Change to get platform name from `kubectl version`

* fix regexp and add test

* Update Server Version match for EKS

* try to get version info from api sever at first

* Change expected expectedResultPattern

Now expectedResultPattern is more verbose

* Update ops tests

* Fix unit tests

* Fix bitmask output syntax

* Changes to be committed:
	modified:   check/check.go
	modified:   check/test.go
	modified:   check/test_test.go
fix unit testing and test.go to resolve conflicts.

* Change found to flagFound

* add missing }

* change found to flag found

Co-authored-by: yoavrotems <yoavrotems97@gmail.com>
2020-12-24 16:38:22 +02:00
Liz Rice
b6f619cdcb GitHub Actions in correct directory (#787)
* Rename workflow to workflows

* Add integration tests to Actions

* Upload code coverage after unit test

* don't need code coverage when we do a release

* Use same Go version as in go.mod

* Use same Go version as go.mod
2020-12-23 12:48:17 +02:00
Liz Rice
e4d6ed2e8e Refactor group skip (#783)
* Add example IAM policy

* Pass RotateKubeletServerCertificate related checks if it's not found (#767)

* Allow for environment variables to be checked in tests (#755)

* Initial commit for checking environment variables for etcd

* Revert config changes

* Remove redundant struct data

* Fix issues with failing tests

* Initial changes based on code review

* Add option to disable envTesting + Update docs

* Initial tests

* Finished testing

* Fix broken tests

* Add a total summary and always show all tests. (#759)

Whether the total summary is shown can be specified with an option.

Fixes #528

Signed-off-by: Christian Zunker <christian.zunker@codecentric.cloud>

* Update Readme.md file with link to Contribution guide (#754)

* Update License with the year and the owner name

Please add this to make your license agreement strong

* Updated Readme.md file with license and proper documentation links

I have added a proper license agreement to the documentation. Also shortened the links to the issues so that it does not break in any on the forks.

* Update LICENSE

* Update README.md

* Update README.md

* Remove erroneous license info

Co-authored-by: Liz Rice <liz@lizrice.com>

* Support auto-detect platform when running on EKS or GKE (#683)

* Support auto-detect platform when running on EKS or GKE

* Change to get platform name from `kubectl version`

* fix regexp and add test

* Update Server Version match for EKS

* try to get version info from api sever at first

* Refactor group skip

changed group 'skip' from being a bool to be 'type' string as done in check

* Change skip: true -> type: skip

Co-authored-by: Huang Huang <mozillazg101@gmail.com>
Co-authored-by: Wicked <jason_attwood@hotmail.co.uk>
Co-authored-by: Christian Zunker <827818+czunker@users.noreply.github.com>
Co-authored-by: Kaiwalya Koparkar <kaiwalyakoparkar@gmail.com>
Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2020-12-21 13:18:54 +02:00
Carol Valencia
abe0954dcb feat: github actions to publish ecr and docker (#782)
* feat: github actions to publish ecr and docker

* fix: yaml lint in build

Co-authored-by: Carol Valencia <krol3@users.noreply.github.com>
2020-12-21 11:10:02 +00:00
Greg DeKoenigsberg
ecdd0b4158 Fix AWS ECR authentication docs (#781)
The command you listed here did not work. The command from the official documentation did:

https://docs.aws.amazon.com/AmazonECR/latest/userguide/getting-started-cli.html

aws ecr get-login-password --region region | docker login --username AWS --password-stdin aws_account_id.dkr.ecr.region.amazonaws.com
2020-12-21 10:39:01 +00:00
Liz Rice
4ebfe684c9 Rename master branch to main 2020-12-17 13:37:02 +00:00
Brian Terry
c3f94dd89f Aws asff (#770)
* add aasf

* add AASF format

* credentials provider

* add finding publisher

* add finding publisher

* add write AASF path

* add testing

* read config from file

* update docker file

* refactor

* remove sample

* add comments

* Add comment in EKS config.yaml

* Fix comment typo

* Fix spelling of ASFF

* Fix typo and other small code review suggestions

* Limit length of Actual result field

Avoids this message seen in testing:
  Message:Finding does not adhere to Amazon Finding Format. data.ProductFields['Actual result'] should NOT be longer than 1024 characters.

* Add comment for ASFF schema

* Add Security Hub documentation

* go mod tidy

* remove dupe lines in docs

* support integration in any region

* fix README link

* fix README links

Co-authored-by: Liz Rice <liz@lizrice.com>
2020-11-23 19:43:53 +00:00
Huang Huang
054c401f71 Support case which run etcd as systemd service instead of pod (#762) 2020-11-16 14:50:15 +02:00
Borko
bd0f59a013 Added Kubernetes Job for AKS-1.0 tests. (#735) 2020-11-16 14:38:02 +02:00
Borko
ab3881420c Created config and test files for Azure Kubernetes Service (AKS). (#733)
* First draft of AKS configuration checks.

* Updated Azure Configurations. Added more policy checks.

* Finalized cfg components for AKS.

* Fixed targets for aks-1.0 in common_test.go

* Fixed yaml linting issues.

* Fixed white space yaml linkting issues in policies.yaml

* Fixed white space yaml linting issues in policies.yaml
2020-11-16 14:35:57 +02:00
bjrara
83b80a5816 automate check 3.2.1 Ensure that a minimal audit policy is created (#742)
Co-authored-by: mengyzhou <mengyzhou@ebay.com>
2020-11-02 09:41:07 +02:00
Wicked
aa2a6f08f3 Add exit-code parameter for when checks have failed (#734)
* Add int command to specify exit code wih a default of 0

* Re-structured to add tests

* Refactor exit code selection
2020-10-29 12:12:45 +02:00
Wicked
3a35c039e5 Add --skip command to skip groups and checks (#751) 2020-10-29 12:03:41 +02:00
Eric Ho
519f632147 Fix command on extract kube-bench binary (#750) 2020-10-29 11:45:07 +02:00
Sinith
a4c3ce9f9e Update policies.yaml (#757) 2020-10-29 10:49:34 +02:00
bjrara
dc84ae3438 Fix defaultkubeconfig in config.yaml to resolve variable exposure in remediation when conf is missing (#758)
Co-authored-by: mengyzhou <mengyzhou@ebay.com>
2020-10-29 10:46:50 +02:00
Wicked
9474472194 Allow for skip to be defined on a group-level skipping all checks inside (#736)
* Allow for skip to be defined on a group-level skipping all checks inside

* Refactor skip code to not run skipped checks
2020-10-19 10:51:33 +03:00
bjrara
724cea4980 Customize kubeconfig location for kube-scheduler and kube-controller-manager (#738) 2020-10-18 18:10:29 +03:00
bjrara
d026e046f7 Check tls-cipher-suites using valid_elements op (#739) 2020-10-18 18:08:19 +03:00
Oleksandr Slynko
58bea9c89b Fix go vet issues (#720)
* Fix go vet issues

* to omit the property from JSON parsing one should use "-". "omit" in
that case would use omit tag
* The error was not reachable in the tests, so I moved it to the place
where it make sense for me (but maybe it was just unnecessary)

* Run all go vet linters in CI

* This return breaks the test
2020-10-09 15:56:22 +01:00
Borko
f213918552 Updated documentation with section on downloading and installing kube-bench on Linux. (#716)
Added section on manually downloading and installing kube-bench
2020-10-09 15:46:57 +01:00
Huang Huang
ff0ce661a8 Fix typo of 1.1.19 in cis-1.6 (#728) 2020-10-09 15:39:05 +01:00
Tom Kelley
8207532d16 Since the 1.3 and 1.4 tests were removed, these files are unnecessary. (#727) 2020-10-07 21:58:44 +03:00
Tom Kelley
a7aa21f32c Improve Proxykubeconfig tests (#708)
* Changes for 1.5

* Update cis-1.3 through 1.6 to also work with configmaps.

* Switch on if proxykubeconfig is set, instead of setting a variable in the script.

* permissons -> proxykubeconfig for 2.2.5/4.1.3 to keep these tests locked with 2.2.6/4.1.4

* Updating test output? Maybe?

* Copy integration test output files into docker image?

* Make entrypoint move integration folder to host, print 1.5 node info.

* Change the order of tests in travis to load files before testing.

* Return tests to place

Those tests comes first since there is more likely to fail with them and then the test will fail "faster" which will save time

* Remove copy integration 

When running in a container we don't need to test, only when build and running in Travis to make sure everything is working fine.

* Add $ mark before proxykubeconfig

If not having $ before the parameter then it won't get substituted

* Add $ mark before proxykubeconfig

If not having $ before the parameter then it won't get substituted

* Remove test relate lines

We don't test while running, only integration testing when building and unit testing

* Add spaces

* Change 4.1.3 4.1.4

Those tests now should pass.

* Change tests 4.1.3 and 4.1.4

Those tests now should PASS

* Update job.data with more accurate counts. Thanks to @yoavrotems for getting the project this far!

* Thanks for linting, yamllint!

Co-authored-by: Yoav Rotem <yoavrotems97@gmail.com>
2020-10-07 21:53:34 +03:00
134 changed files with 12351 additions and 5277 deletions

View File

@@ -3,15 +3,35 @@ name: Bug report
about: Tell us about a problem you are experiencing
---
**What steps did you take and what happened:**
**Overview**
[A clear and concise description of what the bug is, and what commands you ran. If possible please supply logs generated with the `-v 3` parameter.)
[A clear and concise description of what the bug is]
**How did you run kube-bench?**
[Please specify exactly how you ran kube-bench, including details of command parameters and/or job file that you used to run it]
**What happened?**
[Please include output from the report to illustrate the problem. If possible please supply logs generated with the `-v 3` parameter.]
**What did you expect to happen:**
[Please describe what you expected to happen differently.]
**Environment**
[Please specify the version of kube-bench and Kubernetes]
[What is your version of kube-bench? (run `kube-bench version`)]
[What is your version of Kubernetes? (run `kubectl version` or `oc version` on OpenShift.)]
**Running processes**
[Please include the output from running `ps -eaf | grep kube` on the affected node. This will allow us to check what Kubernetes processes are running, and how this compares to what kube-bench detected.]
**Configuration files**
[If kube-bench is reporting an issue related to the settings defined in a config file, please attach the file, or include an extract showing the settings that are being detected incorrectly.]
**Anything else you would like to add:**

15
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
---
version: 2
updates:
- package-ecosystem: gomod
directory: /
schedule:
interval: weekly
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
- package-ecosystem: docker
directory: /
schedule:
interval: weekly

63
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,63 @@
---
name: Build
on:
push:
branches:
- main
paths-ignore:
- "*.md"
- "LICENSE"
- "NOTICE"
pull_request:
paths-ignore:
- "*.md"
- "LICENSE"
- "NOTICE"
env:
GO_VERSION: "1.16"
KIND_VERSION: "v0.11.1"
KIND_IMAGE: "kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6"
jobs:
build:
name: Build
runs-on: ubuntu-18.04
steps:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.16
- name: Checkout code
uses: actions/checkout@v2
- name: yaml-lint
uses: ibiqlik/action-yamllint@v3
- name: Run unit tests
run: make tests
- name: Upload code coverage
uses: codecov/codecov-action@v2
with:
file: ./coverage.txt
- name: Setup Kubernetes cluster (KIND)
uses: engineerd/setup-kind@v0.5.0
with:
version: ${{ env.KIND_VERSION }}
image: ${{ env.KIND_IMAGE }}
name: kube-bench
- name: Test connection to Kubernetes cluster
run: |
kubectl cluster-info
kubectl describe node
- name: Run integration tests
run: |
make integration-test
- name: Compare output with expected output
uses: GuillaumeFalourd/diff-action@v1
with:
first_file_path: ./test.data
second_file_path: integration/testdata/Expected_output.data
expected_result: PASSED
- name: Dry-run release snapshot
uses: goreleaser/goreleaser-action@v2
with:
version: v0.169.0
args: release --snapshot --skip-publish --rm-dist

37
.github/workflows/mkdocs-deploy.yaml vendored Normal file
View File

@@ -0,0 +1,37 @@
---
# This is a manually triggered workflow to build and publish the MkDocs from the
# main branch to GitHub pages at https://aquasecurity.github.io/kube-bench.
name: Deploy documentation
on:
workflow_dispatch:
inputs:
version:
description: Version to be deployed
required: true
jobs:
deploy:
name: Deploy documentation
runs-on: ubuntu-18.04
steps:
- name: Checkout main
uses: actions/checkout@v2
with:
fetch-depth: 0
persist-credentials: true
- uses: actions/setup-python@v2
with:
python-version: 3.x
- run: |
pip install git+https://${GH_TOKEN}@github.com/squidfunk/mkdocs-material-insiders.git
pip install mike
pip install mkdocs-macros-plugin
env:
# Note: It is not the same as ${{ secrets.GITHUB_TOKEN }} !
GH_TOKEN: ${{ secrets.MKDOCS_AQUA_BOT }}
- run: |
git config user.name "aqua-bot"
git config user.email "aqua-bot@users.noreply.github.com"
- run: |
mike deploy --push --update-aliases ${{ github.event.inputs.version }} latest

66
.github/workflows/publish.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
---
name: Publish
on:
workflow_dispatch:
push:
tags:
- "v*"
env:
ALIAS: aquasecurity
DOCKERHUB_ALIAS: aquasec
REP: kube-bench
jobs:
publish:
name: Publish
runs-on: ubuntu-18.04
steps:
- name: Check Out Repo
uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildxarch-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildxarch-
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to ECR
uses: docker/login-action@v1
with:
registry: public.ecr.aws
username: ${{ secrets.ECR_ACCESS_KEY_ID }}
password: ${{ secrets.ECR_SECRET_ACCESS_KEY }}
- name: Get version
id: get_version
uses: crazy-max/ghaction-docker-meta@v3
with:
images: ${{ env.REP }}
tag-semver: |
{{version}}
- name: Build and push - Docker/ECR
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64
builder: ${{ steps.buildx.outputs.name }}
push: true
tags: |
${{ env.DOCKERHUB_ALIAS }}/${{ env.REP }}:${{ steps.get_version.outputs.version }}
public.ecr.aws/${{ env.ALIAS }}/${{ env.REP }}:${{ steps.get_version.outputs.version }}
${{ env.DOCKERHUB_ALIAS }}/${{ env.REP }}:latest
public.ecr.aws/${{ env.ALIAS }}/${{ env.REP }}:latest
cache-from: type=local,src=/tmp/.buildx-cache/release
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache/release
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}

50
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,50 @@
---
name: Release
on:
push:
tags:
- "v*"
env:
GO_VERSION: "1.16"
KIND_VERSION: "v0.11.1"
KIND_IMAGE: "kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6"
jobs:
release:
name: Release
runs-on: ubuntu-18.04
steps:
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: 1.16
- name: Checkout code
uses: actions/checkout@v2
- name: Run unit tests
run: make tests
- name: Setup Kubernetes cluster (KIND)
uses: engineerd/setup-kind@v0.5.0
with:
version: ${{ env.KIND_VERSION }}
image: ${{ env.KIND_IMAGE }}
name: kube-bench
- name: Test connection to Kubernetes cluster
run: |
kubectl cluster-info
kubectl describe node
- name: Run integration tests
run: |
make integration-test
- name: Compare output with expected output
uses: GuillaumeFalourd/diff-action@v1
with:
first_file_path: ./test.data
second_file_path: integration/testdata/Expected_output.data
expected_result: PASSED
- name: Release
uses: goreleaser/goreleaser-action@v2
with:
version: v0.169.0
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

2
.gitignore vendored
View File

@@ -11,3 +11,5 @@ coverage.txt
# Directory junk file
.DS_Store
thumbs.db
/kubeconfig.kube-bench
/test.data

View File

@@ -1,4 +1,5 @@
---
project_name: kube-bench
env:
- GO111MODULE=on
- KUBEBENCH_CFG=/etc/kube-bench/cfg
@@ -24,14 +25,27 @@ archives:
name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{.Arm }}{{ end }}'
files:
- "cfg/**/*"
- "cfg/config.yaml"
nfpms:
-
vendor: Aqua Security
description: "The Kubernetes Bench for Security is a Go application that checks whether Kubernetes is deployed according to security best practices"
maintainer: Yoav Rotem <yoav.rotem@aquasec.com>
license: Apache-2.0
homepage: https://github.com/aquasecurity/kube-bench
files:
"cfg/**/*": "/etc/kube-bench/cfg"
file_name_template: '{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{.Arm }}{{ end }}'
contents:
- src: "cfg/**/*"
dst: "/etc/kube-bench/cfg"
- src: "cfg/config.yaml"
dst: "/etc/kube-bench/cfg/config.yaml"
formats:
- deb
- rpm
changelog:
sort: asc
filters:
exclude:
- '^docs'
- '^test'
- '^release'

View File

@@ -1,53 +0,0 @@
---
language: go
services:
- docker
notifications:
email: false
before_install:
- sudo apt-get -qq update
- sudo apt-get install -y rpm
- pip install --user yamllint==1.18.0
- gem install --no-document fpm
- go get -t -v ./...
- |
if [ "$TRAVIS_BRANCH" = "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then
echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin
fi
script:
- yamllint -c ./.yamllint.yaml .
# Run unit and integration tests
- make tests
- make integration-tests
# Build a local container image to test that the install sub-command works
- IMAGE_NAME=kube-bench make build-docker
- docker run -v `pwd`:/host kube-bench install
- test -d cfg
- test -f kube-bench
# Build and push the multi-arch Docker image
- |
if [ "$TRAVIS_BRANCH" = "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then
make docker
fi
after_success:
- bash <(curl -s https://codecov.io/bash)
deploy:
- provider: script
skip_cleanup: true
script: curl -sL https://git.io/goreleaser | bash
on:
tags: true
condition: "$TRAVIS_OS_NAME = linux"
env:
global:
secure: mb8AYZKDo6hkKN+2F9ldXcw27Yn2AfxpXvKlD8GD7NdGOI+TaiSFbE0I+qqTa/1DqcRekCQwqN7OG/17s9JDkgzUXYuYUGlVUOM4WbeJoSlzJFIOh9r9R/JddluYJohypgkE20IBHIrEHq5sY0Nn1Pl9WgSQFaVcQjxkX009AOuVjN0o5HcoXsb5hAzvHrpoSPkcSSqq7VWab60TgUttVaRlZSGwGdSYQEqk5TdO0hWHuXyxaaEPybgFIyZLLbxPS4JmMz8n3Sngetpw9Jgc+V9Fc7wKXpjvZZ33SpArG5p5ZFFu2YQOXFLZth9qtQOjduQ2gU1kHN6WjWnJ8QX2s8vmU38Tk19kd5i+mz9dvc87IdBvmTIqVYSpM6AAYa2osBGP3f97Rj2S68lTad4ecSVyHdsjz56vdE3ZH4wskswmogbKkVdvO4biPHxT6odszBxYLEJuRJyZ7ckXd52MCzqAUPrw7YUuH8N1mLIlf7V5bW5R+q4DlKw774zxnHiWrymXGvlINSrB0qxBn8Fii6ib+Pacl3PuqSumCcgIHlVjqrzIXaqcTMn2/ABZYC99mralGvwA/EgNa8CBKB5evMCEwWa5Ntvcs2I2DFcO5Q2WzN4H0YScyAzzCzK7/3hWJE/rUIJntwiSXkV3MSa1yxWSGGH8F1lcz+lzgTBm/MU=
matrix:
- GO111MODULE=on

View File

@@ -1,6 +1,8 @@
Thank you for taking an interest in contributing to kube-bench !
## Issues
## Contributing, bug reporting, openning issues and starting discussions
### Issues
- Feel free to open an issue for any reason as long as you make it clear if the issue is about a bug/feature/question/comment.
- Please spend some time giving due diligence to the issue tracker. Your issue might be a duplicate. If it is, please add your comment to the existing issue.
@@ -9,16 +11,69 @@ Thank you for taking an interest in contributing to kube-bench !
- For questions and bug reports, please include the following information:
- version of kube-bench you are running (from kube-bench version) along with the command line options you are using.
- version of Kubernetes you are running (from kubectl version or oc version for Openshift).
- Verbose log output, by setting the `-v 10` command line option.
- Verbose log output, by setting the `-v 3` command line option.
## Pull Requests
### Bugs
If you think you have found a bug please follow the instructions below.
- Open a [new bug](https://github.com/aquasecurity/kube-bench/issues/new?assignees=&labels=&template=bug_report.md) if a duplicate doesn't already exist.
- Make sure to give as much information as possible in the following questions
- Overview
- How did you run kube-bench?
- What happened?
- What did you expect to happen
- Environment
- Running processes
- Configuration files
- Anything else you would like to add
- Set `-v 3` command line option and save the log output. Please paste this into your issue.
### Features
We also use the GitHub discussions to track feature requests. If you have an idea to make kube-bench even more awesome follow the steps below.
- Open a [new discussion](https://github.com/aquasecurity/kube-bench/discussions/new?category_id=19113743) if a duplicate doesn't already exist.
- Remember users might be searching for your discussion in the future, so please give it a meaningful title to helps others.
- Clearly define the use case, using concrete examples. For example, I type `this` and kube-bench does `that`.
- If you would like to include a technical design for your feature please feel free to do so.
### Questions
We also use the GitHub discussions to Q&A.
- Open a [new discussion](https://github.com/aquasecurity/kube-bench/discussions/new) if a duplicate doesn't already exist.
- Remember users might be searching for your discussion in the future, so please give it a meaningful title to helps others.
### Pull Requests
We welcome pull requests!
- Every Pull Request should have an associated Issue, unless you are fixing a trivial documentation issue.
- We will not accept changes to LICENSE, NOTICE or CONTRIBUTING from outside the Aqua Security team. Please raise an Issue if you believe there is a problem with any of these files.
- Your PR is more likely to be accepted if it focuses on just one change.
- Describe what the PR does. There's no convention enforced, but please try to be concise and descriptive. Treat the PR description as a commit message. Titles that start with "fix"/"add"/"improve"/"remove" are good examples.
- Please add the associated Issue in the PR description.
- Please include a comment with the results before and after your change.
- There's no need to add or tag reviewers.
- If a reviewer commented on your code or asked for changes, please remember to mark the discussion as resolved after you address it. PRs with unresolved issues should not be merged (even if the comment is unclear or requires no action from your side).
- Please include a comment with the results before and after your change.
- Your PR is more likely to be accepted if it includes tests (We have not historically been very strict about tests, but we would like to improve this!).
- You're welcome to submit a draft PR if you would like early feedback on an idea or an approach.
- Happy coding!
## Testing locally with kind
Our makefile contains targets to test your current version of kube-bench inside a [Kind](https://kind.sigs.k8s.io/) cluster. This can be very handy if you don't want to run a real Kubernetes cluster for development purposes.
First, you'll need to create the cluster using `make kind-test-cluster` this will create a new cluster if it cannot be found on your machine. By default, the cluster is named `kube-bench` but you can change the name by using the environment variable `KIND_PROFILE`.
*If kind cannot be found on your system the target will try to install it using `go get`*
Next, you'll have to build the kube-bench docker image using `make build-docker`, then we will be able to push the docker image to the cluster using `make kind-push`.
Finally, we can use the `make kind-run` target to run the current version of kube-bench in the cluster and follow the logs of pods created. (Ctrl+C to exit)
Every time you want to test a change, you'll need to rebuild the docker image and push it to cluster before running it again. ( `make build-docker kind-push kind-run` )
1. Every Pull Request should have an associated Issue, unless you are fixing a trivial documentation issue.
1. We will not accept changes to LICENSE, NOTICE or CONTRIBUTING from outside the Aqua Security team. Please raise an Issue if you believe there is a problem with any of these files.
1. Your PR is more likely to be accepted if it focuses on just one change.
1. Describe what the PR does. There's no convention enforced, but please try to be concise and descriptive. Treat the PR description as a commit message. Titles that start with "fix"/"add"/"improve"/"remove" are good examples.
1. Please add the associated Issue in the PR description.
1. There's no need to add or tag reviewers.
1. If a reviewer commented on your code or asked for changes, please remember to mark the discussion as resolved after you address it. PRs with unresolved issues should not be merged (even if the comment is unclear or requires no action from your side).
1. Please include a comment with the results before and after your change.
1. Your PR is more likely to be accepted if it includes tests (We have not historically been very strict about tests, but we would like to improve this!).

View File

@@ -1,23 +1,35 @@
FROM golang:1.15 AS build
FROM golang:1.17.1 AS build
WORKDIR /go/src/github.com/aquasecurity/kube-bench/
COPY go.mod go.sum ./
COPY main.go .
COPY check/ check/
COPY cmd/ cmd/
COPY internal/ internal/
ARG KUBEBENCH_VERSION
ARG GOOS=linux
ARG GOARCH=amd64
RUN GO111MODULE=on CGO_ENABLED=0 GOOS=$GOOS GOARCH=$GOARCH go build -a -ldflags "-X github.com/aquasecurity/kube-bench/cmd.KubeBenchVersion=${KUBEBENCH_VERSION} -w" -o /go/bin/kube-bench
FROM alpine:3.12 AS run
FROM alpine:3.14.2 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
# Upgrading apk-tools to remediate CVE-2021-36159 - https://snyk.io/vuln/SNYK-ALPINE314-APKTOOLS-1533752
# https://github.com/aquasecurity/kube-bench/issues/943
RUN apk --no-cache upgrade apk-tools
# Openssl is used by OpenShift tests
# https://github.com/aquasecurity/kube-bench/issues/535
RUN apk --no-cache add openssl
# Ensuring that we update/upgrade before installing openssl, to mitigate CVE-2021-3711 and CVE-2021-3712
RUN apk update && apk upgrade && apk --no-cache add openssl
# Add glibc for running oc command
RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
RUN wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.33-r0/glibc-2.33-r0.apk
RUN apk add glibc-2.33-r0.apk
RUN apk add jq
ENV PATH=$PATH:/usr/local/mount-from-host/bin

369
README.md
View File

@@ -1,163 +1,36 @@
[![Build Status](https://travis-ci.org/aquasecurity/kube-bench.svg?branch=master)](https://travis-ci.org/aquasecurity/kube-bench)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/aquasecurity/kube-bench/blob/master/LICENSE)
[![GitHub Release][release-img]][release]
![Downloads][download]
![Docker Pulls][docker-pull]
[![Go Report Card][report-card-img]][report-card]
[![Build Status](https://github.com/aquasecurity/kube-bench/workflows/Build/badge.svg?branch=main)](https://github.com/aquasecurity/kube-bench/actions)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/aquasecurity/kube-bench/blob/main/LICENSE)
[![Docker image](https://images.microbadger.com/badges/image/aquasec/kube-bench.svg)](https://microbadger.com/images/aquasec/kube-bench "Get your own image badge on microbadger.com")
[![Source commit](https://images.microbadger.com/badges/commit/aquasec/kube-bench.svg)](https://microbadger.com/images/aquasec/kube-bench)
[![Coverage Status][cov-img]][cov]
[cov-img]: https://codecov.io/github/aquasecurity/kube-bench/branch/master/graph/badge.svg
[download]: https://img.shields.io/github/downloads/aquasecurity/kube-bench/total?logo=github
[release-img]: https://img.shields.io/github/release/aquasecurity/kube-bench.svg?logo=github
[release]: https://github.com/aquasecurity/kube-bench/releases
[docker-pull]: https://img.shields.io/docker/pulls/aquasec/kube-bench?logo=docker&label=docker%20pulls%20%2F%20kube-bench
[cov-img]: https://codecov.io/github/aquasecurity/kube-bench/branch/main/graph/badge.svg
[cov]: https://codecov.io/github/aquasecurity/kube-bench
<img src="images/kube-bench.png" width="200" alt="kube-bench logo">
[report-card-img]: https://goreportcard.com/badge/github.com/aquasecurity/kube-bench
[report-card]: https://goreportcard.com/report/github.com/aquasecurity/kube-bench
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/).
<img src="docs/images/kube-bench.png" width="200" alt="kube-bench logo">
kube-bench is a tool 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.
### Please Note
![Kubernetes Bench for Security](/docs/images/output.png "Kubernetes Bench for Security")
1. kube-bench implements the [CIS Kubernetes Benchmark](https://www.cisecurity.org/benchmark/kubernetes/) as closely as possible. Please raise issues here if kube-bench is not correctly implementing the test as described in the Benchmark. To report issues in the Benchmark itself (for example, tests that you believe are inappropriate), please join the [CIS community](https://cisecurity.org).
1. There is not a one-to-one mapping between releases of Kubernetes and releases of the CIS benchmark. See [CIS Kubernetes Benchmark support](#cis-kubernetes-benchmark-support) to see which releases of Kubernetes are covered by different releases of the benchmark.
1. It is impossible to inspect the master nodes of managed clusters, e.g. GKE, EKS and AKS, using kube-bench as one does not have access to such nodes, although it is still possible to use kube-bench to check worker node configuration in these environments.
![Kubernetes Bench for Security](https://raw.githubusercontent.com/aquasecurity/kube-bench/master/images/output.png "Kubernetes Bench for Security")
Table of Contents
=================
- [CIS Kubernetes Benchmark support](#cis-kubernetes-benchmark-support)
- [Installation](#installation)
- [Running kube-bench](#running-kube-bench)
- [Running inside a container](#running-inside-a-container)
- [Running in a Kubernetes cluster](#running-in-a-kubernetes-cluster)
- [Running in an AKS cluster](#running-in-an-aks-cluster)
- [Running in an EKS cluster](#running-in-an-eks-cluster)
- [Running on OpenShift](#running-on-openshift)
- [Running in an GKE cluster](#running-in-a-gke-cluster)
- [Installing from a container](#installing-from-a-container)
- [Installing from sources](#installing-from-sources)
- [Output](#output)
- [Configuration](#configuration)
- [Troubleshooting](#troubleshooting)
- [Test config YAML representation](#test-config-yaml-representation)
- [Omitting checks](#omitting-checks)
- [Roadmap](#roadmap)
- [Testing locally with kind](#testing-locally-with-kind)
- [Contributing](#contributing)
- [Bugs](#bugs)
- [Features](#features)
- [Pull Requests](#pull-requests)
## CIS Kubernetes Benchmark support
kube-bench supports the tests for Kubernetes as defined in the [CIS Kubernetes Benchmarks](https://www.cisecurity.org/benchmark/kubernetes/).
| CIS Kubernetes Benchmark | kube-bench config | Kubernetes versions |
|---|---|---|
| [1.5.1](https://workbench.cisecurity.org/benchmarks/4892) | cis-1.5 | 1.15- |
| [1.6.0](https://workbench.cisecurity.org/benchmarks/4834) | cis-1.6 | 1.16- |
| [GKE 1.0.0](https://workbench.cisecurity.org/benchmarks/4536) | gke-1.0 | GKE |
| [EKS 1.0.0](https://workbench.cisecurity.org/benchmarks/5190) | eks-1.0 | EKS |
| Red Hat OpenShift hardening guide | rh-0.7 | OCP 3.10-3.11 |
By default, kube-bench will determine the test set to run based on the Kubernetes version running on the machine, but please note that kube-bench does not automatically detect OpenShift and GKE - see the section below on [Running kube-bench](https://github.com/aquasecurity/kube-bench#running-kube-bench).
## Installation
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), though please note that you also need to download the config and test files from the `cfg` directory
* compile it from source.
## Running kube-bench
If you run kube-bench directly from the command line you may need to be root / sudo to have access to all the config files.
kube-bench automatically selects which `controls` to use based on the detected
node type and the version of Kubernetes a cluster is running. This behavior
can be overridden by specifying the `master` or `node` subcommand and the
`--version` flag on the command line.
The Kubernetes version can also be set with the `KUBE_BENCH_VERSION` environment variable.
The value of `--version` takes precedence over the value of `KUBE_BENCH_VERSION`.
For example, run kube-bench against a master with version auto-detection:
```
kube-bench master
```
Or run kube-bench against a worker node using the tests for Kubernetes version 1.13:
```
kube-bench node --version 1.13
```
`kube-bench` will map the `--version` to the corresponding CIS Benchmark version as indicated by the mapping table above. For example, if you specify `--version 1.15`, this is mapped to CIS Benchmark version `cis-1.15`.
Alternatively, you can specify `--benchmark` to run a specific CIS Benchmark version:
```
kube-bench node --benchmark cis-1.5
```
If you want to target specific CIS Benchmark `target` (i.e master, node, etcd, etc...)
you can use the `run --targets` subcommand.
```
kube-bench --benchmark cis-1.5 run --targets master,node
```
or
```
kube-bench --benchmark cis-1.5 run --targets master,node,etcd,policies
```
The following table shows the valid targets based on the CIS Benchmark version.
| CIS Benchmark | Targets |
|---|---|
| cis-1.5| master, controlplane, node, etcd, policies |
| cis-1.6| master, controlplane, node, etcd, policies |
| gke-1.0| master, controlplane, node, etcd, policies, managedservices |
| eks-1.0| controlplane, node, policies, managedservices |
If no targets are specified, `kube-bench` will determine the appropriate targets based on the CIS Benchmark version.
`controls` for the various versions of CIS Benchmark can be found in directories
with same name as the CIS Benchmark versions under `cfg/`, for example `cfg/cis-1.5`.
**Note:** **`It is an error to specify both --version and --benchmark flags together`**
### Running inside a container
You can avoid installing kube-bench on the host by running it inside a container using the host PID namespace and mounting the `/etc` and `/var` directories where the configuration and other files are located on the host so that kube-bench can check their existence and permissions.
```
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -t aquasec/kube-bench:latest [master|node] --version 1.13
```
> Note: the tests require either the kubelet or kubectl binary in the path in order to auto-detect the Kubernetes version. You can pass `-v $(which kubectl):/usr/local/mount-from-host/bin/kubectl` to resolve this. You will also need to pass in kubeconfig credentials. For example:
```
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -v $(which kubectl):/usr/local/mount-from-host/bin/kubectl -v ~/.kube:/.kube -e KUBECONFIG=/.kube/config -t aquasec/kube-bench:latest [master|node]
```
You can use your own configs by mounting them over the default ones in `/opt/kube-bench/cfg/`
```
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -t -v path/to/my-config.yaml:/opt/kube-bench/cfg/config.yam -v $(which kubectl):/usr/local/mount-from-host/bin/kubectl -v ~/.kube:/.kube -e KUBECONFIG=/.kube/config aquasec/kube-bench:latest [master|node]
```
### Running in a Kubernetes cluster
### Quick start
There are multiple ways to run kube-bench.
You can run kube-bench inside a pod, but it will need access to the host's PID namespace in order to check the running processes, as well as access to some directories on the host where config files and other files are stored.
Master nodes are automatically detected by kube-bench and will run master checks when possible.
The detection is done by verifying that mandatory components for master, as defined in the config files, are running (see [Configuration](#configuration)).
The supplied `job.yaml` file can be applied to run the tests as a job. For example:
The supplied `job.yaml` [file](job.yaml) can be applied to run the tests as a job. For example:
```bash
$ kubectl apply -f job.yaml
@@ -178,206 +51,22 @@ kubectl logs kube-bench-j76s9
[INFO] 1.1 API Server
...
```
For more information and different ways to run kube-bench see [documentation](docs/running.md)
### Please Note
You can still force to run specific master or node checks using respectively `job-master.yaml` and `job-node.yaml`.
1. kube-bench implements the [CIS Kubernetes Benchmark](https://www.cisecurity.org/benchmark/kubernetes/) as closely as possible. Please raise issues here if kube-bench is not correctly implementing the test as described in the Benchmark. To report issues in the Benchmark itself (for example, tests that you believe are inappropriate), please join the [CIS community](https://cisecurity.org).
To run the tests on the master node, the pod needs to be scheduled on that node. This involves setting a nodeSelector and tolerations in the pod spec.
The default labels applied to master nodes has changed since Kubernetes 1.11, so if you are using an older version you may need to modify the nodeSelector and tolerations to run the job on the master node.
1. There is not a one-to-one mapping between releases of Kubernetes and releases of the CIS benchmark. See [CIS Kubernetes Benchmark support](docs/platforms.md#cis-kubernetes-benchmark-support) to see which releases of Kubernetes are covered by different releases of the benchmark.
### Running in an AKS cluster
By default, kube-bench will determine the test set to run based on the Kubernetes version running on the machine.
- see the following documentation on [Running kube-bench](docs/running.md#running-kube-bench) for more details.
1. Create an AKS cluster(e.g. 1.13.7) with RBAC enabled, otherwise there would be 4 failures
1. Use the [kubectl-enter plugin] (https://github.com/kvaps/kubectl-enter) to shell into a node
`
kubectl-enter {node-name}
`
or ssh to one agent node
could open nsg 22 port and assign a public ip for one agent node (only for testing purpose)
1. Run CIS benchmark to view results:
```
docker run --rm -v `pwd`:/host aquasec/kube-bench:latest install
./kube-bench node
```
kube-bench cannot be run on AKS master nodes
### Running in an EKS cluster
There is a `job-eks.yaml` file for running the kube-bench node checks on an EKS cluster. The significant difference on EKS is that it's not possible to schedule jobs onto the master node, so master checks can't be performed
1. To create an EKS Cluster refer to [Getting Started with Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) in the *Amazon EKS User Guide*
- Information on configuring `eksctl`, `kubectl` and the AWS CLI is within
2. Create an [Amazon Elastic Container Registry (ECR)](https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html) repository to host the kube-bench container image
```
aws ecr create-repository --repository-name k8s/kube-bench --image-tag-mutability MUTABLE
```
3. Download, build and push the kube-bench container image to your ECR repo
```
git clone https://github.com/aquasecurity/kube-bench.git
cd kube-bench
aws ecr get-login-password --region <AWS_REGION> | docker login --username <AWS_USERNAME> --password-stdin <AWS_ACCT_NUMBER>.dkr.ecr.<AWS_REGION>.amazonaws.com
docker build -t k8s/kube-bench .
docker tag k8s/kube-bench:latest <AWS_ACCT_NUMBER>.dkr.ecr.<AWS_REGION>.amazonaws.com/k8s/kube-bench:latest
docker push <AWS_ACCT_NUMBER>.dkr.ecr.<AWS_REGION>.amazonaws.com/k8s/kube-bench:latest
```
4. Copy the URI of your pushed image, the URI format is like this: `<AWS_ACCT_NUMBER>.dkr.ecr.<AWS_REGION>.amazonaws.com/k8s/kube-bench:latest`
5. Replace the `image` value in `job-eks.yaml` with the URI from Step 4
6. Run the kube-bench job on a Pod in your Cluster: `kubectl apply -f job-eks.yaml`
7. Find the Pod that was created, it *should* be in the `default` namespace: `kubectl get pods --all-namespaces`
8. Retrieve the value of this Pod and output the report, note the Pod name will vary: `kubectl logs kube-bench-<value>`
- You can save the report for later reference: `kubectl logs kube-bench-<value> > kube-bench-report.txt`
### Running on OpenShift
| OpenShift Hardening Guide | kube-bench config |
|---|---|
| ocp-3.10| rh-0.7 |
| ocp-3.11| rh-0.7 |
| ocp-4.* | Not supported |
kube-bench includes a set of test files for Red Hat's OpenShift hardening guide for OCP 3.10 and 3.11. To run this you will need to specify `--benchmark rh-07`, or `--version ocp-3.10` or `--version ocp-3.11`
when you run the `kube-bench` command (either directly or through YAML).
There is work in progress on a [CIS Red Hat OpenShift Container Platform Benchmark](https://workbench.cisecurity.org/benchmarks/5248) which we believe should cover OCP 4.* and we intend to add support in kube-bench when it's published.
### Running in a GKE cluster
| CIS Benchmark | Targets |
|---|---|
| gke-1.0| master, controlplane, node, etcd, policies, managedservices |
kube-bench includes benchmarks for GKE. To run this you will need to specify `--benchmark gke-1.0` when you run the `kube-bench` command.
To run the benchmark as a job in your GKE cluster apply the included `job-gke.yaml`.
```
kubectl apply -f job-gke.yaml
```
### Installing from a container
This command copies the kube-bench binary and configuration files to your host from the Docker container:
** binaries compiled for linux-x86-64 only (so they won't run on macOS or Windows) **
```
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
cd $GOPATH/src/github.com/aquasecurity/kube-bench
go build -o kube-bench .
# See all supported options
./kube-bench --help
# Run all checks
./kube-bench
```
## Output
There are four output states:
- [PASS] indicates that the test was run successfully, and passed.
- [FAIL] indicates that the test was run successfully, and failed. The remediation output describes how to correct the configuration, or includes an error message describing why the test could not be run.
- [WARN] means this test needs further attention, for example it is a test that needs to be run manually. Check the remediation output for further information.
- [INFO] is informational output that needs no further action.
Note:
- If the test is Manual, this always generates WARN (because the user has to run it manually)
- If the test is Scored, and kube-bench was unable to run the test, this generates FAIL (because the test has not been passed, and as a Scored test, if it doesn't pass then it must be considered a failure).
- If the test is Not Scored, and kube-bench was unable to run the test, this generates WARN.
- If the test is Scored, type is empty, and there are no `test_items` present, it generates a WARN. This is to highlight tests that appear to be incompletely defined.
## Configuration
Kubernetes configuration and binary file locations and names can vary from installation to installation, so these are configurable in the `cfg/config.yaml` file.
Any settings in the version-specific config file `cfg/<version>/config.yaml` take precedence over settings in the main `cfg/config.yaml` file.
You can read more about `kube-bench` configuration in our [documentation](docs/README.md#configuration-and-variables).
## Troubleshooting
Running `kube-bench` with the `-v 3` parameter will generate debug logs that can be very helpful for debugging problems.
If you are using one of the example `job*.yaml` files, you will need to edit the `command` field, for example `["kube-bench", "-v", "3"]`. Once the job has run, the logs can be retrieved using `kubectl logs` on the job's pod.
## Test config YAML representation
The tests (or "controls") are represented as YAML documents (installed by default into `./cfg`). There are different versions of these test YAML files reflecting different versions of the CIS Kubernetes Benchmark. You will find more information about the test file YAML definitions in our [documentation](docs/README.md).
### Omitting checks
If you decide that a recommendation is not appropriate for your environment, you can choose to omit it by editing the test YAML file to give it the check type `skip` as in this example:
```yaml
checks:
- id: 2.1.1
text: "Ensure that the --allow-privileged argument is set to false (Scored)"
type: "skip"
scored: true
```
No tests will be run for this check and the output will be marked [INFO].
## Contributing
Kindly read [Contributing](CONTRIBUTING.md) before contributing.
We welcome PRs and issue reports.
## Roadmap
Going forward we plan to release updates to kube-bench to add support for new releases of the CIS Benchmark. Note that these are not released as frequently as Kubernetes releases.
We welcome PRs and issue reports.
## Testing locally with kind
Our makefile contains targets to test your current version of kube-bench inside a [Kind](https://kind.sigs.k8s.io/) cluster. This can be very handy if you don't want to run a real Kubernetes cluster for development purposes.
First, you'll need to create the cluster using `make kind-test-cluster` this will create a new cluster if it cannot be found on your machine. By default, the cluster is named `kube-bench` but you can change the name by using the environment variable `KIND_PROFILE`.
*If kind cannot be found on your system the target will try to install it using `go get`*
Next, you'll have to build the kube-bench docker image using `make build-docker`, then we will be able to push the docker image to the cluster using `make kind-push`.
Finally, we can use the `make kind-run` target to run the current version of kube-bench in the cluster and follow the logs of pods created. (Ctrl+C to exit)
Every time you want to test a change, you'll need to rebuild the docker image and push it to cluster before running it again. ( `make build-docker kind-push kind-run` )
## Contributing
### Bugs
If you think you have found a bug please follow the instructions below.
- Please spend a small amount of time giving due diligence to the issue tracker. Your issue might be a duplicate.
- Open a [new issue](https://github.com/aquasecurity/kube-bench/issues/new) if a duplicate doesn't already exist.
- Note the version of kube-bench you are running (from `kube-bench version`) and the command line options you are using.
- Note the version of Kubernetes you are running (from `kubectl version` or `oc version` for OpenShift).
- Set `-v 10` command line option and save the log output. Please paste this into your issue.
- Remember users might be searching for your issue in the future, so please give it a meaningful title to help others.
### Features
We also use the GitHub issue tracker to track feature requests. If you have an idea to make kube-bench even more awesome follow the steps below.
- Open a [new issue](https://github.com/aquasecurity/kube-bench/issues/new).
- Remember users might be searching for your issue in the future, so please give it a meaningful title to helps others.
- Clearly define the use case, using concrete examples. For example, I type `this` and kube-bench does `that`.
- If you would like to include a technical design for your feature please feel free to do so.
### Pull Requests
We welcome pull requests!
- Your PR is more likely to be accepted if it focuses on just one change.
- Please include a comment with the results before and after your change.
- Your PR is more likely to be accepted if it includes tests. (We have not historically been very strict about tests, but we would like to improve this!).
- You're welcome to submit a draft PR if you would like early feedback on an idea or an approach.
- Happy coding!

2
cfg/ack-1.0/config.yaml Normal file
View File

@@ -0,0 +1,2 @@
---
## Version-specific settings that override the values in cfg/config.yaml

View File

@@ -0,0 +1,39 @@
---
controls:
version: "ack-1.0"
id: 3
text: "Control Plane Configuration"
type: "controlplane"
groups:
- id: 3.1
text: "Authentication and Authorization"
checks:
- id: 3.1.1
text: "Revoke client certificate when possible leakage (Manual)"
type: "manual"
remediation: |
Kubernetes provides the option to use client certificates for user authentication.
ACK issues kubeconfig with its client certificates as the user credentials for connecing to target cluster.
User should revoke his/her issued kubeconfig when possible leakage.
scored: false
- id: 3.2
text: "Logging"
checks:
- id: 3.2.1
text: "Ensure that a minimal audit policy is created (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-policy-file"
remediation: |
Create an audit policy file for your cluster.
scored: false
- id: 3.2.2
text: "Ensure that the audit policy covers key security concerns (Manual)"
type: "manual"
remediation: |
Consider modification of the audit policy in use on the cluster to include these items, at a
minimum.
scored: false

135
cfg/ack-1.0/etcd.yaml Normal file
View File

@@ -0,0 +1,135 @@
---
controls:
version: "ack-1.0"
id: 2
text: "Etcd Node Configuration"
type: "etcd"
groups:
- id: 2
text: "Etcd Node Configuration Files"
checks:
- id: 2.1
text: "Ensure that the --cert-file and --key-file arguments are set as appropriate (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
bin_op: and
test_items:
- flag: "--cert-file"
env: "ETCD_CERT_FILE"
- flag: "--key-file"
env: "ETCD_KEY_FILE"
remediation: |
Follow the etcd service documentation and configure TLS encryption.
Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml
on the master node and set the below parameters.
--cert-file=</path/to/ca-file>
--key-file=</path/to/key-file>
scored: true
- id: 2.2
text: "Ensure that the --client-cert-auth argument is set to true (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
test_items:
- flag: "--client-cert-auth"
env: "ETCD_CLIENT_CERT_AUTH"
compare:
op: eq
value: true
remediation: |
Edit the etcd pod specification file $etcdconf on the master
node and set the below parameter.
--client-cert-auth="true"
scored: true
- id: 2.3
text: "Ensure that the --auto-tls argument is not set to true (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--auto-tls"
env: "ETCD_AUTO_TLS"
set: false
- flag: "--auto-tls"
env: "ETCD_AUTO_TLS"
compare:
op: eq
value: false
remediation: |
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
- id: 2.4
text: "Ensure that the --peer-cert-file and --peer-key-file arguments are
set as appropriate (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
bin_op: and
test_items:
- flag: "--peer-cert-file"
env: "ETCD_PEER_CERT_FILE"
- flag: "--peer-key-file"
env: "ETCD_PEER_KEY_FILE"
remediation: |
Follow the etcd service documentation and configure peer TLS encryption as appropriate
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>
scored: true
- id: 2.5
text: "Ensure that the --peer-client-cert-auth argument is set to true (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
test_items:
- flag: "--peer-client-cert-auth"
env: "ETCD_PEER_CLIENT_CERT_AUTH"
compare:
op: eq
value: true
remediation: |
Edit the etcd pod specification file $etcdconf on the master
node and set the below parameter.
--peer-client-cert-auth=true
scored: true
- id: 2.6
text: "Ensure that the --peer-auto-tls argument is not set to true (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--peer-auto-tls"
env: "ETCD_PEER_AUTO_TLS"
set: false
- flag: "--peer-auto-tls"
env: "ETCD_PEER_AUTO_TLS"
compare:
op: eq
value: false
remediation: |
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
- id: 2.7
text: "Ensure that a unique Certificate Authority is used for etcd (Manual)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
test_items:
- flag: "--trusted-ca-file"
env: "ETCD_TRUSTED_CA_FILE"
remediation: |
[Manual test]
Follow the etcd documentation and create a dedicated certificate authority setup for the
etcd service.
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

View File

@@ -0,0 +1,127 @@
---
controls:
version: "ack-1.0"
id: 6
text: "Managed Services"
type: "managedservices"
groups:
- id: 6.1
text: "Image Registry and Image Scanning"
checks:
- id: 6.1.1
text: "Ensure Image Vulnerability Scanning using ACR image scanning or a third party provider (Manual)"
type: "manual"
remediation: |
Ensure Image Vulnerability Scanning using ACR image scanning or a third party provider by follow the ACR document: https://www.alibabacloud.com/help/doc-detail/160146.htm
scored: false
- id: 6.1.2
text: "Minimize user access to ACR (Manual)"
type: "manual"
remediation: |
Minimize user access to ACR by follow the ACR document to setup network access control: https://www.alibabacloud.com/help/doc-detail/142179.htm
And follow the ACR document to setup Resource Access Management (RAM) policies for ACR: https://www.alibabacloud.com/help/doc-detail/144229.htm
scored: false
- id: 6.1.3
text: "Minimize cluster access to read-only for ACR (Manual)"
type: "manual"
remediation: Minimize cluster access to read-only for ACR
scored: false
- id: 6.1.4
text: "Minimize Container Registries to only those approved (Manual)"
type: "manual"
remediation: Minimize Container Registries to only those approved
scored: false
- id: 6.2
text: "Key Management Service (KMS)"
checks:
- id: 6.2.1
text: "Ensure Kubernetes Secrets are encrypted using keys managed in KMS (Manual)"
type: "manual"
remediation: |
Ensure Kubernetes Secrets are encrypted using keys managed in KMS by follow The ACK document: https://www.alibabacloud.com/help/zh/doc-detail/177372.htm
scored: false
- id: 6.3
text: "Cluster Networking"
checks:
- id: 6.3.1
text: "Restrict Access to the Control Plane Endpoint (Manual)"
type: "manual"
remediation: Restrict Access to the Control Plane Endpoint
scored: false
- id: 6.3.2
text: "Ensure clusters are created with Private Endpoint Enabled and Public Access Disabled (Manual)"
type: "manual"
remediation: Ensure clusters are created with Private Endpoint Enabled and Public Access Disabled
scored: false
- id: 6.3.3
text: "Ensure clusters are created with Private Nodes (Manual)"
type: "manual"
remediation: Ensure clusters are created with Private Nodes
scored: false
- id: 6.3.4
text: "Ensure Network Policy is Enabled and set as appropriate (Manual)"
type: "manual"
remediation: Ensure Network Policy is Enabled and set as appropriate
scored: false
- id: 6.3.5
text: "Encrypt traffic to HTTPS load balancers with TLS certificates (Manual)"
type: "manual"
remediation: Encrypt traffic to HTTPS load balancers with TLS certificates
scored: false
- id: 6.4
text: "Storage"
checks:
- id: 6.4.1
text: "Enable data disk encryption for Alibaba Cloud Disks (Manual)"
type: "manual"
remediation: Enable data disk encryption for Alibaba Cloud Disks
scored: false
- id: 6.5
text: "Logging"
checks:
- id: 6.5.1
text: "Ensure Cluster Auditing is Enabled (Manual)"
type: "manual"
remediation: Ensure Cluster Auditing is Enabled
scored: false
- id: 6.6
text: "Other Cluster Configurations"
checks:
- id: 6.6.1
text: "Ensure Pod Security Policy is Enabled and set as appropriate (Manual)"
type: "manual"
remediation: Ensure Pod Security Policy is Enabled and set as appropriate
scored: false
- id: 6.6.2
text: "Enable Cloud Security Center (Manual)"
type: "manual"
remediation: Enable Cloud Security Center
scored: false
- id: 6.6.3
text: "Consider ACK Sandboxed-Container for running untrusted workloads (Manual)"
type: "manual"
remediation: Consider ACK Sandboxed-Container for running untrusted workloads
- id: 6.6.4
text: "Consider ACK TEE-based when running confidential computing (Manual)"
type: "manual"
remediation: Consider ACK TEE-based when running confidential computing
- id: 6.6.5
text: "Consider use service account token volume projection (Manual)"
type: "manual"
remediation: Consider use service account token volume projection

968
cfg/ack-1.0/master.yaml Normal file
View File

@@ -0,0 +1,968 @@
---
controls:
version: "ack-1.0"
id: 1
text: "Master Node Security Configuration"
type: "master"
groups:
- id: 1.1
text: "Master Node Configuration Files"
checks:
- id: 1.1.1
text: "Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $apiserverconf; then stat -c permissions=%a $apiserverconf; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the
master node.
For example, chmod 644 $apiserverconf
scored: true
- id: 1.1.2
text: "Ensure that the API server pod specification file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $apiserverconf; then stat -c %U:%G $apiserverconf; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $apiserverconf
scored: true
- id: 1.1.3
text: "Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $controllermanagerconf; then stat -c permissions=%a $controllermanagerconf; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 $controllermanagerconf
scored: true
- id: 1.1.4
text: "Ensure that the controller manager pod specification file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $controllermanagerconf; then stat -c %U:%G $controllermanagerconf; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $controllermanagerconf
scored: true
- id: 1.1.5
text: "Ensure that the scheduler pod specification file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $schedulerconf; then stat -c permissions=%a $schedulerconf; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 $schedulerconf
scored: true
- id: 1.1.6
text: "Ensure that the scheduler pod specification file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $schedulerconf; then stat -c %U:%G $schedulerconf; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $schedulerconf
scored: true
- id: 1.1.7
text: "Ensure that the etcd service file permissions are set to 644 or more restrictive (Automated)"
audit: |
stat -c permissions=%a /usr/lib/systemd/system/etcd.service || \
if test -e $etcdconf; then find $etcdconf -name '*etcd*' | xargs stat -c permissions=%a; fi
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 $etcdconf
scored: true
- id: 1.1.8
text: "Ensure that the etcd service file ownership is set to root:root (Automated)"
audit: |
stat -c %U:%G /usr/lib/systemd/system/etcd.service || \
if test -e $etcdconf; then find $etcdconf -name '*etcd*' | xargs stat -c %U:%G; fi
use_multiple_values: true
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $etcdconf
scored: true
- id: 1.1.9
text: "Ensure that the Container Network Interface file permissions are set to 644 or more restrictive (Manual)"
audit: "stat -c permissions=%a <path/to/cni/files>"
type: "manual"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 <path/to/cni/files>
scored: false
- id: 1.1.10
text: "Ensure that the Container Network Interface file ownership is set to root:root (Manual)"
audit: "stat -c %U:%G <path/to/cni/files>"
type: "manual"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root <path/to/cni/files>
scored: false
- id: 1.1.11
text: "Ensure that the etcd data directory permissions are set to 700 or more restrictive (Automated)"
audit: |
stat -c permissions=%a /var/lib/etcd/data.etcd || \
ps -ef | grep $etcdbin | grep -- --data-dir | sed 's%.*data-dir[= ]\([^ ]*\).*%\1%' | xargs stat -c permissions=%a
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "700"
remediation: |
On the etcd server node, get the etcd data directory, passed as an argument --data-dir,
from the below command:
ps -ef | grep etcd
Run the below command (based on the etcd data directory found above). For example,
chmod 700 /var/lib/etcd
scored: true
- id: 1.1.12
text: "Ensure that the etcd data directory ownership is set to etcd:etcd (Automated)"
audit: |
stat -c %U:%G /var/lib/etcd/data.etcd || \
ps -ef | grep $etcdbin | grep -- --data-dir | sed 's%.*data-dir[= ]\([^ ]*\).*%\1%' | xargs stat -c %U:%G
tests:
test_items:
- flag: "etcd:etcd"
remediation: |
On the etcd server node, get the etcd data directory, passed as an argument --data-dir,
from the below command:
ps -ef | grep etcd
Run the below command (based on the etcd data directory found above).
For example, chown etcd:etcd /var/lib/etcd
scored: true
- id: 1.1.13
text: "Ensure that the admin.conf file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e /etc/kubernetes/admin.conf; then stat -c permissions=%a /etc/kubernetes/admin.conf; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 /etc/kubernetes/admin.conf
scored: true
- id: 1.1.14
text: "Ensure that the admin.conf file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e /etc/kubernetes/admin.conf; then stat -c %U:%G /etc/kubernetes/admin.conf; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root /etc/kubernetes/admin.conf
scored: true
- id: 1.1.15
text: "Ensure that the scheduler.conf file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $schedulerkubeconfig; then stat -c permissions=%a $schedulerkubeconfig; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 $schedulerkubeconfig
scored: true
- id: 1.1.16
text: "Ensure that the scheduler.conf file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $schedulerkubeconfig; then stat -c %U:%G $schedulerkubeconfig; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $schedulerkubeconfig
scored: true
- id: 1.1.17
text: "Ensure that the controller-manager.conf file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $controllermanagerkubeconfig; then stat -c permissions=%a $controllermanagerkubeconfig; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 $controllermanagerkubeconfig
scored: true
- id: 1.1.18
text: "Ensure that the controller-manager.conf file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $controllermanagerkubeconfig; then stat -c %U:%G $controllermanagerkubeconfig; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $controllermanagerkubeconfig
scored: true
- id: 1.1.19
text: "Ensure that the Kubernetes PKI directory and file ownership is set to root:root (Automated)"
audit: "find /etc/kubernetes/pki/ | xargs stat -c %U:%G"
use_multiple_values: true
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown -R root:root /etc/kubernetes/pki/
scored: true
- id: 1.1.20
text: "Ensure that the Kubernetes PKI certificate file permissions are set to 644 or more restrictive (Manual)"
audit: "find /etc/kubernetes/pki -name '*.crt' | xargs stat -c permissions=%a"
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod -R 644 /etc/kubernetes/pki/*.crt
scored: false
- id: 1.1.21
text: "Ensure that the Kubernetes PKI key file permissions are set to 600 (Manual)"
audit: "find /etc/kubernetes/pki -name '*.key' | xargs stat -c permissions=%a"
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "600"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod -R 600 /etc/kubernetes/pki/*.key
scored: false
- id: 1.2
text: "API Server"
checks:
- id: 1.2.1
text: "Ensure that the --basic-auth-file argument is not set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--basic-auth-file"
set: false
remediation: |
Follow the documentation and configure alternate mechanisms for authentication. Then,
edit the API server pod specification file $apiserverconf
on the master node and remove the --basic-auth-file=<filename> parameter.
scored: true
- id: 1.2.2
text: "Ensure that the --token-auth-file parameter is not set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--token-auth-file"
set: false
remediation: |
Follow the documentation and configure alternate mechanisms for authentication. Then,
edit the API server pod specification file $apiserverconf
on the master node and remove the --token-auth-file=<filename> parameter.
scored: true
- id: 1.2.3
text: "Ensure that the --kubelet-https argument is set to true (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--kubelet-https"
compare:
op: eq
value: true
- flag: "--kubelet-https"
set: false
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and remove the --kubelet-https parameter.
scored: true
- id: 1.2.4
text: "Ensure that the --kubelet-client-certificate and --kubelet-client-key arguments are set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: and
test_items:
- flag: "--kubelet-client-certificate"
- flag: "--kubelet-client-key"
remediation: |
Follow the Kubernetes documentation and set up the TLS connection between the
apiserver and kubelets. Then, edit API server pod specification file
$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>
scored: true
- id: 1.2.5
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--authorization-mode"
compare:
op: nothave
value: "AlwaysAllow"
remediation: |
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.
--authorization-mode=RBAC
scored: true
- id: 1.2.6
text: "Ensure that the --authorization-mode argument includes Node (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--authorization-mode"
compare:
op: has
value: "Node"
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the --authorization-mode parameter to a value that includes Node.
--authorization-mode=Node,RBAC
scored: true
- id: 1.2.7
text: "Ensure that the --authorization-mode argument includes RBAC (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--authorization-mode"
compare:
op: has
value: "RBAC"
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the --authorization-mode parameter to a value that includes RBAC,
for example:
--authorization-mode=Node,RBAC
scored: true
- id: 1.2.8
text: "Ensure that the admission control plugin EventRateLimit is set (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--enable-admission-plugins"
compare:
op: has
value: "EventRateLimit"
remediation: |
Follow the Kubernetes documentation and set the desired limits in a configuration file.
Then, edit the API server pod specification file $apiserverconf
and set the below parameters.
--enable-admission-plugins=...,EventRateLimit,...
--admission-control-config-file=<path/to/configuration/file>
scored: false
- id: 1.2.9
text: "Ensure that the admission control plugin AlwaysAdmit is not set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--enable-admission-plugins"
compare:
op: nothave
value: AlwaysAdmit
- flag: "--enable-admission-plugins"
set: false
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and either remove the --enable-admission-plugins parameter, or set it to a
value that does not include AlwaysAdmit.
scored: true
- id: 1.2.10
text: "Ensure that the admission control plugin AlwaysPullImages is set (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--enable-admission-plugins"
compare:
op: has
value: "AlwaysPullImages"
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the --enable-admission-plugins parameter to include
AlwaysPullImages.
--enable-admission-plugins=...,AlwaysPullImages,...
scored: false
- id: 1.2.11
text: "Ensure that the admission control plugin SecurityContextDeny is set if PodSecurityPolicy is not used (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--enable-admission-plugins"
compare:
op: has
value: "SecurityContextDeny"
- flag: "--enable-admission-plugins"
compare:
op: has
value: "PodSecurityPolicy"
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the --enable-admission-plugins parameter to include
SecurityContextDeny, unless PodSecurityPolicy is already in place.
--enable-admission-plugins=...,SecurityContextDeny,...
scored: false
- id: 1.2.12
text: "Ensure that the admission control plugin ServiceAccount is set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--disable-admission-plugins"
compare:
op: nothave
value: "ServiceAccount"
- flag: "--disable-admission-plugins"
set: false
remediation: |
Follow the documentation and create ServiceAccount objects as per your environment.
Then, edit the API server pod specification file $apiserverconf
on the master node and ensure that the --disable-admission-plugins parameter is set to a
value that does not include ServiceAccount.
scored: true
- id: 1.2.13
text: "Ensure that the admission control plugin NamespaceLifecycle is set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--disable-admission-plugins"
compare:
op: nothave
value: "NamespaceLifecycle"
- flag: "--disable-admission-plugins"
set: false
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the --disable-admission-plugins parameter to
ensure it does not include NamespaceLifecycle.
scored: true
- id: 1.2.14
text: "Ensure that the admission control plugin PodSecurityPolicy is set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--enable-admission-plugins"
compare:
op: has
value: "PodSecurityPolicy"
remediation: |
Follow the documentation and create Pod Security Policy objects as per your environment.
Then, edit the API server pod specification file $apiserverconf
on the master node and set the --enable-admission-plugins parameter to a
value that includes PodSecurityPolicy:
--enable-admission-plugins=...,PodSecurityPolicy,...
Then restart the API Server.
scored: true
- id: 1.2.15
text: "Ensure that the admission control plugin NodeRestriction is set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--enable-admission-plugins"
compare:
op: has
value: "NodeRestriction"
remediation: |
Follow the Kubernetes documentation and configure NodeRestriction plug-in on kubelets.
Then, edit the API server pod specification file $apiserverconf
on the master node and set the --enable-admission-plugins parameter to a
value that includes NodeRestriction.
--enable-admission-plugins=...,NodeRestriction,...
scored: true
- id: 1.2.16
text: "Ensure that the --insecure-bind-address argument is not set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--insecure-bind-address"
set: false
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and remove the --insecure-bind-address parameter.
scored: true
- id: 1.2.17
text: "Ensure that the --insecure-port argument is set to 0 (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--insecure-port"
compare:
op: eq
value: 0
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the below parameter.
--insecure-port=0
scored: true
- id: 1.2.18
text: "Ensure that the --secure-port argument is not set to 0 (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--secure-port"
compare:
op: gt
value: 0
- flag: "--secure-port"
set: false
remediation: |
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
- id: 1.2.19
text: "Ensure that the --profiling argument is set to false (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--profiling"
compare:
op: eq
value: false
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the below parameter.
--profiling=false
scored: true
- id: 1.2.20
text: "Ensure that the --audit-log-path argument is set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-log-path"
remediation: |
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
scored: true
- id: 1.2.21
text: "Ensure that the --audit-log-maxage argument is set to 30 or as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-log-maxage"
compare:
op: gte
value: 30
remediation: |
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
scored: true
- id: 1.2.22
text: "Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-log-maxbackup"
compare:
op: gte
value: 10
remediation: |
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
scored: true
- id: 1.2.23
text: "Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-log-maxsize"
compare:
op: gte
value: 100
remediation: |
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
scored: true
- id: 1.2.24
text: "Ensure that the --request-timeout argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
type: manual
remediation: |
Edit the API server pod specification file $apiserverconf
and set the below parameter as appropriate and if needed.
For example,
--request-timeout=300s
scored: true
- id: 1.2.25
text: "Ensure that the --service-account-lookup argument is set to true (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--service-account-lookup"
set: false
- flag: "--service-account-lookup"
compare:
op: eq
value: true
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the below parameter.
--service-account-lookup=true
Alternatively, you can delete the --service-account-lookup parameter from this file so
that the default takes effect.
scored: true
- id: 1.2.26
text: "Ensure that the --service-account-key-file argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--service-account-key-file"
remediation: |
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>
scored: true
- id: 1.2.27
text: "Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: and
test_items:
- flag: "--etcd-certfile"
- flag: "--etcd-keyfile"
remediation: |
Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd.
Then, edit the API server pod specification file $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>
scored: true
- id: 1.2.28
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: and
test_items:
- flag: "--tls-cert-file"
- flag: "--tls-private-key-file"
remediation: |
Follow the Kubernetes documentation and set up the TLS connection on the apiserver.
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>
--tls-private-key-file=<path/to/tls-key-file>
scored: true
- id: 1.2.29
text: "Ensure that the --client-ca-file argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--client-ca-file"
remediation: |
Follow the Kubernetes documentation and set up the TLS connection on the apiserver.
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
- id: 1.2.30
text: "Ensure that the --etcd-cafile argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--etcd-cafile"
remediation: |
Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd.
Then, edit the API server pod specification file $apiserverconf
on the master node and set the etcd certificate authority file parameter.
--etcd-cafile=<path/to/ca-file>
scored: true
- id: 1.2.31
text: "Ensure that the --encryption-provider-config argument is set as appropriate (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--encryption-provider-config"
remediation: |
Follow the Kubernetes documentation and configure a EncryptionConfig file.
Then, edit the API server pod specification file $apiserverconf
on the master node and set the --encryption-provider-config parameter to the path of that file: --encryption-provider-config=</path/to/EncryptionConfig/File>
scored: false
- id: 1.2.32
text: "Ensure that encryption providers are appropriately configured (Manual)"
audit: |
ENCRYPTION_PROVIDER_CONFIG=$(ps -ef | grep $apiserverbin | grep -- --encryption-provider-config | sed 's%.*encryption-provider-config[= ]\([^ ]*\).*%\1%')
if test -e $ENCRYPTION_PROVIDER_CONFIG; then grep -A1 'providers:' $ENCRYPTION_PROVIDER_CONFIG | tail -n1 | grep -o "[A-Za-z]*" | sed 's/^/provider=/'; fi
tests:
test_items:
- flag: "provider"
compare:
op: valid_elements
value: "aescbc,kms,secretbox"
remediation: |
Follow the Kubernetes documentation and configure a EncryptionConfig file.
In this file, choose aescbc, kms or secretbox as the encryption provider.
scored: false
- id: 1.2.33
text: "Ensure that the API Server only makes use of Strong Cryptographic Ciphers (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--tls-cipher-suites"
compare:
op: valid_elements
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"
remediation: |
Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml
on the master 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
scored: false
- id: 1.3
text: "Controller Manager"
checks:
- id: 1.3.1
text: "Ensure that the --terminated-pod-gc-threshold argument is set as appropriate (Manual)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
test_items:
- flag: "--terminated-pod-gc-threshold"
remediation: |
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: false
- id: 1.3.2
text: "Ensure that the --profiling argument is set to false (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
test_items:
- flag: "--profiling"
compare:
op: eq
value: false
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
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 to true (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
test_items:
- flag: "--use-service-account-credentials"
compare:
op: noteq
value: false
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
on the master node to set the below parameter.
--use-service-account-credentials=true
scored: true
- id: 1.3.4
text: "Ensure that the --service-account-private-key-file argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
test_items:
- flag: "--service-account-private-key-file"
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
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>
scored: true
- id: 1.3.5
text: "Ensure that the --root-ca-file argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
test_items:
- flag: "--root-ca-file"
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
on the master node and set the --root-ca-file parameter to the certificate bundle file`.
--root-ca-file=<path/to/file>
scored: true
- id: 1.3.6
text: "Ensure that the RotateKubeletServerCertificate argument is set to true (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--feature-gates"
compare:
op: nothave
value: "RotateKubeletServerCertificate=false"
set: true
- flag: "--feature-gates"
set: false
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
on the master node and set the --feature-gates parameter to include RotateKubeletServerCertificate=true.
--feature-gates=RotateKubeletServerCertificate=true
scored: true
- id: 1.3.7
text: "Ensure that the --bind-address argument is set to 127.0.0.1 (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--bind-address"
compare:
op: eq
value: "127.0.0.1"
- flag: "--bind-address"
set: false
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
on the master node and ensure the correct value for the --bind-address parameter
scored: true
- id: 1.4
text: "Scheduler"
checks:
- id: 1.4.1
text: "Ensure that the --profiling argument is set to false (Automated)"
audit: "/bin/ps -ef | grep $schedulerbin | grep -v grep"
tests:
test_items:
- flag: "--profiling"
compare:
op: eq
value: false
remediation: |
Edit the Scheduler pod specification file $schedulerconf file
on the master node and set the below parameter.
--profiling=false
scored: true
- id: 1.4.2
text: "Ensure that the --bind-address argument is set to 127.0.0.1 (Automated)"
audit: "/bin/ps -ef | grep $schedulerbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--bind-address"
compare:
op: eq
value: "127.0.0.1"
- flag: "--bind-address"
set: false
remediation: |
Edit the Scheduler pod specification file $schedulerconf
on the master node and ensure the correct value for the --bind-address parameter
scored: true

392
cfg/ack-1.0/node.yaml Normal file
View File

@@ -0,0 +1,392 @@
---
controls:
version: "ack-1.0"
id: 4
text: "Worker Node Security Configuration"
type: "node"
groups:
- id: 4.1
text: "Worker Node Configuration Files"
checks:
- id: 4.1.1
text: "Ensure that the kubelet service file permissions are set to 644 or more restrictive (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletsvc; then stat -c permissions=%a $kubeletsvc; fi'' '
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 $kubeletsvc
scored: true
- id: 4.1.2
text: "Ensure that the kubelet service file ownership is set to root:root (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletsvc; then stat -c %U:%G $kubeletsvc; fi'' '
tests:
test_items:
- flag: root:root
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: 4.1.3
text: "If proxy kubeconfig file exists ensure permissions are set to 644 or more restrictive (Manual)"
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c permissions=%a $proxykubeconfig; fi'' '
tests:
bin_op: or
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
- flag: "$proxykubeconfig"
set: false
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 $proxykubeconfig
scored: false
- id: 4.1.4
text: "If proxy kubeconfig file exists ensure ownership is set to root:root (Manual)"
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c %U:%G $proxykubeconfig; fi'' '
tests:
bin_op: or
test_items:
- flag: root:root
- flag: "$proxykubeconfig"
set: false
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example, chown root:root $proxykubeconfig
scored: false
- id: 4.1.5
text: "Ensure that the --kubeconfig kubelet.conf file permissions are set to 644 or more restrictive (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletkubeconfig; then stat -c permissions=%a $kubeletkubeconfig; fi'' '
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 $kubeletkubeconfig
scored: true
- id: 4.1.6
text: "Ensure that the --kubeconfig kubelet.conf file ownership is set to root:root (Manual)"
audit: '/bin/sh -c ''if test -e $kubeletkubeconfig; then stat -c %U:%G $kubeletkubeconfig; fi'' '
tests:
test_items:
- flag: root:root
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chown root:root $kubeletkubeconfig
scored: false
- id: 4.1.7
text: "Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Manual)"
audit: |
CAFILE=$(ps -ef | grep kubelet | grep -v apiserver | grep -- --client-ca-file= | awk -F '--client-ca-file=' '{print $2}' | awk '{print $1}')
if test -z $CAFILE; then CAFILE=$kubeletcafile; fi
if test -e $CAFILE; then stat -c permissions=%a $CAFILE; fi
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the following command to modify the file permissions of the
--client-ca-file chmod 644 <filename>
scored: false
- id: 4.1.8
text: "Ensure that the client certificate authorities file ownership is set to root:root (Manual)"
audit: |
CAFILE=$(ps -ef | grep kubelet | grep -v apiserver | grep -- --client-ca-file= | awk -F '--client-ca-file=' '{print $2}' | awk '{print $1}')
if test -z $CAFILE; then CAFILE=$kubeletcafile; fi
if test -e $CAFILE; then stat -c %U:%G $CAFILE; fi
tests:
test_items:
- flag: root:root
compare:
op: eq
value: root:root
remediation: |
Run the following command to modify the ownership of the --client-ca-file.
chown root:root <filename>
scored: false
- id: 4.1.9
text: "Ensure that the kubelet --config configuration file has permissions set to 644 or more restrictive (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletconf; then stat -c permissions=%a $kubeletconf; fi'' '
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the following command (using the config file location identified in the Audit step)
chmod 644 $kubeletconf
scored: true
- id: 4.1.10
text: "Ensure that the kubelet --config configuration file ownership is set to root:root (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletconf; then stat -c %U:%G $kubeletconf; fi'' '
tests:
test_items:
- flag: root:root
remediation: |
Run the following command (using the config file location identified in the Audit step)
chown root:root $kubeletconf
scored: true
- id: 4.2
text: "Kubelet"
checks:
- id: 4.2.1
text: "Ensure that the anonymous-auth argument is set to false (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: "--anonymous-auth"
path: '{.authentication.anonymous.enabled}'
compare:
op: eq
value: false
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
$kubeletsvc 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: 4.2.2
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --authorization-mode
path: '{.authorization.mode}'
compare:
op: nothave
value: AlwaysAllow
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
$kubeletsvc 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: 4.2.3
text: "Ensure that the --client-ca-file argument is set as appropriate (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --client-ca-file
path: '{.authentication.x509.clientCAFile}'
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
$kubeletsvc 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: 4.2.4
text: "Ensure that the --read-only-port argument is set to 0 (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
bin_op: or
test_items:
- flag: "--read-only-port"
path: '{.readOnlyPort}'
compare:
op: eq
value: 0
- flag: "--read-only-port"
path: '{.readOnlyPort}'
set: false
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
$kubeletsvc 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: false
- id: 4.2.5
text: "Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --streaming-connection-idle-timeout
path: '{.streamingConnectionIdleTimeout}'
compare:
op: noteq
value: 0
- flag: --streaming-connection-idle-timeout
path: '{.streamingConnectionIdleTimeout}'
set: false
bin_op: or
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
$kubeletsvc 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: false
- id: 4.2.6
text: "Ensure that the --protect-kernel-defaults argument is set to true (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --protect-kernel-defaults
path: '{.protectKernelDefaults}'
compare:
op: eq
value: 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
$kubeletsvc 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: false
- id: 4.2.7
text: "Ensure that the --make-iptables-util-chains argument is set to true (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --make-iptables-util-chains
path: '{.makeIPTablesUtilChains}'
compare:
op: eq
value: true
- flag: --make-iptables-util-chains
path: '{.makeIPTablesUtilChains}'
set: false
bin_op: or
remediation: |
If using a Kubelet config file, edit the file to set makeIPTablesUtilChains: true.
If using command line arguments, edit the kubelet service file
$kubeletsvc 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: 4.2.8
text: "Ensure that the --event-qps argument is set to 0 or a level which ensures appropriate event capture (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --event-qps
path: '{.eventRecordQPS}'
compare:
op: eq
value: 0
remediation: |
If using a Kubelet config file, edit the file to set eventRecordQPS: to an appropriate level.
If using command line arguments, edit the kubelet service file
$kubeletsvc on each worker node and
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: false
- id: 4.2.9
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --tls-cert-file
path: '{.tlsCertFile}'
- flag: --tls-private-key-file
path: '{.tlsPrivateKeyFile}'
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
$kubeletsvc on each worker node and
set the below parameters in KUBELET_CERTIFICATE_ARGS variable.
--tls-cert-file=<path/to/tls-certificate-file>
--tls-private-key-file=<path/to/tls-key-file>
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: false
- id: 4.2.10
text: "Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --tls-cipher-suites
path: '{range .tlsCipherSuites[:]}{}{'',''}{end}'
compare:
op: valid_elements
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
remediation: |
If using a Kubelet config file, edit the file to set TLSCipherSuites: to
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
or to a subset of these values.
If using executable arguments, edit the kubelet service file
$kubeletsvc on each worker node and
set the --tls-cipher-suites parameter as follows, or to a subset of these values.
--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: false

239
cfg/ack-1.0/policies.yaml Normal file
View File

@@ -0,0 +1,239 @@
---
controls:
version: "ack-1.0"
id: 5
text: "Kubernetes Policies"
type: "policies"
groups:
- id: 5.1
text: "RBAC and Service Accounts"
checks:
- id: 5.1.1
text: "Ensure that the cluster-admin role is only used where required (Manual)"
type: "manual"
remediation: |
Identify all clusterrolebindings to the cluster-admin role. Check if they are used and
if they need this role or if they could use a role with fewer privileges.
Where possible, first bind users to a lower privileged role and then remove the
clusterrolebinding to the cluster-admin role :
kubectl delete clusterrolebinding [name]
scored: false
- id: 5.1.2
text: "Minimize access to secrets (Manual)"
type: "manual"
remediation: |
Where possible, remove get, list and watch access to secret objects in the cluster.
scored: false
- id: 5.1.3
text: "Minimize wildcard use in Roles and ClusterRoles (Manual)"
type: "manual"
remediation: |
Where possible replace any use of wildcards in clusterroles and roles with specific
objects or actions.
scored: false
- id: 5.1.4
text: "Minimize access to create pods (Manual)"
type: "manual"
remediation: |
Where possible, remove create access to pod objects in the cluster.
scored: false
- id: 5.1.5
text: "Ensure that default service accounts are not actively used. (Manual)"
type: "manual"
remediation: |
Create explicit service accounts wherever a Kubernetes workload requires specific access
to the Kubernetes API server.
Modify the configuration of each default service account to include this value
automountServiceAccountToken: false
scored: false
- id: 5.1.6
text: "Ensure that Service Account Tokens are only mounted where necessary (Manual)"
type: "manual"
remediation: |
Modify the definition of pods and service accounts which do not need to mount service
account tokens to disable it.
scored: false
- id: 5.2
text: "Pod Security Policies"
checks:
- id: 5.2.1
text: "Minimize the admission of privileged containers (Manual)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that
the .spec.privileged field is omitted or set to false.
scored: false
- id: 5.2.2
text: "Minimize the admission of containers wishing to share the host process ID namespace (Manual)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostPID field is omitted or set to false.
scored: false
- id: 5.2.3
text: "Minimize the admission of containers wishing to share the host IPC namespace (Manual)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostIPC field is omitted or set to false.
scored: false
- id: 5.2.4
text: "Minimize the admission of containers wishing to share the host network namespace (Manual)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostNetwork field is omitted or set to false.
scored: false
- id: 5.2.5
text: "Minimize the admission of containers with allowPrivilegeEscalation (Manual)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.allowPrivilegeEscalation field is omitted or set to false.
scored: false
- id: 5.2.6
text: "Minimize the admission of root containers (Manual)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.runAsUser.rule is set to either MustRunAsNonRoot or MustRunAs with the range of
UIDs not including 0.
scored: false
- id: 5.2.7
text: "Minimize the admission of containers with the NET_RAW capability (Manual)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.requiredDropCapabilities is set to include either NET_RAW or ALL.
scored: false
- id: 5.2.8
text: "Minimize the admission of containers with added capabilities (Manual)"
type: "manual"
remediation: |
Ensure that allowedCapabilities is not present in PSPs for the cluster unless
it is set to an empty array.
scored: false
- id: 5.2.9
text: "Minimize the admission of containers with capabilities assigned (Manual)"
type: "manual"
remediation: |
Review the use of capabilites in applications runnning on your cluster. Where a namespace
contains applicaions which do not require any Linux capabities to operate consider adding
a PSP which forbids the admission of containers which do not drop all capabilities.
scored: false
- id: 5.3
text: "Network Policies and CNI"
checks:
- id: 5.3.1
text: "Ensure that the CNI in use supports Network Policies (Manual)"
type: "manual"
remediation: |
If the CNI plugin in use does not support network policies, consideration should be given to
making use of a different plugin, or finding an alternate mechanism for restricting traffic
in the Kubernetes cluster.
scored: false
- id: 5.3.2
text: "Ensure that all Namespaces have Network Policies defined (Manual)"
type: "manual"
remediation: |
Follow the documentation and create NetworkPolicy objects as you need them.
scored: false
- id: 5.4
text: "Secrets Management"
checks:
- id: 5.4.1
text: "Prefer using secrets as files over secrets as environment variables (Manual)"
type: "manual"
remediation: |
if possible, rewrite application code to read secrets from mounted secret files, rather than
from environment variables.
scored: false
- id: 5.4.2
text: "Consider external secret storage (Manual)"
type: "manual"
remediation: |
Refer to the secrets management options offered by your cloud provider or a third-party
secrets management solution.
scored: false
- id: 5.5
text: "Extensible Admission Control"
checks:
- id: 5.5.1
text: "Configure Image Provenance using ImagePolicyWebhook admission controller (Manual)"
type: "manual"
remediation: |
Follow the Kubernetes documentation and setup image provenance.
scored: false
- id: 5.6
text: "General Policies"
checks:
- id: 5.6.1
text: "Create administrative boundaries between resources using namespaces (Manual)"
type: "manual"
remediation: |
Follow the documentation and create namespaces for objects in your deployment as you need
them.
scored: false
- id: 5.6.2
text: "Ensure that the seccomp profile is set to docker/default in your pod definitions (Manual)"
type: "manual"
remediation: |
Seccomp is an alpha feature currently. By default, all alpha features are disabled. So, you
would need to enable alpha features in the apiserver by passing "--feature-
gates=AllAlpha=true" argument.
Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS
parameter to "--feature-gates=AllAlpha=true"
KUBE_API_ARGS="--feature-gates=AllAlpha=true"
Based on your system, restart the kube-apiserver service. For example:
systemctl restart kube-apiserver.service
Use annotations to enable the docker/default seccomp profile in your pod definitions. An
example is as below:
apiVersion: v1
kind: Pod
metadata:
name: trustworthy-pod
annotations:
seccomp.security.alpha.kubernetes.io/pod: docker/default
spec:
containers:
- name: trustworthy-container
image: sotrustworthy:latest
scored: false
- id: 5.6.3
text: "Apply Security Context to Your Pods and Containers (Manual)"
type: "manual"
remediation: |
Follow the Kubernetes documentation and apply security contexts to your pods. For a
suggested list of security contexts, you may refer to the CIS Security Benchmark for Docker
Containers.
scored: false
- id: 5.6.4
text: "The default namespace should not be used (Manual)"
type: "manual"
remediation: |
Ensure that namespaces are created to allow for appropriate segregation of Kubernetes
resources and that all new resources are created in a specific namespace.
scored: false

2
cfg/aks-1.0/config.yaml Normal file
View File

@@ -0,0 +1,2 @@
---
## Version-specific settings that override the values in cfg/config.yaml

View File

@@ -0,0 +1,31 @@
---
controls:
version: "aks-1.0"
id: 2
text: "Control Plane Configuration"
type: "controlplane"
groups:
- id: 2.1
text: "Authentication and Authorization"
checks:
- id: 2.1.1
text: "Enable Azure Active Directory Integration"
type: "manual"
remediation: |
Use of OIDC should be implemented in place of client certificates. Cluster administrators can configure Kubernetes role-based access control (RBAC) based on a user's identity or directory group membership. Azure AD authentication is provided to AKS clusters with OpenID Connect. See https://docs.microsoft.com/en-us/azure/aks/managed-aad.
scored: false
- id: 2.1.2
text: "Limit access to cluster configuration file"
type: "manual"
remediation: |
Use Azure role-based access control to define access to the Kubernetes configuration file in Azure Kubernetes Service (AKS). See https://docs.microsoft.com/en-us/azure/aks/control-kubeconfig-access
scored: false
- id: 2.2
text: "Logging"
checks:
- id: 2.2.1
text: "Enable logging for the Kubernetes master components"
type: "manual"
remediation: "Enable log collection for the Kubernetes master components in the AKS cluster using Diagnostic settings."
scored: false

View File

@@ -0,0 +1,255 @@
---
controls:
version: "aks-1.0"
id: 5
text: "Managed Services"
type: "managedservices"
groups:
- id: 5.1
text: "Image Registry and Image Scanning"
checks:
- id: 5.1.1
text: "Ensure Image Vulnerability Scanning"
type: "manual"
remediation: |
Scan your container images for vulnerabilities, and only deploy images that have passed validation. Regularly update the base images and application runtime, then redeploy workloads in the AKS cluster. Deployment workflow should include a process to scan container images using tools such as Twistlock or Aqua, and then only allow verified images to be deployed.
scored: false
- id: 5.1.2
text: "Minimize user access to ACR"
type: "manual"
remediation: |
Use Azure AD and RBAC to minimize user access to ACR. For each Azure container registry, track whether the built-in admin account is enabled or disabled. Disable the account when not in use. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#identity-and-access-control.
scored: false
- id: 5.1.3
text: "Minimize cluster access to read-only for ACR"
type: "manual"
remediation: |
Ensure identity assigned to AKS uses read-only role for accessing ACR.
scored: false
- id: 5.1.4
text: "Protect ACR using NSGs or Azure Firewall on your Virtual Network"
type: "manual"
remediation: |
Restrict access to an Azure container registry using an Azure virtual network or firewall rules. Configure rules to access an Azure container registry behind a firewall. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#11-protect-resources-using-network-security-groups-or-azure-firewall-on-your-virtual-network
scored: false
- id: 5.1.5
text: "Record network packets and flow logs for ACR"
type: "manual"
remediation: |
Enable network security group (NSG) flow logs for the NSG attached to the subnet being used to protect your Azure container registry. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#15-record-network-packets-and-flow-logs
scored: false
- id: 5.1.6
text: "Minimize complexity and administrative overhead of network security rules for ACR"
type: "manual"
remediation: |
For resources that need access to your container registry, use virtual network service tags (instead of specific IP addresses) for the Azure Container Registry service (service tag name "AzureContainerRegistry") to define network access controls on Network Security Groups or Azure Firewall. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#18-minimize-complexity-and-administrative-overhead-of-network-security-rules
scored: false
- id: 5.1.7
text: "Configure central security log management for ACR"
type: "manual"
remediation: |
Ingest logs via Azure Monitor to aggregate security data generated by an Azure container registry. https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#22-configure-central-security-log-management
scored: false
- id: 5.1.8
text: "Enable audit logging for ACR"
type: "manual"
remediation: |
Collect and consume this data to audit registry authentication events and provide a complete activity trail on registry artifacts such as pull and push events so you can diagnose security issues with your registry. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#23-enable-audit-logging-for-azure-resources
scored: false
- id: 5.1.9
text: "Change default passwords for ACR where applicable"
type: "manual"
remediation: |
If the default admin account of an Azure container registry is enabled, complex passwords are automatically created and should be rotated. Disable the account when not in use. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#32-change-default-passwords-where-applicable
scored: false
- id: 5.1.10
text: "Use dedicated administrative accounts"
type: "manual"
remediation: |
Create standard operating procedures around the use of dedicated administrative accounts. Use Azure Security Center Identity and Access Management to monitor the number of administrative accounts. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#33-use-dedicated-administrative-accounts
scored: false
- id: 5.1.11
text: "Use single sign-on (SSO) with Azure Active Directory"
type: "manual"
remediation: |
Wherever possible, use Azure Active Directory SSO instead of configuring individual stand-alone credentials per-service. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#34-use-single-sign-on-sso-with-azure-active-directory
scored: false
- id: 5.1.12
text: "Maintain an inventory of sensitive Information"
type: "manual"
remediation: |
Use resource tags to assist in tracking Azure container registries that store or process sensitive information. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#41-maintain-an-inventory-of-sensitive-information
scored: false
- id: 5.1.13
text: "Isolate systems storing or processing sensitive information"
type: "manual"
remediation: |
Implement separate container registries, subscriptions, and/or management groups for development, test, and production. Resources storing or processing sensitive data should be sufficiently isolated. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#42-isolate-systems-storing-or-processing-sensitive-information
scored: false
- id: 5.1.14
text: "Encrypt all sensitive information in transit to ACR"
type: "manual"
remediation: |
Ensure that any clients connecting to your Azure Container Registry are able to negotiate TLS 1.2 or greater. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#44-encrypt-all-sensitive-information-in-transit
scored: false
- id: 5.1.15
text: "Use Azure RBAC to control access to resources in ACR"
type: "manual"
remediation: |
Use Azure role-based access control (Azure RBAC) to control access to data and resources in an Azure container registry. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#46-use-azure-rbac-to-control-access-to-resources
scored: false
- id: 5.1.16
text: "Encrypt sensitive information at rest in ACR"
type: "manual"
remediation: |
Use encryption at rest on all Azure resources. By default, all data in an Azure container registry is encrypted at rest using Microsoft-managed keys. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#48-encrypt-sensitive-information-at-rest
scored: false
- id: 5.1.17
text: "Ensure regular automated back ups for ACR"
type: "manual"
remediation: |
he data in your Microsoft Azure container registry is always automatically replicated to ensure durability and high availability. Optionally geo-replicate a container registry to maintain registry replicas in multiple Azure regions. See https://docs.microsoft.com/en-us/azure/container-registry/security-baseline#91-ensure-regular-automated-back-ups
scored: false
- id: 5.2
text: "Identity and Access Management (IAM)"
checks:
- id: 5.2.1
text: "Use managed identities in Azure Kubernetes Service"
type: "manual"
remediation: |
Use SystemAssigned managed identity for AKS cluster. See https://docs.microsoft.com/en-us/azure/aks/use-managed-identity
scored: false
- id: 5.2.2
text: "Prefer using AAD Pod Identity"
type: "manual"
remediation: |
AAD Pod Identity enables Kubernetes applications to access cloud resources securely with Azure Active Directory (AAD). See https://github.com/Azure/aad-pod-identity
scored: false
- id: 5.3
text: "Cloud Key Management Service"
checks:
- id: 5.3.1
text: "Ensure Kubernetes Secrets are stored and retrieved from Azure Key Vault."
type: "manual"
remediation: |
Use the Azure Key Vault with Secrets Store CSI Driver to retrieve secrets from Azure Key Vault and load it in the pod. See https://github.com/Azure/secrets-store-csi-driver-provider-azure.
scored: false
- id: 5.4
text: "Cluster Networking"
checks:
- id: 5.4.1
text: "Enable NSG Flow Logs for AKS subnets."
type: "manual"
remediation: |
Enable network security group (NSG) flow logs for the NSG attached to the subnet being used for AKS cluster nodes.
scored: false
- id: 5.4.2
text: "Ensure clusters are created with Private Endpoint Enabled and Public Access Disabled (Scored)"
type: "manual"
remediation: |
In a private cluster, the control plane or API server has internal IP address. See: https://docs.microsoft.com/en-us/azure/aks/private-clusters
scored: false
- id: 5.4.3
text: "Configure NSG on AKS worker node subnet"
type: "manual"
remediation: |
Configure NSG rules on AKS worker node subnet to allow only required network traffic.
scored: false
- id: 5.4.4
text: "Ensure Network Policy is Enabled and set as appropriate (Not Scored)"
type: "manual"
remediation: |
Enable Azure Network Policy or Calico Network policy on the AKS cluster. See https://docs.microsoft.com/en-us/azure/aks/use-network-policies.
scored: false
- id: 5.5
text: "Logging"
checks:
- id: 5.5.1
text: "Enable Azure Monitor for container for kubelet logs"
type: "manual"
remediation: |
Enable Azure Monitor for containers via AKS diagnostics settings for collecting node and kubelet logs. See https://docs.microsoft.com/en-us/azure/azure-monitor/insights/container-insights-overview
scored: false
- id: 5.6
text: "Authentication and Authorization"
checks:
- id: 5.6.1
text: "Use Azure RBAC for Kubernetes Authorization"
type: "manual"
remediation: |
Enabling Azure RBAC for Kubernetes Authorization will use a Kubernetes Authorization webhook server to enable you to manage permissions and assignments of Azure AD-integrated K8s cluster resources using Azure role definition and role assignments. See https://docs.microsoft.com/en-us/azure/aks/manage-azure-rbac
scored: false
- id: 5.6.2
text: "Use Kubernetes RBAC with Azure AD integration"
type: "manual"
remediation: |
Don't use fixed credentials within pods or container images, as they are at risk of exposure or abuse. Instead, use pod identities to automatically request access to other Azure resources using a central Azure AD identity solution. See https://docs.microsoft.com/en-us/azure/aks/operator-best-practices-identity#use-pod-identities
scored: false
- id: 5.6.3
text: "Use pod identities"
type: "manual"
remediation: |
Control access to cluster resources using role-based access control and Azure Active Directory identities in Azure Kubernetes Service. See https://docs.microsoft.com/en-us/azure/aks/azure-ad-rbac
scored: false
- id: 5.7
text: "Storage"
checks:
- id: 5.7.1
text: "Enable host-based encryption"
type: "manual"
remediation: |
Enable host-based encryption on Azure Kubernetes Service (AKS). With host-based encryption, the data stored on the VM host of your AKS agent nodes' VMs is encrypted at rest and flows encrypted to the Storage service. This means the temp disks are encrypted at rest with platform-managed keys. The cache of OS and data disks is encrypted at rest with either platform-managed keys or customer-managed keys depending on the encryption type set on those disks. See https://docs.microsoft.com/en-us/azure/aks/enable-host-encryption.
scored: false
- id: 5.7.2
text: "Bring your own keys (BYOK) with Azure disks in Azure Kubernetes Service (AKS)"
type: "manual"
remediation: |
Azure Storage encrypts all data in a storage account at rest. By default, data is encrypted with Microsoft-managed keys. For additional control over encryption keys, you can supply customer-managed keys to use for encryption at rest for both the OS and data disks for your AKS clusters. See https://docs.microsoft.com/en-us/azure/aks/azure-disk-customer-managed-keys.
scored: false
- id: 5.8
text: "Other Cluster Configurations"
checks:
- id: 5.8.1
text: "Ensure Kubernetes Web UI is Disabled (Scored)"
type: "manual"
remediation: |
The dashboard add-on is disabled by default for all new clusters created on Kubernetes 1.18 or greater. To disable dashboard on existing cluster use command line:
az aks disable-addons -g myRG -n myAKScluster -a kube-dashboard
scored: false
- id: 5.8.2
text: "Secure pods with Azure Policy as appropriate"
type: "manual"
remediation: |
Enable Azure Policy Add-on for AKS to control what functions pods are granted. See https://docs.microsoft.com/en-us/azure/aks/use-pod-security-on-azure-policy.
scored: false

6
cfg/aks-1.0/master.yaml Normal file
View File

@@ -0,0 +1,6 @@
---
controls:
version: "aks-1.0"
id: 1
text: "Control Plane Components"
type: "master"

452
cfg/aks-1.0/node.yaml Normal file
View File

@@ -0,0 +1,452 @@
---
controls:
version: "aks-1.0"
id: 3
text: "Worker Node Security Configuration"
type: "node"
groups:
- id: 3.1
text: "Worker Node Configuration Files"
checks:
- id: 3.1.1
text: "Ensure that the kubelet service file permissions are set to 644 or more restrictive (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletsvc; then stat -c permissions=%a $kubeletsvc; fi'' '
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 $kubeletsvc
scored: true
- id: 3.1.2
text: "Ensure that the kubelet service file ownership is set to root:root (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletsvc; then stat -c %U:%G $kubeletsvc; fi'' '
tests:
test_items:
- flag: root:root
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: 3.1.3
text: "If proxy kubeconfig file exists ensure permissions are set to 644 or more restrictive (Manual)"
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c permissions=%a $proxykubeconfig; fi'' '
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 $proxykubeconfig
scored: false
- id: 3.1.4
text: "Ensure that the proxy kubeconfig file ownership is set to root:root (Manual)"
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c %U:%G $proxykubeconfig; fi'' '
tests:
test_items:
- flag: root:root
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example, chown root:root $proxykubeconfig
scored: false
- id: 3.1.5
text: "Ensure that the --kubeconfig kubelet.conf file permissions are set to 644 or more restrictive (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletkubeconfig; then stat -c permissions=%a $kubeletkubeconfig; fi'' '
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 $kubeletkubeconfig
scored: true
- id: 3.1.6
text: "Ensure that the --kubeconfig kubelet.conf file ownership is set to root:root (Manual)"
audit: '/bin/sh -c ''if test -e $kubeletkubeconfig; then stat -c %U:%G $kubeletkubeconfig; fi'' '
tests:
test_items:
- flag: root:root
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chown root:root $kubeletkubeconfig
scored: false
- id: 3.1.7
text: "Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Manual)"
audit: |
CAFILE=$(ps -ef | grep kubelet | grep -v apiserver | grep -- --client-ca-file= | awk -F '--client-ca-file=' '{print $2}' | awk '{print $1}')
if test -z $CAFILE; then CAFILE=$kubeletcafile; fi
if test -e $CAFILE; then stat -c permissions=%a $CAFILE; fi
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the following command to modify the file permissions of the
--client-ca-file chmod 644 <filename>
scored: false
- id: 3.1.8
text: "Ensure that the client certificate authorities file ownership is set to root:root (Manual)"
audit: |
CAFILE=$(ps -ef | grep kubelet | grep -v apiserver | grep -- --client-ca-file= | awk -F '--client-ca-file=' '{print $2}' | awk '{print $1}')
if test -z $CAFILE; then CAFILE=$kubeletcafile; fi
if test -e $CAFILE; then stat -c %U:%G $CAFILE; fi
tests:
test_items:
- flag: root:root
compare:
op: eq
value: root:root
remediation: |
Run the following command to modify the ownership of the --client-ca-file.
chown root:root <filename>
scored: false
- id: 3.1.9
text: "Ensure that the kubelet --config configuration file has permissions set to 644 or more restrictive (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletconf; then stat -c permissions=%a $kubeletconf; fi'' '
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the following command (using the config file location identified in the Audit step)
chmod 644 $kubeletconf
scored: true
- id: 3.1.10
text: "Ensure that the kubelet --config configuration file ownership is set to root:root (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletconf; then stat -c %U:%G $kubeletconf; fi'' '
tests:
test_items:
- flag: root:root
remediation: |
Run the following command (using the config file location identified in the Audit step)
chown root:root $kubeletconf
scored: true
- id: 3.2
text: "Kubelet"
checks:
- id: 3.2.1
text: "Ensure that the anonymous-auth argument is set to false (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: "--anonymous-auth"
path: '{.authentication.anonymous.enabled}'
compare:
op: eq
value: false
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
$kubeletsvc 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: 3.2.2
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --authorization-mode
path: '{.authorization.mode}'
compare:
op: nothave
value: AlwaysAllow
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
$kubeletsvc 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: 3.2.3
text: "Ensure that the --client-ca-file argument is set as appropriate (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --client-ca-file
path: '{.authentication.x509.clientCAFile}'
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
$kubeletsvc 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: 3.2.4
text: "Ensure that the --read-only-port argument is set to 0 (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
bin_op: or
test_items:
- flag: "--read-only-port"
path: '{.readOnlyPort}'
compare:
op: eq
value: 0
- flag: "--read-only-port"
path: '{.readOnlyPort}'
set: false
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
$kubeletsvc 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: false
- id: 3.2.5
text: "Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --streaming-connection-idle-timeout
path: '{.streamingConnectionIdleTimeout}'
compare:
op: noteq
value: 0
- flag: --streaming-connection-idle-timeout
path: '{.streamingConnectionIdleTimeout}'
set: false
bin_op: or
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
$kubeletsvc 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: false
- id: 3.2.6
text: "Ensure that the --protect-kernel-defaults argument is set to true (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --protect-kernel-defaults
path: '{.protectKernelDefaults}'
compare:
op: eq
value: 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
$kubeletsvc 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: 3.2.7
text: "Ensure that the --make-iptables-util-chains argument is set to true (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --make-iptables-util-chains
path: '{.makeIPTablesUtilChains}'
compare:
op: eq
value: true
- flag: --make-iptables-util-chains
path: '{.makeIPTablesUtilChains}'
set: false
bin_op: or
remediation: |
If using a Kubelet config file, edit the file to set makeIPTablesUtilChains: true.
If using command line arguments, edit the kubelet service file
$kubeletsvc 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: 3.2.8
text: "Ensure that the --hostname-override argument is not set (Manual)"
# This is one of those properties that can only be set as a command line argument.
# To check if the property is set as expected, we need to parse the kubelet command
# instead reading the Kubelet Configuration file.
audit: "/bin/ps -fC $kubeletbin "
tests:
test_items:
- flag: --hostname-override
set: false
remediation: |
Edit the kubelet service file $kubeletsvc
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: false
- id: 3.2.9
text: "Ensure that the --event-qps argument is set to 0 or a level which ensures appropriate event capture (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --event-qps
path: '{.eventRecordQPS}'
compare:
op: eq
value: 0
remediation: |
If using a Kubelet config file, edit the file to set eventRecordQPS: to an appropriate level.
If using command line arguments, edit the kubelet service file
$kubeletsvc on each worker node and
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: false
- id: 3.2.10
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --tls-cert-file
path: '{.tlsCertFile}'
- flag: --tls-private-key-file
path: '{.tlsPrivateKeyFile}'
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
$kubeletsvc on each worker node and
set the below parameters in KUBELET_CERTIFICATE_ARGS variable.
--tls-cert-file=<path/to/tls-certificate-file>
--tls-private-key-file=<path/to/tls-key-file>
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: false
- id: 3.2.11
text: "Ensure that the --rotate-certificates argument is not set to false (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --rotate-certificates
path: '{.rotateCertificates}'
compare:
op: eq
value: true
- flag: --rotate-certificates
path: '{.rotateCertificates}'
set: false
bin_op: or
remediation: |
If using a Kubelet config file, edit the file to add the line rotateCertificates: true or
remove it altogether to use the default value.
If using command line arguments, edit the kubelet service file
$kubeletsvc on each worker node and
remove --rotate-certificates=false argument from the KUBELET_CERTIFICATE_ARGS
variable.
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: false
- id: 3.2.12
text: "Verify that the RotateKubeletServerCertificate argument is set to true (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: RotateKubeletServerCertificate
path: '{.featureGates.RotateKubeletServerCertificate}'
compare:
op: eq
value: true
remediation: |
Edit the kubelet service file $kubeletsvc
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: false
- id: 3.2.13
text: "Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --tls-cipher-suites
path: '{range .tlsCipherSuites[:]}{}{'',''}{end}'
compare:
op: valid_elements
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
remediation: |
If using a Kubelet config file, edit the file to set TLSCipherSuites: to
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
or to a subset of these values.
If using executable arguments, edit the kubelet service file
$kubeletsvc on each worker node and
set the --tls-cipher-suites parameter as follows, or to a subset of these values.
--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: false

256
cfg/aks-1.0/policies.yaml Normal file
View File

@@ -0,0 +1,256 @@
---
controls:
version: "aks-1.0"
id: 4
text: "Kubernetes Policies"
type: "policies"
groups:
- id: 4.1
text: "RBAC and Service Accounts"
checks:
- id: 4.1.1
text: "Ensure that the cluster-admin role is only used where required (Not Scored)"
type: "manual"
remediation: |
Identify all clusterrolebindings to the cluster-admin role. Check if they are used and
if they need this role or if they could use a role with fewer privileges.
Where possible, first bind users to a lower privileged role and then remove the
clusterrolebinding to the cluster-admin role :
kubectl delete clusterrolebinding [name]
scored: false
- id: 4.1.2
text: "Minimize access to secrets (Not Scored)"
type: "manual"
remediation: |
Where possible, remove get, list and watch access to secret objects in the cluster.
scored: false
- id: 4.1.3
text: "Minimize wildcard use in Roles and ClusterRoles (Not Scored)"
type: "manual"
remediation: |
Where possible replace any use of wildcards in clusterroles and roles with specific
objects or actions.
scored: false
- id: 4.1.4
text: "Minimize access to create pods (Not Scored)"
type: "manual"
Remediation: |
Where possible, remove create access to pod objects in the cluster.
scored: false
- id: 4.1.5
text: "Ensure that default service accounts are not actively used. (Scored)"
type: "manual"
remediation: |
Create explicit service accounts wherever a Kubernetes workload requires specific access
to the Kubernetes API server.
Modify the configuration of each default service account to include this value
automountServiceAccountToken: false
scored: true
- id: 4.1.6
text: "Ensure that Service Account Tokens are only mounted where necessary (Not Scored)"
type: "manual"
remediation: |
Modify the definition of pods and service accounts which do not need to mount service
account tokens to disable it.
scored: false
- id: 4.2
text: "Pod Security Policies"
checks:
- id: 4.2.1
text: "Minimize the admission of privileged containers (Not Scored)"
type: "manual"
remediation: |
Implement Azure Policy to disallow running of privileged containers. See https://docs.microsoft.com/en-us/azure/aks/use-pod-security-on-azure-policy#built-in-policy-initiatives
scored: false
- id: 4.2.2
text: "Disallow shared usage of host namespaces."
type: "manual"
remediation: |
Implement Azure Policy to disallow shared usage of host namespaces. See https://docs.microsoft.com/en-us/azure/aks/use-pod-security-on-azure-policy#built-in-policy-initiatives
scored: false
- id: 4.2.3
text: "Restrict all usage of host networking and ports"
type: "manual"
remediation: |
Implement Azure Policy to restrict all usage of host networking and ports. See https://docs.microsoft.com/en-us/azure/aks/use-pod-security-on-azure-policy#built-in-policy-initiatives
scored: false
- id: 4.2.4
text: "Restrict any usage of the host filesystem."
type: "manual"
remediation: |
Implement Azure Policy to restrict all usage of host networking and ports. See https://docs.microsoft.com/en-us/azure/aks/use-pod-security-on-azure-policy#built-in-policy-initiatives
scored: false
- id: 4.2.5
text: "Restrict Linux capabilities to the default set."
type: "manual"
remediation: |
Implement Azure Policy to restrict Linux capabilities to the default set. See https://docs.microsoft.com/en-us/azure/aks/use-pod-security-on-azure-policy#built-in-policy-initiatives
scored: false
- id: 4.2.6
text: "Restrict usage of defined volume types"
type: "manual"
remediation: |
Implement Azure Policy to restrict usage of defined volume types. See https://docs.microsoft.com/en-us/azure/aks/use-pod-security-on-azure-policy#built-in-policy-initiatives
scored: false
- id: 4.2.7
text: "Restrict the user and group IDs of the container"
type: "manual"
remediation: |
Implement Azure Policy to restrict the user and group IDs of the container. See https://docs.microsoft.com/en-us/azure/aks/use-pod-security-on-azure-policy#built-in-policy-initiatives
scored: false
- id: 4.2.8
text: "Restrict allocating an FSGroup that owns the pod's volumes"
type: "manual"
remediation: |
Implement Azure Policy to restrict allocating an FSGroup that owns the pod's volumes. See https://docs.microsoft.com/en-us/azure/aks/use-pod-security-on-azure-policy#built-in-policy-initiatives
scored: false
- id: 4.2.9
text: "Requires seccomp profile"
type: "manual"
remediation: |
Implement Azure Policy to requires seccomp profile. See https://docs.microsoft.com/en-us/azure/aks/use-pod-security-on-azure-policy#built-in-policy-initiatives.
scored: false
- id: 4.2.10
text: "Define the AppArmor profile used by containers"
type: "manual"
remediation: |
Implement Azure Policy to define the AppArmor profile used by containers. See https://docs.microsoft.com/en-us/azure/aks/use-pod-security-on-azure-policy#additional-optional-policies.
scored: false
- id: 4.3
text: "Network Policies and CNI"
checks:
- id: 4.3.1
text: "Ensure that the CNI in use supports Network Policies (Not Scored)"
type: "manual"
remediation: |
To use a CNI plugin with Network Policy, enable Network Policy in AKS. See Recommendation 6.4.4.
scored: false
- id: 4.3.2
text: "Ensure that all Namespaces have Network Policies defined (Scored)"
type: "manual"
remediation: |
Follow the documentation and create NetworkPolicy objects as you need them.
scored: false
- id: 4.4
text: "Secrets Management"
checks:
- id: 4.4.1
text: "Prefer using secrets as files over secrets as environment variables (Not Scored)"
type: "manual"
remediation: |
If possible, rewrite application code to read secrets from mounted secret files, rather than
from environment variables.
scored: false
- id: 4.4.2
text: "Consider external secret storage (Not Scored)"
type: "manual"
remediation: |
Use the Azure Key Vault with Secrets Store CSI Driver to retrieve secrets from Azure Key Vault and load it in the pod. See https://github.com/Azure/secrets-store-csi-driver-provider-azure.
scored: false
- id: 4.5
text: "Extensible Admission Control"
checks:
- id: 4.5.1
text: "Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)"
type: "manual"
remediation: |
Follow the Kubernetes documentation and setup image provenance.
scored: false
- id: 4.6
text: "General Policies"
checks:
- id: 4.6.1
text: "Create administrative boundaries between resources using namespaces (Not Scored)"
type: "manual"
remediation: |
Follow the documentation and create namespaces for objects in your deployment as you need
them.
scored: false
- id: 4.6.2
text: "Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)"
type: "manual"
remediation: |
Seccomp is an alpha feature currently. By default, all alpha features are disabled. So, you
would need to enable alpha features in the apiserver by passing "--feature-
gates=AllAlpha=true" argument.
Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS
parameter to "--feature-gates=AllAlpha=true"
KUBE_API_ARGS="--feature-gates=AllAlpha=true"
Based on your system, restart the kube-apiserver service. For example:
systemctl restart kube-apiserver.service
Use annotations to enable the docker/default seccomp profile in your pod definitions. An
example is as below:
apiVersion: v1
kind: Pod
metadata:
name: trustworthy-pod
annotations:
seccomp.security.alpha.kubernetes.io/pod: docker/default
spec:
containers:
- name: trustworthy-container
image: sotrustworthy:latest
scored: false
- id: 4.6.3
text: "Apply Security Context to Your Pods and Containers (Not Scored)"
type: "manual"
remediation: |
Follow the Kubernetes documentation and apply security contexts to your pods. For a
suggested list of security contexts, you may refer to the CIS Security Benchmark for Docker
Containers.
scored: false
- id: 4.6.4
text: "The default namespace should not be used (Scored)"
type: "manual"
remediation: |
Ensure that namespaces are created to allow for appropriate segregation of Kubernetes
resources and that all new resources are created in a specific namespace.
scored: false
- id: 4.7
text: "Azure Policy Controls for ACR"
checks:
- id: 4.7.1
text: "Container Registry should use a virtual network service endpoint"
type: "manual"
remediation: |
Implement Azure Policy for Container Registry should use a virtual network service endpoint. See https://docs.microsoft.com/en-us/azure/container-registry/security-controls-policy#azure-security-benchmark
scored: false
- id: 4.7.2
text: "Container registries should not allow unrestricted network access"
type: "manual"
remediation: |
Implement Azure Policy for Container registries should not allow unrestricted network access. See https://docs.microsoft.com/en-us/azure/container-registry/container-registry-azure-policy#built-in-policy-definitions
scored: false
- id: 4.7.3
text: "Container registries should use private links"
type: "manual"
remediation: |
Implement Azure Policy for Container registries should use private links. See https://docs.microsoft.com/en-us/azure/container-registry/container-registry-azure-policy#built-in-policy-definitions
scored: false

2
cfg/cis-1.20/config.yaml Normal file
View File

@@ -0,0 +1,2 @@
---
## Version-specific settings that override the values in cfg/config.yaml

View File

@@ -0,0 +1,39 @@
---
controls:
version: "cis-1.20"
id: 3
text: "Control Plane Configuration"
type: "controlplane"
groups:
- id: 3.1
text: "Authentication and Authorization"
checks:
- id: 3.1.1
text: "Client certificate authentication should not be used for users (Manual)"
type: "manual"
remediation: |
Alternative mechanisms provided by Kubernetes such as the use of OIDC should be
implemented in place of client certificates.
scored: false
- id: 3.2
text: "Logging"
checks:
- id: 3.2.1
text: "Ensure that a minimal audit policy is created (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-policy-file"
set: true
remediation: |
Create an audit policy file for your cluster.
scored: false
- id: 3.2.2
text: "Ensure that the audit policy covers key security concerns (Manual)"
type: "manual"
remediation: |
Consider modification of the audit policy in use on the cluster to include these items, at a
minimum.
scored: false

135
cfg/cis-1.20/etcd.yaml Normal file
View File

@@ -0,0 +1,135 @@
---
controls:
version: "cis-1.20"
id: 2
text: "Etcd Node Configuration"
type: "etcd"
groups:
- id: 2
text: "Etcd Node Configuration Files"
checks:
- id: 2.1
text: "Ensure that the --cert-file and --key-file arguments are set as appropriate (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
bin_op: and
test_items:
- flag: "--cert-file"
env: "ETCD_CERT_FILE"
- flag: "--key-file"
env: "ETCD_KEY_FILE"
remediation: |
Follow the etcd service documentation and configure TLS encryption.
Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml
on the master node and set the below parameters.
--cert-file=</path/to/ca-file>
--key-file=</path/to/key-file>
scored: true
- id: 2.2
text: "Ensure that the --client-cert-auth argument is set to true (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
test_items:
- flag: "--client-cert-auth"
env: "ETCD_CLIENT_CERT_AUTH"
compare:
op: eq
value: true
remediation: |
Edit the etcd pod specification file $etcdconf on the master
node and set the below parameter.
--client-cert-auth="true"
scored: true
- id: 2.3
text: "Ensure that the --auto-tls argument is not set to true (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--auto-tls"
env: "ETCD_AUTO_TLS"
set: false
- flag: "--auto-tls"
env: "ETCD_AUTO_TLS"
compare:
op: eq
value: false
remediation: |
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
- id: 2.4
text: "Ensure that the --peer-cert-file and --peer-key-file arguments are
set as appropriate (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
bin_op: and
test_items:
- flag: "--peer-cert-file"
env: "ETCD_PEER_CERT_FILE"
- flag: "--peer-key-file"
env: "ETCD_PEER_KEY_FILE"
remediation: |
Follow the etcd service documentation and configure peer TLS encryption as appropriate
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>
scored: true
- id: 2.5
text: "Ensure that the --peer-client-cert-auth argument is set to true (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
test_items:
- flag: "--peer-client-cert-auth"
env: "ETCD_PEER_CLIENT_CERT_AUTH"
compare:
op: eq
value: true
remediation: |
Edit the etcd pod specification file $etcdconf on the master
node and set the below parameter.
--peer-client-cert-auth=true
scored: true
- id: 2.6
text: "Ensure that the --peer-auto-tls argument is not set to true (Automated)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--peer-auto-tls"
env: "ETCD_PEER_AUTO_TLS"
set: false
- flag: "--peer-auto-tls"
env: "ETCD_PEER_AUTO_TLS"
compare:
op: eq
value: false
remediation: |
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
- id: 2.7
text: "Ensure that a unique Certificate Authority is used for etcd (Manual)"
audit: "/bin/ps -ef | /bin/grep $etcdbin | /bin/grep -v grep"
tests:
test_items:
- flag: "--trusted-ca-file"
env: "ETCD_TRUSTED_CA_FILE"
remediation: |
[Manual test]
Follow the etcd documentation and create a dedicated certificate authority setup for the
etcd service.
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

989
cfg/cis-1.20/master.yaml Normal file
View File

@@ -0,0 +1,989 @@
---
controls:
version: "cis-1.20"
id: 1
text: "Master Node Security Configuration"
type: "master"
groups:
- id: 1.1
text: "Master Node Configuration Files"
checks:
- id: 1.1.1
text: "Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $apiserverconf; then stat -c permissions=%a $apiserverconf; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the
master node.
For example, chmod 644 $apiserverconf
scored: true
- id: 1.1.2
text: "Ensure that the API server pod specification file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $apiserverconf; then stat -c %U:%G $apiserverconf; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $apiserverconf
scored: true
- id: 1.1.3
text: "Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $controllermanagerconf; then stat -c permissions=%a $controllermanagerconf; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 $controllermanagerconf
scored: true
- id: 1.1.4
text: "Ensure that the controller manager pod specification file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $controllermanagerconf; then stat -c %U:%G $controllermanagerconf; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $controllermanagerconf
scored: true
- id: 1.1.5
text: "Ensure that the scheduler pod specification file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $schedulerconf; then stat -c permissions=%a $schedulerconf; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 $schedulerconf
scored: true
- id: 1.1.6
text: "Ensure that the scheduler pod specification file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $schedulerconf; then stat -c %U:%G $schedulerconf; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $schedulerconf
scored: true
- id: 1.1.7
text: "Ensure that the etcd pod specification file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $etcdconf; then find $etcdconf -name '*etcd*' | xargs stat -c permissions=%a; fi'"
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 $etcdconf
scored: true
- id: 1.1.8
text: "Ensure that the etcd pod specification file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $etcdconf; then find $etcdconf -name '*etcd*' | xargs stat -c %U:%G; fi'"
use_multiple_values: true
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $etcdconf
scored: true
- id: 1.1.9
text: "Ensure that the Container Network Interface file permissions are set to 644 or more restrictive (Manual)"
audit: |
ps -ef | grep $kubeletbin | grep -- --cni-conf-dir | sed 's%.*cni-conf-dir[= ]\([^ ]*\).*%\1%' | xargs -I{} find {} -mindepth 1 | xargs --no-run-if-empty stat -c permissions=%a
find /var/lib/cni/networks -type f 2> /dev/null | xargs --no-run-if-empty stat -c permissions=%a
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 <path/to/cni/files>
scored: false
- id: 1.1.10
text: "Ensure that the Container Network Interface file ownership is set to root:root (Manual)"
audit: |
ps -ef | grep $kubeletbin | grep -- --cni-conf-dir | sed 's%.*cni-conf-dir[= ]\([^ ]*\).*%\1%' | xargs -I{} find {} -mindepth 1 | xargs --no-run-if-empty stat -c %U:%G
find /var/lib/cni/networks -type f 2> /dev/null | xargs --no-run-if-empty stat -c %U:%G
use_multiple_values: true
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root <path/to/cni/files>
scored: false
- id: 1.1.11
text: "Ensure that the etcd data directory permissions are set to 700 or more restrictive (Automated)"
audit: ps -ef | grep $etcdbin | grep -- --data-dir | sed 's%.*data-dir[= ]\([^ ]*\).*%\1%' | xargs stat -c permissions=%a
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "700"
remediation: |
On the etcd server node, get the etcd data directory, passed as an argument --data-dir,
from the below command:
ps -ef | grep etcd
Run the below command (based on the etcd data directory found above). For example,
chmod 700 /var/lib/etcd
scored: true
- id: 1.1.12
text: "Ensure that the etcd data directory ownership is set to etcd:etcd (Automated)"
audit: ps -ef | grep $etcdbin | grep -- --data-dir | sed 's%.*data-dir[= ]\([^ ]*\).*%\1%' | xargs stat -c %U:%G
tests:
test_items:
- flag: "etcd:etcd"
remediation: |
On the etcd server node, get the etcd data directory, passed as an argument --data-dir,
from the below command:
ps -ef | grep etcd
Run the below command (based on the etcd data directory found above).
For example, chown etcd:etcd /var/lib/etcd
scored: true
- id: 1.1.13
text: "Ensure that the admin.conf file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e /etc/kubernetes/admin.conf; then stat -c permissions=%a /etc/kubernetes/admin.conf; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 /etc/kubernetes/admin.conf
scored: true
- id: 1.1.14
text: "Ensure that the admin.conf file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e /etc/kubernetes/admin.conf; then stat -c %U:%G /etc/kubernetes/admin.conf; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root /etc/kubernetes/admin.conf
scored: true
- id: 1.1.15
text: "Ensure that the scheduler.conf file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $schedulerkubeconfig; then stat -c permissions=%a $schedulerkubeconfig; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 $schedulerkubeconfig
scored: true
- id: 1.1.16
text: "Ensure that the scheduler.conf file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $schedulerkubeconfig; then stat -c %U:%G $schedulerkubeconfig; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $schedulerkubeconfig
scored: true
- id: 1.1.17
text: "Ensure that the controller-manager.conf file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $controllermanagerkubeconfig; then stat -c permissions=%a $controllermanagerkubeconfig; fi'"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 $controllermanagerkubeconfig
scored: true
- id: 1.1.18
text: "Ensure that the controller-manager.conf file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $controllermanagerkubeconfig; then stat -c %U:%G $controllermanagerkubeconfig; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root $controllermanagerkubeconfig
scored: true
- id: 1.1.19
text: "Ensure that the Kubernetes PKI directory and file ownership is set to root:root (Automated)"
audit: "find /etc/kubernetes/pki/ | xargs stat -c %U:%G"
use_multiple_values: true
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown -R root:root /etc/kubernetes/pki/
scored: true
- id: 1.1.20
text: "Ensure that the Kubernetes PKI certificate file permissions are set to 644 or more restrictive (Manual)"
audit: "find /etc/kubernetes/pki/ -name '*.crt' | xargs stat -c permissions=%a"
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod -R 644 /etc/kubernetes/pki/*.crt
scored: false
- id: 1.1.21
text: "Ensure that the Kubernetes PKI key file permissions are set to 600 (Manual)"
audit: "find /etc/kubernetes/pki/ -name '*.key' | xargs stat -c permissions=%a"
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "600"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod -R 600 /etc/kubernetes/pki/*.key
scored: false
- id: 1.2
text: "API Server"
checks:
- id: 1.2.1
text: "Ensure that the --anonymous-auth argument is set to false (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--anonymous-auth"
compare:
op: eq
value: false
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the below parameter.
--anonymous-auth=false
scored: false
- id: 1.2.2
text: "Ensure that the --token-auth-file parameter is not set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--token-auth-file"
set: false
remediation: |
Follow the documentation and configure alternate mechanisms for authentication. Then,
edit the API server pod specification file $apiserverconf
on the master node and remove the --token-auth-file=<filename> parameter.
scored: true
- id: 1.2.3
text: "Ensure that the --kubelet-https argument is set to true (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--kubelet-https"
compare:
op: eq
value: true
- flag: "--kubelet-https"
set: false
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and remove the --kubelet-https parameter.
scored: true
- id: 1.2.4
text: "Ensure that the --kubelet-client-certificate and --kubelet-client-key arguments are set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: and
test_items:
- flag: "--kubelet-client-certificate"
- flag: "--kubelet-client-key"
remediation: |
Follow the Kubernetes documentation and set up the TLS connection between the
apiserver and kubelets. Then, edit API server pod specification file
$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>
scored: true
- id: 1.2.5
text: "Ensure that the --kubelet-certificate-authority argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--kubelet-certificate-authority"
remediation: |
Follow the Kubernetes documentation and setup the TLS connection between
the apiserver and kubelets. Then, edit the API server pod specification file
$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>
scored: true
- id: 1.2.6
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--authorization-mode"
compare:
op: nothave
value: "AlwaysAllow"
remediation: |
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.
--authorization-mode=RBAC
scored: true
- id: 1.2.7
text: "Ensure that the --authorization-mode argument includes Node (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--authorization-mode"
compare:
op: has
value: "Node"
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the --authorization-mode parameter to a value that includes Node.
--authorization-mode=Node,RBAC
scored: true
- id: 1.2.8
text: "Ensure that the --authorization-mode argument includes RBAC (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--authorization-mode"
compare:
op: has
value: "RBAC"
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the --authorization-mode parameter to a value that includes RBAC,
for example:
--authorization-mode=Node,RBAC
scored: true
- id: 1.2.9
text: "Ensure that the admission control plugin EventRateLimit is set (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--enable-admission-plugins"
compare:
op: has
value: "EventRateLimit"
remediation: |
Follow the Kubernetes documentation and set the desired limits in a configuration file.
Then, edit the API server pod specification file $apiserverconf
and set the below parameters.
--enable-admission-plugins=...,EventRateLimit,...
--admission-control-config-file=<path/to/configuration/file>
scored: false
- id: 1.2.10
text: "Ensure that the admission control plugin AlwaysAdmit is not set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--enable-admission-plugins"
compare:
op: nothave
value: AlwaysAdmit
- flag: "--enable-admission-plugins"
set: false
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and either remove the --enable-admission-plugins parameter, or set it to a
value that does not include AlwaysAdmit.
scored: true
- id: 1.2.11
text: "Ensure that the admission control plugin AlwaysPullImages is set (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--enable-admission-plugins"
compare:
op: has
value: "AlwaysPullImages"
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the --enable-admission-plugins parameter to include
AlwaysPullImages.
--enable-admission-plugins=...,AlwaysPullImages,...
scored: false
- id: 1.2.12
text: "Ensure that the admission control plugin SecurityContextDeny is set if PodSecurityPolicy is not used (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--enable-admission-plugins"
compare:
op: has
value: "SecurityContextDeny"
- flag: "--enable-admission-plugins"
compare:
op: has
value: "PodSecurityPolicy"
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the --enable-admission-plugins parameter to include
SecurityContextDeny, unless PodSecurityPolicy is already in place.
--enable-admission-plugins=...,SecurityContextDeny,...
scored: false
- id: 1.2.13
text: "Ensure that the admission control plugin ServiceAccount is set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--disable-admission-plugins"
compare:
op: nothave
value: "ServiceAccount"
- flag: "--disable-admission-plugins"
set: false
remediation: |
Follow the documentation and create ServiceAccount objects as per your environment.
Then, edit the API server pod specification file $apiserverconf
on the master node and ensure that the --disable-admission-plugins parameter is set to a
value that does not include ServiceAccount.
scored: true
- id: 1.2.14
text: "Ensure that the admission control plugin NamespaceLifecycle is set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--disable-admission-plugins"
compare:
op: nothave
value: "NamespaceLifecycle"
- flag: "--disable-admission-plugins"
set: false
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the --disable-admission-plugins parameter to
ensure it does not include NamespaceLifecycle.
scored: true
- id: 1.2.15
text: "Ensure that the admission control plugin PodSecurityPolicy is set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--enable-admission-plugins"
compare:
op: has
value: "PodSecurityPolicy"
remediation: |
Follow the documentation and create Pod Security Policy objects as per your environment.
Then, edit the API server pod specification file $apiserverconf
on the master node and set the --enable-admission-plugins parameter to a
value that includes PodSecurityPolicy:
--enable-admission-plugins=...,PodSecurityPolicy,...
Then restart the API Server.
scored: true
- id: 1.2.16
text: "Ensure that the admission control plugin NodeRestriction is set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--enable-admission-plugins"
compare:
op: has
value: "NodeRestriction"
remediation: |
Follow the Kubernetes documentation and configure NodeRestriction plug-in on kubelets.
Then, edit the API server pod specification file $apiserverconf
on the master node and set the --enable-admission-plugins parameter to a
value that includes NodeRestriction.
--enable-admission-plugins=...,NodeRestriction,...
scored: true
- id: 1.2.17
text: "Ensure that the --insecure-bind-address argument is not set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--insecure-bind-address"
set: false
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and remove the --insecure-bind-address parameter.
scored: true
- id: 1.2.18
text: "Ensure that the --insecure-port argument is set to 0 (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--insecure-port"
compare:
op: eq
value: 0
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the below parameter.
--insecure-port=0
scored: true
- id: 1.2.19
text: "Ensure that the --secure-port argument is not set to 0 (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--secure-port"
compare:
op: gt
value: 0
- flag: "--secure-port"
set: false
remediation: |
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
- id: 1.2.20
text: "Ensure that the --profiling argument is set to false (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--profiling"
compare:
op: eq
value: false
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the below parameter.
--profiling=false
scored: true
- id: 1.2.21
text: "Ensure that the --audit-log-path argument is set (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-log-path"
remediation: |
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
scored: true
- id: 1.2.22
text: "Ensure that the --audit-log-maxage argument is set to 30 or as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-log-maxage"
compare:
op: gte
value: 30
remediation: |
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
scored: true
- id: 1.2.23
text: "Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-log-maxbackup"
compare:
op: gte
value: 10
remediation: |
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
scored: true
- id: 1.2.24
text: "Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-log-maxsize"
compare:
op: gte
value: 100
remediation: |
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
scored: true
- id: 1.2.25
text: "Ensure that the --request-timeout argument is set as appropriate (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
type: manual
remediation: |
Edit the API server pod specification file $apiserverconf
and set the below parameter as appropriate and if needed.
For example,
--request-timeout=300s
scored: false
- id: 1.2.26
text: "Ensure that the --service-account-lookup argument is set to true (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--service-account-lookup"
set: false
- flag: "--service-account-lookup"
compare:
op: eq
value: true
remediation: |
Edit the API server pod specification file $apiserverconf
on the master node and set the below parameter.
--service-account-lookup=true
Alternatively, you can delete the --service-account-lookup parameter from this file so
that the default takes effect.
scored: true
- id: 1.2.27
text: "Ensure that the --service-account-key-file argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--service-account-key-file"
remediation: |
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>
scored: true
- id: 1.2.28
text: "Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: and
test_items:
- flag: "--etcd-certfile"
- flag: "--etcd-keyfile"
remediation: |
Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd.
Then, edit the API server pod specification file $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>
scored: true
- id: 1.2.29
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: and
test_items:
- flag: "--tls-cert-file"
- flag: "--tls-private-key-file"
remediation: |
Follow the Kubernetes documentation and set up the TLS connection on the apiserver.
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>
--tls-private-key-file=<path/to/tls-key-file>
scored: true
- id: 1.2.30
text: "Ensure that the --client-ca-file argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--client-ca-file"
remediation: |
Follow the Kubernetes documentation and set up the TLS connection on the apiserver.
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
- id: 1.2.31
text: "Ensure that the --etcd-cafile argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--etcd-cafile"
remediation: |
Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd.
Then, edit the API server pod specification file $apiserverconf
on the master node and set the etcd certificate authority file parameter.
--etcd-cafile=<path/to/ca-file>
scored: true
- id: 1.2.32
text: "Ensure that the --encryption-provider-config argument is set as appropriate (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--encryption-provider-config"
remediation: |
Follow the Kubernetes documentation and configure a EncryptionConfig file.
Then, edit the API server pod specification file $apiserverconf
on the master node and set the --encryption-provider-config parameter to the path of that file: --encryption-provider-config=</path/to/EncryptionConfig/File>
scored: false
- id: 1.2.33
text: "Ensure that encryption providers are appropriately configured (Manual)"
audit: |
ENCRYPTION_PROVIDER_CONFIG=$(ps -ef | grep $apiserverbin | grep -- --encryption-provider-config | sed 's%.*encryption-provider-config[= ]\([^ ]*\).*%\1%')
if test -e $ENCRYPTION_PROVIDER_CONFIG; then grep -A1 'providers:' $ENCRYPTION_PROVIDER_CONFIG | tail -n1 | grep -o "[A-Za-z]*" | sed 's/^/provider=/'; fi
tests:
test_items:
- flag: "provider"
compare:
op: valid_elements
value: "aescbc,kms,secretbox"
remediation: |
Follow the Kubernetes documentation and configure a EncryptionConfig file.
In this file, choose aescbc, kms or secretbox as the encryption provider.
scored: false
- id: 1.2.34
text: "Ensure that the API Server only makes use of Strong Cryptographic Ciphers (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--tls-cipher-suites"
compare:
op: valid_elements
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"
remediation: |
Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml
on the master 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
scored: false
- id: 1.3
text: "Controller Manager"
checks:
- id: 1.3.1
text: "Ensure that the --terminated-pod-gc-threshold argument is set as appropriate (Manual)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
test_items:
- flag: "--terminated-pod-gc-threshold"
remediation: |
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: false
- id: 1.3.2
text: "Ensure that the --profiling argument is set to false (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
test_items:
- flag: "--profiling"
compare:
op: eq
value: false
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
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 to true (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
test_items:
- flag: "--use-service-account-credentials"
compare:
op: noteq
value: false
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
on the master node to set the below parameter.
--use-service-account-credentials=true
scored: true
- id: 1.3.4
text: "Ensure that the --service-account-private-key-file argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
test_items:
- flag: "--service-account-private-key-file"
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
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>
scored: true
- id: 1.3.5
text: "Ensure that the --root-ca-file argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
test_items:
- flag: "--root-ca-file"
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
on the master node and set the --root-ca-file parameter to the certificate bundle file`.
--root-ca-file=<path/to/file>
scored: true
- id: 1.3.6
text: "Ensure that the RotateKubeletServerCertificate argument is set to true (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--feature-gates"
compare:
op: nothave
value: "RotateKubeletServerCertificate=false"
set: true
- flag: "--feature-gates"
set: false
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
on the master node and set the --feature-gates parameter to include RotateKubeletServerCertificate=true.
--feature-gates=RotateKubeletServerCertificate=true
scored: true
- id: 1.3.7
text: "Ensure that the --bind-address argument is set to 127.0.0.1 (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--bind-address"
compare:
op: eq
value: "127.0.0.1"
- flag: "--bind-address"
set: false
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
on the master node and ensure the correct value for the --bind-address parameter
scored: true
- id: 1.4
text: "Scheduler"
checks:
- id: 1.4.1
text: "Ensure that the --profiling argument is set to false (Automated)"
audit: "/bin/ps -ef | grep $schedulerbin | grep -v grep"
tests:
test_items:
- flag: "--profiling"
compare:
op: eq
value: false
remediation: |
Edit the Scheduler pod specification file $schedulerconf file
on the master node and set the below parameter.
--profiling=false
scored: true
- id: 1.4.2
text: "Ensure that the --bind-address argument is set to 127.0.0.1 (Automated)"
audit: "/bin/ps -ef | grep $schedulerbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--bind-address"
compare:
op: eq
value: "127.0.0.1"
- flag: "--bind-address"
set: false
remediation: |
Edit the Scheduler pod specification file $schedulerconf
on the master node and ensure the correct value for the --bind-address parameter
scored: true

463
cfg/cis-1.20/node.yaml Normal file
View File

@@ -0,0 +1,463 @@
---
controls:
version: "cis-1.20"
id: 4
text: "Worker Node Security Configuration"
type: "node"
groups:
- id: 4.1
text: "Worker Node Configuration Files"
checks:
- id: 4.1.1
text: "Ensure that the kubelet service file permissions are set to 644 or more restrictive (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletsvc; then stat -c permissions=%a $kubeletsvc; fi'' '
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 $kubeletsvc
scored: true
- id: 4.1.2
text: "Ensure that the kubelet service file ownership is set to root:root (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletsvc; then stat -c %U:%G $kubeletsvc; fi'' '
tests:
test_items:
- flag: root:root
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: 4.1.3
text: "If proxy kubeconfig file exists ensure permissions are set to 644 or more restrictive (Manual)"
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c permissions=%a $proxykubeconfig; fi'' '
tests:
bin_op: or
test_items:
- flag: "permissions"
set: true
compare:
op: bitmask
value: "644"
- flag: "$proxykubeconfig"
set: false
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 $proxykubeconfig
scored: false
- id: 4.1.4
text: "If proxy kubeconfig file exists ensure ownership is set to root:root (Manual)"
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c %U:%G $proxykubeconfig; fi'' '
tests:
bin_op: or
test_items:
- flag: root:root
- flag: "$proxykubeconfig"
set: false
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example, chown root:root $proxykubeconfig
scored: false
- id: 4.1.5
text: "Ensure that the --kubeconfig kubelet.conf file permissions are set to 644 or more restrictive (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletkubeconfig; then stat -c permissions=%a $kubeletkubeconfig; fi'' '
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chmod 644 $kubeletkubeconfig
scored: true
- id: 4.1.6
text: "Ensure that the --kubeconfig kubelet.conf file ownership is set to root:root (Manual)"
audit: '/bin/sh -c ''if test -e $kubeletkubeconfig; then stat -c %U:%G $kubeletkubeconfig; fi'' '
tests:
test_items:
- flag: root:root
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
chown root:root $kubeletkubeconfig
scored: false
- id: 4.1.7
text: "Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Manual)"
audit: |
CAFILE=$(ps -ef | grep kubelet | grep -v apiserver | grep -- --client-ca-file= | awk -F '--client-ca-file=' '{print $2}' | awk '{print $1}')
if test -z $CAFILE; then CAFILE=$kubeletcafile; fi
if test -e $CAFILE; then stat -c permissions=%a $CAFILE; fi
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the following command to modify the file permissions of the
--client-ca-file chmod 644 <filename>
scored: false
- id: 4.1.8
text: "Ensure that the client certificate authorities file ownership is set to root:root (Manual)"
audit: |
CAFILE=$(ps -ef | grep kubelet | grep -v apiserver | grep -- --client-ca-file= | awk -F '--client-ca-file=' '{print $2}' | awk '{print $1}')
if test -z $CAFILE; then CAFILE=$kubeletcafile; fi
if test -e $CAFILE; then stat -c %U:%G $CAFILE; fi
tests:
test_items:
- flag: root:root
compare:
op: eq
value: root:root
remediation: |
Run the following command to modify the ownership of the --client-ca-file.
chown root:root <filename>
scored: false
- id: 4.1.9
text: "Ensure that the kubelet --config configuration file has permissions set to 644 or more restrictive (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletconf; then stat -c permissions=%a $kubeletconf; fi'' '
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the following command (using the config file location identified in the Audit step)
chmod 644 $kubeletconf
scored: true
- id: 4.1.10
text: "Ensure that the kubelet --config configuration file ownership is set to root:root (Automated)"
audit: '/bin/sh -c ''if test -e $kubeletconf; then stat -c %U:%G $kubeletconf; fi'' '
tests:
test_items:
- flag: root:root
remediation: |
Run the following command (using the config file location identified in the Audit step)
chown root:root $kubeletconf
scored: true
- id: 4.2
text: "Kubelet"
checks:
- id: 4.2.1
text: "Ensure that the anonymous-auth argument is set to false (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: "--anonymous-auth"
path: '{.authentication.anonymous.enabled}'
compare:
op: eq
value: false
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
$kubeletsvc 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: 4.2.2
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --authorization-mode
path: '{.authorization.mode}'
compare:
op: nothave
value: AlwaysAllow
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
$kubeletsvc 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: 4.2.3
text: "Ensure that the --client-ca-file argument is set as appropriate (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --client-ca-file
path: '{.authentication.x509.clientCAFile}'
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
$kubeletsvc 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: 4.2.4
text: "Ensure that the --read-only-port argument is set to 0 (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
bin_op: or
test_items:
- flag: "--read-only-port"
path: '{.readOnlyPort}'
compare:
op: eq
value: 0
- flag: "--read-only-port"
path: '{.readOnlyPort}'
set: false
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
$kubeletsvc 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: false
- id: 4.2.5
text: "Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --streaming-connection-idle-timeout
path: '{.streamingConnectionIdleTimeout}'
compare:
op: noteq
value: 0
- flag: --streaming-connection-idle-timeout
path: '{.streamingConnectionIdleTimeout}'
set: false
bin_op: or
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
$kubeletsvc 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: false
- id: 4.2.6
text: "Ensure that the --protect-kernel-defaults argument is set to true (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --protect-kernel-defaults
path: '{.protectKernelDefaults}'
compare:
op: eq
value: 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
$kubeletsvc 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: 4.2.7
text: "Ensure that the --make-iptables-util-chains argument is set to true (Automated)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --make-iptables-util-chains
path: '{.makeIPTablesUtilChains}'
compare:
op: eq
value: true
- flag: --make-iptables-util-chains
path: '{.makeIPTablesUtilChains}'
set: false
bin_op: or
remediation: |
If using a Kubelet config file, edit the file to set makeIPTablesUtilChains: true.
If using command line arguments, edit the kubelet service file
$kubeletsvc 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: 4.2.8
text: "Ensure that the --hostname-override argument is not set (Manual)"
# This is one of those properties that can only be set as a command line argument.
# To check if the property is set as expected, we need to parse the kubelet command
# instead reading the Kubelet Configuration file.
audit: "/bin/ps -fC $kubeletbin "
tests:
test_items:
- flag: --hostname-override
set: false
remediation: |
Edit the kubelet service file $kubeletsvc
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: false
- id: 4.2.9
text: "Ensure that the --event-qps argument is set to 0 or a level which ensures appropriate event capture (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --event-qps
path: '{.eventRecordQPS}'
compare:
op: eq
value: 0
remediation: |
If using a Kubelet config file, edit the file to set eventRecordQPS: to an appropriate level.
If using command line arguments, edit the kubelet service file
$kubeletsvc on each worker node and
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: false
- id: 4.2.10
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --tls-cert-file
path: '{.tlsCertFile}'
- flag: --tls-private-key-file
path: '{.tlsPrivateKeyFile}'
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
$kubeletsvc on each worker node and
set the below parameters in KUBELET_CERTIFICATE_ARGS variable.
--tls-cert-file=<path/to/tls-certificate-file>
--tls-private-key-file=<path/to/tls-key-file>
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: false
- id: 4.2.11
text: "Ensure that the --rotate-certificates argument is not set to false (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --rotate-certificates
path: '{.rotateCertificates}'
compare:
op: eq
value: true
- flag: --rotate-certificates
path: '{.rotateCertificates}'
set: false
bin_op: or
remediation: |
If using a Kubelet config file, edit the file to add the line rotateCertificates: true or
remove it altogether to use the default value.
If using command line arguments, edit the kubelet service file
$kubeletsvc on each worker node and
remove --rotate-certificates=false argument from the KUBELET_CERTIFICATE_ARGS
variable.
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: false
- id: 4.2.12
text: "Verify that the RotateKubeletServerCertificate argument is set to true (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
bin_op: or
test_items:
- flag: RotateKubeletServerCertificate
path: '{.featureGates.RotateKubeletServerCertificate}'
compare:
op: nothave
value: false
- flag: RotateKubeletServerCertificate
path: '{.featureGates.RotateKubeletServerCertificate}'
set: false
remediation: |
Edit the kubelet service file $kubeletsvc
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: false
- id: 4.2.13
text: "Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Manual)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --tls-cipher-suites
path: '{range .tlsCipherSuites[:]}{}{'',''}{end}'
compare:
op: valid_elements
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
remediation: |
If using a Kubelet config file, edit the file to set TLSCipherSuites: to
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
or to a subset of these values.
If using executable arguments, edit the kubelet service file
$kubeletsvc on each worker node and
set the --tls-cipher-suites parameter as follows, or to a subset of these values.
--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: false

238
cfg/cis-1.20/policies.yaml Normal file
View File

@@ -0,0 +1,238 @@
---
controls:
version: "cis-1.20"
id: 5
text: "Kubernetes Policies"
type: "policies"
groups:
- id: 5.1
text: "RBAC and Service Accounts"
checks:
- id: 5.1.1
text: "Ensure that the cluster-admin role is only used where required (Manual)"
type: "manual"
remediation: |
Identify all clusterrolebindings to the cluster-admin role. Check if they are used and
if they need this role or if they could use a role with fewer privileges.
Where possible, first bind users to a lower privileged role and then remove the
clusterrolebinding to the cluster-admin role :
kubectl delete clusterrolebinding [name]
scored: false
- id: 5.1.2
text: "Minimize access to secrets (Manual)"
type: "manual"
remediation: |
Where possible, remove get, list and watch access to secret objects in the cluster.
scored: false
- id: 5.1.3
text: "Minimize wildcard use in Roles and ClusterRoles (Manual)"
type: "manual"
remediation: |
Where possible replace any use of wildcards in clusterroles and roles with specific
objects or actions.
scored: false
- id: 5.1.4
text: "Minimize access to create pods (Manual)"
type: "manual"
remediation: |
Where possible, remove create access to pod objects in the cluster.
scored: false
- id: 5.1.5
text: "Ensure that default service accounts are not actively used. (Manual)"
type: "manual"
remediation: |
Create explicit service accounts wherever a Kubernetes workload requires specific access
to the Kubernetes API server.
Modify the configuration of each default service account to include this value
automountServiceAccountToken: false
scored: false
- id: 5.1.6
text: "Ensure that Service Account Tokens are only mounted where necessary (Manual)"
type: "manual"
remediation: |
Modify the definition of pods and service accounts which do not need to mount service
account tokens to disable it.
scored: false
- id: 5.1.7
text: "Avoid use of system:masters group (Manual)"
type: "manual"
remediation: |
Remove the system:masters group from all users in the cluster.
scored: false
- id: 5.1.8
text: "Limit use of the Bind, Impersonate and Escalate permissions in the Kubernetes cluster (Manual)"
type: "manual"
remediation: |
Where possible, remove the impersonate, bind and escalate rights from subjects.
scored: false
- id: 5.2
text: "Pod Security Policies"
checks:
- id: 5.2.1
text: "Minimize the admission of privileged containers (Automated)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that
the .spec.privileged field is omitted or set to false.
scored: false
- id: 5.2.2
text: "Minimize the admission of containers wishing to share the host process ID namespace (Automated)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostPID field is omitted or set to false.
scored: false
- id: 5.2.3
text: "Minimize the admission of containers wishing to share the host IPC namespace (Automated)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostIPC field is omitted or set to false.
scored: false
- id: 5.2.4
text: "Minimize the admission of containers wishing to share the host network namespace (Automated)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.hostNetwork field is omitted or set to false.
scored: false
- id: 5.2.5
text: "Minimize the admission of containers with allowPrivilegeEscalation (Automated)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.allowPrivilegeEscalation field is omitted or set to false.
scored: false
- id: 5.2.6
text: "Minimize the admission of root containers (Automated)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.runAsUser.rule is set to either MustRunAsNonRoot or MustRunAs with the range of
UIDs not including 0.
scored: false
- id: 5.2.7
text: "Minimize the admission of containers with the NET_RAW capability (Automated)"
type: "manual"
remediation: |
Create a PSP as described in the Kubernetes documentation, ensuring that the
.spec.requiredDropCapabilities is set to include either NET_RAW or ALL.
scored: false
- id: 5.2.8
text: "Minimize the admission of containers with added capabilities (Automated)"
type: "manual"
remediation: |
Ensure that allowedCapabilities is not present in PSPs for the cluster unless
it is set to an empty array.
scored: false
- id: 5.2.9
text: "Minimize the admission of containers with capabilities assigned (Manual)"
type: "manual"
remediation: |
Review the use of capabilites in applications running on your cluster. Where a namespace
contains applicaions which do not require any Linux capabities to operate consider adding
a PSP which forbids the admission of containers which do not drop all capabilities.
scored: false
- id: 5.3
text: "Network Policies and CNI"
checks:
- id: 5.3.1
text: "Ensure that the CNI in use supports Network Policies (Manual)"
type: "manual"
remediation: |
If the CNI plugin in use does not support network policies, consideration should be given to
making use of a different plugin, or finding an alternate mechanism for restricting traffic
in the Kubernetes cluster.
scored: false
- id: 5.3.2
text: "Ensure that all Namespaces have Network Policies defined (Manual)"
type: "manual"
remediation: |
Follow the documentation and create NetworkPolicy objects as you need them.
scored: false
- id: 5.4
text: "Secrets Management"
checks:
- id: 5.4.1
text: "Prefer using secrets as files over secrets as environment variables (Manual)"
type: "manual"
remediation: |
if possible, rewrite application code to read secrets from mounted secret files, rather than
from environment variables.
scored: false
- id: 5.4.2
text: "Consider external secret storage (Manual)"
type: "manual"
remediation: |
Refer to the secrets management options offered by your cloud provider or a third-party
secrets management solution.
scored: false
- id: 5.5
text: "Extensible Admission Control"
checks:
- id: 5.5.1
text: "Configure Image Provenance using ImagePolicyWebhook admission controller (Manual)"
type: "manual"
remediation: |
Follow the Kubernetes documentation and setup image provenance.
scored: false
- id: 5.7
text: "General Policies"
checks:
- id: 5.7.1
text: "Create administrative boundaries between resources using namespaces (Manual)"
type: "manual"
remediation: |
Follow the documentation and create namespaces for objects in your deployment as you need
them.
scored: false
- id: 5.7.2
text: "Ensure that the seccomp profile is set to docker/default in your pod definitions (Manual)"
type: "manual"
remediation: |
Use security context to enable the docker/default seccomp profile in your pod definitions.
An example is as below:
securityContext:
seccompProfile:
type: RuntimeDefault
scored: false
- id: 5.7.3
text: "Apply Security Context to Your Pods and Containers (Manual)"
type: "manual"
remediation: |
Follow the Kubernetes documentation and apply security contexts to your pods. For a
suggested list of security contexts, you may refer to the CIS Security Benchmark for Docker
Containers.
scored: false
- id: 5.7.4
text: "The default namespace should not be used (Manual)"
type: "manual"
remediation: |
Ensure that namespaces are created to allow for appropriate segregation of Kubernetes
resources and that all new resources are created in a specific namespace.
scored: false

View File

@@ -1,6 +1,6 @@
---
controls:
version: 1.5
version: "cis-1.5"
id: 3
text: "Control Plane Configuration"
type: "controlplane"
@@ -21,7 +21,11 @@ groups:
checks:
- id: 3.2.1
text: "Ensure that a minimal audit policy is created (Scored)"
type: "manual"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-policy-file"
set: true
remediation: |
Create an audit policy file for your cluster.
scored: true

View File

@@ -1,6 +1,6 @@
---
controls:
version: 1.15
version: "cis-1.5"
id: 2
text: "Etcd Node Configuration"
type: "etcd"

View File

@@ -1,6 +1,6 @@
---
controls:
version: 1.5
version: "cis-1.5"
id: 1
text: "Master Node Security Configuration"
type: "master"
@@ -223,7 +223,7 @@ groups:
- id: 1.1.15
text: "Ensure that the scheduler.conf file permissions are set to 644 or more restrictive (Scored)"
audit: "/bin/sh -c 'if test -e /etc/kubernetes/scheduler.conf; then stat -c permissions=%a /etc/kubernetes/scheduler.conf; fi'"
audit: "/bin/sh -c 'if test -e $schedulerkubeconfig; then stat -c permissions=%a $schedulerkubeconfig; fi'"
tests:
test_items:
- flag: "permissions"
@@ -234,12 +234,12 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 /etc/kubernetes/scheduler.conf
chmod 644 $schedulerkubeconfig
scored: true
- id: 1.1.16
text: "Ensure that the scheduler.conf file ownership is set to root:root (Scored)"
audit: "/bin/sh -c 'if test -e /etc/kubernetes/scheduler.conf; then stat -c %U:%G /etc/kubernetes/scheduler.conf; fi'"
audit: "/bin/sh -c 'if test -e $schedulerkubeconfig; then stat -c %U:%G $schedulerkubeconfig; fi'"
tests:
test_items:
- flag: "root:root"
@@ -250,12 +250,12 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root /etc/kubernetes/scheduler.conf
chown root:root $schedulerkubeconfig
scored: true
- id: 1.1.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 /etc/kubernetes/controller-manager.conf; then stat -c permissions=%a /etc/kubernetes/controller-manager.conf; fi'"
audit: "/bin/sh -c 'if test -e $controllermanagerkubeconfig; then stat -c permissions=%a $controllermanagerkubeconfig; fi'"
tests:
test_items:
- flag: "permissions"
@@ -266,12 +266,12 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 /etc/kubernetes/controller-manager.conf
chmod 644 $controllermanagerkubeconfig
scored: true
- id: 1.1.18
text: "Ensure that the controller-manager.conf file ownership is set to root:root (Scored)"
audit: "/bin/sh -c 'if test -e /etc/kubernetes/controller-manager.conf; then stat -c %U:%G /etc/kubernetes/controller-manager.conf; fi'"
audit: "/bin/sh -c 'if test -e $controllermanagerkubeconfig; then stat -c %U:%G $controllermanagerkubeconfig; fi'"
tests:
test_items:
- flag: "root:root"
@@ -282,7 +282,7 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root /etc/kubernetes/controller-manager.conf
chown root:root $controllermanagerkubeconfig
scored: true
- id: 1.1.19
@@ -766,13 +766,7 @@ groups:
- id: 1.2.26
text: "Ensure that the --request-timeout argument is set as appropriate (Scored)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--request-timeout"
set: false
- flag: "--request-timeout"
set: true
type: manual
remediation: |
Edit the API server pod specification file $apiserverconf
and set the below parameter as appropriate and if needed.
@@ -908,7 +902,7 @@ groups:
test_items:
- flag: "--tls-cipher-suites"
compare:
op: has
op: valid_elements
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: |
@@ -997,12 +991,15 @@ groups:
text: "Ensure that the RotateKubeletServerCertificate argument is set to true (Scored)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--feature-gates"
compare:
op: eq
value: "RotateKubeletServerCertificate=true"
op: nothave
value: "RotateKubeletServerCertificate=false"
set: true
- flag: "--feature-gates"
set: false
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
on the master node and set the --feature-gates parameter to include RotateKubeletServerCertificate=true.

View File

@@ -1,6 +1,6 @@
---
controls:
version: 1.5
version: "cis-1.5"
id: 4
text: "Worker Node Security Configuration"
type: "node"
@@ -41,12 +41,15 @@ groups:
text: "Ensure that the proxy kubeconfig file permissions are set to 644 or more restrictive (Scored)"
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c permissions=%a $proxykubeconfig; fi'' '
tests:
bin_op: or
test_items:
- flag: "permissions"
set: true
compare:
op: bitmask
value: "644"
- flag: "$proxykubeconfig"
set: false
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
@@ -57,9 +60,12 @@ groups:
text: "Ensure that the proxy kubeconfig file ownership is set to root:root (Scored)"
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c %U:%G $proxykubeconfig; fi'' '
tests:
bin_op: or
test_items:
- flag: root:root
set: true
- flag: "$proxykubeconfig"
set: false
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example, chown root:root $proxykubeconfig
@@ -436,13 +442,17 @@ groups:
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
bin_op: or
test_items:
- flag: RotateKubeletServerCertificate
path: '{.featureGates.RotateKubeletServerCertificate}'
set: true
compare:
op: eq
value: true
op: nothave
value: false
- flag: RotateKubeletServerCertificate
path: '{.featureGates.RotateKubeletServerCertificate}'
set: false
remediation: |
Edit the kubelet service file $kubeletsvc
on each worker node and set the below parameter in KUBELET_CERTIFICATE_ARGS variable.

View File

@@ -1,6 +1,6 @@
---
controls:
version: 1.5
version: "cis-1.5"
id: 5
text: "Kubernetes Policies"
type: "policies"
@@ -131,7 +131,7 @@ groups:
text: "Minimize the admission of containers with capabilities assigned (Not Scored)"
type: "manual"
remediation: |
Review the use of capabilites in applications runnning on your cluster. Where a namespace
Review the use of capabilites in applications running on your cluster. Where a namespace
contains applicaions which do not require any Linux capabities to operate consider adding
a PSP which forbids the admission of containers which do not drop all capabilities.
scored: false

View File

@@ -1,6 +1,6 @@
---
controls:
version: 1.6
version: "cis-1.6"
id: 3
text: "Control Plane Configuration"
type: "controlplane"
@@ -21,7 +21,11 @@ groups:
checks:
- id: 3.2.1
text: "Ensure that a minimal audit policy is created (Manual)"
type: "manual"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
test_items:
- flag: "--audit-policy-file"
set: true
remediation: |
Create an audit policy file for your cluster.
scored: false

View File

@@ -1,6 +1,6 @@
---
controls:
version: 1.6
version: "cis-1.6"
id: 2
text: "Etcd Node Configuration"
type: "etcd"
@@ -15,7 +15,9 @@ groups:
bin_op: and
test_items:
- flag: "--cert-file"
env: "ETCD_CERT_FILE"
- flag: "--key-file"
env: "ETCD_KEY_FILE"
remediation: |
Follow the etcd service documentation and configure TLS encryption.
Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml
@@ -30,6 +32,7 @@ groups:
tests:
test_items:
- flag: "--client-cert-auth"
env: "ETCD_CLIENT_CERT_AUTH"
compare:
op: eq
value: true
@@ -46,8 +49,10 @@ groups:
bin_op: or
test_items:
- flag: "--auto-tls"
env: "ETCD_AUTO_TLS"
set: false
- flag: "--auto-tls"
env: "ETCD_AUTO_TLS"
compare:
op: eq
value: false
@@ -65,7 +70,9 @@ groups:
bin_op: and
test_items:
- flag: "--peer-cert-file"
env: "ETCD_PEER_CERT_FILE"
- flag: "--peer-key-file"
env: "ETCD_PEER_KEY_FILE"
remediation: |
Follow the etcd service documentation and configure peer TLS encryption as appropriate
for your etcd cluster.
@@ -81,6 +88,7 @@ groups:
tests:
test_items:
- flag: "--peer-client-cert-auth"
env: "ETCD_PEER_CLIENT_CERT_AUTH"
compare:
op: eq
value: true
@@ -97,8 +105,10 @@ groups:
bin_op: or
test_items:
- flag: "--peer-auto-tls"
env: "ETCD_PEER_AUTO_TLS"
set: false
- flag: "--peer-auto-tls"
env: "ETCD_PEER_AUTO_TLS"
compare:
op: eq
value: false
@@ -114,6 +124,7 @@ groups:
tests:
test_items:
- flag: "--trusted-ca-file"
env: "ETCD_TRUSTED_CA_FILE"
remediation: |
[Manual test]
Follow the etcd documentation and create a dedicated certificate authority setup for the

View File

@@ -1,6 +1,6 @@
---
controls:
version: 1.6
version: "cis-1.6"
id: 1
text: "Master Node Security Configuration"
type: "master"
@@ -91,7 +91,8 @@ groups:
- id: 1.1.7
text: "Ensure that the etcd pod specification file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e $etcdconf; then stat -c permissions=%a $etcdconf; fi'"
audit: "/bin/sh -c 'if test -e $etcdconf; then find $etcdconf -name '*etcd*' | xargs stat -c permissions=%a; fi'"
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
@@ -106,7 +107,8 @@ groups:
- id: 1.1.8
text: "Ensure that the etcd pod specification file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e $etcdconf; then stat -c %U:%G $etcdconf; fi'"
audit: "/bin/sh -c 'if test -e $etcdconf; then find $etcdconf -name '*etcd*' | xargs stat -c %U:%G; fi'"
use_multiple_values: true
tests:
test_items:
- flag: "root:root"
@@ -118,8 +120,16 @@ groups:
- id: 1.1.9
text: "Ensure that the Container Network Interface file permissions are set to 644 or more restrictive (Manual)"
audit: "stat -c permissions=%a <path/to/cni/files>"
type: "manual"
audit: |
ps -ef | grep $kubeletbin | grep -- --cni-conf-dir | sed 's%.*cni-conf-dir[= ]\([^ ]*\).*%\1%' | xargs -I{} find {} -mindepth 1 | xargs --no-run-if-empty stat -c permissions=%a
find /var/lib/cni/networks -type f 2> /dev/null | xargs --no-run-if-empty stat -c permissions=%a
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
@@ -128,8 +138,13 @@ groups:
- id: 1.1.10
text: "Ensure that the Container Network Interface file ownership is set to root:root (Manual)"
audit: "stat -c %U:%G <path/to/cni/files>"
type: "manual"
audit: |
ps -ef | grep $kubeletbin | grep -- --cni-conf-dir | sed 's%.*cni-conf-dir[= ]\([^ ]*\).*%\1%' | xargs -I{} find {} -mindepth 1 | xargs --no-run-if-empty stat -c %U:%G
find /var/lib/cni/networks -type f 2> /dev/null | xargs --no-run-if-empty stat -c %U:%G
use_multiple_values: true
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
@@ -196,7 +211,7 @@ groups:
- id: 1.1.15
text: "Ensure that the scheduler.conf file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e /etc/kubernetes/scheduler.conf; then stat -c permissions=%a /etc/kubernetes/scheduler.conf; fi'"
audit: "/bin/sh -c 'if test -e $schedulerkubeconfig; then stat -c permissions=%a $schedulerkubeconfig; fi'"
tests:
test_items:
- flag: "permissions"
@@ -206,24 +221,24 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 /etc/kubernetes/scheduler.conf
chmod 644 $schedulerkubeconfig
scored: true
- id: 1.1.16
text: "Ensure that the scheduler.conf file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e /etc/kubernetes/scheduler.conf; then stat -c %U:%G /etc/kubernetes/scheduler.conf; fi'"
audit: "/bin/sh -c 'if test -e $schedulerkubeconfig; then stat -c %U:%G $schedulerkubeconfig; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root /etc/kubernetes/scheduler.conf
chown root:root $schedulerkubeconfig
scored: true
- id: 1.1.17
text: "Ensure that the controller-manager.conf file permissions are set to 644 or more restrictive (Automated)"
audit: "/bin/sh -c 'if test -e /etc/kubernetes/controller-manager.conf; then stat -c permissions=%a /etc/kubernetes/controller-manager.conf; fi'"
audit: "/bin/sh -c 'if test -e $controllermanagerkubeconfig; then stat -c permissions=%a $controllermanagerkubeconfig; fi'"
tests:
test_items:
- flag: "permissions"
@@ -233,19 +248,19 @@ groups:
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chmod 644 /etc/kubernetes/controller-manager.conf
chmod 644 $controllermanagerkubeconfig
scored: true
- id: 1.1.18
text: "Ensure that the controller-manager.conf file ownership is set to root:root (Automated)"
audit: "/bin/sh -c 'if test -e /etc/kubernetes/controller-manager.conf; then stat -c %U:%G /etc/kubernetes/controller-manager.conf; fi'"
audit: "/bin/sh -c 'if test -e $controllermanagerkubeconfig; then stat -c %U:%G $controllermanagerkubeconfig; fi'"
tests:
test_items:
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
chown root:root /etc/kubernetes/controller-manager.conf
chown root:root $controllermanagerkubeconfig
scored: true
- id: 1.1.19
@@ -254,7 +269,7 @@ groups:
use_multiple_values: true
tests:
test_items:
- flag: "root root"
- flag: "root:root"
remediation: |
Run the below command (based on the file location on your system) on the master node.
For example,
@@ -263,7 +278,7 @@ groups:
- id: 1.1.20
text: "Ensure that the Kubernetes PKI certificate file permissions are set to 644 or more restrictive (Manual)"
audit: "find /etc/kubernetes/pki -name '*.crt' | xargs stat -c permissions=%a"
audit: "find /etc/kubernetes/pki/ -name '*.crt' | xargs stat -c permissions=%a"
use_multiple_values: true
tests:
test_items:
@@ -279,7 +294,7 @@ groups:
- id: 1.1.21
text: "Ensure that the Kubernetes PKI key file permissions are set to 600 (Manual)"
audit: "find /etc/kubernetes/pki -name '*.key' | xargs stat -c permissions=%a"
audit: "find /etc/kubernetes/pki/ -name '*.key' | xargs stat -c permissions=%a"
use_multiple_values: true
tests:
test_items:
@@ -299,7 +314,6 @@ groups:
- id: 1.2.1
text: "Ensure that the --anonymous-auth argument is set to false (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
type: manual
tests:
test_items:
- flag: "--anonymous-auth"
@@ -700,12 +714,7 @@ groups:
- id: 1.2.26
text: "Ensure that the --request-timeout argument is set as appropriate (Automated)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--request-timeout"
set: false
- flag: "--request-timeout"
type: manual
remediation: |
Edit the API server pod specification file $apiserverconf
and set the below parameter as appropriate and if needed.
@@ -818,8 +827,15 @@ groups:
- id: 1.2.34
text: "Ensure that encryption providers are appropriately configured (Manual)"
audit: "/bin/ps -ef | grep $apiserverbin | grep -v grep"
type: "manual"
audit: |
ENCRYPTION_PROVIDER_CONFIG=$(ps -ef | grep $apiserverbin | grep -- --encryption-provider-config | sed 's%.*encryption-provider-config[= ]\([^ ]*\).*%\1%')
if test -e $ENCRYPTION_PROVIDER_CONFIG; then grep -A1 'providers:' $ENCRYPTION_PROVIDER_CONFIG | tail -n1 | grep -o "[A-Za-z]*" | sed 's/^/provider=/'; fi
tests:
test_items:
- flag: "provider"
compare:
op: valid_elements
value: "aescbc,kms,secretbox"
remediation: |
Follow the Kubernetes documentation and configure a EncryptionConfig file.
In this file, choose aescbc, kms or secretbox as the encryption provider.
@@ -832,7 +848,7 @@ groups:
test_items:
- flag: "--tls-cipher-suites"
compare:
op: has
op: valid_elements
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"
remediation: |
Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml
@@ -918,11 +934,15 @@ groups:
text: "Ensure that the RotateKubeletServerCertificate argument is set to true (Automated)"
audit: "/bin/ps -ef | grep $controllermanagerbin | grep -v grep"
tests:
bin_op: or
test_items:
- flag: "--feature-gates"
compare:
op: eq
value: "RotateKubeletServerCertificate=true"
op: nothave
value: "RotateKubeletServerCertificate=false"
set: true
- flag: "--feature-gates"
set: false
remediation: |
Edit the Controller Manager pod specification file $controllermanagerconf
on the master node and set the --feature-gates parameter to include RotateKubeletServerCertificate=true.

View File

@@ -1,6 +1,6 @@
---
controls:
version: 1.6
version: "cis-1.6"
id: 4
text: "Worker Node Security Configuration"
type: "node"
@@ -39,11 +39,15 @@ groups:
text: "If proxy kubeconfig file exists ensure permissions are set to 644 or more restrictive (Manual)"
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c permissions=%a $proxykubeconfig; fi'' '
tests:
bin_op: or
test_items:
- flag: "permissions"
set: true
compare:
op: bitmask
value: "644"
- flag: "$proxykubeconfig"
set: false
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example,
@@ -54,8 +58,11 @@ groups:
text: "Ensure that the proxy kubeconfig file ownership is set to root:root (Manual)"
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c %U:%G $proxykubeconfig; fi'' '
tests:
bin_op: or
test_items:
- flag: root:root
- flag: "$proxykubeconfig"
set: false
remediation: |
Run the below command (based on the file location on your system) on the each worker node.
For example, chown root:root $proxykubeconfig
@@ -412,12 +419,16 @@ groups:
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
bin_op: or
test_items:
- flag: RotateKubeletServerCertificate
path: '{.featureGates.RotateKubeletServerCertificate}'
compare:
op: eq
value: true
op: nothave
value: false
- flag: RotateKubeletServerCertificate
path: '{.featureGates.RotateKubeletServerCertificate}'
set: false
remediation: |
Edit the kubelet service file $kubeletsvc
on each worker node and set the below parameter in KUBELET_CERTIFICATE_ARGS variable.

View File

@@ -1,6 +1,6 @@
---
controls:
version: 1.6
version: "cis-1.6"
id: 5
text: "Kubernetes Policies"
type: "policies"
@@ -131,7 +131,7 @@ groups:
text: "Minimize the admission of containers with capabilities assigned (Manual)"
type: "manual"
remediation: |
Review the use of capabilites in applications runnning on your cluster. Where a namespace
Review the use of capabilites in applications running on your cluster. Where a namespace
contains applicaions which do not require any Linux capabities to operate consider adding
a PSP which forbids the admission of containers which do not drop all capabilities.
scored: false

View File

@@ -15,6 +15,7 @@ master:
- flanneld
# kubernetes is a component to cover the config file /etc/kubernetes/config that is referred to in the benchmark
- kubernetes
- kubelet
kubernetes:
defaultconf: /etc/kubernetes/config
@@ -25,12 +26,15 @@ master:
- "hyperkube apiserver"
- "hyperkube kube-apiserver"
- "apiserver"
- "openshift start master api"
- "hypershift openshift-kube-apiserver"
confs:
- /etc/kubernetes/manifests/kube-apiserver.yaml
- /etc/kubernetes/manifests/kube-apiserver.yml
- /etc/kubernetes/manifests/kube-apiserver.manifest
- /var/snap/kube-apiserver/current/args
- /var/snap/microk8s/current/args/kube-apiserver
- /etc/origin/master/master-config.yaml
defaultconf: /etc/kubernetes/manifests/kube-apiserver.yaml
scheduler:
@@ -39,13 +43,20 @@ master:
- "hyperkube scheduler"
- "hyperkube kube-scheduler"
- "scheduler"
- "openshift start master controllers"
confs:
- /etc/kubernetes/manifests/kube-scheduler.yaml
- /etc/kubernetes/manifests/kube-scheduler.yml
- /etc/kubernetes/manifests/kube-scheduler.manifest
- /var/snap/kube-scheduler/current/args
- /var/snap/microk8s/current/args/kube-scheduler
- /etc/origin/master/scheduler.json
defaultconf: /etc/kubernetes/manifests/kube-scheduler.yaml
kubeconfig:
- /etc/kubernetes/scheduler.conf
- /var/lib/kube-scheduler/kubeconfig
- /var/lib/kube-scheduler/config.yaml
defaultkubeconfig: /etc/kubernetes/scheduler.conf
controllermanager:
bins:
@@ -54,6 +65,8 @@ master:
- "hyperkube controller-manager"
- "hyperkube kube-controller-manager"
- "controller-manager"
- "openshift start master controllers"
- "hypershift openshift-controller-manager"
confs:
- /etc/kubernetes/manifests/kube-controller-manager.yaml
- /etc/kubernetes/manifests/kube-controller-manager.yml
@@ -61,11 +74,16 @@ master:
- /var/snap/kube-controller-manager/current/args
- /var/snap/microk8s/current/args/kube-controller-manager
defaultconf: /etc/kubernetes/manifests/kube-controller-manager.yaml
kubeconfig:
- /etc/kubernetes/controller-manager.conf
- /var/lib/kube-controller-manager/kubeconfig
defaultkubeconfig: /etc/kubernetes/controller-manager.conf
etcd:
optional: true
bins:
- "etcd"
- "openshift start etcd"
confs:
- /etc/kubernetes/manifests/etcd.yaml
- /etc/kubernetes/manifests/etcd.yml
@@ -74,6 +92,7 @@ master:
- /var/snap/etcd/common/etcd.conf.yml
- /var/snap/etcd/common/etcd.conf.yaml
- /var/snap/microk8s/current/args/etcd
- /usr/lib/systemd/system/etcd.service
defaultconf: /etc/kubernetes/manifests/etcd.yaml
flanneld:
@@ -82,6 +101,12 @@ master:
- flanneld
defaultconf: /etc/sysconfig/flanneld
kubelet:
optional: true
bins:
- "hyperkube kubelet"
- "kubelet"
node:
components:
- kubelet
@@ -106,6 +131,8 @@ node:
- "/lib/systemd/system/kubelet.service"
- "/etc/systemd/system/snap.kubelet.daemon.service"
- "/etc/systemd/system/snap.microk8s.daemon-kubelet.service"
- "/etc/systemd/system/atomic-openshift-node.service"
- "/etc/systemd/system/origin-node.service"
bins:
- "hyperkube kubelet"
- "kubelet"
@@ -113,13 +140,17 @@ node:
- "/etc/kubernetes/kubelet.conf"
- "/var/lib/kubelet/kubeconfig"
- "/etc/kubernetes/kubelet-kubeconfig"
- "/etc/kubernetes/kubelet/kubeconfig"
- "/var/snap/microk8s/current/credentials/kubelet.config"
confs:
- "/etc/kubernetes/kubelet-config.yaml"
- "/var/lib/kubelet/config.yaml"
- "/var/lib/kubelet/config.yml"
- "/etc/kubernetes/kubelet/kubelet-config.json"
- "/etc/kubernetes/kubelet/config"
- "/home/kubernetes/kubelet-config.yaml"
- "/home/kubernetes/kubelet-config.yml"
- "/etc/default/kubeletconfig.json"
- "/etc/default/kubelet"
- "/var/lib/kubelet/kubeconfig"
- "/var/snap/kubelet/current/args"
@@ -146,6 +177,7 @@ node:
- "hyperkube proxy"
- "hyperkube kube-proxy"
- "proxy"
- "openshift start network"
confs:
- /etc/kubernetes/proxy
- /etc/kubernetes/addons/kube-proxy-daemonset.yaml
@@ -154,6 +186,7 @@ node:
- /var/snap/microk8s/current/args/kube-proxy
kubeconfig:
- "/etc/kubernetes/kubelet-kubeconfig"
- "/etc/kubernetes/kubelet/config"
- "/var/lib/kubelet/kubeconfig"
- "/var/snap/microk8s/current/credentials/proxy.config"
svc:
@@ -177,10 +210,19 @@ etcd:
- /var/snap/etcd/common/etcd.conf.yml
- /var/snap/etcd/common/etcd.conf.yaml
- /var/snap/microk8s/current/args/etcd
- /usr/lib/systemd/system/etcd.service
defaultconf: /etc/kubernetes/manifests/etcd.yaml
controlplane:
components: []
components:
- apiserver
apiserver:
bins:
- "kube-apiserver"
- "hyperkube apiserver"
- "hyperkube kube-apiserver"
- "apiserver"
policies:
components: []
@@ -193,11 +235,15 @@ version_mapping:
"1.16": "cis-1.6"
"1.17": "cis-1.6"
"1.18": "cis-1.6"
"1.19": "cis-1.6"
"1.19": "cis-1.20"
"1.20": "cis-1.20"
"eks-1.0": "eks-1.0"
"gke-1.0": "gke-1.0"
"ocp-3.10": "rh-0.7"
"ocp-3.11": "rh-0.7"
"ocp-4.0": "rh-1.0"
"aks-1.0": "aks-1.0"
"ack-1.0": "ack-1.0"
target_mapping:
"cis-1.5":
@@ -212,6 +258,12 @@ target_mapping:
- "controlplane"
- "etcd"
- "policies"
"cis-1.20":
- "master"
- "node"
- "controlplane"
- "etcd"
- "policies"
"gke-1.0":
- "master"
- "node"
@@ -228,3 +280,22 @@ target_mapping:
"rh-0.7":
- "master"
- "node"
"aks-1.0":
- "master"
- "node"
- "controlplane"
- "policies"
- "managedservices"
"ack-1.0":
- "master"
- "node"
- "controlplane"
- "etcd"
- "policies"
- "managedservices"
"rh-1.0":
- "master"
- "node"
- "controlplane"
- "policies"
- "etcd"

View File

@@ -1,2 +1,9 @@
---
## Version-specific settings that override the values in cfg/config.yaml
## These settings are required if you are using the --asff option to report findings to AWS Security Hub
## AWS account number is required.
AWS_ACCOUNT: "<AWS_ACCT_NUMBER>"
## AWS region is required.
AWS_REGION: "<AWS_REGION>"
## EKS Cluster ARN is required.
CLUSTER_ARN: "<AWS_CLUSTER_ARN>"

View File

@@ -131,7 +131,7 @@ groups:
text: "Minimize the admission of containers with capabilities assigned (Not Scored)"
type: "manual"
remediation: |
Review the use of capabilites in applications runnning on your cluster. Where a namespace
Review the use of capabilities in applications running on your cluster. Where a namespace
contains applications which do not require any Linux capabities to operate consider adding
a PSP which forbids the admission of containers which do not drop all capabilities.
scored: false

View File

@@ -20,6 +20,7 @@ groups:
- id: 3.2
text: "Logging"
type: skip
checks:
- id: 3.2.1
text: "Ensure that a minimal audit policy is created (Not Scored)"

View File

@@ -7,6 +7,7 @@ type: "etcd"
groups:
- id: 2
text: "Etcd Node Configuration Files"
type: skip
checks:
- id: 2.1
text: "Ensure that the --cert-file and --key-file arguments are set as appropriate (Not Scored)"

View File

@@ -7,6 +7,7 @@ type: "master"
groups:
- id: 1.1
text: "Master Node Configuration Files "
type: skip
checks:
- id: 1.1.1
text: "Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Not Scored)"
@@ -115,6 +116,7 @@ groups:
- id: 1.2
text: "API Server"
type: skip
checks:
- id: 1.2.1
text: "Ensure that the --anonymous-auth argument is set to false (Not Scored)"
@@ -298,6 +300,7 @@ groups:
- id: 1.3
text: "Controller Manager"
type: skip
checks:
- id: 1.3.1
text: "Ensure that the --terminated-pod-gc-threshold argument is set as appropriate (Not Scored)"
@@ -336,6 +339,7 @@ groups:
- id: 1.4
text: "Scheduler"
type: skip
checks:
- id: 1.4.1
text: "Ensure that the --profiling argument is set to false (Not Scored)"

View File

@@ -10,55 +10,25 @@ groups:
checks:
- id: 4.1.1
text: "Ensure that the kubelet service file permissions are set to 644 or more restrictive (Not Scored)"
type: skip
remediation: "This control cannot be modified in GKE."
scored: false
- id: 4.1.2
text: "Ensure that the kubelet service file ownership is set to root:root (Not Scored)"
type: skip
remediation: "This control cannot be modified in GKE."
scored: false
- id: 4.1.3
text: "Ensure that the proxy kubeconfig file permissions are set to 644 or more restrictive (Scored)"
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c %a $proxykubeconfig; fi'' '
audit: '/bin/sh -c ''if test -e $proxykubeconfig; then stat -c permissions=%a $proxykubeconfig; fi'' '
tests:
test_items:
- flag: "644"
- flag: "permissions"
compare:
op: eq
op: bitmask
value: "644"
set: true
- flag: "640"
compare:
op: eq
value: "640"
set: true
- flag: "600"
compare:
op: eq
value: "600"
set: true
- flag: "444"
compare:
op: eq
value: "444"
set: true
- flag: "440"
compare:
op: eq
value: "440"
set: true
- flag: "400"
compare:
op: eq
value: "400"
set: true
- flag: "000"
compare:
op: eq
value: "000"
set: true
bin_op: or
remediation: |
Run the below command (based on the file location on your system) on each worker node.
For example,
@@ -71,7 +41,6 @@ groups:
tests:
test_items:
- flag: root:root
set: true
remediation: |
Run the below command (based on the file location on your system) on each worker node.
For example, chown root:root $proxykubeconfig
@@ -79,65 +48,38 @@ groups:
- id: 4.1.5
text: "Ensure that the kubelet.conf file permissions are set to 644 or more restrictive (Not Scored)"
type: skip
remediation: "This control cannot be modified in GKE."
scored: false
- id: 4.1.6
text: "Ensure that the kubelet.conf file ownership is set to root:root (Not Scored)"
type: skip
remediation: "This control cannot be modified in GKE."
scored: false
- id: 4.1.7
text: "Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Not Scored)"
type: skip
remediation: "This control cannot be modified in GKE."
scored: false
- id: 4.1.8
text: "Ensure that the client certificate authorities file ownership is set to root:root (Not Scored)"
type: skip
remediation: "This control cannot be modified in GKE."
scored: false
- id: 4.1.9
text: "Ensure that the kubelet configuration file has permissions set to 644 or more restrictive (Scored)"
audit: '/bin/sh -c ''if test -e $kubeletconf; then stat -c %a $kubeletconf; fi'' '
audit: '/bin/sh -c ''if test -e $kubeletconf; then stat -c permissions=%a $kubeletconf; fi'' '
tests:
test_items:
- flag: "644"
- flag: "permissions"
set: true
compare:
op: eq
op: bitmask
value: "644"
- flag: "640"
set: true
compare:
op: eq
value: "640"
- flag: "600"
set: true
compare:
op: eq
value: "600"
- flag: "444"
compare:
op: eq
value: "444"
set: true
- flag: "440"
compare:
op: eq
value: "440"
set: true
- flag: "400"
compare:
op: eq
value: "400"
set: true
- flag: "000"
compare:
op: eq
value: "000"
set: true
bin_op: or
remediation: |
Run the following command (using the config file location identified in the Audit step)
chmod 644 $kubeletconf
@@ -149,7 +91,6 @@ groups:
tests:
test_items:
- flag: root:root
set: true
remediation: |
Run the following command (using the config file location identified in the Audit step)
chown root:root $kubeletconf
@@ -166,7 +107,6 @@ groups:
test_items:
- flag: "--anonymous-auth"
path: '{.authentication.anonymous.enabled}'
set: true
compare:
op: eq
value: false
@@ -190,7 +130,6 @@ groups:
test_items:
- flag: --authorization-mode
path: '{.authorization.mode}'
set: true
compare:
op: nothave
value: AlwaysAllow
@@ -228,25 +167,8 @@ groups:
- id: 4.2.4
text: "Ensure that the --read-only-port argument is set to 0 (Scored)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: "--read-only-port"
path: '{.readOnlyPort}'
set: true
compare:
op: eq
value: 0
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
$kubeletsvc 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
type: skip
remediation: "This control cannot be modified in GKE."
scored: true
- id: 4.2.5
@@ -257,7 +179,6 @@ groups:
test_items:
- flag: --streaming-connection-idle-timeout
path: '{.streamingConnectionIdleTimeout}'
set: true
compare:
op: noteq
value: 0
@@ -279,26 +200,8 @@ groups:
- id: 4.2.6
text: "Ensure that the --protect-kernel-defaults argument is set to true (Scored)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --protect-kernel-defaults
path: '{.protectKernelDefaults}'
set: true
compare:
op: eq
value: 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
$kubeletsvc 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
type: skip
remediation: "This control cannot be modified in GKE."
- id: 4.2.7
text: "Ensure that the --make-iptables-util-chains argument is set to true (Scored) "
@@ -308,7 +211,6 @@ groups:
test_items:
- flag: --make-iptables-util-chains
path: '{.makeIPTablesUtilChains}'
set: true
compare:
op: eq
value: true
@@ -329,9 +231,6 @@ groups:
- id: 4.2.8
text: "Ensure that the --hostname-override argument is not set (Scored)"
# This is one of those properties that can only be set as a command line argument.
# To check if the property is set as expected, we need to parse the kubelet command
# instead reading the Kubelet Configuration file.
audit: "/bin/ps -fC $kubeletbin "
tests:
test_items:
@@ -348,51 +247,13 @@ groups:
- id: 4.2.9
text: "Ensure that the --event-qps argument is set to 0 or a level which ensures appropriate event capture (Scored)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --event-qps
path: '{.eventRecordQPS}'
set: true
compare:
op: eq
value: 0
remediation: |
If using a Kubelet config file, edit the file to set eventRecordQPS: to an appropriate level.
If using command line arguments, edit the kubelet service file
$kubeletsvc on each worker node and
set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable.
Based on your system, restart the kubelet service. For example:
systemctl daemon-reload
systemctl restart kubelet.service
scored: true
type: skip
remediation: "This control cannot be modified in GKE."
- id: 4.2.10
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)"
audit: "/bin/ps -fC $kubeletbin"
audit_config: "/bin/cat $kubeletconf"
tests:
test_items:
- flag: --tls-cert-file
path: '{.tlsCertFile}'
set: true
- flag: --tls-private-key-file
path: '{.tlsPrivateKeyFile}'
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
$kubeletsvc on each worker node and
set the below parameters in KUBELET_CERTIFICATE_ARGS variable.
--tls-cert-file=<path/to/tls-certificate-file>
--tls-private-key-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
type: skip
remediation: "This control cannot be modified in GKE."
- id: 4.2.11
text: "Ensure that the --rotate-certificates argument is not set to false (Scored)"
@@ -402,7 +263,6 @@ groups:
test_items:
- flag: --rotate-certificates
path: '{.rotateCertificates}'
set: true
compare:
op: eq
value: true
@@ -430,7 +290,6 @@ groups:
test_items:
- flag: RotateKubeletServerCertificate
path: '{.featureGates.RotateKubeletServerCertificate}'
set: true
compare:
op: eq
value: true
@@ -445,5 +304,6 @@ groups:
- id: 4.2.13
text: "Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Not Scored)"
type: skip
remediation: "This control cannot be modified in GKE."
scored: false

View File

@@ -131,7 +131,7 @@ groups:
text: "Minimize the admission of containers with capabilities assigned (Scored) "
type: "manual"
remediation: |
Review the use of capabilites in applications runnning on your cluster. Where a namespace
Review the use of capabilites in applications running on your cluster. Where a namespace
contains applications which do not require any Linux capabities to operate consider adding
a PSP which forbids the admission of containers which do not drop all capabilities.
scored: true

View File

@@ -1,32 +1,2 @@
---
## Version-specific settings that override the values in cfg/config.yaml
master:
apiserver:
bins:
- openshift start master api
- hypershift openshift-kube-apiserver
scheduler:
bins:
- "openshift start master controllers"
- "hyperkube kube-scheduler"
confs:
- /etc/origin/master/scheduler.json
controllermanager:
bins:
- "openshift start master controllers"
- "hypershift openshift-controller-manager"
etcd:
bins:
- openshift start etcd
node:
svcs:
- /etc/systemd/system/atomic-openshift-node.service
- /etc/systemd/system/origin-node.service
proxy:
bins:
- openshift start network

View File

@@ -1,6 +1,6 @@
---
controls:
version: 3.10
version: "rh-0.7"
id: 1
text: "Securing the OpenShift Master"
type: "master"
@@ -16,13 +16,10 @@ groups:
- id: 1.2
text: "Verify that the basic-auth-file method is not enabled"
audit: "grep -A2 basic-auth-file /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "--basic-auth-file"
compare:
op: eq
value: ""
- path: "{.kubernetesMasterConfig.apiServerArguments.basic-auth-file}"
set: false
remediation: |
Edit the kubernetes master config file /etc/origin/master/master-config.yaml and
@@ -41,35 +38,27 @@ groups:
- id: 1.4
text: "Secure communications between the API server and master nodes"
audit: "grep -A4 kubeletClientInfo /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: and
test_items:
- flag: "kubeletClientInfo:"
compare:
op: eq
value: "kubeletClientInfo:"
set: true
- flag: "ca"
- path: "{.kubeletClientInfo.ca}"
compare:
op: has
value: "ca-bundle.crt"
set: true
- flag: "certFile"
- path: "{.kubeletClientInfo.certFile}"
compare:
op: has
value: "master.kubelet-client.crt"
set: true
- flag: "keyFile"
- path: "{.kubeletClientInfo.keyFile}"
compare:
op: has
value: "master.kubelet-client.key"
set: true
- flag: "port: 10250"
- path: "{.kubeletClientInfo.port}"
compare:
op: eq
value: "port: 10250"
set: true
value: "10250"
remediation: |
Edit the kubernetes master config file /etc/origin/master/master-config.yaml
and change it to match the below.
@@ -83,10 +72,10 @@ groups:
- id: 1.5
text: "Prevent insecure bindings"
audit: "grep -A2 insecure-bind-address /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "insecure-bind-address"
- path: "{.kubernetesMasterConfig.insecure-bind-address}"
set: false
remediation: |
Edit the kubernetes master config file /etc/origin/master/master-config.yaml
@@ -100,10 +89,10 @@ groups:
- id: 1.6
text: "Prevent insecure port access"
audit: "grep -A2 insecure-port /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "insecure-port"
- path: "{.kubernetesMasterConfig.apiServerArguments.insecure-port}"
set: false
remediation: |
Edit the kubernetes master config file /etc/origin/master/master-config.yaml
@@ -117,17 +106,16 @@ groups:
- id: 1.7
text: "Use Secure Ports for API Server Traffic"
audit: "grep -A2 secure-port /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: or
test_items:
- flag: "secure-port"
- path: "{.kubernetesMasterConfig.apiServerArguments.secure-port}"
set: false
- flag: "secure-port"
- path: "{.kubernetesMasterConfig.apiServerArguments.secure-port}"
compare:
op: nothave
op: noteq
value: "0"
set: true
remediation: |
Edit the kubernetes master config file /etc/origin/master/master-config.yaml
and either remove the secure-port parameter or set it to a different (non-zero)
@@ -146,17 +134,16 @@ groups:
- id: 1.9
text: "Verify repair-malformed-updates argument for API compatibility"
audit: "grep -A2 repair-malformed-updates /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: or
test_items:
- flag: "repair-malformed-updates"
- path: "{.repair-malformed-updates}"
set: false
- flag: "repair-malformed-updates"
- path: "{.repair-malformed-updates}"
compare:
op: has
op: eq
value: "true"
set: true
remediation: |
Edit the kubernetes master config file /etc/origin/master/master-config.yaml
and remove the repair-malformed-updates entry or set repair-malformed-updates=true.
@@ -164,10 +151,10 @@ groups:
- id: 1.10
text: "Verify that the AlwaysAdmit admission controller is disabled"
audit: "grep -A4 AlwaysAdmit /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "AlwaysAdmit"
- path: "{.AlwaysAdmit}"
set: false
remediation: |
Edit the kubernetes master config file /etc/origin/master/master-config.yaml
@@ -182,14 +169,13 @@ groups:
- id: 1.11
text: "Manage the AlwaysPullImages admission controller"
audit: "grep -A4 AlwaysPullImages /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "disable"
- path: "{.admissionConfig.pluginConfig.configuration.disable}"
compare:
op: has
op: eq
value: "false"
set: true
remediation: |
Edit the kubernetes master config file /etc/origin/master/master-config.yaml
and add the entry below.
@@ -215,10 +201,10 @@ groups:
- id: 1.14
text: "Manage the NamespaceLifecycle admission controller"
audit: "grep -A4 NamespaceLifecycle /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "NamespaceLifecycle"
- path: "{.NamespaceLifecycle}"
set: false
remediation: |
Edit the kubernetes master config file /etc/origin/master/master-config.yaml
@@ -233,14 +219,13 @@ groups:
- id: 1.15
text: "Configure API server auditing - audit log file path"
audit: "grep -A5 auditConfig /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "enabled"
- path: "{.auditConfig.enabled}"
compare:
op: has
op: eq
value: "true"
set: true
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml, update the following entry and restart the API server.
@@ -257,14 +242,13 @@ groups:
- id: 1.16
text: "Configure API server auditing - audit log retention"
audit: "grep -A5 auditConfig /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "maximumFileRetentionDays: 30"
- path: "{.auditConfig.maximumFileRetentionDays}"
compare:
op: has
value: "maximumFileRetentionDays"
set: true
op: gte
value: 30
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml,
update the maximumFileRetentionDays entry and restart the API server.
@@ -282,14 +266,13 @@ groups:
- id: 1.17
text: "Configure API server auditing - audit log backup retention"
audit: "grep -A5 auditConfig /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "maximumRetainedFiles: 10"
- path: "{.auditConfig.maximumRetainedFiles}"
compare:
op: has
value: "maximumRetainedFiles"
set: true
op: eq
value: "10"
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml, update the maximumRetainedFiles entry,
set enabled to true and restart the API server.
@@ -307,14 +290,13 @@ groups:
- id: 1.18
text: "Configure audit log file size"
audit: "grep -A5 auditConfig /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "maximumFileSizeMegabytes: 30"
- path: "{.auditConfig.maximumFileSizeMegabytes}"
compare:
op: has
value: "maximumFileSizeMegabytes"
set: true
op: eq
value: "30"
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml, update the maximumFileSizeMegabytes entry,
set enabled to true and restart the API server.
@@ -332,10 +314,10 @@ groups:
- id: 1.19
text: "Verify that authorization-mode is not set to AlwaysAllow"
audit: "grep -A1 authorization-mode /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "authorization-mode"
- path: "{.kubernetesMasterConfig.apiServerArguments.authorization-mode}"
set: false
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and remove the authorization-mode
@@ -349,10 +331,10 @@ groups:
- id: 1.20
text: "Verify that the token-auth-file flag is not set"
audit: "grep token-auth-file /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "token-auth-file"
- path: "{.kubernetesMasterConfig.apiServerArguments.token-auth-file}"
set: false
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and remove the token-auth-file
@@ -366,10 +348,10 @@ groups:
- id: 1.21
text: "Verify the API server certificate authority"
audit: "grep -A1 kubelet-certificate-authority /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "kubelet-certificate-authority"
- path: "{.kubernetesMasterConfig.apiServerArguments.kubelet-certificat-authority}"
set: false
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and remove the following
@@ -383,20 +365,18 @@ groups:
- id: 1.22
text: "Verify the API server client certificate and client key"
audit: "grep -A4 kubeletClientInfo /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: and
test_items:
- flag: "keyFile"
- path: "{.kubeletClientInfo.keyFile}"
compare:
op: has
op: eq
value: "master.kubelet-client.key"
set: true
- flag: "certFile"
- path: "{.kubeletClientInfo.certFile}"
compare:
op: has
op: eq
value: "master.kubelet-client.crt"
set: true
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and add the following
configuration under kubeletClientInfo
@@ -420,20 +400,18 @@ groups:
- id: 1.25
text: "Verify that the service account key file argument is not set"
audit: "grep -A9 serviceAccountConfig /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: and
test_items:
- flag: "privateKeyFile"
- path: "{.serviceAccountConfig.privateKeyFile}"
compare:
op: has
op: eq
value: "serviceaccounts.private.key"
set: true
- flag: "serviceaccounts.public.key"
- path: "{.serviceAccountConfig.publicKeyFiles}"
compare:
op: has
value: "serviceaccounts.public.key"
set: true
remediation: |
OpenShift API server does not use the service-account-key-file argument.
Even if value is set in master-config.yaml, it will not be used to verify
@@ -460,20 +438,18 @@ groups:
- id: 1.26
text: "Verify the certificate and key used for communication with etcd"
audit: "grep -A3 etcdClientInfo /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: and
test_items:
- flag: "certFile"
- path: "{.etcdClientInfo.certFile}"
compare:
op: has
op: eq
value: "master.etcd-client.crt"
set: true
- flag: "keyFile"
- path: "{.etcdClientInfo.keyFile}"
compare:
op: has
op: eq
value: "master.etcd-client.key"
set: true
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and set keyFile and certFile
under etcdClientInfo like below.
@@ -486,17 +462,16 @@ groups:
- id: 1.27
text: "Verify that the ServiceAccount admission controller is enabled"
audit: "grep -A4 ServiceAccount /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: or
test_items:
- flag: "ServiceAccount"
- path: "{.ServiceAccount.configuration.disable}"
set: false
- flag: "disable"
- path: "{.ServiceAccount.configuration.disable}"
compare:
op: has
op: eq
value: "false"
set: true
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and enable ServiceAccount
admission control policy.
@@ -510,20 +485,18 @@ groups:
- id: 1.28
text: "Verify the certificate and key used to encrypt API server traffic"
audit: "grep -A7 servingInfo /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: and
test_items:
- flag: "certFile"
- path: "{.servingInfo.certFile}"
compare:
op: has
op: eq
value: "master.server.crt"
set: true
- flag: "keyFile"
- path: "{.servingInfo.keyFile}"
compare:
op: has
op: eq
value: "master.server.key"
set: true
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and set keyFile and certFile under servingInfo.
@@ -539,10 +512,10 @@ groups:
- id: 1.29
text: "Verify that the --client-ca-file argument is not set"
audit: "grep client-ca-file /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "clientCA: ca.crt"
- path: "{.servingInfo.clientCA}"
set: false
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and set clientCA under servingInfo.
@@ -559,14 +532,13 @@ groups:
- id: 1.30
text: "Verify the CA used for communication with etcd"
audit: "grep -A3 etcdClientInfo /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "ca"
- path: "{.etcdClientInfo.ca}"
compare:
op: has
op: eq
value: "master.etcd-ca.crt"
set: true
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and set ca under etcdClientInfo.
@@ -583,17 +555,16 @@ groups:
- id: 1.32
text: "Verify that the NodeRestriction admission controller is enabled"
audit: "grep -A4 NodeRestriction /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: or
test_items:
- flag: "NodeRestriction"
- path: "{.NodeRestriction.configuration.disable}"
set: false
- flag: "disable"
- path: "{.NodeRestriction.configuration.disable}"
compare:
op: has
op: eq
value: "false"
set: true
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and enable NodeRestriction ca under etcdClientInfo.
@@ -606,14 +577,10 @@ groups:
- id: 1.33
text: "Configure encryption of data at rest in etcd datastore"
audit: "grep -A1 experimental-encryption-provider-config /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "experimental-encryption-provider-config:"
compare:
op: has
value: "experimental-encryption-provider-config:"
set: true
- path: "{.kubernetesMasterConfig.apiServerArguments.experimental-encryption-provider-config}"
remediation: |
Follow the instructions in the documentation to configure encryption.
https://docs.openshift.com/container-platform/3.10/admin_guide/encrypting_data.html
@@ -621,14 +588,14 @@ groups:
- id: 1.34
text: "Set the encryption provider to aescbc for etcd data at rest"
audit: "grep -A1 experimental-encryption-provider-config /etc/origin/master/master-config.yaml | sed -n '2p' | awk '{ print $2 }' | xargs grep -A1 providers"
audit_config: "grep -A1 experimental-encryption-provider-config /etc/origin/master/master-config.yaml | sed -n '2p' | awk '{ print $2 }' | xargs cat"
tests:
test_items:
- flag: "aescbc:"
- path: "{.providers.aescbc.experimental-encryption-provider-config}"
compare:
op: has
value: "aescbc:"
set: true
value: "aescbc"
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and set aescbc as the first provider in encryption provider config.
See https://docs.openshift.com/container-platform/3.10/admin_guide/encrypting_data.html.
@@ -636,14 +603,13 @@ groups:
- id: 1.35
text: "Enable the EventRateLimit plugin"
audit: "grep -A4 EventRateLimit /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "disable"
- path: "{.admissionConfig.pluginConfig.AlwaysPullImages.configuration.disable}"
compare:
op: has
op: eq
value: "false"
set: true
remediation: |
Follow the documentation to enable the EventRateLimit plugin.
https://docs.openshift.com/container-platform/3.10/architecture/additional_concepts/admission_controllers.html#admission-controllers-general-admission-rules
@@ -651,16 +617,15 @@ groups:
- id: 1.36
text: "Configure advanced auditing"
audit: "grep AdvancedAuditing /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: or
test_items:
- flag: "AdvancedAuditing"
- path: "{.kubernetesMasterConfig.apiServerArguments.feature-gates.AdvancedAuditing}"
compare:
op: eq
value: "true"
set: true
- flag: "AdvancedAuditing"
- path: "{.kubernetesMasterConfig.apiServerArguments.feature-gates.AdvancedAuditing}"
set: false
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and enable AdvancedAuditing,
@@ -696,14 +661,13 @@ groups:
checks:
- id: 3.1
text: "Adjust the terminated-pod-gc-threshold argument as needed"
audit: "grep terminated-pod-gc-threshold -A1 /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "terminated-pod-gc-threshold:"
- path: "{.kubernetesMasterConfig.controllerArguments.terminated-pod-gc-threshold}"
compare:
op: has
op: eq
value: "12500"
set: true
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and enable terminated-pod-gc-threshold.
@@ -722,17 +686,16 @@ groups:
- id: 3.3
text: "Verify that the --use-service-account-credentials argument is set to true"
audit: "grep -A2 use-service-account-credentials /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: or
test_items:
- flag: "use-service-account-credentials"
- path: "{.kubernetesMasterConfig.controllerArguments.use-service-account-credentials}"
set: false
- flag: "true"
- path: "{.kubernetesMasterConfig.controllerArguments.use-service-account-credentials}"
compare:
op: has
op: eq
value: "true"
set: true
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and set use-service-account-credentials
to true under controllerArguments section.
@@ -743,45 +706,45 @@ groups:
    - true
scored: true
# Review 3.4
- id: 3.4
text: "Verify that the --service-account-private-key-file argument is set as appropriate"
audit: |
grep -A9 serviceAccountConfig /etc/origin/master/master-config.yaml | grep privateKeyFile;
grep -A2 service-account-private-key-file /etc/origin/master/master-config.yaml
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: and
test_items:
- flag: "privateKeyFile: serviceaccounts.private.key"
path: "{.serviceAccountConfig.privateKeyFile}"
compare:
op: has
value: "privateKeyFile"
op: eq
value: "serviceaccounts.private.key"
- flag: "service-account-private-key-file"
set: false
remediation:
remediation: |
Edit the Openshift master config file /etc/origin/master/master-config.yaml and remove service-account-private-key-file
scored: true
# Review 3.5
- id: 3.5
text: "Verify that the --root-ca-file argument is set as appropriate"
audit: "/bin/sh -c 'grep root-ca-file /etc/origin/master/master-config.yaml; grep -A9 serviceAccountConfig /etc/origin/master/master-config.yaml'"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
bin_op: and
test_items:
- flag: "root-ca-file=/etc/origin/master/ca-bundle.crt"
- path: "{.serviceAccountConfig.root-ca-file}"
compare:
op: has
op: eq
value: "/etc/origin/master/ca-bundle.crt"
set: true
- flag: "masterCA"
- path: "{.serviceAccountConfig.masterCA}"
compare:
op: has
op: eq
value: "ca-bundle.crt"
set: true
remediation:
remediation: |
Reset to OpenShift defaults OpenShift starts kube-controller-manager with
root-ca-file=/etc/origin/master/ca-bundle.crt by default.  OpenShift Advanced
root-ca-file=/etc/origin/master/ca-bundle.crt by default. OpenShift Advanced
Installation creates this certificate authority and configuration without any
configuration required.
@@ -795,15 +758,14 @@ groups:
- id: 3.7
text: "Manage certificate rotation"
audit: "grep -B3 RotateKubeletServerCertificate=true /etc/origin/master/master-config.yaml"
audit_config: "cat /etc/origin/master/master-config.yaml"
tests:
test_items:
- flag: "RotateKubeletServerCertificate"
- path: "{.kubeletArguments.feature-gates.RotateKubeletServerCertificate}"
compare:
op: eq
value: "true"
set: true
remediation:
remediation: |
If you decide not to enable the RotateKubeletServerCertificate feature,
be sure to use the Ansible playbooks provided with the OpenShift installer to
automate re-deploying certificates.
@@ -822,7 +784,6 @@ groups:
compare:
op: bitmask
value: "600"
set: true
remediation: |
Run the below command.
@@ -835,10 +796,6 @@ groups:
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: "root:root"
set: true
remediation: |
Run the below command on the master node.
@@ -854,7 +811,6 @@ groups:
compare:
op: bitmask
value: "600"
set: true
remediation: |
Run the below command on the master node.
@@ -867,10 +823,6 @@ groups:
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: "root:root"
set: true
remediation: |
Run the below command on the master node.
@@ -886,7 +838,6 @@ groups:
compare:
op: bitmask
value: "600"
set: true
remediation: |
Run the below command.
@@ -899,10 +850,6 @@ groups:
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: "root:root"
set: true
remediation: |
Run the below command on the master node.
@@ -918,7 +865,6 @@ groups:
compare:
op: bitmask
value: "600"
set: true
remediation: |
Run the below command.
@@ -931,10 +877,6 @@ groups:
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: "root:root"
set: true
remediation: |
Run the below command on the master node.
@@ -944,13 +886,13 @@ groups:
- id: 4.9
text: "Verify the default OpenShift Container Network Interface file permissions"
audit: "stat -c permissions=%a /etc/origin/openvswitch/ /etc/cni/net.d/"
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
set: true
remediation: |
Run the below command.
@@ -960,13 +902,10 @@ groups:
- id: 4.10
text: "Verify the default OpenShift Container Network Interface file ownership"
audit: "stat -c %U:%G /etc/origin/openvswitch/ /etc/cni/net.d/"
use_multiple_values: true
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: "root:root"
set: true
remediation: |
Run the below command on the master node.
@@ -982,7 +921,6 @@ groups:
compare:
op: bitmask
value: "700"
set: true
remediation: |
On the etcd server node, get the etcd data directory, passed as an argument --data-dir ,
from the below command:
@@ -997,10 +935,6 @@ groups:
tests:
test_items:
- flag: "etcd:etcd"
compare:
op: eq
value: "etcd:etcd"
set: true
remediation: |
Run the below command on the master node.
@@ -1016,7 +950,6 @@ groups:
compare:
op: bitmask
value: "644"
set: true
remediation: |
Run the below command.
@@ -1029,10 +962,6 @@ groups:
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: "root:root"
set: true
remediation: |
Run the below command on the master node.
@@ -1048,7 +977,6 @@ groups:
compare:
op: bitmask
value: "644"
set: true
remediation: |
Run the below command.
@@ -1061,10 +989,6 @@ groups:
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: "root:root"
set: true
remediation: |
Run the below command on the master node.
@@ -1080,7 +1004,6 @@ groups:
compare:
op: bitmask
value: "644"
set: true
remediation: |
Run the below command.
@@ -1109,45 +1032,34 @@ groups:
checks:
- id: 5.1
text: "Verify the default OpenShift cert-file and key-file configuration"
audit: "/bin/sh -c '/usr/local/bin/master-exec etcd etcd grep ETCD_CERT_FILE=/etc/etcd/server.crt /proc/1/environ; /usr/local/bin/master-exec etcd etcd grep etcd_key_file=/etc/etcd/server.key /proc/1/environ; grep ETCD_CERT_FILE=/etc/etcd/server.crt /etc/etcd/etcd.conf; grep ETCD_KEY_FILE=/etc/etcd/server.key /etc/etcd/etcd.conf'"
audit: "/bin/sh -c '/usr/local/bin/master-exec etcd etcd grep ETCD_CERT_FILE=/etc/etcd/server.crt /proc/1/environ; /usr/local/bin/master-exec etcd etcd grep ETCD_KEY_FILE=/etc/etcd/server.key /proc/1/environ; grep ETCD_CERT_FILE=/etc/etcd/server.crt /etc/etcd/etcd.conf; grep ETCD_KEY_FILE=/etc/etcd/server.key /etc/etcd/etcd.conf'"
tests:
bin_op: and
test_items:
- flag: "Binary file /proc/1/environ matches"
- flag: "ETCD_CERT_FILE"
compare:
op: has
value: "Binary file /proc/1/environ matches"
set: true
- flag: "ETCD_CERT_FILE=/etc/etcd/server.crt"
op: eq
value: "/etc/etcd/server.crt"
- flag: "ETCD_KEY_FILE"
compare:
op: has
value: "ETCD_CERT_FILE=/etc/etcd/server.crt"
set: true
- flag: "ETCD_KEY_FILE=/etc/etcd/server.key"
compare:
op: has
value: "ETCD_KEY_FILE=/etc/etcd/server.key"
set: true
op: eq
value: "/etc/etcd/server.key"
remediation: |
Reset to the OpenShift default configuration.
scored: true
- id: 5.2
text: "Verify the default OpenShift setting for the client-cert-auth argument"
audit: "/bin/sh -c'/usr/local/bin/master-exec etcd etcd grep ETCD_CLIENT_CERT_AUTH=true /proc/1/environ; grep ETCD_CLIENT_CERT_AUTH /etc/etcd/etcd.conf'"
audit: "/bin/sh -c '/usr/local/bin/master-exec etcd etcd grep ETCD_CLIENT_CERT_AUTH=true /proc/1/environ; grep ETCD_CLIENT_CERT_AUTH /etc/etcd/etcd.conf'"
tests:
bin_op: and
test_items:
- flag: "Binary file /proc/1/environ matches"
- flag: "ETCD_CLIENT_CERT_AUTH"
compare:
op: has
value: "Binary file /proc/1/environ matches"
set: true
- flag: "ETCD_CLIENT_CERT_AUTH=true"
compare:
op: has
value: "ETCD_CLIENT_CERT_AUTH=true"
set: true
op: eq
value: "true"
remediation: |
Reset to the OpenShift default configuration.
scored: true
@@ -1158,41 +1070,29 @@ groups:
tests:
bin_op: or
test_items:
- flag: "ETCD_AUTO_TLS=false"
- flag: "ETCD_AUTO_TLS"
compare:
op: has
value: "ETCD_AUTO_TLS=false"
set: true
- flag: "#ETCD_AUTO_TLS"
compare:
op: has
value: "#ETCD_AUTO_TLS"
set: true
op: eq
value: "false"
remediation: |
Reset to the OpenShift default configuration.
scored: true
- id: 5.4
text: "Verify the OpenShift default peer-cert-file and peer-key-file arguments for etcd"
audit: "/bin/sh -c'/usr/local/bin/master-exec etcd etcd grep ETCD_PEER_CERT_FILE=/etc/etcd/peer.crt /proc/1/environ; /usr/local/bin/master-exec etcd etcd grep ETCD_PEER_KEY_FILE=/etc/etcd/peer.key /proc/1/environ; grep ETCD_PEER_CERT_FILE /etc/etcd/etcd.conf; grep ETCD_PEER_KEY_FILE /etc/etcd/etcd.conf'"
audit: "/bin/sh -c '/usr/local/bin/master-exec etcd etcd grep ETCD_PEER_CERT_FILE=/etc/etcd/peer.crt /proc/1/environ; /usr/local/bin/master-exec etcd etcd grep ETCD_PEER_KEY_FILE=/etc/etcd/peer.key /proc/1/environ; grep ETCD_PEER_CERT_FILE /etc/etcd/etcd.conf; grep ETCD_PEER_KEY_FILE /etc/etcd/etcd.conf'"
tests:
bin_op: and
test_items:
- flag: "Binary file /proc/1/environ matches"
- flag: "ETCD_PEER_CERT_FILE"
compare:
op: has
value: "Binary file /proc/1/environ matches"
set: true
- flag: "ETCD_PEER_CERT_FILE=/etc/etcd/peer.crt"
op: eq
value: "/etc/etcd/peer.crt"
- flag: "ETCD_PEER_KEY_FILE"
compare:
op: has
value: "ETCD_PEER_CERT_FILE=/etc/etcd/peer.crt"
set: true
- flag: "ETCD_PEER_KEY_FILE=/etc/etcd/peer.key"
compare:
op: has
value: "ETCD_PEER_KEY_FILE=/etc/etcd/peer.key"
set: true
op: eq
value: "/etc/etcd/peer.key"
remediation: |
Reset to the OpenShift default configuration.
scored: true
@@ -1204,15 +1104,10 @@ groups:
bin_op: and
test_items:
- flag: "Binary file /proc/1/environ matches"
- flag: "ETCD_PEER_CLIENT_CERT_AUTH"
compare:
op: has
value: "Binary file /proc/1/environ matches"
set: true
- flag: "ETCD_PEER_CLIENT_CERT_AUTH=true"
compare:
op: has
value: "ETCD_PEER_CLIENT_CERT_AUTH=true"
set: true
op: eq
value: "true"
remediation: |
Reset to the OpenShift default configuration.
scored: true
@@ -1221,18 +1116,11 @@ groups:
text: "Verify the OpenShift default configuration for the peer-auto-tls argument"
audit: "/bin/sh -c '/usr/local/bin/master-exec etcd etcd grep ETCD_PEER_AUTO_TLS /proc/1/environ; grep ETCD_PEER_AUTO_TLS /etc/etcd/etcd.conf'"
tests:
bin_op: and
test_items:
- flag: "Binary file /proc/1/environ matches"
- flag: "ETCD_PEER_AUTO_TLS"
compare:
op: has
value: "Binary file /proc/1/environ matches"
set: true
- flag: "#ETCD_PEER_AUTO_TLS=false"
compare:
op: has
value: "#ETCD_PEER_AUTO_TLS=false"
set: true
op: noteq
value: "true"
remediation: |
Reset to the OpenShift default configuration.
scored: true
@@ -1253,10 +1141,6 @@ groups:
tests:
test_items:
- flag: "issuer= /CN=etcd-signer"
compare:
op: has
value: "issuer= /CN=etcd-signer"
set: true
remediation: |
Reset to the OpenShift default configuration.
scored: false

View File

@@ -1,5 +1,6 @@
---
controls:
version: "rh-0.7"
id: 2
text: "Worker Node Security Configuration"
type: "node"
@@ -19,17 +20,16 @@ groups:
- id: 7.3
text: "Verify that the --authorization-mode argument is set to WebHook"
audit: "grep -A1 authorization-mode /etc/origin/node/node-config.yaml"
audit_config: "cat /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "authorization-mode"
- path: "{.kubeletArguments.authorization-mode}"
set: false
- flag: "authorization-mode"
- path: "{.kubeletArguments.authorization-mode}"
compare:
op: has
value: "Webhook"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and remove authorization-mode under
kubeletArguments in /etc/origin/node/node-config.yaml or set it to "Webhook".
@@ -37,10 +37,10 @@ groups:
- id: 7.4
text: "Verify the OpenShift default for the client-ca-file argument"
audit: "grep -A1 client-ca-file /etc/origin/node/node-config.yaml"
audit_config: "cat /etc/origin/node/node-config.yaml"
tests:
test_items:
- flag: "client-ca-file"
- path: "{.PodManifestConfig.client-ca-file}"
set: false
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and remove any configuration returned by the following:
@@ -53,31 +53,32 @@ groups:
- id: 7.5
text: "Verify the OpenShift default setting for the read-only-port argument"
audit: "grep -A1 read-only-port /etc/origin/node/node-config.yaml"
audit_config: "cat /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "read-only-port"
- path: "{.kubeletArguments.read-only-port}"
set: false
- flag: "read-only-port"
- path: "{.kubeletArguments.read-only-port}"
compare:
op: has
op: eq
value: "0"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and removed so that the OpenShift default is applied.
scored: true
- id: 7.6
text: "Adjust the streaming-connection-idle-timeout argument"
audit: "grep -A1 streaming-connection-idle-timeout /etc/origin/node/node-config.yaml"
audit_config: "cat /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "streaming-connection-idle-timeout"
set: false
- flag: "5m"
- path: "{.kubeletArguments.streaming-connection-idle-timeout}"
set: false
- path: "{.kubeletArguments.streaming-connection-idle-timeout}"
compare:
op: eq
value: "5m"
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and set the streaming-connection-timeout
value like the following in node-config.yaml.
@@ -94,17 +95,16 @@ groups:
- id: 7.8
text: "Verify the OpenShift default value of true for the make-iptables-util-chains argument"
audit: "grep -A1 make-iptables-util-chains /etc/origin/node/node-config.yaml"
audit_config: "cat /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "make-iptables-util-chains"
- path: "{.kubeletArguments.make-iptables-util-chains}"
set: false
- flag: "make-iptables-util-chains"
- path: "{.kubeletArguments.make-iptables-util-chains}"
compare:
op: has
op: eq
value: "true"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and reset make-iptables-util-chains to the OpenShift
default value of true.
@@ -112,14 +112,16 @@ groups:
- id: 7.9
text: "Verify that the --keep-terminated-pod-volumes argument is set to false"
audit: "grep -A1 keep-terminated-pod-volumes /etc/origin/node/node-config.yaml"
audit_config: "cat /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "keep-terminated-pod-volumes"
- path: "{.kubeletArguments.keep-terminated-pod-volumes}"
set: false
- path: "{.kubeletArguments.keep-terminated-pod-volumes}"
compare:
op: has
op: eq
value: "false"
set: true
remediation: |
Reset to the OpenShift defaults
scored: true
@@ -131,17 +133,16 @@ groups:
- id: 7.11
text: "Set the --event-qps argument to 0"
audit: "grep -A1 event-qps /etc/origin/node/node-config.yaml"
audit_config: "cat /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "event-qps"
- path: "{.kubeletArguments.event-qps}"
set: false
- flag: "event-qps"
- path: "{.kubeletArguments.event-qps}"
compare:
op: has
op: eq
value: "0"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml set the event-qps argument to 0 in
the kubeletArguments section of.
@@ -149,31 +150,29 @@ groups:
- id: 7.12
text: "Verify the OpenShift cert-dir flag for HTTPS traffic"
audit: "grep -A1 cert-dir /etc/origin/node/node-config.yaml"
audit_config: "cat /etc/origin/node/node-config.yaml"
tests:
test_items:
- flag: "/etc/origin/node/certificates"
- path: "{.kubeletArguments.cert-dir}"
compare:
op: has
value: "/etc/origin/node/certificates"
set: true
remediation: |
Reset to the OpenShift default values.
scored: true
- id: 7.13
text: "Verify the OpenShift default of 0 for the cadvisor-port argument"
audit: "grep -A1 cadvisor-port /etc/origin/node/node-config.yaml"
audit_config: "cat /etc/origin/node/node-config.yaml"
tests:
bin_op: or
test_items:
- flag: "cadvisor-port"
- path: "{.kubeletArguments.cadvisor-port}"
set: false
- flag: "cadvisor-port"
- path: "{.kubeletArguments.cadvisor-port}"
compare:
op: has
op: eq
value: "0"
set: true
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and remove the cadvisor-port flag
if it is set in the kubeletArguments section.
@@ -181,28 +180,26 @@ groups:
- id: 7.14
text: "Verify that the RotateKubeletClientCertificate argument is set to true"
audit: "grep -B1 RotateKubeletClientCertificate=true /etc/origin/node/node-config.yaml"
audit_config: "cat /etc/origin/node/node-config.yaml"
tests:
test_items:
- flag: "RotateKubeletClientCertificate=true"
- path: "{.kubeletArguments.feature-gates}"
compare:
op: has
value: "true"
set: true
value: "RotateKubeletClientCertificate=true"
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and set RotateKubeletClientCertificate to true.
scored: true
- id: 7.15
text: "Verify that the RotateKubeletServerCertificate argument is set to true"
audit: "grep -B1 RotateKubeletServerCertificate=true /etc/origin/node/node-config.yaml"
audit_config: "cat /etc/origin/node/node-config.yaml"
tests:
test_items:
- flag: "RotateKubeletServerCertificate=true"
- path: "{.kubeletArguments.feature-gates}"
compare:
op: has
value: "true"
set: true
value: "RotateKubeletServerCertificate=true"
remediation: |
Edit the Openshift node config file /etc/origin/node/node-config.yaml and set RotateKubeletServerCertificate to true.
scored: true
@@ -220,7 +217,6 @@ groups:
compare:
op: bitmask
value: "644"
set: true
remediation: |
Run the below command on each worker node.
chmod 644 /etc/origin/node/node.kubeconfig
@@ -232,10 +228,6 @@ groups:
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: root:root
set: true
remediation: |
Run the below command on each worker node.
chown root:root /etc/origin/node/node.kubeconfig
@@ -243,32 +235,27 @@ groups:
- id: 8.3
text: "Verify the kubelet service file permissions of 644"
audit: "stat -c permissions=%a $nodesvc"
audit: "stat -c permissions=%a $kubeletsvc"
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
set: true
remediation: |
Run the below command on each worker node.
chmod 644 $nodesvc
chmod 644 $kubeletsvc
scored: true
- id: 8.4
text: "Verify the kubelet service file ownership of root:root"
audit: "stat -c %U:%G $nodesvc"
audit: "stat -c %U:%G $kubeletsvc"
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: root:root
set: true
remediation: |
Run the below command on each worker node.
chown root:root $nodesvc
chown root:root $kubeletsvc
scored: true
- id: 8.5
@@ -280,7 +267,6 @@ groups:
compare:
op: bitmask
value: "644"
set: true
remediation: |
Run the below command on each worker node.
chmod 644 /etc/origin/node/node.kubeconfig
@@ -292,10 +278,6 @@ groups:
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: root:root
set: true
remediation: |
Run the below command on each worker node.
chown root:root /etc/origin/node/node.kubeconfig
@@ -310,7 +292,6 @@ groups:
compare:
op: bitmask
value: "644"
set: true
remediation: |
Run the below command on each worker node.
chmod 644 /etc/origin/node/client-ca.crt
@@ -322,10 +303,6 @@ groups:
tests:
test_items:
- flag: "root:root"
compare:
op: eq
value: root:root
set: true
remediation: |
Run the below command on each worker node.
chown root:root /etc/origin/node/client-ca.crt

2
cfg/rh-1.0/config.yaml Normal file
View File

@@ -0,0 +1,2 @@
---
## Version-specific settings that override the values in cfg/config.yaml

View File

@@ -0,0 +1,62 @@
---
controls:
version: rh-1.0
id: 3
text: "Control Plane Configuration"
type: "controlplane"
groups:
- id: 3.1
text: "Authentication and Authorization"
checks:
- id: 3.1.1
text: "Client certificate authentication should not be used for users (Manual)"
audit: |
# To verify user authentication is enabled
oc describe authentication
# To verify that an identity provider is configured
oc get identity
# To verify that a custom cluster-admin user exists
oc get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].kind | grep cluster-admin | grep User
# To verity that kbueadmin is removed, no results should be returned
oc get secrets kubeadmin -n kube-system
type: manual
remediation: |
Configure an identity provider for the OpenShift cluster.
Understanding identity provider configuration | Authentication | OpenShift
Container Platform 4.5. Once an identity provider has been defined,
you can use RBAC to define and apply permissions.
After you define an identity provider and create a new cluster-admin user,
remove the kubeadmin user to improve cluster security.
scored: false
- id: 3.2
text: "Logging"
checks:
- id: 3.2.1
text: "Ensure that a minimal audit policy is created (Manual)"
audit: |
#To view kube apiserver log files
oc adm node-logs --role=master --path=kube-apiserver/
#To view openshift apiserver log files
oc adm node-logs --role=master --path=openshift-apiserver/
#To verify kube apiserver audit config
oc get configmap config -n openshift-kube-apiserver -ojson | jq -r '.data["config.yaml"]' | jq '.auditConfig[]'
#To verify openshift apiserver audit config
oc get configmap config -n openshift-apiserver -ojson | jq -r '.data["config.yaml"]' | jq '.auditConfig[]'
type: manual
remediation: |
No remediation required.
scored: false
- id: 3.2.2
text: "Ensure that the audit policy covers key security concerns (Manual)"
audit: |
#To verify openshift apiserver audit config
oc get configmap config -n openshift-kube-apiserver -ojson | jq -r '.data["config.yaml"]' | jq '.auditConfig.policyConfiguration.rules[]'
#To verify kube apiserver audit config
oc get configmap config -n openshift-apiserver -ojson | jq -r '.data["config.yaml"]' | jq '.auditConfig.policyConfiguration.rules[]'
type: manual
remediation: |
In OpenShift 4.6 and higher, if appropriate for your needs,
modify the audit policy.
scored: false

154
cfg/rh-1.0/etcd.yaml Normal file
View File

@@ -0,0 +1,154 @@
---
controls:
version: rh-1.0
id: 2
text: "Etcd Node Configuration"
type: "etcd"
groups:
- id: 2
text: "Etcd Node Configuration Files"
checks:
- id: 2.1
text: "Ensure that the --cert-file and --key-file arguments are set as appropriate (Manual)"
audit: |
# For --cert-file
for i in $(oc get pods -oname -n openshift-etcd)
do
oc exec -n openshift-etcd -c etcd $i -- ps -o command= -C etcd | sed 's/.*\(--cert-file=[^ ]*\).*/\1/'
done 2>/dev/null
# For --key-file
for i in $(oc get pods -oname -n openshift-etcd)
do
oc exec -n openshift-etcd -c etcd $i -- ps -o command= -C etcd | sed 's/.*\(--key-file=[^ ]*\).*/\1/'
done 2>/dev/null
use_multiple_values: true
tests:
test_items:
- flag: "file"
compare:
op: regex
value: '\/etc\/kubernetes\/static-pod-certs\/secrets\/etcd-all-serving\/etcd-serving-.*\.(?:crt|key)'
remediation: |
OpenShift does not use the etcd-certfile or etcd-keyfile flags.
Certificates for etcd are managed by the etcd cluster operator.
scored: false
- id: 2.2
text: "Ensure that the --client-cert-auth argument is set to true (Manual)"
audit: |
for i in $(oc get pods -oname -n openshift-etcd)
do
oc exec -n openshift-etcd -c etcd $i -- ps -o command= -C etcd | sed 's/.*\(--client-cert-auth=[^ ]*\).*/\1/'
done 2>/dev/null
use_multiple_values: true
tests:
test_items:
- flag: "--client-cert-auth"
compare:
op: eq
value: true
remediation: |
This setting is managed by the cluster etcd operator. No remediation required."
scored: false
- id: 2.3
text: "Ensure that the --auto-tls argument is not set to true (Manual)"
audit: |
# Returns 0 if found, 1 if not found
for i in $(oc get pods -oname -n openshift-etcd)
do
oc exec -n openshift-etcd -c etcd $i -- ps -o command= -C etcd | grep -- --auto-tls=true 2>&1>/dev/null ; echo exit_code=$?
done 2>/dev/null
use_multiple_values: true
tests:
test_items:
- flag: "exit_code"
compare:
op: eq
value: "1"
remediation: |
This setting is managed by the cluster etcd operator. No remediation required.e
scored: false
- id: 2.4
text: "Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Manual)"
audit: |
# For --peer-cert-file
for i in $(oc get pods -oname -n openshift-etcd)
do
oc exec -n openshift-etcd -c etcd $i -- ps -o command= -C etcd | sed 's/.*\(--peer-cert-file=[^ ]*\).*/\1/'
done 2>/dev/null
# For --peer-key-file
for i in $(oc get pods -oname -n openshift-etcd)
do
oc exec -n openshift-etcd -c etcd $i -- ps -o command= -C etcd | sed 's/.*\(--peer-key-file=[^ ]*\).*/\1/'
done 2>/dev/null
use_multiple_values: true
tests:
test_items:
- flag: "file"
compare:
op: regex
value: '\/etc\/kubernetes\/static-pod-certs\/secrets\/etcd-all-peer\/etcd-peer-.*\.(?:crt|key)'
remediation: |
None. This configuration is managed by the etcd operator.
scored: false
- id: 2.5
text: "Ensure that the --peer-client-cert-auth argument is set to true (Manual)"
audit: |
for i in $(oc get pods -oname -n openshift-etcd)
do
oc exec -n openshift-etcd -c etcd $i -- ps -o command= -C etcd | sed 's/.*\(--peer-client-cert-auth=[^ ]*\).*/\1/'
done 2>/dev/null
use_multiple_values: true
tests:
test_items:
- flag: "--peer-client-cert-auth"
compare:
op: eq
value: true
remediation: |
This setting is managed by the cluster etcd operator. No remediation required.
scored: false
- id: 2.6
text: "Ensure that the --peer-auto-tls argument is not set to true (Manual)"
audit: |
# Returns 0 if found, 1 if not found
for i in $(oc get pods -oname -n openshift-etcd)
do
oc exec -n openshift-etcd -c etcd $i -- ps -o command= -C etcd | grep -- --peer-auto-tls=true 2>&1>/dev/null ; echo exit_code=$?
done 2>/dev/null
use_multiple_values: true
tests:
test_items:
- flag: "exit_code"
compare:
op: eq
value: "1"
remediation: |
This setting is managed by the cluster etcd operator. No remediation required.
scored: false
- id: 2.7
text: "Ensure that a unique Certificate Authority is used for etcd (Manual)"
audit: |
for i in $(oc get pods -oname -n openshift-etcd)
do
oc exec -n openshift-etcd -c etcd $i -- ps -o command= -C etcd | sed 's/.*\(--trusted-ca-file=[^ ]*\).*/\1/'
done 2>/dev/null
for i in $(oc get pods -oname -n openshift-etcd)
do
oc exec -n openshift-etcd -c etcd $i -- ps -o command= -C etcd | sed 's/.*\(--peer-trusted-ca-file=[^ ]*\).*/\1/'
done 2>/dev/null
use_multiple_values: true
tests:
test_items:
- flag: "file"
compare:
op: regex
value: '\/etc\/kubernetes\/static-pod-certs\/configmaps\/etcd-(?:serving|peer-client)-ca\/ca-bundle\.(?:crt|key)'
remediation: |
None required. Certificates for etcd are managed by the OpenShift cluster etcd operator.
scored: false

1262
cfg/rh-1.0/master.yaml Normal file

File diff suppressed because it is too large Load Diff

453
cfg/rh-1.0/node.yaml Normal file
View File

@@ -0,0 +1,453 @@
---
controls:
version: rh-1.0
id: 4
text: "Worker Node Security Configuration"
type: "node"
groups:
- id: 4.1
text: "Worker Node Configuration Files"
checks:
- id: 4.1.1
text: "Ensure that the kubelet service file permissions are set to 644 or more restrictive (Automated)"
audit: |
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host stat -c "$node %n permissions=%a" /etc/systemd/system/kubelet.service
done 2> /dev/null
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
By default, the kubelet service file has permissions of 644.
scored: true
- id: 4.1.2
text: "Ensure that the kubelet service file ownership is set to root:root (Automated)"
audit: |
# Should return root:root for each node
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host stat -c "$node %n %U:%G" /etc/systemd/system/kubelet.service
done 2> /dev/null
use_multiple_values: true
tests:
test_items:
- flag: root:root
remediation: |
By default, the kubelet service file has ownership of root:root.
scored: true
- id: 4.1.3
text: "If proxy kubeconfig file exists ensure permissions are set to 644 or more restrictive (Manual)"
audit: |
for i in $(oc get pods -n openshift-sdn -l app=sdn -oname)
do
oc exec -n openshift-sdn $i -- stat -Lc "$i %n permissions=%a" /config/kube-proxy-config.yaml
done 2> /dev/null
use_multiple_values: true
tests:
bin_op: or
test_items:
- flag: "permissions"
set: true
compare:
op: bitmask
value: "644"
remediation: |
None needed.
scored: false
- id: 4.1.4
text: "Ensure that the proxy kubeconfig file ownership is set to root:root (Manual)"
audit: |
for i in $(oc get pods -n openshift-sdn -l app=sdn -oname)
do
oc exec -n openshift-sdn $i -- stat -Lc "$i %n %U:%G" /config/kube-proxy-config.yaml
done 2> /dev/null
use_multiple_values: true
tests:
bin_op: or
test_items:
- flag: root:root
remediation: |
None required. The configuration is managed by OpenShift operators.
scored: false
- id: 4.1.5
text: "Ensure that the --kubeconfig kubelet.conf file permissions are set to 644 or more restrictive (Manual)"
audit: |
# Check permissions
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host stat -c "$node %n permissions=%a" /etc/kubernetes/kubelet.conf
done 2> /dev/null
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
None required.
scored: false
- id: 4.1.6
text: "Ensure that the --kubeconfig kubelet.conf file ownership is set to root:root (Manual)"
audit: |
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host stat -c "$node %n %U:%G" /etc/kubernetes/kubelet.conf
done 2> /dev/null
use_multiple_values: true
tests:
test_items:
- flag: root:root
remediation: |
None required.
scored: false
- id: 4.1.7
text: "Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Automated)"
audit: |
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host stat -c "$node %n permissions=%a" /etc/kubernetes/kubelet-ca.crt
done 2> /dev/null
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
None required.
scored: true
- id: 4.1.8
text: "Ensure that the client certificate authorities file ownership is set to root:root (Automated)"
audit: |
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host stat -c "$node %n %U:%G" /etc/kubernetes/kubelet-ca.crt
done 2> /dev/null
use_multiple_values: true
tests:
test_items:
- flag: root:root
remediation: |
None required.
scored: true
- id: 4.1.9
text: "Ensure that the kubelet --config configuration file has permissions set to 644 or more restrictive (Automated)"
audit: |
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host stat -c "$node %n permissions=%a" /var/lib/kubelet/kubeconfig
done 2> /dev/null
use_multiple_values: true
tests:
test_items:
- flag: "permissions"
compare:
op: bitmask
value: "644"
remediation: |
None required.
scored: true
- id: 4.1.10
text: "Ensure that the kubelet configuration file ownership is set to root:root (Automated)"
audit: |
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host stat -c "$node %n %U:%G" /var/lib/kubelet/kubeconfig
done 2> /dev/null
use_multiple_values: true
tests:
test_items:
- flag: root:root
remediation: |
None required.
scored: true
- id: 4.2
text: "Kubelet"
checks:
- id: 4.2.1
text: "Ensure that the --anonymous-auth argument is set to false (Automated)"
audit: |
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host grep -B4 -A1 anonymous: /etc/kubernetes/kubelet.conf
done
use_multiple_values: true
tests:
test_items:
- flag: "enabled: true"
set: false
remediation: |
Follow the instructions in the documentation to create a Kubelet config CRD
and set the anonymous-auth is set to false.
scored: true
- id: 4.2.2
text: "Ensure that the --authorization-mode argument is not set to AlwaysAllow (Automated)"
type: manual
# Takes a lot of time for connection to fail and
audit: |
POD=$(oc -n openshift-kube-apiserver get pod -l app=openshift-kube-apiserver -o jsonpath='{.items[0].metadata.name}')
TOKEN=$(oc whoami -t)
for name in $(oc get nodes -ojsonpath='{.items[*].metadata.name}')
do
oc exec -n openshift-kube-apiserver $POD -- curl -sS https://172.25.0.1/api/v1/nodes/$name/proxy/configz -k -H "Authorization:Bearer $TOKEN" | jq -r '.kubeletconfig.authorization.mode'
done
use_multiple_values: true
tests:
test_items:
- flag: "Connection timed out"
remediation: |
None required. Unauthenticated/Unauthorized users have no access to OpenShift nodes.
scored: true
- id: 4.2.3
text: "Ensure that the --client-ca-file argument is set as appropriate (Automated)"
audit: |
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host grep clientCAFile: /etc/kubernetes/kubelet.conf
done 2> /dev/null
use_multiple_values: true
tests:
test_items:
- flag: "clientCAFile"
compare:
op: eq
value: "/etc/kubernetes/kubelet-ca.crt"
remediation: |
None required. Changing the clientCAFile value is unsupported.
scored: true
- id: 4.2.4
text: "Verify that the read only port is not used or is set to 0 (Automated)"
audit: |
echo `oc -n openshift-kube-apiserver get cm kube-apiserver-pod -o yaml | grep --color read-only-port` 2> /dev/null
echo `oc -n openshift-kube-apiserver get cm config -o yaml | grep --color "read-only-port"` 2> /dev/null
tests:
bin_op: or
test_items:
- flag: "read-only-port"
compare:
op: has
value: "[\"0\"]"
- flag: "read-only-port"
set: false
remediation: |
In earlier versions of OpenShift 4, the read-only-port argument is not used.
Follow the instructions in the documentation to create a Kubelet config CRD
and set the --read-only-port is set to 0.
scored: true
- id: 4.2.5
text: "Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Automated)"
audit: |
# Should return 1 for each node
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host ps -ef | grep kubelet | grep streaming-connection-idle-timeout
echo exit_code=$?
done 2>/dev/null
# Should return 1 for each node
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host grep streamingConnectionIdleTimeout /etc/kubernetes/kubelet.conf
echo exit_code=$?
done 2>/dev/null
use_multiple_values: true
tests:
bin_op: or
test_items:
- flag: --streaming-connection-idle-timeout
compare:
op: noteq
value: 0
- flag: "exit_code"
compare:
op: eq
value: 1
remediation: |
Follow the instructions in the documentation to create a Kubelet config CRD and set
the --streaming-connection-idle-timeout to the desired value. Do not set the value to 0.
scored: true
- id: 4.2.6
text: "Ensure that the --protect-kernel-defaults argument is not set (Manual)"
audit: |
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}');
do
oc debug node/${node} -- chroot /host more /etc/kubernetes/kubelet.conf;
done
tests:
test_items:
- flag: protectKernelDefaults
set: false
remediation: |
None required. The OpenShift 4 kubelet modifies the system tunable;
using the protect-kernel-defaults flag will cause the kubelet to fail on start if the tunables
don't match the kubelet configuration and the OpenShift node will fail to start.
scored: false
- id: 4.2.7
text: "Ensure that the --make-iptables-util-chains argument is set to true (Manual)"
audit: |
/bin/bash
flag=make-iptables-util-chains
opt=makeIPTablesUtilChains
# look at each machineconfigpool
while read -r pool nodeconfig; do
# true by default
value='true'
# first look for the flag
oc get machineconfig $nodeconfig -o json | jq -r '.spec.config.systemd[][] | select(.name=="kubelet.service") | .contents' | sed -n "/^ExecStart=/,/^\$/ { /^\\s*--$flag=false/ q 100 }"
# if the above command exited with 100, the flag was false
[ $? == 100 ] && value='false'
# now look in the yaml KubeletConfig
yamlconfig=$(oc get machineconfig $nodeconfig -o json | jq -r '.spec.config.storage.files[] | select(.path=="/etc/kubernetes/kubelet.conf") | .contents.source ' | sed 's/^data:,//' | while read; do echo -e ${REPLY//%/\\x}; done)
echo "$yamlconfig" | sed -n "/^$opt:\\s*false\\s*$/ q 100"
[ $? == 100 ] && value='false'
echo "Pool $pool has $flag ($opt) set to $value"
done < <(oc get machineconfigpools -o json | jq -r '.items[] | select(.status.machineCount>0) | .metadata.name + " " + .spec.configuration.name')
use_multiple_values: true
tests:
test_items:
- flag: "set to true"
remediation: |
None required. The --make-iptables-util-chains argument is set to true by default.
scored: false
- id: 4.2.8
text: "Ensure that the --hostname-override argument is not set (Manual)"
audit: |
echo `oc get machineconfig 01-worker-kubelet -o yaml | grep hostname-override`
echo `oc get machineconfig 01-master-kubelet -o yaml | grep hostname-override`
tests:
test_items:
- flag: hostname-override
set: false
remediation: |
By default, --hostname-override argument is not set.
scored: false
- id: 4.2.9
text: "Ensure that the kubeAPIQPS [--event-qps] argument is set to 0 or a level which ensures appropriate event capture (Automated)"
audit: |
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}');
do
oc debug node/${node} -- chroot /host more /etc/kubernetes/kubelet.conf;
done
oc get machineconfig 01-worker-kubelet -o yaml | grep --color kubeAPIQPS%3A%2050
oc get machineconfig 01-master-kubelet -o yaml | grep --color kubeAPIQPS%3A%2050
type: "manual"
remediation: |
Follow the documentation to edit kubelet parameters
https://docs.openshift.com/container-platform/4.5/scalability_and_performance/recommended-host-practices.html#create-a-kubeletconfig-crd-to-edit-kubelet-parameters
KubeAPIQPS: <QPS>
scored: true
- id: 4.2.10
text: "Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Automated)"
audit: |
oc get configmap config -n openshift-kube-apiserver -ojson | jq -r '.data["config.yaml"]' | jq '.kubeletClientInfo'
tests:
bin_op: and
test_items:
- flag: "/etc/kubernetes/static-pod-certs/secrets/kubelet-client/tls.crt"
- flag: "/etc/kubernetes/static-pod-certs/secrets/kubelet-client/tls.key"
remediation: |
OpenShift automatically manages TLS authentication for the API server communication with the node/kublet.
This is not configurable.
scored: true
- id: 4.2.11
text: "Ensure that the --rotate-certificates argument is not set to false (Manual)"
audit: |
#Verify the rotateKubeletClientCertificate feature gate is not set to false
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot /host cat /etc/kubernetes/kubelet.conf | grep RotateKubeletClientCertificate
done 2> /dev/null
# Verify the rotateCertificates argument is set to true
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot host grep rotate /etc/kubernetes/kubelet.conf;
done 2> /dev/null
use_multiple_values: true
tests:
bin_op: or
test_items:
- flag: rotateCertificates
compare:
op: eq
value: true
- flag: rotateKubeletClientCertificates
compare:
op: noteq
value: false
- flag: rotateKubeletClientCertificates
set: false
remediation: |
None required.
scored: false
- id: 4.2.12
text: "Verify that the RotateKubeletServerCertificate argument is set to true (Manual)"
audit: |
#Verify the rotateKubeletServerCertificate feature gate is on
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}');
do
oc debug node/${node} -- chroot /host grep RotateKubeletServerCertificate /etc/kubernetes/kubelet.conf;
done 2> /dev/null
# Verify the rotateCertificates argument is set to true
for node in $(oc get nodes -o jsonpath='{.items[*].metadata.name}')
do
oc debug node/${node} -- chroot host grep rotate /etc/kubernetes/kubelet.conf;
done 2> /dev/null
use_multiple_values: true
tests:
bin_op: or
test_items:
- flag: RotateKubeletServerCertificate
compare:
op: eq
value: true
- flag: rotateCertificates
compare:
op: eq
value: true
remediation: |
By default, kubelet server certificate rotation is disabled.
scored: false
- id: 4.2.13
text: "Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Manual)"
audit: |
# needs verification
# verify cipher suites
oc describe --namespace=openshift-ingress-operator ingresscontroller/default
oc get kubeapiservers.operator.openshift.io cluster -o json |jq .spec.observedConfig.servingInfo
oc get openshiftapiservers.operator.openshift.io cluster -o json |jq .spec.observedConfig.servingInfo
oc get cm -n openshift-authentication v4-0-config-system-cliconfig -o jsonpath='{.data.v4\-0\-config\-system\-cliconfig}' | jq .servingInfo
#check value for tlsSecurityProfile; null is returned if default is used
oc get kubeapiservers.operator.openshift.io cluster -o json |jq .spec.tlsSecurityProfile
type: manual
remediation: |
Follow the directions above and in the OpenShift documentation to configure the tlsSecurityProfile.
Configuring Ingress
scored: false

283
cfg/rh-1.0/policies.yaml Normal file
View File

@@ -0,0 +1,283 @@
---
controls:
version: rh-1.0
id: 5
text: "Kubernetes Policies"
type: "policies"
groups:
- id: 5.1
text: "RBAC and Service Accounts"
checks:
- id: 5.1.1
text: "Ensure that the cluster-admin role is only used where required (Manual)"
type: "manual"
remediation: |
Identify all clusterrolebindings to the cluster-admin role. Check if they are used and
if they need this role or if they could use a role with fewer privileges.
Where possible, first bind users to a lower privileged role and then remove the
clusterrolebinding to the cluster-admin role :
kubectl delete clusterrolebinding [name]
scored: false
- id: 5.1.2
text: "Minimize access to secrets (Manual)"
type: "manual"
remediation: |
Where possible, remove get, list and watch access to secret objects in the cluster.
scored: false
- id: 5.1.3
text: "Minimize wildcard use in Roles and ClusterRoles (Manual)"
type: "manual"
remediation: |
Where possible replace any use of wildcards in clusterroles and roles with specific
objects or actions.
scored: false
- id: 5.1.4
text: "Minimize access to create pods (Manual)"
type: "manual"
remediation: |
Where possible, remove create access to pod objects in the cluster.
scored: false
- id: 5.1.5
text: "Ensure that default service accounts are not actively used. (Manual)"
type: "manual"
remediation: |
None required.
scored: false
- id: 5.1.6
text: "Ensure that Service Account Tokens are only mounted where necessary (Manual)"
type: "manual"
remediation: |
Modify the definition of pods and service accounts which do not need to mount service
account tokens to disable it.
scored: false
- id: 5.2
text: "Pod Security Policies"
checks:
- id: 5.2.1
text: "Minimize the admission of privileged containers (Manual)"
audit: |
# needs verification
for i in `oc get scc --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}'`;
do
echo "$i"; oc describe scc $i | grep "Allow Privileged";
done
tests:
test_items:
- flag: "false"
remediation: |
Create a SCC as described in the OpenShift documentation, ensuring that the Allow
Privileged field is set to false.
scored: false
- id: 5.2.2
text: "Minimize the admission of containers wishing to share the host process ID namespace (Manual)"
audit: |
for i in `oc get scc --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}'`;
do
echo "$i"; oc describe scc $i | grep "Allow Host PID";
done
tests:
test_items:
- flag: "false"
remediation: |
Create a SCC as described in the OpenShift documentation, ensuring that the Allow Host
PID field is set to false.
scored: false
- id: 5.2.3
text: "Minimize the admission of containers wishing to share the host IPC namespace (Manual)"
audit: |
for i in `oc get scc --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}'`;
do
echo "$i"; oc describe scc $i | grep "Allow Host IPC";
done
tests:
test_items:
- flag: "false"
remediation: |
Create a SCC as described in the OpenShift documentation, ensuring that the Allow Host
IPC field is set to false.
scored: false
- id: 5.2.4
text: "Minimize the admission of containers wishing to share the host network namespace (Manual)"
audit: |
for i in `oc get scc --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}'`;
do
echo "$i"; oc describe scc $i | grep "Allow Host Network";
done
tests:
test_items:
- flag: "false"
remediation: |
Create a SCC as described in the OpenShift documentation, ensuring that the Allow Host
Network field is omitted or set to false.
scored: false
- id: 5.2.5
text: "Minimize the admission of containers with allowPrivilegeEscalation (Manual)"
audit: |
for i in `oc get scc --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}'`;
do
echo "$i"; oc describe scc $i | grep "Allow Privilege Escalation";
done
tests:
test_items:
- flag: "false"
remediation: |
Create a SCC as described in the OpenShift documentation, ensuring that the Allow
Privilege Escalation field is omitted or set to false.
scored: false
- id: 5.2.6
text: "Minimize the admission of root containers (Manual)"
audit: |
# needs verification
for i in `oc get scc --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}'`;
do
echo "$i";
oc describe scc $i | grep "Run As User Strategy";
done
#For SCCs with MustRunAs verify that the range of UIDs does not include 0
for i in `oc get scc --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}'`;
do
echo "$i";
oc describe scc $i | grep "\sUID";
done
tests:
bin_op: or
test_items:
- flag: "MustRunAsNonRoot"
- flag: "MustRunAs"
compare:
op: nothave
value: 0
remediation: |
None required. By default, OpenShift includes the non-root SCC with the the Run As User
Strategy is set to either MustRunAsNonRoot. If additional SCCs are appropriate, follow the
OpenShift documentation to create custom SCCs.
scored: false
- id: 5.2.7
text: "Minimize the admission of containers with the NET_RAW capability (Manual)"
audit: |
# needs verification
for i in `oc get scc --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}'`;
do
echo "$i";
oc describe scc $i | grep "Required Drop Capabilities";
done
tests:
bin_op: or
test_items:
- flag: "ALL"
- flag: "NET_RAW"
remediation: |
Create a SCC as described in the OpenShift documentation, ensuring that the Required
Drop Capabilities is set to include either NET_RAW or ALL.
scored: false
- id: 5.2.8
text: "Minimize the admission of containers with added capabilities (Manual)"
type: "manual"
remediation: |
Ensure that Allowed Capabilities is set to an empty array for every SCC in the cluster
except for the privileged SCC.
scored: false
- id: 5.2.9
text: "Minimize the admission of containers with capabilities assigned (Manual)"
type: "manual"
remediation: |
Review the use of capabilites in applications running on your cluster. Where a namespace
contains applicaions which do not require any Linux capabities to operate consider
adding a SCC which forbids the admission of containers which do not drop all capabilities.
scored: false
- id: 5.3
text: "Network Policies and CNI"
checks:
- id: 5.3.1
text: "Ensure that the CNI in use supports Network Policies (Manual)"
type: "manual"
remediation: |
None required.
scored: false
- id: 5.3.2
text: "Ensure that all Namespaces have Network Policies defined (Manual)"
type: "manual"
remediation: |
Follow the documentation and create NetworkPolicy objects as you need them.
scored: false
- id: 5.4
text: "Secrets Management"
checks:
- id: 5.4.1
text: "Prefer using secrets as files over secrets as environment variables (Manual)"
type: "manual"
remediation: |
If possible, rewrite application code to read secrets from mounted secret files, rather than
from environment variables.
scored: false
- id: 5.4.2
text: "Consider external secret storage (Manual)"
type: "manual"
remediation: |
Refer to the secrets management options offered by your cloud provider or a third-party
secrets management solution.
scored: false
- id: 5.5
text: "Extensible Admission Control"
checks:
- id: 5.5.1
text: "Configure Image Provenance using ImagePolicyWebhook admission controller (Manual)"
type: "manual"
remediation: |
Follow the OpenShift documentation: [Image configuration resources](https://docs.openshift.com/container-platform/4.5/openshift_images/image-configuration.html
scored: false
- id: 5.7
text: "General Policies"
checks:
- id: 5.7.1
text: "Create administrative boundaries between resources using namespaces (Manual)"
type: "manual"
remediation: |
Follow the documentation and create namespaces for objects in your deployment as you need
them.
scored: false
- id: 5.7.2
text: "Ensure that the seccomp profile is set to docker/default in your pod definitions (Manual)"
type: "manual"
remediation: |
To enable the default seccomp profile, use the reserved value /runtime/default that will
make sure that the pod uses the default policy available on the host.
scored: false
- id: 5.7.3
text: "Apply Security Context to Your Pods and Containers (Manual)"
type: "manual"
remediation: |
Follow the Kubernetes documentation and apply security contexts to your pods. For a
suggested list of security contexts, you may refer to the CIS Security Benchmark for Docker
Containers.
scored: false
- id: 5.7.4
text: "The default namespace should not be used (Manual)"
type: "manual"
remediation: |
Ensure that namespaces are created to allow for appropriate segregation of Kubernetes
resources and that all new resources are created in a specific namespace.
scored: false

View File

@@ -39,6 +39,9 @@ const (
// INFO informational message
INFO State = "INFO"
// SKIP for when a check should be skipped.
SKIP = "skip"
// MASTER a master node
MASTER NodeType = "master"
// NODE a node
@@ -65,10 +68,11 @@ type Check struct {
ID string `yaml:"id" json:"test_number"`
Text string `json:"test_desc"`
Audit string `json:"audit"`
AuditEnv string `yaml:"audit_env"`
AuditConfig string `yaml:"audit_config"`
Type string `json:"type"`
Tests *tests `json:"omit"`
Set bool `json:"omit"`
Tests *tests `json:"-"`
Set bool `json:"-"`
Remediation string `json:"remediation"`
TestInfo []string `json:"test_info"`
State `json:"status"`
@@ -77,8 +81,10 @@ type Check struct {
IsMultiple bool `yaml:"use_multiple_values"`
ExpectedResult string `json:"expected_result"`
Reason string `json:"reason,omitempty"`
AuditOutput string `json:"omit"`
AuditConfigOutput string `json:"omit"`
AuditOutput string `json:"-"`
AuditEnvOutput string `json:"-"`
AuditConfigOutput string `json:"-"`
DisableEnvTesting bool `json:"-"`
}
// Runner wraps the basic Run method.
@@ -101,20 +107,22 @@ func (r *defaultRunner) Run(c *Check) State {
// Run executes the audit commands specified in a check and outputs
// the results.
func (c *Check) run() State {
glog.V(3).Infof("----- Running check %v -----", c.ID)
// Since this is an Scored check
// without tests return a 'WARN' to alert
// the user that this check needs attention
if c.Scored && strings.TrimSpace(c.Type) == "" && c.Tests == nil {
c.Reason = "There are no tests"
c.State = WARN
glog.V(3).Info(c.Reason)
return c.State
}
// If check type is skip, force result to INFO
if c.Type == "skip" {
if c.Type == SKIP {
c.Reason = "Test marked as skip"
c.State = INFO
glog.V(3).Info(c.Reason)
return c.State
}
@@ -122,6 +130,7 @@ func (c *Check) run() State {
if c.Type == MANUAL {
c.Reason = "Test marked as a manual test"
c.State = WARN
glog.V(3).Info(c.Reason)
return c.State
}
@@ -133,6 +142,7 @@ func (c *Check) run() State {
} else {
c.State = WARN
}
glog.V(3).Info(c.Reason)
return c.State
}
@@ -167,12 +177,13 @@ func (c *Check) run() State {
} else {
c.State = WARN
}
glog.V(3).Info(c.Reason)
}
if finalOutput != nil {
glog.V(3).Infof("Check.ID: %s Command: %q TestResult: %t State: %q \n", c.ID, lastCommand, finalOutput.testResult, c.State)
glog.V(3).Infof("Command: %q TestResult: %t State: %q \n", lastCommand, finalOutput.testResult, c.State)
} else {
glog.V(3).Infof("Check.ID: %s Command: %q TestResult: <<EMPTY>> \n", c.ID, lastCommand)
glog.V(3).Infof("Command: %q TestResult: <<EMPTY>> \n", lastCommand)
}
if c.Reason != "" {
@@ -182,6 +193,14 @@ func (c *Check) run() State {
}
func (c *Check) runAuditCommands() (lastCommand string, err error) {
// Always run auditEnvOutput if needed
if c.AuditEnv != "" {
c.AuditEnvOutput, err = runAudit(c.AuditEnv)
if err != nil {
return c.AuditEnv, err
}
}
// Run the audit command and auditConfig commands, if present
c.AuditOutput, err = runAudit(c.Audit)
if err != nil {
@@ -199,18 +218,31 @@ func (c *Check) execute() (finalOutput *testOutput, err error) {
res := make([]testOutput, len(ts.TestItems))
expectedResultArr := make([]string, len(res))
glog.V(3).Infof("%d tests", len(ts.TestItems))
glog.V(3).Infof("Running %d test_items", len(ts.TestItems))
for i, t := range ts.TestItems {
t.isMultipleOutput = c.IsMultiple
// Try with the auditOutput first, and if that's not found, try the auditConfigOutput
t.isConfigSetting = false
t.auditUsed = AuditCommand
result := *(t.execute(c.AuditOutput))
if !result.flagFound {
t.isConfigSetting = true
// Check for AuditConfigOutput only if AuditConfig is set
if !result.flagFound && c.AuditConfig != "" {
//t.isConfigSetting = true
t.auditUsed = AuditConfig
result = *(t.execute(c.AuditConfigOutput))
if !result.flagFound && t.Env != "" {
t.auditUsed = AuditEnv
result = *(t.execute(c.AuditEnvOutput))
}
}
if !result.flagFound && t.Env != "" {
t.auditUsed = AuditEnv
result = *(t.execute(c.AuditEnvOutput))
}
glog.V(2).Infof("Used %s", t.auditUsed)
res[i] = result
expectedResultArr[i] = res[i].ExpectedResult
}
@@ -264,8 +296,8 @@ func runAudit(audit string) (output string, err error) {
if err != nil {
err = fmt.Errorf("failed to run: %q, output: %q, error: %s", audit, output, err)
} else {
glog.V(3).Infof("Command %q\n - Output:\n %q", audit, output)
glog.V(3).Infof("Command: %q", audit)
glog.V(3).Infof("Output:\n %q", output)
}
return output, err
}

View File

@@ -81,6 +81,39 @@ func TestCheck_Run(t *testing.T) {
}
}
func TestCheckAuditEnv(t *testing.T) {
passingCases := []*Check{
controls.Groups[2].Checks[0],
controls.Groups[2].Checks[2],
controls.Groups[2].Checks[3],
controls.Groups[2].Checks[4],
}
failingCases := []*Check{
controls.Groups[2].Checks[1],
controls.Groups[2].Checks[5],
controls.Groups[2].Checks[6],
}
for _, c := range passingCases {
t.Run(c.Text, func(t *testing.T) {
c.run()
if c.State != "PASS" {
t.Errorf("Should PASS, got: %v", c.State)
}
})
}
for _, c := range failingCases {
t.Run(c.Text, func(t *testing.T) {
c.run()
if c.State != "FAIL" {
t.Errorf("Should FAIL, got: %v", c.State)
}
})
}
}
func TestCheckAuditConfig(t *testing.T) {
passingCases := []*Check{

View File

@@ -19,25 +19,47 @@ import (
"encoding/json"
"encoding/xml"
"fmt"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/securityhub"
"github.com/golang/glog"
"github.com/onsi/ginkgo/reporters"
"github.com/spf13/viper"
"gopkg.in/yaml.v2"
)
const (
// UNKNOWN is when the AWS account can't be found
UNKNOWN = "Unknown"
// ARN for the AWS Security Hub service
ARN = "arn:aws:securityhub:%s::product/aqua-security/kube-bench"
// SCHEMA for the AWS Security Hub service
SCHEMA = "2018-10-08"
// TYPE is type of Security Hub finding
TYPE = "Software and Configuration Checks/Industry and Regulatory Standards/CIS Kubernetes Benchmark"
)
type OverallControls struct {
Controls []*Controls
Totals Summary
}
// Controls holds all controls to check for master nodes.
type Controls struct {
ID string `yaml:"id" json:"id"`
Version string `json:"version"`
Text string `json:"text"`
Type NodeType `json:"node_type"`
Groups []*Group `json:"tests"`
ID string `yaml:"id" json:"id"`
Version string `json:"version"`
DetectedVersion string `json:"detected_version,omitempty"`
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" json:"section"`
Type string `yaml:"type" json:"type"`
Pass int `json:"pass"`
Fail int `json:"fail"`
Warn int `json:"warn"`
@@ -58,7 +80,7 @@ type Summary struct {
type Predicate func(group *Group, check *Check) bool
// NewControls instantiates a new master Controls object.
func NewControls(t NodeType, in []byte) (*Controls, error) {
func NewControls(t NodeType, in []byte, detectedVersion string) (*Controls, error) {
c := new(Controls)
err := yaml.Unmarshal(in, c)
@@ -69,12 +91,12 @@ func NewControls(t NodeType, in []byte) (*Controls, error) {
if t != c.Type {
return nil, fmt.Errorf("non-%s controls file specified", t)
}
c.DetectedVersion = detectedVersion
return c, nil
}
// RunChecks runs the checks with the given Runner. Only checks for which the filter Predicate returns `true` will run.
func (controls *Controls) RunChecks(runner Runner, filter Predicate) Summary {
func (controls *Controls) RunChecks(runner Runner, filter Predicate, skipIDMap map[string]bool) Summary {
var g []*Group
m := make(map[string]*Group)
controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn, controls.Info = 0, 0, 0, 0
@@ -86,7 +108,15 @@ func (controls *Controls) RunChecks(runner Runner, filter Predicate) Summary {
continue
}
_, groupSkippedViaCmd := skipIDMap[group.ID]
_, checkSkippedViaCmd := skipIDMap[check.ID]
if group.Type == SKIP || groupSkippedViaCmd || checkSkippedViaCmd {
check.Type = SKIP
}
state := runner.Run(check)
check.TestInfo = append(check.TestInfo, check.Remediation)
// Check if we have already added this checks group.
@@ -175,6 +205,93 @@ func (controls *Controls) JUnit() ([]byte, error) {
return b.Bytes(), nil
}
// ASFF encodes the results of last run to AWS Security Finding Format(ASFF).
func (controls *Controls) ASFF() ([]*securityhub.AwsSecurityFinding, error) {
fs := []*securityhub.AwsSecurityFinding{}
a, err := getConfig("AWS_ACCOUNT")
if err != nil {
return nil, err
}
c, err := getConfig("CLUSTER_ARN")
if err != nil {
return nil, err
}
region, err := getConfig("AWS_REGION")
if err != nil {
return nil, err
}
arn := fmt.Sprintf(ARN, region)
ti := time.Now()
tf := ti.Format(time.RFC3339)
for _, g := range controls.Groups {
for _, check := range g.Checks {
if check.State == FAIL || check.State == WARN {
// ASFF ProductFields['Actual result'] can't be longer than 1024 characters
actualValue := check.ActualValue
remediation := check.Remediation
reason := check.Reason
if len(check.ActualValue) > 1024 {
actualValue = check.ActualValue[0:1023]
}
// Fix issue https://github.com/aquasecurity/kube-bench/issues/903
if len(check.Remediation) > 512 {
remediation = check.Remediation[0:511]
}
if len(check.Reason) > 1024 {
reason = check.Reason[0:1023]
}
f := securityhub.AwsSecurityFinding{
AwsAccountId: aws.String(a),
Confidence: aws.Int64(100),
GeneratorId: aws.String(fmt.Sprintf("%s/cis-kubernetes-benchmark/%s/%s", arn, controls.Version, check.ID)),
Id: aws.String(fmt.Sprintf("%s%sEKSnodeID+%s%s", arn, a, check.ID, tf)),
CreatedAt: aws.String(tf),
Description: aws.String(check.Text),
ProductArn: aws.String(arn),
SchemaVersion: aws.String(SCHEMA),
Title: aws.String(fmt.Sprintf("%s %s", check.ID, check.Text)),
UpdatedAt: aws.String(tf),
Types: []*string{aws.String(TYPE)},
Severity: &securityhub.Severity{
Label: aws.String(securityhub.SeverityLabelHigh),
},
Remediation: &securityhub.Remediation{
Recommendation: &securityhub.Recommendation{
Text: aws.String(remediation),
},
},
ProductFields: map[string]*string{
"Reason": aws.String(reason),
"Actual result": aws.String(actualValue),
"Expected result": aws.String(check.ExpectedResult),
"Section": aws.String(fmt.Sprintf("%s %s", controls.ID, controls.Text)),
"Subsection": aws.String(fmt.Sprintf("%s %s", g.ID, g.Text)),
},
Resources: []*securityhub.Resource{
{
Id: aws.String(c),
Type: aws.String(TYPE),
},
},
}
fs = append(fs, &f)
}
}
}
return fs, nil
}
func getConfig(name string) (string, error) {
r := viper.GetString(name)
if len(r) == 0 {
return "", fmt.Errorf("%s not set", name)
}
return r, nil
}
func summarize(controls *Controls, state State) {
switch state {
case PASS:

View File

@@ -18,12 +18,17 @@ import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/securityhub"
"github.com/onsi/ginkgo/reporters"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"gopkg.in/yaml.v2"
@@ -69,7 +74,6 @@ func TestYamlFiles(t *testing.T) {
}
func TestNewControls(t *testing.T) {
t.Run("Should return error when node type is not specified", func(t *testing.T) {
// given
in := []byte(`
@@ -79,7 +83,7 @@ type: # not specified
groups:
`)
// when
_, err := NewControls(MASTER, in)
_, err := NewControls(MASTER, in, "")
// then
assert.EqualError(t, err, "non-master controls file specified")
})
@@ -88,15 +92,82 @@ groups:
// given
in := []byte("BOOM")
// when
_, err := NewControls(MASTER, in)
_, err := NewControls(MASTER, in, "")
// then
assert.EqualError(t, err, "failed to unmarshal YAML: yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `BOOM` into check.Controls")
})
}
func TestControls_RunChecks(t *testing.T) {
func TestControls_RunChecks_SkippedCmd(t *testing.T) {
t.Run("Should skip checks and groups specified by skipMap", func(t *testing.T) {
// given
normalRunner := &defaultRunner{}
// and
in := []byte(`
---
type: "master"
groups:
- id: G1
checks:
- id: G1/C1
- id: G1/C2
- id: G1/C3
- id: G2
checks:
- id: G2/C1
- id: G2/C2
`)
controls, err := NewControls(MASTER, in, "")
assert.NoError(t, err)
var allChecks Predicate = func(group *Group, c *Check) bool {
return true
}
skipMap := make(map[string]bool, 0)
skipMap["G1"] = true
skipMap["G2/C1"] = true
skipMap["G2/C2"] = true
controls.RunChecks(normalRunner, allChecks, skipMap)
G1 := controls.Groups[0]
assertEqualGroupSummary(t, 0, 0, 3, 0, G1)
G2 := controls.Groups[1]
assertEqualGroupSummary(t, 0, 0, 2, 0, G2)
})
}
func TestControls_RunChecks_Skipped(t *testing.T) {
t.Run("Should skip checks where the parent group is marked as skip", func(t *testing.T) {
// given
normalRunner := &defaultRunner{}
// and
in := []byte(`
---
type: "master"
groups:
- id: G1
type: skip
checks:
- id: G1/C1
`)
controls, err := NewControls(MASTER, in, "")
assert.NoError(t, err)
var allChecks Predicate = func(group *Group, c *Check) bool {
return true
}
emptySkipList := make(map[string]bool, 0)
controls.RunChecks(normalRunner, allChecks, emptySkipList)
G1 := controls.Groups[0]
assertEqualGroupSummary(t, 0, 0, 1, 0, G1)
})
}
func TestControls_RunChecks(t *testing.T) {
t.Run("Should run checks matching the filter and update summaries", func(t *testing.T) {
// given
runner := new(mockRunner)
@@ -125,7 +196,7 @@ groups:
scored: true
`)
// and
controls, err := NewControls(MASTER, in)
controls, err := NewControls(MASTER, in, "")
assert.NoError(t, err)
// and
runner.On("Run", controls.Groups[0].Checks[0]).Return(PASS)
@@ -134,8 +205,9 @@ groups:
var runAll Predicate = func(group *Group, c *Check) bool {
return true
}
var emptySkipList = make(map[string]bool, 0)
// when
controls.RunChecks(runner, runAll)
controls.RunChecks(runner, runAll, emptySkipList)
// then
assert.Equal(t, 2, len(controls.Groups))
// and
@@ -184,7 +256,7 @@ func TestControls_JUnitIncludesJSON(t *testing.T) {
},
expect: []byte(`<testsuite name="" tests="0" failures="0" errors="0" time="0">
<testcase name="check1id check1text" classname="" time="0">
<system-out>{&#34;test_number&#34;:&#34;check1id&#34;,&#34;test_desc&#34;:&#34;check1text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;PASS&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
<system-out>{&#34;test_number&#34;:&#34;check1id&#34;,&#34;test_desc&#34;:&#34;check1text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditEnv&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;PASS&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
</testcase>
</testsuite>`),
}, {
@@ -207,7 +279,7 @@ func TestControls_JUnitIncludesJSON(t *testing.T) {
},
expect: []byte(`<testsuite name="" tests="402" failures="99" errors="0" time="0">
<testcase name="check1id check1text" classname="" time="0">
<system-out>{&#34;test_number&#34;:&#34;check1id&#34;,&#34;test_desc&#34;:&#34;check1text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;PASS&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
<system-out>{&#34;test_number&#34;:&#34;check1id&#34;,&#34;test_desc&#34;:&#34;check1text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditEnv&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;PASS&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
</testcase>
</testsuite>`),
}, {
@@ -227,19 +299,19 @@ func TestControls_JUnitIncludesJSON(t *testing.T) {
},
expect: []byte(`<testsuite name="" tests="0" failures="0" errors="0" time="0">
<testcase name="check1id check1text" classname="" time="0">
<system-out>{&#34;test_number&#34;:&#34;check1id&#34;,&#34;test_desc&#34;:&#34;check1text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;PASS&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
<system-out>{&#34;test_number&#34;:&#34;check1id&#34;,&#34;test_desc&#34;:&#34;check1text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditEnv&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;PASS&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
</testcase>
<testcase name="check2id check2text" classname="" time="0">
<skipped></skipped>
<system-out>{&#34;test_number&#34;:&#34;check2id&#34;,&#34;test_desc&#34;:&#34;check2text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;INFO&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
<system-out>{&#34;test_number&#34;:&#34;check2id&#34;,&#34;test_desc&#34;:&#34;check2text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditEnv&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;INFO&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
</testcase>
<testcase name="check3id check3text" classname="" time="0">
<skipped></skipped>
<system-out>{&#34;test_number&#34;:&#34;check3id&#34;,&#34;test_desc&#34;:&#34;check3text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;WARN&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
<system-out>{&#34;test_number&#34;:&#34;check3id&#34;,&#34;test_desc&#34;:&#34;check3text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditEnv&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;WARN&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
</testcase>
<testcase name="check4id check4text" classname="" time="0">
<failure type=""></failure>
<system-out>{&#34;test_number&#34;:&#34;check4id&#34;,&#34;test_desc&#34;:&#34;check4text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;FAIL&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
<system-out>{&#34;test_number&#34;:&#34;check4id&#34;,&#34;test_desc&#34;:&#34;check4text&#34;,&#34;audit&#34;:&#34;&#34;,&#34;AuditEnv&#34;:&#34;&#34;,&#34;AuditConfig&#34;:&#34;&#34;,&#34;type&#34;:&#34;&#34;,&#34;remediation&#34;:&#34;&#34;,&#34;test_info&#34;:null,&#34;status&#34;:&#34;FAIL&#34;,&#34;actual_value&#34;:&#34;&#34;,&#34;scored&#34;:false,&#34;IsMultiple&#34;:false,&#34;expected_result&#34;:&#34;&#34;}</system-out>
</testcase>
</testsuite>`),
},
@@ -290,3 +362,104 @@ func assertEqualGroupSummary(t *testing.T, pass, fail, info, warn int, actual *G
assert.Equal(t, info, actual.Info)
assert.Equal(t, warn, actual.Warn)
}
func TestControls_ASFF(t *testing.T) {
type fields struct {
ID string
Version string
Text string
Groups []*Group
Summary Summary
}
tests := []struct {
name string
fields fields
want []*securityhub.AwsSecurityFinding
wantErr bool
}{
{
name: "Test simple conversion",
fields: fields{
ID: "test1",
Version: "1",
Text: "test runnner",
Summary: Summary{
Fail: 99,
Pass: 100,
Warn: 101,
Info: 102,
},
Groups: []*Group{
{
ID: "g1",
Text: "Group text",
Checks: []*Check{
{ID: "check1id",
Text: "check1text",
State: FAIL,
Remediation: "fix me",
Reason: "failed",
ExpectedResult: "failed",
ActualValue: "failed",
},
},
},
}},
want: []*securityhub.AwsSecurityFinding{
{
AwsAccountId: aws.String("foo account"),
Confidence: aws.Int64(100),
GeneratorId: aws.String(fmt.Sprintf("%s/cis-kubernetes-benchmark/%s/%s", fmt.Sprintf(ARN, "somewhere"), "1", "check1id")),
Description: aws.String("check1text"),
ProductArn: aws.String(fmt.Sprintf(ARN, "somewhere")),
SchemaVersion: aws.String(SCHEMA),
Title: aws.String(fmt.Sprintf("%s %s", "check1id", "check1text")),
Types: []*string{aws.String(TYPE)},
Severity: &securityhub.Severity{
Label: aws.String(securityhub.SeverityLabelHigh),
},
Remediation: &securityhub.Remediation{
Recommendation: &securityhub.Recommendation{
Text: aws.String("fix me"),
},
},
ProductFields: map[string]*string{
"Reason": aws.String("failed"),
"Actual result": aws.String("failed"),
"Expected result": aws.String("failed"),
"Section": aws.String(fmt.Sprintf("%s %s", "test1", "test runnner")),
"Subsection": aws.String(fmt.Sprintf("%s %s", "g1", "Group text")),
},
Resources: []*securityhub.Resource{
{
Id: aws.String("foo Cluster"),
Type: aws.String(TYPE),
},
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
viper.Set("AWS_ACCOUNT", "foo account")
viper.Set("CLUSTER_ARN", "foo Cluster")
viper.Set("AWS_REGION", "somewhere")
controls := &Controls{
ID: tt.fields.ID,
Version: tt.fields.Version,
Text: tt.fields.Text,
Groups: tt.fields.Groups,
Summary: tt.fields.Summary,
}
got, _ := controls.ASFF()
tt.want[0].CreatedAt = got[0].CreatedAt
tt.want[0].UpdatedAt = got[0].UpdatedAt
tt.want[0].Id = got[0].Id
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Controls.ASFF() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -1,14 +1,15 @@
---
controls:
id: 1
text: "Master Checks"
text: "Test Checks"
type: "master"
groups:
- id: 1.1
text: "Kube-apiserver"
text: "First Group"
checks:
- id: 0
text: "flag is set"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--allow-privileged"
@@ -16,6 +17,7 @@ groups:
- id: 1
text: "flag is not set"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--basic-auth"
@@ -23,6 +25,7 @@ groups:
- id: 2
text: "flag value is set to some value"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--insecure-port"
@@ -33,6 +36,7 @@ groups:
- id: 3
text: "flag value is greater than or equal some number"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--audit-log-maxage"
@@ -43,6 +47,7 @@ groups:
- id: 4
text: "flag value is less than some number"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--max-backlog"
@@ -53,6 +58,7 @@ groups:
- id: 5
text: "flag value does not have some value"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--admission-control"
@@ -63,6 +69,7 @@ groups:
- id: 6
text: "test AND binary operation"
audit: "echo \"Non empty command\""
tests:
bin_op: and
test_items:
@@ -73,6 +80,7 @@ groups:
- id: 7
text: "test OR binary operation"
audit: "echo \"Non empty command\""
tests:
bin_op: or
test_items:
@@ -87,38 +95,29 @@ groups:
- id: 8
text: "test flag with arbitrary text"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "644"
- flag: "permissions"
compare:
op: eq
value: "644"
value: "SomeValue"
set: true
- id: 9
text: "test permissions"
audit: "/bin/sh -c 'if test -e $config; then stat -c %a $config; fi'"
audit: "/bin/sh -c 'if test -e $config; then stat -c permissions=%a $config; fi'"
tests:
bin_op: or
test_items:
- flag: "644"
- flag: "permissions"
compare:
op: eq
op: bitmask
value: "644"
set: true
- flag: "640"
compare:
op: eq
value: "640"
set: true
- flag: "600"
compare:
op: eq
value: "600"
set: true
- id: 10
text: "flag value includes some value in a comma-separated list, value is last in list"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--admission-control"
@@ -129,6 +128,7 @@ groups:
- id: 11
text: "flag value includes some value in a comma-separated list, value is first in list"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--admission-control"
@@ -139,6 +139,7 @@ groups:
- id: 12
text: "flag value includes some value in a comma-separated list, value middle of list"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--admission-control"
@@ -149,6 +150,7 @@ groups:
- id: 13
text: "flag value includes some value in a comma-separated list, value only one in list"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--admission-control"
@@ -159,6 +161,7 @@ groups:
- id: 14
text: "check that flag some-arg is set to some-val with ':' separator"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "some-arg"
@@ -169,7 +172,10 @@ groups:
- id: 15
text: "jsonpath correct value on field"
audit: "echo \"Non empty command\""
audit_config: "echo \"Non empty command\""
tests:
bin_op: or
test_items:
- path: "{.readOnlyPort}"
compare:
@@ -189,6 +195,8 @@ groups:
- id: 16
text: "jsonpath correct case-sensitive value on string field"
audit: "echo \"Non empty command\""
audit_config: "echo \"Non empty command\""
tests:
test_items:
- path: "{.stringValue}"
@@ -209,6 +217,8 @@ groups:
- id: 17
text: "jsonpath correct value on boolean field"
audit: "echo \"Non empty command\""
audit_config: "echo \"Non empty command\""
tests:
test_items:
- path: "{.trueValue}"
@@ -229,6 +239,8 @@ groups:
- id: 18
text: "jsonpath field absent"
audit: "echo \"Non empty command\""
audit_config: "echo \"Non empty command\""
tests:
test_items:
- path: "{.notARealField}"
@@ -236,6 +248,8 @@ groups:
- id: 19
text: "jsonpath correct value on nested field"
audit: "echo \"Non empty command\""
audit_config: "echo \"Non empty command\""
tests:
test_items:
- path: "{.authentication.anonymous.enabled}"
@@ -246,6 +260,8 @@ groups:
- id: 20
text: "yamlpath correct value on field"
audit: "echo \"Non empty command\""
audit_config: "echo \"Non empty command\""
tests:
test_items:
- path: "{.readOnlyPort}"
@@ -256,6 +272,8 @@ groups:
- id: 21
text: "yamlpath field absent"
audit: "echo \"Non empty command\""
audit_config: "echo \"Non empty command\""
tests:
test_items:
- path: "{.fieldThatIsUnset}"
@@ -263,6 +281,8 @@ groups:
- id: 22
text: "yamlpath correct value on nested field"
audit: "echo \"Non empty command\""
audit_config: "echo \"Non empty command\""
tests:
test_items:
- path: "{.authentication.anonymous.enabled}"
@@ -273,6 +293,8 @@ groups:
- id: 23
text: "path on invalid json"
audit: "echo \"Non empty command\""
audit_config: "echo \"Non empty command\""
tests:
test_items:
- path: "{.authentication.anonymous.enabled}"
@@ -283,13 +305,16 @@ groups:
- id: 24
text: "path with broken expression"
audit: "echo \"Non empty command\""
audit_config: "echo \"Non empty command\""
tests:
test_items:
- path: "{.missingClosingBrace"
- path: "{.missingClosingBrace}"
set: true
- id: 25
text: "yamlpath on invalid yaml"
audit: "echo \"Non empty command\""
tests:
test_items:
- path: "{.authentication.anonymous.enabled}"
@@ -300,6 +325,8 @@ groups:
- id: 26
text: "check regex op matches"
audit: "echo \"Non empty command\""
audit_config: "echo \"Non empty command\""
tests:
test_items:
- path: "{.currentMasterVersion}"
@@ -310,6 +337,7 @@ groups:
- id: 27
text: "check boolean flag with no value"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--peer-client-cert-auth"
@@ -320,6 +348,7 @@ groups:
- id: 28
text: "check boolean flag with false value"
audit: "echo \"Non empty command\""
tests:
test_items:
- flag: "--peer-client-cert-auth"
@@ -327,6 +356,53 @@ groups:
op: eq
value: false
set: true
- id: 29
text: "flag is set (via env)"
tests:
test_items:
- flag: "--allow-privileged"
env: "ALLOW_PRIVILEGED"
set: true
- id: 30
text: "flag is not set (via env)"
tests:
test_items:
- flag: "--basic-auth"
env: "BASIC_AUTH"
set: false
- id: 31
text: "flag value is set to some value (via env)"
tests:
test_items:
- flag: "--insecure-port"
env: "INSECURE_PORT"
compare:
op: eq
value: 0
set: true
- id: 32
text: "flag value is greater than or equal some number (via env)"
tests:
test_items:
- flag: "--audit-log-maxage"
env: "AUDIT_LOG_MAXAGE"
compare:
op: gte
value: 30
set: true
- id: 33
text: "flag value is less than some number (via env)"
tests:
test_items:
- env: "MAX_BACKLOG"
compare:
op: lt
value: 30
set: true
- id: 2.1
text: "audit and audit_config commands"
@@ -540,7 +616,7 @@ groups:
path: '{.readOnlyPort}'
set: false
scored: true
- id: 15
- id: 16
text: "parameter and config file don't have same default - parameter has bad value and config is not present - failing"
audit: "echo '--read-only-port=1'"
audit_config: "echo ''"
@@ -557,3 +633,104 @@ groups:
path: '{.readOnlyPort}'
set: false
scored: true
- id: 3.1
text: "audit_env commands"
checks:
- id: 0
text: "audit fails to find flag, audit_env finds flag -> pass"
audit: "echo in=incorrect"
audit_env: "echo flag=correct"
tests:
test_items:
- flag: "flag"
env: "flag"
compare:
op: eq
value: "correct"
set: true
scored: true
- id: 1
text: "audit fails to find flag, audit_env finds flag and fails -> fail"
audit: "echo in=wrong"
audit_env: "echo flag=wrong"
tests:
test_items:
- flag: "flag"
env: "flag"
compare:
op: eq
value: "correct"
set: true
scored: true
- id: 2
text: "audit finds correct flag, audit_env is incorrect -> pass"
audit: "echo flag=correct"
audit_env: "echo flag=incorrect"
tests:
test_items:
- flag: "flag"
env: "flag"
compare:
op: eq
value: "correct"
set: true
scored: true
- id: 3
text: "audit doesn't flag flag, audit_config finds it and passes, audit_env is not present -> pass"
audit: "echo in=correct"
audit_config: "echo 'flag: correct'"
tests:
test_items:
- flag: "flag"
path: "{.flag}"
compare:
op: eq
value: "correct"
set: true
scored: true
- id: 4
text: "audit doesn't flag flag, audit_config doesn't find flag, audit_env finds and passes -> pass"
audit: "echo in=correct"
audit_config: "echo 'in: correct'"
audit_env: "echo flag=correct"
tests:
test_items:
- flag: "flag"
path: "{.flag}"
env: "flag"
compare:
op: eq
value: "correct"
set: true
scored: true
- id: 5
text: "audit doesn't find flag, audit_config doesn't find flag, audit_env finds and fails -> fails"
audit: "echo in=correct"
audit_config: "echo 'in: correct'"
audit_env: "echo flag=incorrect"
tests:
test_items:
- flag: "flag"
path: "{.flag}"
env: "flag"
compare:
op: eq
value: "correct"
set: true
scored: true
- id: 6
text: "audit finds flag and fails, audit_config finds flag and fails, audit_env finds and passes -> fails"
audit: "echo flag=incorrect"
audit_config: "echo 'flag: incorrect'"
audit_env: "echo flag=correct"
tests:
test_items:
- flag: "flag"
path: "{.flag}"
env: "flag"
compare:
op: eq
value: "correct"
set: true
scored: true

View File

@@ -48,17 +48,27 @@ type tests struct {
BinOp binOp `yaml:"bin_op"`
}
type AuditUsed string
const (
AuditCommand AuditUsed = "auditCommand"
AuditConfig AuditUsed = "auditConfig"
AuditEnv AuditUsed = "auditEnv"
)
type testItem struct {
Flag string
Env string
Path string
Output string
Value string
Set bool
Compare compare
isMultipleOutput bool
isConfigSetting bool
auditUsed AuditUsed
}
type envTestItem testItem
type pathTestItem testItem
type flagTestItem testItem
@@ -78,16 +88,25 @@ func failTestItem(s string) *testOutput {
return &testOutput{testResult: false, actualResult: s}
}
func (t testItem) flagValue() string {
if t.isConfigSetting {
func (t testItem) value() string {
if t.auditUsed == AuditConfig {
return t.Path
}
if t.auditUsed == AuditEnv {
return t.Env
}
return t.Flag
}
func (t testItem) findValue(s string) (match bool, value string, err error) {
if t.isConfigSetting {
if t.auditUsed == AuditEnv {
et := envTestItem(t)
return et.findValue(s)
}
if t.auditUsed == AuditConfig {
pt := pathTestItem(t)
return pt.findValue(s)
}
@@ -107,6 +126,9 @@ func (t flagTestItem) findValue(s string) (match bool, value string, err error)
// flag: somevalue
// --flag
// somevalue
// DOESN'T COVER - use pathTestItem implementation of findValue() for this
// flag:
// - wehbook
pttn := `(` + t.Flag + `)(=|: *)*([^\s]*) *`
flagRe := regexp.MustCompile(pttn)
vals := flagRe.FindStringSubmatch(s)
@@ -126,7 +148,7 @@ func (t flagTestItem) findValue(s string) (match bool, value string, err error)
err = fmt.Errorf("invalid flag in testItem definition: %s", s)
}
}
glog.V(3).Infof("In flagTestItem.findValue %s, match %v, s %s, t.Flag %s", value, match, s, t.Flag)
glog.V(3).Infof("In flagTestItem.findValue %s", value)
return match, value, err
}
@@ -145,10 +167,29 @@ func (t pathTestItem) findValue(s string) (match bool, value string, err error)
}
glog.V(3).Infof("In pathTestItem.findValue %s", value)
match = (value != "")
match = value != ""
return match, value, err
}
func (t envTestItem) findValue(s string) (match bool, value string, err error) {
if s != "" && t.Env != "" {
r, _ := regexp.Compile(fmt.Sprintf("%s=.*(?:$|\\n)", t.Env))
out := r.FindString(s)
out = strings.Replace(out, "\n", "", 1)
out = strings.Replace(out, fmt.Sprintf("%s=", t.Env), "", 1)
if len(out) > 0 {
match = true
value = out
} else {
match = false
value = ""
}
}
glog.V(3).Infof("In envTestItem.findValue %s", value)
return match, value, nil
}
func (t testItem) execute(s string) *testOutput {
result := &testOutput{}
s = strings.TrimRight(s, " \n")
@@ -184,23 +225,36 @@ func (t testItem) evaluate(s string) *testOutput {
if t.Set {
if match && t.Compare.Op != "" {
result.ExpectedResult, result.testResult = compareOp(t.Compare.Op, value, t.Compare.Value)
result.ExpectedResult, result.testResult = compareOp(t.Compare.Op, value, t.Compare.Value, t.value())
} else {
result.ExpectedResult = fmt.Sprintf("'%s' is present", t.flagValue())
result.ExpectedResult = fmt.Sprintf("'%s' is present", t.value())
result.testResult = match
}
} else {
result.ExpectedResult = fmt.Sprintf("'%s' is not present", t.flagValue())
result.ExpectedResult = fmt.Sprintf("'%s' is not present", t.value())
result.testResult = !match
}
result.flagFound = match
glog.V(3).Info(fmt.Sprintf("flagFound %v", result.flagFound))
var isExist = "exists"
if !result.flagFound {
isExist = "does not exist"
}
switch t.auditUsed {
case "auditCommand":
glog.V(3).Infof("Flag '%s' %s", t.Flag, isExist)
case "auditConfig":
glog.V(3).Infof("Path '%s' %s", t.Path, isExist)
case "auditEnv":
glog.V(3).Infof("Env '%s' %s", t.Env, isExist)
default:
glog.V(3).Infof("Error with identify audit used %s", t.auditUsed)
}
return result
}
func compareOp(tCompareOp string, flagVal string, tCompareValue string) (string, bool) {
func compareOp(tCompareOp string, flagVal string, tCompareValue string, flagName string) (string, bool) {
expectedResultPattern := ""
testResult := false
@@ -229,24 +283,25 @@ func compareOp(tCompareOp string, flagVal string, tCompareValue string) (string,
case "gt", "gte", "lt", "lte":
a, b, err := toNumeric(flagVal, tCompareValue)
if err != nil {
expectedResultPattern = "Invalid Number(s) used for comparison: '%s' '%s'"
glog.V(1).Infof(fmt.Sprintf("Not numeric value - flag: %q - compareValue: %q %v\n", flagVal, tCompareValue, err))
return "Invalid Number(s) used for comparison", false
return fmt.Sprintf(expectedResultPattern, flagVal, tCompareValue), false
}
switch tCompareOp {
case "gt":
expectedResultPattern = "%s is greater than %s"
expectedResultPattern = "'%s' is greater than %s"
testResult = a > b
case "gte":
expectedResultPattern = "%s is greater or equal to %s"
expectedResultPattern = "'%s' is greater or equal to %s"
testResult = a >= b
case "lt":
expectedResultPattern = "%s is lower than %s"
expectedResultPattern = "'%s' is lower than %s"
testResult = a < b
case "lte":
expectedResultPattern = "%s is lower or equal to %s"
expectedResultPattern = "'%s' is lower or equal to %s"
testResult = a <= b
}
@@ -255,11 +310,11 @@ func compareOp(tCompareOp string, flagVal string, tCompareValue string) (string,
testResult = strings.Contains(flagVal, tCompareValue)
case "nothave":
expectedResultPattern = " '%s' not have '%s'"
expectedResultPattern = "'%s' does not have '%s'"
testResult = !strings.Contains(flagVal, tCompareValue)
case "regex":
expectedResultPattern = " '%s' matched by '%s'"
expectedResultPattern = "'%s' matched by regex expression '%s'"
opRe := regexp.MustCompile(tCompareValue)
testResult = opRe.MatchString(flagVal)
@@ -270,7 +325,7 @@ func compareOp(tCompareOp string, flagVal string, tCompareValue string) (string,
testResult = allElementsValid(s, target)
case "bitmask":
expectedResultPattern = "bitmask '%s' AND '%s'"
expectedResultPattern = "%s has permissions " + flagVal + ", expected %s or more restrictive"
requested, err := strconv.ParseInt(flagVal, 8, 64)
if err != nil {
glog.V(1).Infof(fmt.Sprintf("Not numeric value - flag: %q - compareValue: %q %v\n", flagVal, tCompareValue, err))
@@ -287,7 +342,7 @@ func compareOp(tCompareOp string, flagVal string, tCompareValue string) (string,
return expectedResultPattern, testResult
}
return fmt.Sprintf(expectedResultPattern, flagVal, tCompareValue), testResult
return fmt.Sprintf(expectedResultPattern, flagName, tCompareValue), testResult
}
func unmarshal(s string, jsonInterface *interface{}) error {

File diff suppressed because it is too large Load Diff

View File

@@ -32,7 +32,6 @@ import (
// NewRunFilter constructs a Predicate based on FilterOpts which determines whether tested Checks should be run or not.
func NewRunFilter(opts FilterOpts) (check.Predicate, error) {
if opts.CheckList != "" && opts.GroupList != "" {
return nil, fmt.Errorf("group option and check option can't be used together")
}
@@ -65,7 +64,7 @@ func NewRunFilter(opts FilterOpts) (check.Predicate, error) {
}, nil
}
func runChecks(nodetype check.NodeType, testYamlFile string) {
func runChecks(nodetype check.NodeType, testYamlFile, detectedVersion string) {
// Verify config file was loaded into Viper during Cobra sub-command initialization.
if configFileError != nil {
colorPrint(check.FAIL, fmt.Sprintf("Failed to read config file: %v\n", configFileError))
@@ -101,13 +100,13 @@ func runChecks(nodetype check.NodeType, testYamlFile string) {
// 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, "svc", svcmap)
s = makeSubstitutions(s, "kubeconfig", kubeconfmap)
s = makeSubstitutions(s, "cafile", cafilemap)
s, binSubs := makeSubstitutions(s, "bin", binmap)
s, _ = makeSubstitutions(s, "conf", confmap)
s, _ = makeSubstitutions(s, "svc", svcmap)
s, _ = makeSubstitutions(s, "kubeconfig", kubeconfmap)
s, _ = makeSubstitutions(s, "cafile", cafilemap)
controls, err := check.NewControls(nodetype, []byte(s))
controls, err := check.NewControls(nodetype, []byte(s), detectedVersion)
if err != nil {
exitWithError(fmt.Errorf("error setting up %s controls: %v", nodetype, err))
}
@@ -118,10 +117,46 @@ func runChecks(nodetype check.NodeType, testYamlFile string) {
exitWithError(fmt.Errorf("error setting up run filter: %v", err))
}
controls.RunChecks(runner, filter)
generateDefaultEnvAudit(controls, binSubs)
controls.RunChecks(runner, filter, parseSkipIds(skipIds))
controlsCollection = append(controlsCollection, controls)
}
func generateDefaultEnvAudit(controls *check.Controls, binSubs []string) {
for _, group := range controls.Groups {
for _, checkItem := range group.Checks {
if checkItem.Tests != nil && !checkItem.DisableEnvTesting {
for _, test := range checkItem.Tests.TestItems {
if test.Env != "" && checkItem.AuditEnv == "" {
binPath := ""
if len(binSubs) == 1 {
binPath = binSubs[0]
} else {
fmt.Printf("AuditEnv not explicit for check (%s), where bin path cannot be determined\n", checkItem.ID)
}
if test.Env != "" && checkItem.AuditEnv == "" {
checkItem.AuditEnv = fmt.Sprintf("cat \"/proc/$(/bin/ps -C %s -o pid= | tr -d ' ')/environ\" | tr '\\0' '\\n'", binPath)
}
}
}
}
}
}
}
func parseSkipIds(skipIds string) map[string]bool {
var skipIdMap = make(map[string]bool, 0)
if skipIds != "" {
for _, id := range strings.Split(skipIds, ",") {
skipIdMap[strings.Trim(id, " ")] = true
}
}
return skipIdMap
}
// colorPrint outputs the state in a specific colour, along with a message string
func colorPrint(state check.State, s string) {
colors[state].Printf("[%s] ", state)
@@ -150,7 +185,7 @@ func prettyPrint(r *check.Controls, summary check.Summary) {
// Print remediations.
if !noRemediations {
if summary.Fail > 0 || summary.Warn > 0 {
colors[check.WARN].Printf("== Remediations ==\n")
colors[check.WARN].Printf("== Remediations %s ==\n", r.Type)
for _, g := range r.Groups {
for _, c := range g.Checks {
if c.State == check.FAIL {
@@ -172,22 +207,26 @@ func prettyPrint(r *check.Controls, summary check.Summary) {
// 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%d checks INFO\n",
summary.Pass, summary.Fail, summary.Warn, summary.Info,
)
printSummary(summary, string(r.Type))
}
}
func printSummary(summary check.Summary, sectionName string) {
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 %s ==\n", sectionName)
fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n%d checks INFO\n\n",
summary.Pass, summary.Fail, summary.Warn, summary.Info,
)
}
// loadConfig finds the correct config dir based on the kubernetes version,
// merges any specific config.yaml file found with the main config
// and returns the benchmark file to use.
@@ -274,17 +313,26 @@ func loadTargetMapping(v *viper.Viper) (map[string][]string, error) {
return benchmarkVersionToTargetsMap, nil
}
func getBenchmarkVersion(kubeVersion, benchmarkVersion string, v *viper.Viper) (bv string, err error) {
func getBenchmarkVersion(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper) (bv string, err error) {
detecetedKubeVersion = "none"
if !isEmpty(kubeVersion) && !isEmpty(benchmarkVersion) {
return "", fmt.Errorf("It is an error to specify both --version and --benchmark flags")
}
if isEmpty(benchmarkVersion) && isEmpty(kubeVersion) && !isEmpty(platformName) {
benchmarkVersion = getPlatformBenchmarkVersion(platformName)
if !isEmpty(benchmarkVersion) {
detecetedKubeVersion = benchmarkVersion
}
}
if isEmpty(benchmarkVersion) {
if isEmpty(kubeVersion) {
kubeVersion, err = getKubeVersion()
kv, err := getKubeVersion()
if err != nil {
return "", fmt.Errorf("Version check failed: %s\nAlternatively, you can specify the version with --version", err)
}
kubeVersion = kv.BaseVersion()
detecetedKubeVersion = kubeVersion
}
kubeToBenchmarkMap, err := loadVersionMapping(v)
@@ -336,6 +384,16 @@ func isThisNodeRunning(nodeType check.NodeType) bool {
return true
}
func exitCodeSelection(controlsCollection []*check.Controls) int {
for _, control := range controlsCollection {
if control.Fail > 0 {
return exitCode
}
}
return 0
}
func writeOutput(controlsCollection []*check.Controls) {
sort.Slice(controlsCollection, func(i, j int) bool {
iid, _ := strconv.Atoi(controlsCollection[i].ID)
@@ -354,11 +412,24 @@ func writeOutput(controlsCollection []*check.Controls) {
writePgsqlOutput(controlsCollection)
return
}
if aSFF {
writeASFFOutput(controlsCollection)
return
}
writeStdoutOutput(controlsCollection)
}
func writeJSONOutput(controlsCollection []*check.Controls) {
out, err := json.Marshal(controlsCollection)
var out []byte
var err error
if !noTotals {
var totals check.OverallControls
totals.Controls = controlsCollection
totals.Totals = getSummaryTotals(controlsCollection)
out, err = json.Marshal(totals)
} else {
out, err = json.Marshal(controlsCollection)
}
if err != nil {
exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
}
@@ -366,13 +437,19 @@ func writeJSONOutput(controlsCollection []*check.Controls) {
}
func writeJunitOutput(controlsCollection []*check.Controls) {
// QuickFix for issue https://github.com/aquasecurity/kube-bench/issues/883
// Should consider to deprecate of switch to using Junit template
prefix := "<testsuites>\n"
suffix := "\n</testsuites>"
var outputAllControls []byte
for _, controls := range controlsCollection {
out, err := controls.JUnit()
tempOut, err := controls.JUnit()
outputAllControls = append(outputAllControls[:], tempOut[:]...)
if err != nil {
exitWithError(fmt.Errorf("failed to output in JUnit format: %v", err))
}
printOutput(string(out), outputFile)
}
printOutput(prefix+string(outputAllControls)+suffix, outputFile)
}
func writePgsqlOutput(controlsCollection []*check.Controls) {
@@ -385,11 +462,38 @@ func writePgsqlOutput(controlsCollection []*check.Controls) {
}
}
func writeASFFOutput(controlsCollection []*check.Controls) {
for _, controls := range controlsCollection {
out, err := controls.ASFF()
if err != nil {
exitWithError(fmt.Errorf("failed to format findings as ASFF: %v", err))
}
if err := writeFinding(out); err != nil {
exitWithError(fmt.Errorf("failed to output to ASFF: %v", err))
}
}
}
func writeStdoutOutput(controlsCollection []*check.Controls) {
for _, controls := range controlsCollection {
summary := controls.Summary
prettyPrint(controls, summary)
}
if !noTotals {
printSummary(getSummaryTotals(controlsCollection), "total")
}
}
func getSummaryTotals(controlsCollection []*check.Controls) check.Summary {
var totalSummary check.Summary
for _, controls := range controlsCollection {
summary := controls.Summary
totalSummary.Fail = totalSummary.Fail + summary.Fail
totalSummary.Warn = totalSummary.Warn + summary.Warn
totalSummary.Pass = totalSummary.Pass + summary.Pass
totalSummary.Info = totalSummary.Info + summary.Info
}
return totalSummary
}
func printRawOutput(output string) {

View File

@@ -30,6 +30,27 @@ import (
"github.com/stretchr/testify/assert"
)
type JsonOutputFormat struct {
Controls []*check.Controls `json:"Controls"`
TotalSummary map[string]int `json:"Totals"`
}
type JsonOutputFormatNoTotals struct {
Controls []*check.Controls `json:"Controls"`
}
func TestParseSkipIds(t *testing.T) {
skipMap := parseSkipIds("4.12,4.13,5")
_, fourTwelveExists := skipMap["4.12"]
_, fourThirteenExists := skipMap["4.13"]
_, fiveExists := skipMap["5"]
_, other := skipMap["G1"]
assert.True(t, fourThirteenExists)
assert.True(t, fourTwelveExists)
assert.True(t, fiveExists)
assert.False(t, other)
}
func TestNewRunFilter(t *testing.T) {
type TestCase struct {
@@ -174,17 +195,19 @@ func TestIsMaster(t *testing.T) {
defer restore()
for _, tc := range testCases {
cfgFile = tc.cfgFile
initConfig()
func() {
cfgFile = tc.cfgFile
initConfig()
oldGetBinariesFunc := getBinariesFunc
getBinariesFunc = tc.getBinariesFunc
defer func() {
getBinariesFunc = oldGetBinariesFunc
cfgFile = ""
oldGetBinariesFunc := getBinariesFunc
getBinariesFunc = tc.getBinariesFunc
defer func() {
getBinariesFunc = oldGetBinariesFunc
cfgFile = ""
}()
assert.Equal(t, tc.isMaster, isMaster(), tc.name)
}()
assert.Equal(t, tc.isMaster, isMaster(), tc.name)
}
}
@@ -214,7 +237,9 @@ func TestMapToCISVersion(t *testing.T) {
{kubeVersion: "1.16", succeed: true, exp: "cis-1.6"},
{kubeVersion: "1.17", succeed: true, exp: "cis-1.6"},
{kubeVersion: "1.18", succeed: true, exp: "cis-1.6"},
{kubeVersion: "1.19", succeed: true, exp: "cis-1.6"},
{kubeVersion: "1.19", succeed: true, exp: "cis-1.20"},
{kubeVersion: "1.20", succeed: true, exp: "cis-1.20"},
{kubeVersion: "1.21", succeed: true, exp: "cis-1.20"},
{kubeVersion: "gke-1.0", succeed: true, exp: "gke-1.0"},
{kubeVersion: "ocp-3.10", succeed: true, exp: "rh-0.7"},
{kubeVersion: "ocp-3.11", succeed: true, exp: "rh-0.7"},
@@ -299,11 +324,11 @@ func TestGetBenchmarkVersion(t *testing.T) {
t.Fatalf("Unable to load config file %v", err)
}
type getBenchmarkVersionFnToTest func(kubeVersion, benchmarkVersion string, v *viper.Viper) (string, error)
type getBenchmarkVersionFnToTest func(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper) (string, error)
withFakeKubectl := func(kubeVersion, benchmarkVersion string, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) {
withFakeKubectl := func(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) {
execCode := `#!/bin/sh
echo "Server Version: v1.15.10"
echo '{"serverVersion": {"major": "1", "minor": "18", "gitVersion": "v1.18.10"}}'
`
restore, err := fakeExecutableInPath("kubectl", execCode)
if err != nil {
@@ -311,39 +336,40 @@ func TestGetBenchmarkVersion(t *testing.T) {
}
defer restore()
return fn(kubeVersion, benchmarkVersion, v)
return fn(kubeVersion, benchmarkVersion, platformName, v)
}
withNoPath := func(kubeVersion, benchmarkVersion string, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) {
withNoPath := func(kubeVersion, benchmarkVersion, platformName string, v *viper.Viper, fn getBenchmarkVersionFnToTest) (string, error) {
restore, err := prunePath()
if err != nil {
t.Fatal("Failed when calling prunePath ", err)
}
defer restore()
return fn(kubeVersion, benchmarkVersion, v)
return fn(kubeVersion, benchmarkVersion, platformName, v)
}
type getBenchmarkVersionFn func(string, string, *viper.Viper, getBenchmarkVersionFnToTest) (string, error)
type getBenchmarkVersionFn func(string, string, string, *viper.Viper, getBenchmarkVersionFnToTest) (string, error)
cases := []struct {
n string
kubeVersion string
benchmarkVersion string
platformName string
v *viper.Viper
callFn getBenchmarkVersionFn
exp string
succeed bool
}{
{n: "both versions", kubeVersion: "1.11", benchmarkVersion: "cis-1.3", exp: "cis-1.3", callFn: withNoPath, v: viper.New(), succeed: false},
{n: "no version-missing-kubectl", kubeVersion: "", benchmarkVersion: "", v: viperWithData, exp: "", callFn: withNoPath, succeed: false},
{n: "no version-fakeKubectl", kubeVersion: "", benchmarkVersion: "", v: viperWithData, exp: "cis-1.5", callFn: withFakeKubectl, succeed: true},
{n: "kubeVersion", kubeVersion: "1.15", benchmarkVersion: "", v: viperWithData, exp: "cis-1.5", callFn: withNoPath, succeed: true},
{n: "ocpVersion310", kubeVersion: "ocp-3.10", benchmarkVersion: "", v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true},
{n: "ocpVersion311", kubeVersion: "ocp-3.11", benchmarkVersion: "", v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true},
{n: "gke10", kubeVersion: "gke-1.0", benchmarkVersion: "", v: viperWithData, exp: "gke-1.0", callFn: withNoPath, succeed: true},
{n: "both versions", kubeVersion: "1.11", benchmarkVersion: "cis-1.3", platformName: "", exp: "cis-1.3", callFn: withNoPath, v: viper.New(), succeed: false},
{n: "no version-missing-kubectl", kubeVersion: "", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "cis-1.6", callFn: withNoPath, succeed: true},
{n: "no version-fakeKubectl", kubeVersion: "", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "cis-1.6", callFn: withFakeKubectl, succeed: true},
{n: "kubeVersion", kubeVersion: "1.15", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "cis-1.5", callFn: withNoPath, succeed: true},
{n: "ocpVersion310", kubeVersion: "ocp-3.10", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true},
{n: "ocpVersion311", kubeVersion: "ocp-3.11", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "rh-0.7", callFn: withNoPath, succeed: true},
{n: "gke10", kubeVersion: "gke-1.0", benchmarkVersion: "", platformName: "", v: viperWithData, exp: "gke-1.0", callFn: withNoPath, succeed: true},
}
for _, c := range cases {
rv, err := c.callFn(c.kubeVersion, c.benchmarkVersion, c.v, getBenchmarkVersion)
rv, err := c.callFn(c.kubeVersion, c.benchmarkVersion, c.platformName, c.v, getBenchmarkVersion)
if c.succeed {
if err != nil {
t.Errorf("[%q]-Unexpected error: %v", c.n, err)
@@ -405,6 +431,12 @@ func TestValidTargets(t *testing.T) {
targets: []string{"master", "node", "controlplane", "etcd", "policies", "managedservices"},
expected: true,
},
{
name: "aks-1.0 valid",
benchmark: "aks-1.0",
targets: []string{"node", "policies", "controlplane", "managedservices"},
expected: true,
},
{
name: "eks-1.0 valid",
benchmark: "eks-1.0",
@@ -479,17 +511,19 @@ func TestIsEtcd(t *testing.T) {
defer restore()
for _, tc := range testCases {
cfgFile = tc.cfgFile
initConfig()
func() {
cfgFile = tc.cfgFile
initConfig()
oldGetBinariesFunc := getBinariesFunc
getBinariesFunc = tc.getBinariesFunc
defer func() {
getBinariesFunc = oldGetBinariesFunc
cfgFile = ""
oldGetBinariesFunc := getBinariesFunc
getBinariesFunc = tc.getBinariesFunc
defer func() {
getBinariesFunc = oldGetBinariesFunc
cfgFile = ""
}()
assert.Equal(t, tc.isEtcd, isEtcd(), tc.name)
}()
assert.Equal(t, tc.isEtcd, isEtcd(), tc.name)
}
}
@@ -509,13 +543,13 @@ func TestWriteResultToJsonFile(t *testing.T) {
}
writeOutput(controlsCollection)
var expect []*check.Controls
var result []*check.Controls
result, err = parseControlsJsonFile(outputFile)
var expect JsonOutputFormat
var result JsonOutputFormat
result, err = parseResultJsonFile(outputFile)
if err != nil {
t.Error(err)
}
expect, err = parseControlsJsonFile("./testdata/result.json")
expect, err = parseResultJsonFile("./testdata/result.json")
if err != nil {
t.Error(err)
}
@@ -523,6 +557,199 @@ func TestWriteResultToJsonFile(t *testing.T) {
assert.Equal(t, expect, result)
}
func TestWriteResultNoTotalsToJsonFile(t *testing.T) {
defer func() {
controlsCollection = []*check.Controls{}
jsonFmt = false
outputFile = ""
}()
var err error
jsonFmt = true
outputFile = path.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().UnixNano()))
noTotals = true
controlsCollection, err = parseControlsJsonFile("./testdata/controlsCollection.json")
if err != nil {
t.Error(err)
}
writeOutput(controlsCollection)
var expect []*check.Controls
var result []*check.Controls
result, err = parseResultNoTotalsJsonFile(outputFile)
if err != nil {
t.Error(err)
}
expect, err = parseResultNoTotalsJsonFile("./testdata/result_no_totals.json")
if err != nil {
t.Error(err)
}
assert.Equal(t, expect, result)
}
func TestExitCodeSelection(t *testing.T) {
exitCode = 10
controlsCollectionAllPassed, errPassed := parseControlsJsonFile("./testdata/passedControlsCollection.json")
if errPassed != nil {
t.Error(errPassed)
}
controlsCollectionWithFailures, errFailure := parseControlsJsonFile("./testdata/controlsCollection.json")
if errFailure != nil {
t.Error(errFailure)
}
exitCodePassed := exitCodeSelection(controlsCollectionAllPassed)
assert.Equal(t, 0, exitCodePassed)
exitCodeFailure := exitCodeSelection(controlsCollectionWithFailures)
assert.Equal(t, 10, exitCodeFailure)
}
func TestGenerationDefaultEnvAudit(t *testing.T) {
input := []byte(`
---
type: "master"
groups:
- id: G1
checks:
- id: G1/C1
- id: G2
checks:
- id: G2/C1
text: "Verify that the SomeSampleFlag argument is set to true"
audit: "grep -B1 SomeSampleFlag=true /this/is/a/file/path"
tests:
test_items:
- flag: "SomeSampleFlag=true"
env: "SOME_SAMPLE_FLAG"
compare:
op: has
value: "true"
set: true
remediation: |
Edit the config file /this/is/a/file/path and set SomeSampleFlag to true.
scored: true
`)
controls, err := check.NewControls(check.MASTER, input, "")
assert.NoError(t, err)
binSubs := []string{"TestBinPath"}
generateDefaultEnvAudit(controls, binSubs)
expectedAuditEnv := fmt.Sprintf("cat \"/proc/$(/bin/ps -C %s -o pid= | tr -d ' ')/environ\" | tr '\\0' '\\n'", binSubs[0])
assert.Equal(t, expectedAuditEnv, controls.Groups[1].Checks[0].AuditEnv)
}
func TestGetSummaryTotals(t *testing.T) {
controlsCollection, err := parseControlsJsonFile("./testdata/controlsCollection.json")
if err != nil {
t.Error(err)
}
resultTotals := getSummaryTotals(controlsCollection)
assert.Equal(t, 12, resultTotals.Fail)
assert.Equal(t, 14, resultTotals.Warn)
assert.Equal(t, 0, resultTotals.Info)
assert.Equal(t, 49, resultTotals.Pass)
}
func TestPrintSummary(t *testing.T) {
controlsCollection, err := parseControlsJsonFile("./testdata/controlsCollection.json")
if err != nil {
t.Error(err)
}
resultTotals := getSummaryTotals(controlsCollection)
rescueStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
printSummary(resultTotals, "totals")
w.Close()
out, _ := ioutil.ReadAll(r)
os.Stdout = rescueStdout
assert.Contains(t, string(out), "49 checks PASS\n12 checks FAIL\n14 checks WARN\n0 checks INFO\n\n")
}
func TestPrettyPrintNoSummary(t *testing.T) {
controlsCollection, err := parseControlsJsonFile("./testdata/controlsCollection.json")
if err != nil {
t.Error(err)
}
resultTotals := getSummaryTotals(controlsCollection)
rescueStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
noSummary = true
prettyPrint(controlsCollection[0], resultTotals)
w.Close()
out, _ := ioutil.ReadAll(r)
os.Stdout = rescueStdout
assert.NotContains(t, string(out), "49 checks PASS")
}
func TestPrettyPrintSummary(t *testing.T) {
controlsCollection, err := parseControlsJsonFile("./testdata/controlsCollection.json")
if err != nil {
t.Error(err)
}
resultTotals := getSummaryTotals(controlsCollection)
rescueStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
noSummary = false
prettyPrint(controlsCollection[0], resultTotals)
w.Close()
out, _ := ioutil.ReadAll(r)
os.Stdout = rescueStdout
assert.Contains(t, string(out), "49 checks PASS")
}
func TestWriteStdoutOutputNoTotal(t *testing.T) {
controlsCollection, err := parseControlsJsonFile("./testdata/controlsCollection.json")
if err != nil {
t.Error(err)
}
rescueStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
noTotals = true
writeStdoutOutput(controlsCollection)
w.Close()
out, _ := ioutil.ReadAll(r)
os.Stdout = rescueStdout
assert.NotContains(t, string(out), "49 checks PASS")
}
func TestWriteStdoutOutputTotal(t *testing.T) {
controlsCollection, err := parseControlsJsonFile("./testdata/controlsCollection.json")
if err != nil {
t.Error(err)
}
rescueStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
noTotals = false
writeStdoutOutput(controlsCollection)
w.Close()
out, _ := ioutil.ReadAll(r)
os.Stdout = rescueStdout
assert.Contains(t, string(out), "49 checks PASS")
}
func parseControlsJsonFile(filepath string) ([]*check.Controls, error) {
var result []*check.Controls
@@ -538,6 +765,36 @@ func parseControlsJsonFile(filepath string) ([]*check.Controls, error) {
return result, nil
}
func parseResultJsonFile(filepath string) (JsonOutputFormat, error) {
var result JsonOutputFormat
d, err := ioutil.ReadFile(filepath)
if err != nil {
return result, err
}
err = json.Unmarshal(d, &result)
if err != nil {
return result, err
}
return result, nil
}
func parseResultNoTotalsJsonFile(filepath string) ([]*check.Controls, error) {
var result []*check.Controls
d, err := ioutil.ReadFile(filepath)
if err != nil {
return nil, err
}
err = json.Unmarshal(d, &result)
if err != nil {
return nil, err
}
return result, nil
}
func loadConfigForTest() (*viper.Viper, error) {
viperWithData := viper.New()
viperWithData.SetConfigFile("../cfg/config.yaml")

View File

@@ -6,9 +6,9 @@ import (
"time"
"github.com/golang/glog"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres" // database packages get blank imports
"github.com/spf13/viper"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
func savePgsql(jsonInfo string) {
@@ -48,11 +48,10 @@ func savePgsql(jsonInfo string) {
ScanInfo string `gorm:"type:jsonb not null"`
}
db, err := gorm.Open("postgres", connInfo)
db, err := gorm.Open(postgres.Open(connInfo), &gorm.Config{})
if err != nil {
exitWithError(fmt.Errorf("received error connecting to database: %s", err))
}
defer db.Close()
db.Debug().AutoMigrate(&ScanResult{})
db.Save(&ScanResult{ScanHost: hostname, ScanTime: timestamp, ScanInfo: jsonInfo})

View File

@@ -14,31 +14,53 @@ import (
"github.com/golang/glog"
)
func getKubeVersionFromRESTAPI() (string, error) {
type KubeVersion struct {
Major string
Minor string
baseVersion string
GitVersion string
}
func (k *KubeVersion) BaseVersion() string {
if k.baseVersion != "" {
return k.baseVersion
}
// Some provides return the minor version like "15+"
minor := strings.Replace(k.Minor, "+", "", -1)
ver := fmt.Sprintf("%s.%s", k.Major, minor)
k.baseVersion = ver
return ver
}
func getKubeVersionFromRESTAPI() (*KubeVersion, error) {
glog.V(2).Info("Try to get version from Rest API")
k8sVersionURL := getKubernetesURL()
serviceaccount := "/var/run/secrets/kubernetes.io/serviceaccount"
cacertfile := fmt.Sprintf("%s/ca.crt", serviceaccount)
tokenfile := fmt.Sprintf("%s/token", serviceaccount)
tlsCert, err := loadCertficate(cacertfile)
tlsCert, err := loadCertificate(cacertfile)
if err != nil {
return "", err
glog.V(2).Infof("Failed loading certificate Error: %s", err)
return nil, err
}
tb, err := ioutil.ReadFile(tokenfile)
if err != nil {
return "", err
glog.V(2).Infof("Failed reading token file Error: %s", err)
return nil, err
}
token := strings.TrimSpace(string(tb))
data, err := getWebDataWithRetry(k8sVersionURL, token, tlsCert)
if err != nil {
return "", err
glog.V(2).Infof("Failed to get data Error: %s", err)
return nil, err
}
k8sVersion, err := extractVersion(data)
if err != nil {
return "", err
return nil, err
}
return k8sVersion, nil
}
@@ -61,31 +83,32 @@ func getWebDataWithRetry(k8sVersionURL, token string, cacert *tls.Certificate) (
return
}
func extractVersion(data []byte) (string, error) {
type versionResponse struct {
Major string
Minor string
GitVersion string
GitCommit string
GitTreeState string
BuildDate string
GoVersion string
Compiler string
Platform string
}
type VersionResponse struct {
Major string
Minor string
GitVersion string
GitCommit string
GitTreeState string
BuildDate string
GoVersion string
Compiler string
Platform string
}
vrObj := &versionResponse{}
func extractVersion(data []byte) (*KubeVersion, error) {
vrObj := &VersionResponse{}
glog.V(2).Info(fmt.Sprintf("vd: %s\n", string(data)))
err := json.Unmarshal(data, vrObj)
if err != nil {
return "", err
return nil, err
}
glog.V(2).Info(fmt.Sprintf("vrObj: %#v\n", vrObj))
// Some provides return the minor version like "15+"
minor := strings.Replace(vrObj.Minor, "+", "", -1)
ver := fmt.Sprintf("%s.%s", vrObj.Major, minor)
return ver, nil
return &KubeVersion{
Major: vrObj.Major,
Minor: vrObj.Minor,
GitVersion: vrObj.GitVersion,
}, nil
}
func getWebData(srvURL, token string, cacert *tls.Certificate) ([]byte, error) {
@@ -124,7 +147,7 @@ func getWebData(srvURL, token string, cacert *tls.Certificate) ([]byte, error) {
return ioutil.ReadAll(resp.Body)
}
func loadCertficate(certFile string) (*tls.Certificate, error) {
func loadCertificate(certFile string) (*tls.Certificate, error) {
cacert, err := ioutil.ReadFile(certFile)
if err != nil {
return nil, err

View File

@@ -11,8 +11,8 @@ import (
"testing"
)
func TestLoadCertficate(t *testing.T) {
tmp, err := ioutil.TempDir("", "TestFakeLoadCertficate")
func TestLoadCertificate(t *testing.T) {
tmp, err := ioutil.TempDir("", "TestFakeLoadCertificate")
if err != nil {
t.Fatalf("unable to create temp directory: %v", err)
}
@@ -58,7 +58,7 @@ FAjB57z2NcIgJuVpQnGRYtr/JcH2Qdsq8bLtXaojUIWOOqoTDRLYozdMOOQ=
for id, c := range cases {
t.Run(strconv.Itoa(id), func(t *testing.T) {
tlsCert, err := loadCertficate(c.file)
tlsCert, err := loadCertificate(c.file)
if !c.fail {
if err != nil {
t.Errorf("unexpected error: %v", err)
@@ -218,7 +218,7 @@ func TestExtractVersion(t *testing.T) {
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if c.expectedVer != ver {
if c.expectedVer != ver.BaseVersion() {
t.Errorf("Expected %q but Got %q", c.expectedVer, ver)
}
} else {

View File

@@ -28,15 +28,16 @@ var masterCmd = &cobra.Command{
Short: "Run Kubernetes benchmark checks from the master.yaml file.",
Long: `Run Kubernetes benchmark checks from the master.yaml file in cfg/<version>.`,
Run: func(cmd *cobra.Command, args []string) {
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper())
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper())
if err != nil {
exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err))
}
filename := loadConfig(check.MASTER, bv)
runChecks(check.MASTER, filename)
runChecks(check.MASTER, filename, detecetedKubeVersion)
writeOutput(controlsCollection)
},
Deprecated: "this command will be retired soon. Please use the `run` command with `--targets=master` instead.",
}
func init() {

View File

@@ -28,15 +28,16 @@ var nodeCmd = &cobra.Command{
Short: "Run Kubernetes benchmark checks from the node.yaml file.",
Long: `Run Kubernetes benchmark checks from the node.yaml file in cfg/<version>.`,
Run: func(cmd *cobra.Command, args []string) {
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper())
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper())
if err != nil {
exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err))
}
filename := loadConfig(check.NODE, bv)
runChecks(check.NODE, filename)
runChecks(check.NODE, filename, detecetedKubeVersion)
writeOutput(controlsCollection)
},
Deprecated: "this command will be retired soon. Please use the `run` command with `--targets=node` instead.",
}
func init() {

View File

@@ -33,29 +33,34 @@ type FilterOpts struct {
}
var (
envVarsPrefix = "KUBE_BENCH"
defaultKubeVersion = "1.18"
kubeVersion string
benchmarkVersion string
cfgFile string
cfgDir = "./cfg/"
jsonFmt bool
junitFmt bool
pgSQL bool
masterFile = "master.yaml"
nodeFile = "node.yaml"
etcdFile = "etcd.yaml"
controlplaneFile = "controlplane.yaml"
policiesFile = "policies.yaml"
managedservicesFile = "managedservices.yaml"
noResults bool
noSummary bool
noRemediations bool
filterOpts FilterOpts
includeTestOutput bool
outputFile string
configFileError error
controlsCollection []*check.Controls
envVarsPrefix = "KUBE_BENCH"
defaultKubeVersion = "1.18"
kubeVersion string
detecetedKubeVersion string
benchmarkVersion string
cfgFile string
cfgDir = "./cfg/"
jsonFmt bool
junitFmt bool
pgSQL bool
aSFF bool
masterFile = "master.yaml"
nodeFile = "node.yaml"
etcdFile = "etcd.yaml"
controlplaneFile = "controlplane.yaml"
policiesFile = "policies.yaml"
managedservicesFile = "managedservices.yaml"
exitCode int
noResults bool
noSummary bool
noRemediations bool
skipIds string
noTotals bool
filterOpts FilterOpts
includeTestOutput bool
outputFile string
configFileError error
controlsCollection []*check.Controls
)
// RootCmd represents the base command when called without any subcommands
@@ -64,7 +69,7 @@ var RootCmd = &cobra.Command{
Short: "Run CIS Benchmarks checks against a Kubernetes deployment",
Long: `This tool runs the CIS Kubernetes Benchmark (https://www.cisecurity.org/benchmark/kubernetes/)`,
Run: func(cmd *cobra.Command, args []string) {
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper())
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper())
if err != nil {
exitWithError(fmt.Errorf("unable to determine benchmark version: %v", err))
}
@@ -72,7 +77,7 @@ var RootCmd = &cobra.Command{
if isMaster() {
glog.V(1).Info("== Running master checks ==")
runChecks(check.MASTER, loadConfig(check.MASTER, bv))
runChecks(check.MASTER, loadConfig(check.MASTER, bv), detecetedKubeVersion)
// Control Plane is only valid for CIS 1.5 and later,
// this a gatekeeper for previous versions
@@ -82,8 +87,10 @@ var RootCmd = &cobra.Command{
}
if valid {
glog.V(1).Info("== Running control plane checks ==")
runChecks(check.CONTROLPLANE, loadConfig(check.CONTROLPLANE, bv))
runChecks(check.CONTROLPLANE, loadConfig(check.CONTROLPLANE, bv), detecetedKubeVersion)
}
} else {
glog.V(1).Info("== Skipping master checks ==")
}
// Etcd is only valid for CIS 1.5 and later,
@@ -94,11 +101,13 @@ var RootCmd = &cobra.Command{
}
if valid && isEtcd() {
glog.V(1).Info("== Running etcd checks ==")
runChecks(check.ETCD, loadConfig(check.ETCD, bv))
runChecks(check.ETCD, loadConfig(check.ETCD, bv), detecetedKubeVersion)
} else {
glog.V(1).Info("== Skipping etcd checks ==")
}
glog.V(1).Info("== Running node checks ==")
runChecks(check.NODE, loadConfig(check.NODE, bv))
runChecks(check.NODE, loadConfig(check.NODE, bv), detecetedKubeVersion)
// Policies is only valid for CIS 1.5 and later,
// this a gatekeeper for previous versions.
@@ -108,7 +117,9 @@ var RootCmd = &cobra.Command{
}
if valid {
glog.V(1).Info("== Running policies checks ==")
runChecks(check.POLICIES, loadConfig(check.POLICIES, bv))
runChecks(check.POLICIES, loadConfig(check.POLICIES, bv), detecetedKubeVersion)
} else {
glog.V(1).Info("== Skipping policies checks ==")
}
// Managedservices is only valid for GKE 1.0 and later,
@@ -119,10 +130,14 @@ var RootCmd = &cobra.Command{
}
if valid {
glog.V(1).Info("== Running managed services checks ==")
runChecks(check.MANAGEDSERVICES, loadConfig(check.MANAGEDSERVICES, bv))
runChecks(check.MANAGEDSERVICES, loadConfig(check.MANAGEDSERVICES, bv), detecetedKubeVersion)
} else {
glog.V(1).Info("== Skipping managed services checks ==")
}
writeOutput(controlsCollection)
exitCode := exitCodeSelection(controlsCollection)
os.Exit(exitCode)
},
}
@@ -145,14 +160,18 @@ func init() {
cobra.OnInitialize(initConfig)
// Output control
RootCmd.PersistentFlags().IntVar(&exitCode, "exit-code", 0, "Specify the exit code for when checks fail")
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(&noTotals, "nototals", false, "Disable printing of totals for failed, passed, ... checks across all sections")
RootCmd.PersistentFlags().BoolVar(&jsonFmt, "json", false, "Prints the results as JSON")
RootCmd.PersistentFlags().BoolVar(&junitFmt, "junit", false, "Prints the results as JUnit")
RootCmd.PersistentFlags().BoolVar(&pgSQL, "pgsql", false, "Save the results to PostgreSQL")
RootCmd.PersistentFlags().BoolVar(&aSFF, "asff", false, "Send the results to AWS Security Hub")
RootCmd.PersistentFlags().BoolVar(&filterOpts.Scored, "scored", true, "Run the scored CIS checks")
RootCmd.PersistentFlags().BoolVar(&filterOpts.Unscored, "unscored", true, "Run the unscored CIS checks")
RootCmd.PersistentFlags().StringVar(&skipIds, "skip", "", "List of comma separated values of checks to be skipped")
RootCmd.PersistentFlags().BoolVar(&includeTestOutput, "include-test-output", false, "Prints the actual result when test fails")
RootCmd.PersistentFlags().StringVar(&outputFile, "outputfile", "", "Writes the JSON results to output file")

View File

@@ -32,7 +32,7 @@ var runCmd = &cobra.Command{
exitWithError(fmt.Errorf("unable to get `targets` from command line :%v", err))
}
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, viper.GetViper())
bv, err := getBenchmarkVersion(kubeVersion, benchmarkVersion, getPlatformName(), viper.GetViper())
if err != nil {
exitWithError(fmt.Errorf("unable to get benchmark version. error: %v", err))
}
@@ -52,7 +52,10 @@ var runCmd = &cobra.Command{
// Merge version-specific config if any.
path := filepath.Join(cfgDir, bv)
mergeConfig(path)
err = mergeConfig(path)
if err != nil {
fmt.Printf("Error in mergeConfig: %v\n", err)
}
err = run(targets, bv)
if err != nil {
@@ -72,7 +75,7 @@ func run(targets []string, benchmarkVersion string) (err error) {
for _, yamlFile := range yamlFiles {
_, name := filepath.Split(yamlFile)
testType := check.NodeType(strings.Split(name, ".")[0])
runChecks(testType, yamlFile)
runChecks(testType, yamlFile, detecetedKubeVersion)
}
writeOutput(controlsCollection)

47
cmd/securityHub.go Normal file
View File

@@ -0,0 +1,47 @@
package cmd
import (
"fmt"
"log"
"github.com/aquasecurity/kube-bench/internal/findings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/securityhub"
"github.com/spf13/viper"
)
//REGION ...
const REGION = "AWS_REGION"
func writeFinding(in []*securityhub.AwsSecurityFinding) error {
r := viper.GetString(REGION)
if len(r) == 0 {
return fmt.Errorf("%s not set", REGION)
}
sess, err := session.NewSession(&aws.Config{
Region: aws.String(r)},
)
if err != nil {
return err
}
svc := securityhub.New(sess)
p := findings.New(svc)
out, perr := p.PublishFinding(in)
print(out)
return perr
}
func print(out *findings.PublisherOutput) {
if out.SuccessCount > 0 {
log.Printf("Number of findings that were successfully imported:%v\n", out.SuccessCount)
}
if out.FailedCount > 0 {
log.Printf("Number of findings that failed to import:%v\n", out.FailedCount)
for _, f := range out.FailedFindings {
log.Printf("ID:%s", *f.Id)
log.Printf("Message:%s", *f.ErrorMessage)
log.Printf("Error Code:%s", *f.ErrorCode)
}
}
}

View File

@@ -111,4 +111,4 @@
"total_warn": 11,
"total_info": 0
}
]
]

View File

@@ -0,0 +1,77 @@
[
{
"id": "2",
"version": "1.15",
"text": "Etcd Node Configuration",
"node_type": "etcd",
"tests": [
{
"section": "2",
"pass": 7,
"fail": 0,
"warn": 0,
"info": 0,
"desc": "Etcd Node Configuration Files",
"results": [
{
"test_number": "2.1",
"test_desc": "Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)",
"audit": "/bin/ps -ef | /bin/grep etcd | /bin/grep -v grep",
"AuditConfig": "",
"type": "",
"remediation": "Follow the etcd service documentation and configure TLS encryption.\nThen, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml\non the master node and set the below parameters.\n--cert-file=</path/to/ca-file>\n--key-file=</path/to/key-file>\n",
"test_info": [
"Follow the etcd service documentation and configure TLS encryption.\nThen, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml\non the master node and set the below parameters.\n--cert-file=</path/to/ca-file>\n--key-file=</path/to/key-file>\n"
],
"status": "PASS",
"actual_value": "root 3277 3218 3 Apr19 ? 03:57:52 etcd --advertise-client-urls=https://192.168.64.4:2379 --cert-file=/var/lib/minikube/certs/etcd/server.crt --client-cert-auth=true --data-dir=/var/lib/minikube/etcd --initial-advertise-peer-urls=https://192.168.64.4:2380 --initial-cluster=minikube=https://192.168.64.4:2380 --key-file=/var/lib/minikube/certs/etcd/server.key --listen-client-urls=https://127.0.0.1:2379,https://192.168.64.4:2379 --listen-metrics-urls=http://127.0.0.1:2381 --listen-peer-urls=https://192.168.64.4:2380 --name=minikube --peer-cert-file=/var/lib/minikube/certs/etcd/peer.crt --peer-client-cert-auth=true --peer-key-file=/var/lib/minikube/certs/etcd/peer.key --peer-trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt --snapshot-count=10000 --trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt\nroot 4624 4605 8 Apr21 ? 04:55:10 kube-apiserver --advertise-address=192.168.64.4 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/var/lib/minikube/certs/ca.crt --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,PodSecurityPolicy --enable-bootstrap-token-auth=true --etcd-cafile=/var/lib/minikube/certs/etcd/ca.crt --etcd-certfile=/var/lib/minikube/certs/apiserver-etcd-client.crt --etcd-keyfile=/var/lib/minikube/certs/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --insecure-port=0 --kubelet-client-certificate=/var/lib/minikube/certs/apiserver-kubelet-client.crt --kubelet-client-key=/var/lib/minikube/certs/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/var/lib/minikube/certs/front-proxy-client.crt --proxy-client-key-file=/var/lib/minikube/certs/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=8443 --service-account-key-file=/var/lib/minikube/certs/sa.pub --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/var/lib/minikube/certs/apiserver.crt --tls-private-key-file=/var/lib/minikube/certs/apiserver.key\n",
"scored": true,
"expected_result": "'--cert-file' is present AND '--key-file' is present"
}
]
}
],
"total_pass": 7,
"total_fail": 0,
"total_warn": 0,
"total_info": 0
},
{
"id": "3",
"version": "1.5",
"text": "Control Plane Configuration",
"node_type": "controlplane",
"tests": [
{
"section": "3.1",
"pass": 0,
"fail": 0,
"warn": 1,
"info": 0,
"desc": "Authentication and Authorization",
"results": [
{
"test_number": "3.1.1",
"test_desc": "Client certificate authentication should not be used for users (Not Scored)",
"audit": "",
"AuditConfig": "",
"type": "manual",
"remediation": "Alternative mechanisms provided by Kubernetes such as the use of OIDC should be\nimplemented in place of client certificates.\n",
"test_info": [
"Alternative mechanisms provided by Kubernetes such as the use of OIDC should be\nimplemented in place of client certificates.\n"
],
"status": "WARN",
"actual_value": "",
"scored": false,
"expected_result": "",
"reason": "Test marked as a manual test"
}
]
}
],
"total_pass": 0,
"total_fail": 0,
"total_warn": 3,
"total_info": 0
}
]

View File

@@ -1,114 +1,122 @@
[
{
"id": "1",
"version": "1.5",
"text": "Master Node Security Configuration",
"node_type": "master",
"tests": [
{
"section": "1.1",
"pass": 15,
"fail": 1,
"warn": 5,
"info": 0,
"desc": "Master Node Configuration Files",
"results": [
{
"test_number": "1.1.1",
"test_desc": "Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Scored)",
"audit": "/bin/sh -c 'if test -e /etc/kubernetes/manifests/kube-apiserver.yaml; then stat -c permissions=%a /etc/kubernetes/manifests/kube-apiserver.yaml; fi'",
"AuditConfig": "",
"type": "",
"remediation": "Run the below command (based on the file location on your system) on the\nmaster node.\nFor example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml\n",
"test_info": [
"Run the below command (based on the file location on your system) on the\nmaster node.\nFor example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml\n"
],
"status": "PASS",
"actual_value": "permissions=600\n",
"scored": true,
"expected_result": "bitmask '600' AND '644'"
}
]
}
],
"total_pass": 42,
{
"Controls": [
{
"id": "1",
"version": "1.5",
"text": "Master Node Security Configuration",
"node_type": "master",
"tests": [
{
"section": "1.1",
"pass": 15,
"fail": 1,
"warn": 5,
"info": 0,
"desc": "Master Node Configuration Files",
"results": [
{
"test_number": "1.1.1",
"test_desc": "Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Scored)",
"audit": "/bin/sh -c 'if test -e /etc/kubernetes/manifests/kube-apiserver.yaml; then stat -c permissions=%a /etc/kubernetes/manifests/kube-apiserver.yaml; fi'",
"AuditConfig": "",
"type": "",
"remediation": "Run the below command (based on the file location on your system) on the\nmaster node.\nFor example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml\n",
"test_info": [
"Run the below command (based on the file location on your system) on the\nmaster node.\nFor example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml\n"
],
"status": "PASS",
"actual_value": "permissions=600\n",
"scored": true,
"expected_result": "bitmask '600' AND '644'"
}
]
}
],
"total_pass": 42,
"total_fail": 12,
"total_warn": 11,
"total_info": 0
},
{
"id": "2",
"version": "1.15",
"text": "Etcd Node Configuration",
"node_type": "etcd",
"tests": [
{
"section": "2",
"pass": 7,
"fail": 0,
"warn": 0,
"info": 0,
"desc": "Etcd Node Configuration Files",
"results": [
{
"test_number": "2.1",
"test_desc": "Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)",
"audit": "/bin/ps -ef | /bin/grep etcd | /bin/grep -v grep",
"AuditConfig": "",
"type": "",
"remediation": "Follow the etcd service documentation and configure TLS encryption.\nThen, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml\non the master node and set the below parameters.\n--cert-file=</path/to/ca-file>\n--key-file=</path/to/key-file>\n",
"test_info": [
"Follow the etcd service documentation and configure TLS encryption.\nThen, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml\non the master node and set the below parameters.\n--cert-file=</path/to/ca-file>\n--key-file=</path/to/key-file>\n"
],
"status": "PASS",
"actual_value": "root 3277 3218 3 Apr19 ? 03:57:52 etcd --advertise-client-urls=https://192.168.64.4:2379 --cert-file=/var/lib/minikube/certs/etcd/server.crt --client-cert-auth=true --data-dir=/var/lib/minikube/etcd --initial-advertise-peer-urls=https://192.168.64.4:2380 --initial-cluster=minikube=https://192.168.64.4:2380 --key-file=/var/lib/minikube/certs/etcd/server.key --listen-client-urls=https://127.0.0.1:2379,https://192.168.64.4:2379 --listen-metrics-urls=http://127.0.0.1:2381 --listen-peer-urls=https://192.168.64.4:2380 --name=minikube --peer-cert-file=/var/lib/minikube/certs/etcd/peer.crt --peer-client-cert-auth=true --peer-key-file=/var/lib/minikube/certs/etcd/peer.key --peer-trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt --snapshot-count=10000 --trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt\nroot 4624 4605 8 Apr21 ? 04:55:10 kube-apiserver --advertise-address=192.168.64.4 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/var/lib/minikube/certs/ca.crt --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,PodSecurityPolicy --enable-bootstrap-token-auth=true --etcd-cafile=/var/lib/minikube/certs/etcd/ca.crt --etcd-certfile=/var/lib/minikube/certs/apiserver-etcd-client.crt --etcd-keyfile=/var/lib/minikube/certs/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --insecure-port=0 --kubelet-client-certificate=/var/lib/minikube/certs/apiserver-kubelet-client.crt --kubelet-client-key=/var/lib/minikube/certs/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/var/lib/minikube/certs/front-proxy-client.crt --proxy-client-key-file=/var/lib/minikube/certs/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=8443 --service-account-key-file=/var/lib/minikube/certs/sa.pub --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/var/lib/minikube/certs/apiserver.crt --tls-private-key-file=/var/lib/minikube/certs/apiserver.key\n",
"scored": true,
"expected_result": "'--cert-file' is present AND '--key-file' is present"
}
]
}
],
"total_pass": 7,
"total_fail": 0,
"total_warn": 0,
"total_info": 0
},
{
"id": "3",
"version": "1.5",
"text": "Control Plane Configuration",
"node_type": "controlplane",
"tests": [
{
"section": "3.1",
"pass": 0,
"fail": 0,
"warn": 1,
"info": 0,
"desc": "Authentication and Authorization",
"results": [
{
"test_number": "3.1.1",
"test_desc": "Client certificate authentication should not be used for users (Not Scored)",
"audit": "",
"AuditConfig": "",
"type": "manual",
"remediation": "Alternative mechanisms provided by Kubernetes such as the use of OIDC should be\nimplemented in place of client certificates.\n",
"test_info": [
"Alternative mechanisms provided by Kubernetes such as the use of OIDC should be\nimplemented in place of client certificates.\n"
],
"status": "WARN",
"actual_value": "",
"scored": false,
"expected_result": "",
"reason": "Test marked as a manual test"
}
]
}
],
"total_pass": 0,
"total_fail": 0,
"total_warn": 3,
"total_info": 0
}
],
"Totals": {
"total_pass": 49,
"total_fail": 12,
"total_warn": 11,
"total_info": 0
},
{
"id": "2",
"version": "1.15",
"text": "Etcd Node Configuration",
"node_type": "etcd",
"tests": [
{
"section": "2",
"pass": 7,
"fail": 0,
"warn": 0,
"info": 0,
"desc": "Etcd Node Configuration Files",
"results": [
{
"test_number": "2.1",
"test_desc": "Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)",
"audit": "/bin/ps -ef | /bin/grep etcd | /bin/grep -v grep",
"AuditConfig": "",
"type": "",
"remediation": "Follow the etcd service documentation and configure TLS encryption.\nThen, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml\non the master node and set the below parameters.\n--cert-file=</path/to/ca-file>\n--key-file=</path/to/key-file>\n",
"test_info": [
"Follow the etcd service documentation and configure TLS encryption.\nThen, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml\non the master node and set the below parameters.\n--cert-file=</path/to/ca-file>\n--key-file=</path/to/key-file>\n"
],
"status": "PASS",
"actual_value": "root 3277 3218 3 Apr19 ? 03:57:52 etcd --advertise-client-urls=https://192.168.64.4:2379 --cert-file=/var/lib/minikube/certs/etcd/server.crt --client-cert-auth=true --data-dir=/var/lib/minikube/etcd --initial-advertise-peer-urls=https://192.168.64.4:2380 --initial-cluster=minikube=https://192.168.64.4:2380 --key-file=/var/lib/minikube/certs/etcd/server.key --listen-client-urls=https://127.0.0.1:2379,https://192.168.64.4:2379 --listen-metrics-urls=http://127.0.0.1:2381 --listen-peer-urls=https://192.168.64.4:2380 --name=minikube --peer-cert-file=/var/lib/minikube/certs/etcd/peer.crt --peer-client-cert-auth=true --peer-key-file=/var/lib/minikube/certs/etcd/peer.key --peer-trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt --snapshot-count=10000 --trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt\nroot 4624 4605 8 Apr21 ? 04:55:10 kube-apiserver --advertise-address=192.168.64.4 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/var/lib/minikube/certs/ca.crt --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,PodSecurityPolicy --enable-bootstrap-token-auth=true --etcd-cafile=/var/lib/minikube/certs/etcd/ca.crt --etcd-certfile=/var/lib/minikube/certs/apiserver-etcd-client.crt --etcd-keyfile=/var/lib/minikube/certs/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --insecure-port=0 --kubelet-client-certificate=/var/lib/minikube/certs/apiserver-kubelet-client.crt --kubelet-client-key=/var/lib/minikube/certs/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/var/lib/minikube/certs/front-proxy-client.crt --proxy-client-key-file=/var/lib/minikube/certs/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=8443 --service-account-key-file=/var/lib/minikube/certs/sa.pub --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/var/lib/minikube/certs/apiserver.crt --tls-private-key-file=/var/lib/minikube/certs/apiserver.key\n",
"scored": true,
"expected_result": "'--cert-file' is present AND '--key-file' is present"
}
]
}
],
"total_pass": 7,
"total_fail": 0,
"total_warn": 0,
"total_info": 0
},
{
"id": "3",
"version": "1.5",
"text": "Control Plane Configuration",
"node_type": "controlplane",
"tests": [
{
"section": "3.1",
"pass": 0,
"fail": 0,
"warn": 1,
"info": 0,
"desc": "Authentication and Authorization",
"results": [
{
"test_number": "3.1.1",
"test_desc": "Client certificate authentication should not be used for users (Not Scored)",
"audit": "",
"AuditConfig": "",
"type": "manual",
"remediation": "Alternative mechanisms provided by Kubernetes such as the use of OIDC should be\nimplemented in place of client certificates.\n",
"test_info": [
"Alternative mechanisms provided by Kubernetes such as the use of OIDC should be\nimplemented in place of client certificates.\n"
],
"status": "WARN",
"actual_value": "",
"scored": false,
"expected_result": "",
"reason": "Test marked as a manual test"
}
]
}
],
"total_pass": 0,
"total_fail": 0,
"total_warn": 3,
"total_warn": 14,
"total_info": 0
}
]
}

114
cmd/testdata/result_no_totals.json vendored Normal file
View File

@@ -0,0 +1,114 @@
[
{
"id": "1",
"version": "1.5",
"text": "Master Node Security Configuration",
"node_type": "master",
"tests": [
{
"section": "1.1",
"pass": 15,
"fail": 1,
"warn": 5,
"info": 0,
"desc": "Master Node Configuration Files",
"results": [
{
"test_number": "1.1.1",
"test_desc": "Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Scored)",
"audit": "/bin/sh -c 'if test -e /etc/kubernetes/manifests/kube-apiserver.yaml; then stat -c permissions=%a /etc/kubernetes/manifests/kube-apiserver.yaml; fi'",
"AuditConfig": "",
"type": "",
"remediation": "Run the below command (based on the file location on your system) on the\nmaster node.\nFor example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml\n",
"test_info": [
"Run the below command (based on the file location on your system) on the\nmaster node.\nFor example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml\n"
],
"status": "PASS",
"actual_value": "permissions=600\n",
"scored": true,
"expected_result": "bitmask '600' AND '644'"
}
]
}
],
"total_pass": 42,
"total_fail": 12,
"total_warn": 11,
"total_info": 0
},
{
"id": "2",
"version": "1.15",
"text": "Etcd Node Configuration",
"node_type": "etcd",
"tests": [
{
"section": "2",
"pass": 7,
"fail": 0,
"warn": 0,
"info": 0,
"desc": "Etcd Node Configuration Files",
"results": [
{
"test_number": "2.1",
"test_desc": "Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)",
"audit": "/bin/ps -ef | /bin/grep etcd | /bin/grep -v grep",
"AuditConfig": "",
"type": "",
"remediation": "Follow the etcd service documentation and configure TLS encryption.\nThen, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml\non the master node and set the below parameters.\n--cert-file=</path/to/ca-file>\n--key-file=</path/to/key-file>\n",
"test_info": [
"Follow the etcd service documentation and configure TLS encryption.\nThen, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml\non the master node and set the below parameters.\n--cert-file=</path/to/ca-file>\n--key-file=</path/to/key-file>\n"
],
"status": "PASS",
"actual_value": "root 3277 3218 3 Apr19 ? 03:57:52 etcd --advertise-client-urls=https://192.168.64.4:2379 --cert-file=/var/lib/minikube/certs/etcd/server.crt --client-cert-auth=true --data-dir=/var/lib/minikube/etcd --initial-advertise-peer-urls=https://192.168.64.4:2380 --initial-cluster=minikube=https://192.168.64.4:2380 --key-file=/var/lib/minikube/certs/etcd/server.key --listen-client-urls=https://127.0.0.1:2379,https://192.168.64.4:2379 --listen-metrics-urls=http://127.0.0.1:2381 --listen-peer-urls=https://192.168.64.4:2380 --name=minikube --peer-cert-file=/var/lib/minikube/certs/etcd/peer.crt --peer-client-cert-auth=true --peer-key-file=/var/lib/minikube/certs/etcd/peer.key --peer-trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt --snapshot-count=10000 --trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt\nroot 4624 4605 8 Apr21 ? 04:55:10 kube-apiserver --advertise-address=192.168.64.4 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/var/lib/minikube/certs/ca.crt --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,PodSecurityPolicy --enable-bootstrap-token-auth=true --etcd-cafile=/var/lib/minikube/certs/etcd/ca.crt --etcd-certfile=/var/lib/minikube/certs/apiserver-etcd-client.crt --etcd-keyfile=/var/lib/minikube/certs/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --insecure-port=0 --kubelet-client-certificate=/var/lib/minikube/certs/apiserver-kubelet-client.crt --kubelet-client-key=/var/lib/minikube/certs/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/var/lib/minikube/certs/front-proxy-client.crt --proxy-client-key-file=/var/lib/minikube/certs/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=8443 --service-account-key-file=/var/lib/minikube/certs/sa.pub --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/var/lib/minikube/certs/apiserver.crt --tls-private-key-file=/var/lib/minikube/certs/apiserver.key\n",
"scored": true,
"expected_result": "'--cert-file' is present AND '--key-file' is present"
}
]
}
],
"total_pass": 7,
"total_fail": 0,
"total_warn": 0,
"total_info": 0
},
{
"id": "3",
"version": "1.5",
"text": "Control Plane Configuration",
"node_type": "controlplane",
"tests": [
{
"section": "3.1",
"pass": 0,
"fail": 0,
"warn": 1,
"info": 0,
"desc": "Authentication and Authorization",
"results": [
{
"test_number": "3.1.1",
"test_desc": "Client certificate authentication should not be used for users (Not Scored)",
"audit": "",
"AuditConfig": "",
"type": "manual",
"remediation": "Alternative mechanisms provided by Kubernetes such as the use of OIDC should be\nimplemented in place of client certificates.\n",
"test_info": [
"Alternative mechanisms provided by Kubernetes such as the use of OIDC should be\nimplemented in place of client certificates.\n"
],
"status": "WARN",
"actual_value": "",
"scored": false,
"expected_result": "",
"reason": "Test marked as a manual test"
}
]
}
],
"total_pass": 0,
"total_fail": 0,
"total_warn": 3,
"total_info": 0
}
]

View File

@@ -1,6 +1,7 @@
package cmd
import (
"encoding/json"
"fmt"
"os"
"os/exec"
@@ -29,10 +30,10 @@ var psFunc func(string) string
var statFunc func(string) (os.FileInfo, error)
var getBinariesFunc func(*viper.Viper, check.NodeType) (map[string]string, error)
var TypeMap = map[string][]string{
"ca": []string{"cafile", "defaultcafile"},
"kubeconfig": []string{"kubeconfig", "defaultkubeconfig"},
"service": []string{"svc", "defaultsvc"},
"config": []string{"confs", "defaultconf"},
"ca": {"cafile", "defaultcafile"},
"kubeconfig": {"kubeconfig", "defaultkubeconfig"},
"service": {"svc", "defaultsvc"},
"config": {"confs", "defaultconf"},
}
func init() {
@@ -93,7 +94,7 @@ func getBinaries(v *viper.Viper, nodetype check.NodeType) (map[string]string, er
if len(bins) > 0 {
bin, err := findExecutable(bins)
if err != nil && !optional {
glog.Warning(buildComponentMissingErrorMessage(nodetype, component, bins))
glog.V(1).Info(buildComponentMissingErrorMessage(nodetype, component, bins))
return nil, fmt.Errorf("unable to detect running programs for component %q", component)
}
@@ -279,7 +280,7 @@ Alternatively, you can specify the version with --version
kube-bench --version <VERSION> ...
`
func getKubeVersion() (string, error) {
func getKubeVersion() (*KubeVersion, error) {
if k8sVer, err := getKubeVersionFromRESTAPI(); err == nil {
glog.V(2).Info(fmt.Sprintf("Kubernetes REST API Reported version: %s", k8sVer))
@@ -290,17 +291,22 @@ func getKubeVersion() (string, error) {
_, err := exec.LookPath("kubectl")
if err != nil {
glog.V(3).Infof("Error locating kubectl: %s", err)
_, err = exec.LookPath("kubelet")
if err != nil {
glog.V(3).Infof("Error locating kubelet: %s", err)
// Search for the kubelet binary all over the filesystem and run the first match to get the kubernetes version
cmd := exec.Command("/bin/sh", "-c", "`find / -type f -executable -name kubelet 2>/dev/null | grep -m1 .` --version")
out, err := cmd.CombinedOutput()
if err == nil {
glog.V(3).Infof("Found kubelet and query kubernetes version is: %s", string(out))
return getVersionFromKubeletOutput(string(out)), nil
}
glog.Warning(missingKubectlKubeletMessage)
return "", fmt.Errorf("unable to find the programs kubectl or kubelet in the PATH")
glog.V(1).Info("unable to find the programs kubectl or kubelet in the PATH")
glog.V(1).Infof("Cant detect version, assuming default %s", defaultKubeVersion)
return &KubeVersion{baseVersion: defaultKubeVersion}, nil
}
return getKubeVersionFromKubelet(), nil
}
@@ -308,52 +314,65 @@ func getKubeVersion() (string, error) {
return getKubeVersionFromKubectl(), nil
}
func getKubeVersionFromKubectl() string {
cmd := exec.Command("kubectl", "version", "--short")
func getKubeVersionFromKubectl() *KubeVersion {
cmd := exec.Command("kubectl", "version", "-o", "json")
out, err := cmd.CombinedOutput()
if err != nil {
glog.V(2).Infof("Failed to query kubectl: %s", err)
glog.V(2).Info(err)
}
return getVersionFromKubectlOutput(string(out))
}
func getKubeVersionFromKubelet() string {
func getKubeVersionFromKubelet() *KubeVersion {
cmd := exec.Command("kubelet", "--version")
out, err := cmd.CombinedOutput()
if err != nil {
glog.V(2).Infof("Failed to query kubelet: %s", err)
glog.V(2).Info(err)
}
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 {
func getVersionFromKubectlOutput(s string) *KubeVersion {
glog.V(2).Infof("Kubectl output: %s", s)
type versionResult struct {
ServerVersion VersionResponse
}
vrObj := &versionResult{}
if err := json.Unmarshal([]byte(s), vrObj); err != nil {
glog.V(2).Info(err)
if strings.Contains(s, "The connection to the server") {
msg := fmt.Sprintf(`Warning: Kubernetes version was not auto-detected because kubectl could not connect to the Kubernetes server. This may be because the kubeconfig information is missing or has credentials that do not match the server. Assuming default version %s`, defaultKubeVersion)
fmt.Fprintln(os.Stderr, msg)
}
glog.V(1).Info(fmt.Sprintf("Unable to get Kubernetes version from kubectl, using default version: %s", defaultKubeVersion))
return defaultKubeVersion
return &KubeVersion{baseVersion: defaultKubeVersion}
}
sv := vrObj.ServerVersion
return &KubeVersion{
Major: sv.Major,
Minor: sv.Minor,
GitVersion: sv.GitVersion,
}
return subs[1]
}
func getVersionFromKubeletOutput(s string) string {
func getVersionFromKubeletOutput(s string) *KubeVersion {
glog.V(2).Infof("Kubelet output: %s", s)
serverVersionRe := regexp.MustCompile(`Kubernetes v(\d+.\d+)`)
subs := serverVersionRe.FindStringSubmatch(s)
if len(subs) < 2 {
glog.V(1).Info(fmt.Sprintf("Unable to get Kubernetes version from kubelet, using default version: %s", defaultKubeVersion))
return defaultKubeVersion
return &KubeVersion{baseVersion: defaultKubeVersion}
}
return subs[1]
return &KubeVersion{baseVersion: subs[1]}
}
func makeSubstitutions(s string, ext string, m map[string]string) string {
func makeSubstitutions(s string, ext string, m map[string]string) (string, []string) {
substitutions := make([]string, 0)
for k, v := range m {
subst := "$" + k + ext
if v == "" {
@@ -361,10 +380,14 @@ func makeSubstitutions(s string, ext string, m map[string]string) string {
continue
}
glog.V(2).Info(fmt.Sprintf("Substituting %s with '%s'\n", subst, v))
beforeS := s
s = multiWordReplace(s, subst, v)
if beforeS != s {
substitutions = append(substitutions, v)
}
}
return s
return s, substitutions
}
func isEmpty(str string) bool {
@@ -403,3 +426,95 @@ These program names are provided in the config.yaml, section '%s.%s.bins'
return fmt.Sprintf(errMessageTemplate, component, componentRoleName, binList, componentType, component)
}
func getPlatformName() string {
openShiftVersion := getOpenShiftVersion()
if openShiftVersion != "" {
return openShiftVersion
}
kv, err := getKubeVersion()
if err != nil {
glog.V(2).Info(err)
return ""
}
return getPlatformNameFromVersion(kv.GitVersion)
}
func getPlatformNameFromVersion(s string) string {
versionRe := regexp.MustCompile(`v\d+\.\d+\.\d+-(\w+)(?:[.\-])\w+`)
subs := versionRe.FindStringSubmatch(s)
if len(subs) < 2 {
return ""
}
return subs[1]
}
func getPlatformBenchmarkVersion(platform string) string {
glog.V(3).Infof("getPlatformBenchmarkVersion platform: %s", platform)
switch platform {
case "eks":
return "eks-1.0"
case "gke":
return "gke-1.0"
case "aliyun":
return "ack-1.0"
case "ocp-3.10":
return "rh-0.7"
case "ocp-4.1":
return "rh-1.0"
}
return ""
}
func getOpenShiftVersion() string {
glog.V(1).Info("Checking for oc")
_, err := exec.LookPath("oc")
if err == nil {
cmd := exec.Command("oc", "version")
out, err := cmd.CombinedOutput()
if err == nil {
versionRe := regexp.MustCompile(`oc v(\d+\.\d+)`)
subs := versionRe.FindStringSubmatch(string(out))
if len(subs) < 1 {
versionRe = regexp.MustCompile(`Client Version:\s*(\d+\.\d+)`)
subs = versionRe.FindStringSubmatch(string(out))
}
if len(subs) > 1 {
glog.V(2).Infof("OCP output '%s' \nplatform is %s \nocp %v", string(out), getPlatformNameFromVersion(string(out)), subs[1])
ocpBenchmarkVersion, err := getOcpValidVersion(subs[1])
if err == nil {
return fmt.Sprintf("ocp-%s", ocpBenchmarkVersion)
} else {
glog.V(1).Infof("Can't get getOcpValidVersion: %v", err)
}
} else {
glog.V(1).Infof("Can't parse version output: %v", subs)
}
} else {
glog.V(1).Infof("Can't use oc command: %v", err)
}
} else {
glog.V(1).Infof("Can't find oc command: %v", err)
}
return ""
}
func getOcpValidVersion(ocpVer string) (string, error) {
ocpOriginal := ocpVer
for !isEmpty(ocpVer) {
glog.V(3).Info(fmt.Sprintf("getOcpBenchmarkVersion check for ocp: %q \n", ocpVer))
if ocpVer == "3.10" || ocpVer == "4.1" {
glog.V(1).Info(fmt.Sprintf("getOcpBenchmarkVersion found valid version for ocp: %q \n", ocpVer))
return ocpVer, nil
}
ocpVer = decrementVersion(ocpVer)
}
glog.V(1).Info(fmt.Sprintf("getOcpBenchmarkVersion unable to find a match for: %q", ocpOriginal))
return "", fmt.Errorf("unable to find a matching Benchmark Version match for ocp version: %s", ocpOriginal)
}

View File

@@ -19,9 +19,12 @@ import (
"os"
"path/filepath"
"reflect"
"sort"
"strconv"
"testing"
"github.com/magiconair/properties/assert"
"github.com/aquasecurity/kube-bench/check"
"github.com/spf13/viper"
)
@@ -201,17 +204,21 @@ func TestMultiWordReplace(t *testing.T) {
}
}
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)
func Test_getVersionFromKubectlOutput(t *testing.T) {
ver := getVersionFromKubectlOutput(`{
"serverVersion": {
"major": "1",
"minor": "8",
"gitVersion": "v1.8.0"
}
}`)
if ver.BaseVersion() != "1.8" {
t.Fatalf("Expected 1.8 got %s", ver.BaseVersion())
}
ver = getVersionFromKubectlOutput("Something completely different")
if ver != defaultKubeVersion {
t.Fatalf("Expected %s got %s", defaultKubeVersion, ver)
if ver.BaseVersion() != defaultKubeVersion {
t.Fatalf("Expected %s got %s", defaultKubeVersion, ver.BaseVersion())
}
}
@@ -384,20 +391,23 @@ func TestGetServiceFiles(t *testing.T) {
func TestMakeSubsitutions(t *testing.T) {
cases := []struct {
input string
subst map[string]string
exp string
input string
subst map[string]string
exp string
expectedSubs []string
}{
{input: "Replace $thisbin", subst: map[string]string{"this": "that"}, exp: "Replace that"},
{input: "Replace $thisbin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that"},
{input: "Replace $thisbin and $herebin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that and there"},
{input: "Replace $thisbin", subst: map[string]string{"this": "that"}, exp: "Replace that", expectedSubs: []string{"that"}},
{input: "Replace $thisbin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that", expectedSubs: []string{"that"}},
{input: "Replace $thisbin and $herebin", subst: map[string]string{"this": "that", "here": "there"}, exp: "Replace that and there", expectedSubs: []string{"that", "there"}},
}
for _, c := range cases {
t.Run(c.input, func(t *testing.T) {
s := makeSubstitutions(c.input, "bin", c.subst)
s, subs := makeSubstitutions(c.input, "bin", c.subst)
if s != c.exp {
t.Fatalf("Got %s expected %s", s, c.exp)
}
sort.Strings(subs)
assert.Equal(t, c.expectedSubs, subs)
})
}
}
@@ -509,3 +519,144 @@ func TestGetYamlFilesFromDir(t *testing.T) {
t.Fatalf("Expected to find something.yaml, found %s", files[0])
}
}
func Test_getPlatformNameFromKubectlOutput(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
args args
want string
}{
{
name: "eks",
args: args{s: "v1.17.9-eks-4c6976"},
want: "eks",
},
{
name: "gke",
args: args{s: "v1.17.6-gke.1"},
want: "gke",
},
{
name: "ack",
args: args{s: "v1.18.8-aliyun.1"},
want: "aliyun",
},
{
name: "unknown",
args: args{s: "v1.17.6"},
want: "",
},
{
name: "empty string",
args: args{s: ""},
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getPlatformNameFromVersion(tt.args.s); got != tt.want {
t.Errorf("getPlatformNameFromKubectlOutput() = %v, want %v", got, tt.want)
}
})
}
}
func Test_getPlatformBenchmarkVersion(t *testing.T) {
type args struct {
platform string
}
tests := []struct {
name string
args args
want string
}{
{
name: "eks",
args: args{
platform: "eks",
},
want: "eks-1.0",
},
{
name: "gke",
args: args{
platform: "gke",
},
want: "gke-1.0",
},
{
name: "aliyun",
args: args{
platform: "aliyun",
},
want: "ack-1.0",
},
{
name: "unknown",
args: args{
platform: "rh",
},
want: "",
},
{
name: "empty",
args: args{
platform: "",
},
want: "",
},
{
name: "openshift3",
args: args{
platform: "ocp-3.10",
},
want: "rh-0.7",
},
{
name: "openshift4",
args: args{
platform: "ocp-4.1",
},
want: "rh-1.0",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getPlatformBenchmarkVersion(tt.args.platform); got != tt.want {
t.Errorf("getPlatformBenchmarkVersion() = %v, want %v", got, tt.want)
}
})
}
}
func Test_getOcpValidVersion(t *testing.T) {
cases := []struct {
openShiftVersion string
succeed bool
exp string
}{
{openShiftVersion: "3.11", succeed: true, exp: "3.10"},
{openShiftVersion: "3.10", succeed: true, exp: "3.10"},
{openShiftVersion: "2.9", succeed: false, exp: ""},
{openShiftVersion: "4.1", succeed: true, exp: "4.1"},
{openShiftVersion: "4.5", succeed: true, exp: "4.1"},
{openShiftVersion: "4.6", succeed: true, exp: "4.1"},
{openShiftVersion: "invalid", succeed: false, exp: ""},
}
for _, c := range cases {
ocpVer, _ := getOcpValidVersion(c.openShiftVersion)
if c.succeed {
if c.exp != ocpVer {
t.Errorf("getOcpValidVersion(%q) - Got %q expected %s", c.openShiftVersion, ocpVer, c.exp)
}
} else {
if len(ocpVer) > 0 {
t.Errorf("getOcpValidVersion(%q) - Expected empty string but Got %s", c.openShiftVersion, ocpVer)
}
}
}
}

View File

@@ -1,3 +1,4 @@
---
coverage:
status:
project:

27
docs/architecture.md Normal file
View File

@@ -0,0 +1,27 @@
## Test config YAML representation
The tests (or "controls") are maintained in YAML documents. There are different versions of these test YAML files reflecting different [versions and platforms of the CIS Kubernetes Benchmark](./platforms.md). You will find more information about the test file YAML definitions in our [controls documentation](./controls.md).
## Kube-bench benchmarks
The test files for the various versions of Benchmarks can be found in directories
with same name as the Benchmark versions under the `cfg` directory next to the kube-bench executable,
for example `./cfg/cis-1.5` will contain all test files for [CIS Kubernetes Benchmark v1.5.1](https://workbench.cisecurity.org/benchmarks/4892) which are:
master.yaml, controlplane.yaml, node.yaml, etcd.yaml, policies.yaml and config.yaml
Check the contents of the benchmark directory under `cfg` to see which targets are available for that benchmark. Each file except `config.yaml` represents a target (also known as a `control` in other parts of this documentation).
The following table shows the valid targets based on the CIS Benchmark version.
| CIS Benchmark | Targets |
|---|---|
| cis-1.5| master, controlplane, node, etcd, policies |
| cis-1.6| master, controlplane, node, etcd, policies |
|cis-1.20| master, controlplane, node, etcd, policies |
| gke-1.0| master, controlplane, node, etcd, policies, managedservices |
| eks-1.0| controlplane, node, policies, managedservices |
| ack-1.0| master, controlplane, node, etcd, policies, managedservices |
| rh-0.7| master,node|
| rh-1.0| master, controlplane, node, etcd, policies |

54
docs/asff.md Normal file
View File

@@ -0,0 +1,54 @@
# Integrating kube-bench with AWS Security Hub
You can configure kube-bench with the `--asff` to send findings to AWS Security Hub. There are some additional steps required so that kube-bench has information and permissions to send these findings.
## Enable the AWS Security Hub integration
* You will need AWS Security Hub to be enabled in your account
* In the Security Hub console, under Integrations, search for kube-bench
<p align="center">
<img src="../images/kube-bench-security-hub.png">
</p>
* Click on `Accept findings`. This gives information about the IAM permissions required to send findings to your Security Hub account. kube-bench runs within a pod on your EKS cluster, and will need to be associated with a Role that has these permissions.
## Configure permissions in an IAM Role
* Grant these permissions to the IAM Role that the kube-bench pod will be associated with. There are two options:
* You can run the kube-bench pod under a specific [service account associated with an IAM role](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) that has these permissions to write Security Hub findings.
* Alternatively the pod can be granted permissions specified by the Role that your [EKS node group uses](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html).
Here is an example IAM Policy that you can attach to your EKS node group's IAM Role:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "securityhub:BatchImportFindings",
"Resource": [
"arn:aws:securityhub:us-east-1::product/aqua-security/kube-bench"
]
}
]
}
```
### Modify the job configuration
* Modify the kube-bench Configmap in `job-eks-asff.yaml` to specify the AWS account, AWS region, and the EKS Cluster ARN.
* In the same file, modify the image specifed in the Job to use the kube-bench image pushed to your ECR
* [Optional] - If you have created a dedicated IAM role to be used with kube-bench as described above in [Configure permissions in an IAM Role](#configure-permissions-in-an-iam-role), you will need to add the IAM role arn to the kube-bench ServiceAccount in `job-eks-asff.yaml`.
* Make sure that `job-eks-asff.yaml` specifies the container image you just pushed to your ECR registry.
You can now run kube-bench as a pod in your cluster: `kubectl apply -f job-eks-asff.yaml`
Findings will be generated for any kube-bench test that generates a `[FAIL]` or `[WARN]` output. If all tests pass, no findings will be generated. However, it's recommended that you consult the pod log output to check whether any findings were generated but could not be written to Security Hub.
<p align="center">
<img src="../images/asff-example-finding.png">
</p>
[eks-instructions]: ../README.md#running-in-an-EKS-cluster

View File

@@ -41,7 +41,7 @@ groups:
text: "Ensure that the --profiling argument is set to false (Scored)"
audit: "ps -ef | grep kube-scheduler | grep -v grep"
tests:
bin_op: or
bin_op: and
test_items:
- flag: "--profiling"
set: true
@@ -150,11 +150,15 @@ pass a check. This criteria is made up of keywords extracted from the output of
the `audit` command and operations that compare these keywords against
values expected by the CIS Kubernetes Benchmark.
There are two ways to extract keywords from the output of the `audit` command,
`flag` and `path`.
There are three ways to run and extract keywords from the output of the command used,
| Command | Output var |
|---|---|
| `audit` | `flag` |
| `audit_config` | `path` |
| `audit_env` | `env` |
`flag` is used when the keyword is a command-line flag. The associated `audit`
command is usually a `ps` command and a `grep` for the binary whose flag we are
`flag` is used when the keyword is a command-line flag. The associated `audit` command could
be any binaries available on the system like `ps` command and a `grep` for the binary whose flag we are
checking:
```sh
@@ -173,7 +177,7 @@ tests:
```
`path` is used when the keyword is an option set in a JSON or YAML config file.
The associated `audit` command is usually `cat /path/to/config-yaml-or-json`.
The associated `audit_command` command is usually `cat /path/to/config-yaml-or-json`.
For example:
```yml
@@ -186,6 +190,24 @@ tests:
# ...
```
`env` is used to check if the value is present within a specified environment variable. The presence of `env` is treated as an OR operation, if both `flag` and `env` are supplied it will use either to attempt pass the check.
The command used for checking the environment variables of a process **is generated by default**.
If the command being generated is causing errors, you can override the command used by setting `audit_env` on the check.
Similarly, if you don't want the environment checking command to be generated or run at all, specify `disableEnvTesting` as true on the check.
The example below will check if the flag `--auto-tls` is equal to false *OR* `ETCD_AUTO_TLS` is equal to false
```yml
test_items:
- flag: "--auto-tls"
env: "ETCD_AUTO_TLS"
compare:
op: eq
value: false
```
**Note:** flag, path and env will act as OR if more then one present.
`test_item` compares the output of the audit command and keywords using the
`set` and `compare` fields.
@@ -203,6 +225,7 @@ tests:
If `set` is true, the check passes only if the keyword is present in the output
of the audit command, or config file. If `set` is false, the check passes only
if the keyword is not present in the output of the audit command, or config file.
`set` is true by default.
`compare` has two fields `op` and `value` to compare keywords with expected
value. `op` specifies which operation is used for the comparison, and `value`
@@ -223,6 +246,22 @@ The `op` (operations) currently supported in `kube-bench` are:
- `regex`: tests if the flag value matches the compared value regular expression.
When defining regular expressions in YAML it is generally easier to wrap them in
single quotes, for example `'^[abc]$'`, to avoid issues with string escaping.
- `bitmask` : tests if keyward is bitmasked with the compared value, common usege is for
comparing file permissions in linux.
## Omitting checks
If you decide that a recommendation is not appropriate for your environment, you can choose to omit it by editing the test YAML file to give it the check type `skip` as in this example:
```yaml
checks:
- id: 2.1.1
text: "Ensure that the --allow-privileged argument is set to false (Scored)"
type: "skip"
scored: true
```
No tests will be run for this check and the output will be marked [INFO].
## Configuration and Variables
@@ -239,7 +278,7 @@ version-specific config overwrite similar values in `cfg/config.yaml`.
For example, the kube-apiserver in Red Hat OCP distribution is run as
`hypershift openshift-kube-apiserver` instead of the default `kube-apiserver`.
This difference can be specified by editing the `master.apiserver.defaultbin`
entry `cfg/ocp-3.10/config.yaml`.
entry `cfg/rh-0.7/config.yaml`.
Below is the structure of `cfg/config.yaml`:
@@ -266,7 +305,7 @@ Every node type has a subsection that specifies the main configuration items.
Each component has the following entries:
- `bins`: A list of candidate binaries for a component. `kube-bench` checks this
list and selects the first binary that is running on the node.
list and selects the **first** binary that is running on the node.
If none of the binaries in `bins` list is running, `kube-bench` checks if the
binary specified by `defaultbin` is running and terminates if none of the
@@ -285,7 +324,7 @@ Every node type has a subsection that specifies the main configuration items.
```
- `confs`: A list of candidate configuration files for a component. `kube-bench`
checks this list and selects the first config file that is found on the node.
checks this list and selects the **first** config file that is found on the node.
If none of the config files exists, `kube-bench` defaults conf to the value
of `defaultconf`.
@@ -302,7 +341,7 @@ Every node type has a subsection that specifies the main configuration items.
```
- `svcs`: A list of candidate unitfiles for a component. `kube-bench` checks this
list and selects the first unitfile that is found on the node. If none of the
list and selects the **first** unitfile that is found on the node. If none of the
unitfiles exists, `kube-bench` defaults unitfile to the value of `defaultsvc`.
The selected unitfile for a component can be referenced in `controls` via a
@@ -324,7 +363,7 @@ Every node type has a subsection that specifies the main configuration items.
```
- `kubeconfig`: A list of candidate kubeconfig files for a component. `kube-bench`
checks this list and selects the first file that is found on the node. If none
checks this list and selects the **first** file that is found on the node. If none
of the files exists, `kube-bench` defaults kubeconfig to the value of
`defaultkubeconfig`.

137
docs/flags-and-commands.md Normal file
View File

@@ -0,0 +1,137 @@
## Commands
Command | Description
--- | ---
help | Prints help about any command
run | List of components to run
version | Print kube-bench version
## Flags
Flag | Description
--- | ---
--alsologtostderr | log to standard error as well as files
--asff | Send findings to AWS Security Hub for any benchmark tests that fail or that generate a warning. See [this page][kube-bench-aws-security-hub] for more information on how to enable the kube-bench integration with AWS Security Hub.
--benchmark | Manually specify CIS benchmark version
-c, --check | A comma-delimited list of checks to run as specified in Benchmark document.
--config | config file (default is ./cfg/config.yaml)
--exit-code | Specify the exit code for when checks fail
--group | Run all the checks under this comma-delimited list of groups.
--include-test-output | Prints the actual result when test fails.
--json | Prints the results as JSON
--junit | Prints the results as JUnit
--log_backtrace_at traceLocation | when logging hits line file:N, emit a stack trace (default :0)
--logtostderr | log to standard error instead of files
--noremediations | Disable printing of remediations section to stdout.
--noresults | Disable printing of results section to stdout.
--nototals | Disable calculating and printing of totals for failed, passed, ... checks across all sections
--outputfile | Writes the JSON results to output file
--pgsql | Save the results to PostgreSQL
--scored | Run the scored CIS checks (default true)
--skip string | List of comma separated values of checks to be skipped
--stderrthreshold severity | logs at or above this threshold go to stderr (default 2)
-v, --v Level | log level for V logs (default 0)
--version string | Manually specify Kubernetes version, automatically detected if unset
--vmodule moduleSpec | comma-separated list of pattern=N settings for file-filtered logging
### Examples
#### Report kube-bench findings to AWS Security Hub
You can configure kube-bench with the `--asff` option to send findings to AWS Security Hub for any benchmark tests that fail or that generate a warning. See [this page](asff.md) for more information on how to enable the kube-bench integration with AWS Security Hub.
#### Specifying the benchmark or Kubernetes version
`kube-bench` uses the Kubernetes API, or access to the `kubectl` or `kubelet` executables to try to determine the Kubernetes version, and hence which benchmark to run. If you wish to override this, or if none of these methods are available, you can specify either the Kubernetes version or CIS Benchmark as a command line parameter.
You can specify a particular version of Kubernetes by setting the `--version` flag or with the `KUBE_BENCH_VERSION` environment variable. The value of `--version` takes precedence over the value of `KUBE_BENCH_VERSION`.
For example, run kube-bench using the tests for Kubernetes version 1.13:
```
kube-bench --version 1.13
```
You can specify `--benchmark` to run a specific CIS Benchmark version:
```
kube-bench --benchmark cis-1.5
```
**Note:** It is an error to specify both `--version` and `--benchmark` flags together
#### Specifying Benchmark sections
If you want to run specific CIS Benchmark sections (i.e master, node, etcd, etc...)
you can use the `run --targets` subcommand.
```
kube-bench run --targets master,node
```
or
```
kube-bench run --targets master,node,etcd,policies
```
If no targets are specified, `kube-bench` will determine the appropriate targets based on the CIS Benchmark version and the components detected on the node. The detection is done by verifying which components are running, as defined in the config files (see [Configuration](controls.md#configuration-and-variables).
#### Run specific check or group
`kube-bench` supports running individual checks by specifying the check's `id`
as a comma-delimited list on the command line with the `--check` | `-c` flag.
`kube-bench --check="1.1.1,1.1.2,1.2.1,1.3.3"`
`kube-bench` supports running all checks under group by specifying the group's `id`
as a comma-delimited list on the command line with the `--group` | `-g` flag.
`kube-bench --check="1.1,2.2"`
Will run all checks 1.1.X and 2.2.X.
#### Skip specific check or group
`kube-bench` supports skipping checks or groups by specifying the `id`
as a comma-delimited list on the command line with the `--skip` flag.
`kube-bench --skip="1.1,1.2.1,1.3.3"`
Will skip 1.1.X group and individual checks 1.2.1, 1.3.3.
Skipped checks returns [INFO] output.
#### Exit code
`kube-bench` supports using uniqe exit code when failing a check or more.
`kube-bench --exit-code 42`
Will return 42 if one check or more failed, and 0 incase none failed.
**Note:** [WARN] is not [FAIL].
#### Output manipulation flags
There are four output states:
- [PASS] indicates that the test was run successfully, and passed.
- [FAIL] indicates that the test was run successfully, and failed. The remediation output describes how to correct the configuration, or includes an error message describing why the test could not be run.
- [WARN] means this test needs further attention, for example it is a test that needs to be run manually. Check the remediation output for further information.
- [INFO] is informational output that needs no further action.
Note:
- If the test is Manual, this always generates WARN (because the user has to run it manually)
- If the test is Scored, and kube-bench was unable to run the test, this generates FAIL (because the test has not been passed, and as a Scored test, if it doesn't pass then it must be considered a failure).
- If the test is Not Scored, and kube-bench was unable to run the test, this generates WARN.
- If the test is Scored, type is empty, and there are no `test_items` present, it generates a WARN. This is to highlight tests that appear to be incompletely defined.
`kube-bench` supports multiple output manipulation flags.
`kube-bench --include-test-output` will print failing checks output in the results section
```
[INFO] 1 Master Node Security Configuration
[INFO] 1.1 Master Node Configuration Files
[FAIL] 1.1.1 Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Automated)
**permissions=777**
```
**Note:** `--noresults` `--noremediations` and `--include-test-output` **will not** effect the json output but only stdout.
Only `--nototals` will effect the json output and thats because it will not call the function to calculate totals.
#### Troubleshooting
Running `kube-bench` with the `-v 3` parameter will generate debug logs that can be very helpful for debugging problems.
If you are using one of the example `job*.yaml` files, you will need to edit the `command` field, for example `["kube-bench", "-v", "3"]`. Once the job has run, the logs can be retrieved using `kubectl logs` on the job's pod.

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
docs/images/kube-bench.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
docs/images/kube-bench.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 25.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="_x30_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="500px" height="135px" viewBox="0 0 500 135" enable-background="new 0 0 500 135" xml:space="preserve">
<polygon fill="#1904DA" points="71.153,8.189 31.4,62.284 71.153,112.569 110.419,62.923 "/>
<path fill="#FF445F" d="M46.731,131.015c0.001,0,0.002,0,0.003,0l48.846-0.011c0.002,0,0.004,0,0.005,0
c1.14,0,2.273-0.246,3.319-0.694l-27.752-17.741l-27.598,17.813C44.561,130.792,45.643,131.015,46.731,131.015z"/>
<path fill="#FFC900" d="M110.419,62.923l-39.266,49.646l27.752,17.741c1.262-0.541,2.397-1.376,3.256-2.442l27.959-34.782
l2.489-3.097c0.513-0.638,0.923-1.354,1.224-2.112c0.143-0.359,0.261-0.728,0.353-1.103L110.419,62.923z"/>
<path fill="#FFC900" d="M8.078,86.64c0.217,0.956,0.599,1.875,1.137,2.697c0.149,0.229,0.309,0.45,0.478,0.664l30.461,37.873
c0.892,1.108,2.08,1.969,3.402,2.508l27.598-17.813L31.4,62.284L8.078,86.64z"/>
<path fill="#00FFE4" d="M20.78,32.099c-0.897,1.028-1.543,2.271-1.856,3.634L8.072,82.937c-0.242,1.052-0.266,2.15-0.089,3.214
c0.027,0.164,0.058,0.327,0.095,0.488L31.4,62.284L20.78,32.099z"/>
<path fill="#00FFE4" d="M134.188,86.774c0.311-1.258,0.34-2.585,0.049-3.848l-10.873-47.232c-0.295-1.279-0.884-2.452-1.7-3.438
l-11.244,30.667L134.188,86.774z"/>
<g>
<path fill="#08B1D5" d="M56.624,27.961L71.153,8.189c-0.004,0-0.008,0-0.013,0c-0.017,0-0.035,0.001-0.052,0.001
C70.964,8.191,70.84,8.194,70.715,8.2c-0.014,0.001-0.028,0.003-0.043,0.004c-1.1,0.06-2.188,0.337-3.182,0.812L23.483,30.043
c-1.046,0.5-1.96,1.204-2.703,2.056L31.4,62.284L56.624,27.95V27.961z"/>
<path fill="#08B1D5" d="M118.832,30.042L74.797,9.016c-1.132-0.542-2.387-0.825-3.643-0.827l39.266,54.733l11.244-30.667
C120.901,31.333,119.94,30.571,118.832,30.042z"/>
</g>
<g>
<path fill="#07242D" d="M179,108.611h-8.361l-16.315-16.496c-0.664,0.083-1.34,0.126-2.027,0.126v16.37h-5.959V62.369h5.959
c0,0-0.011,23.984,0,23.984c2.902,0,5.558-1.198,7.443-3.125l7.132-7.286h8.545l-11.596,11.514
c-1.027,1.028-2.192,1.921-3.462,2.646L179,108.611z"/>
<path fill="#07242D" d="M211.871,75.856v16.505c0,0,0,0.024,0,0.035c0,8.961-7.261,16.215-16.223,16.215
c-8.961,0-16.217-7.276-16.217-16.237c0-0.012,0-16.518,0-16.518h5.778v16.505c0,5.762,4.677,10.457,10.439,10.457
c5.762,0,10.433-4.695,10.433-10.457V75.856H211.871z"/>
<path fill="#07242D" d="M250.26,92.238c0,9.042-7.33,16.373-16.373,16.373c-3.967,0-7.605-1.411-10.438-3.758v3.758h-5.944
c0.004-0.373,0.004-46.242,0.004-46.242h5.944l-0.003,17.254c2.834-2.348,6.471-3.758,10.439-3.758
C242.93,75.864,250.261,83.195,250.26,92.238z M244.333,92.238c0-5.769-4.677-10.445-10.446-10.445
c-5.637,0-10.447,4.578-10.447,10.429c0,5.851,4.81,10.462,10.447,10.462C239.656,102.683,244.333,98.007,244.333,92.238z"/>
<path fill="#07242D" d="M286.212,94.367h-26.414c0.994,4.714,5.176,8.271,10.181,8.271c3.265,0,6.176-1.516,8.081-3.878h6.927
c-2.529,5.792-8.3,9.851-15.007,9.851c-9.033,0-16.379-7.358-16.379-16.402s7.345-16.353,16.379-16.353
C279.783,75.779,287.568,84.659,286.212,94.367z M279.65,88.392c-1.521-3.845-5.277-6.553-9.672-6.553s-8.155,2.71-9.679,6.553
H279.65z"/>
<path fill="#07242D" d="M307.437,86.979v5.459h-16.855v-5.459H307.437z"/>
<path fill="#07242D" d="M345.923,92.238c0,9.042-7.33,16.373-16.373,16.373c-3.967,0-7.605-1.411-10.438-3.758v3.758h-5.944
c0.004-0.373,0.004-46.242,0.004-46.242h5.944l-0.003,17.254c2.834-2.348,6.471-3.758,10.438-3.758
C338.593,75.864,345.924,83.195,345.923,92.238z M339.996,92.238c0-5.769-4.677-10.445-10.446-10.445
c-5.637,0-10.447,4.578-10.447,10.429c0,5.851,4.81,10.462,10.447,10.462C335.318,102.683,339.996,98.007,339.996,92.238z"/>
<path fill="#07242D" d="M381.874,94.367H355.46c0.994,4.714,5.176,8.271,10.181,8.271c3.265,0,6.176-1.516,8.081-3.878h6.927
c-2.529,5.792-8.3,9.851-15.007,9.851c-9.033,0-16.379-7.358-16.379-16.402s7.345-16.353,16.379-16.353
C375.445,75.779,383.23,84.659,381.874,94.367z M375.312,88.392c-1.521-3.845-5.277-6.553-9.672-6.553s-8.155,2.71-9.679,6.553
H375.312z"/>
<path fill="#07242D" d="M419.609,92.201c0,11.479,0,16.41,0,16.41h-5.976c0,0,0-10.761,0-16.41c0-5.855-4.767-10.363-10.389-10.363
c-5.622,0-10.41,4.458-10.41,10.363c0,5.652,0,16.41,0,16.41h-5.975V75.856c0,0,2.56,0,5.975,0v3.69c0,0,3.921-3.69,10.41-3.69
C410.942,75.856,419.609,81.839,419.609,92.201z"/>
<path fill="#07242D" d="M447.468,99.621l4.194,4.194c-2.964,2.964-7.058,4.797-11.581,4.797c-4.522,0-8.616-1.833-11.581-4.797
c-2.964-2.964-4.797-7.058-4.797-11.581s1.833-8.616,4.797-11.581c2.964-2.964,7.058-4.797,11.581-4.797
c4.522,0,8.616,1.833,11.581,4.797l-4.194,4.194c-1.89-1.891-4.502-3.061-7.386-3.061s-5.497,1.17-7.386,3.061
c-1.891,1.89-3.06,4.502-3.06,7.386c0,2.885,1.169,5.497,3.06,7.387c1.89,1.89,4.502,3.059,7.386,3.059
S445.577,101.511,447.468,99.621z"/>
<path fill="#07242D" d="M488.639,92.244c0,11.448,0,16.366,0,16.366h-5.96c0,0,0-10.733,0-16.366
c0-5.838-4.756-10.334-10.361-10.334c-5.607,0-10.382,4.446-10.382,10.334c0,5.637,0,16.366,0,16.366h-5.958v-46.24h5.958v17.255
c0,0,3.909-3.679,10.382-3.679C479.996,75.945,488.639,81.912,488.639,92.244z"/>
</g>
<g>
<path fill="#07242D" d="M180.326,58.699h3.129V39.263c0.01-0.171,0-0.344,0-0.517c0-4.751-3.841-8.602-8.592-8.602
c-4.751,0-8.602,3.851-8.602,8.602s3.851,8.602,8.602,8.602h0.435l3.164-3.15h-3.36h-0.239c-3.011,0-5.451-2.441-5.451-5.451
s2.441-5.451,5.451-5.451c3.011,0,5.463,2.441,5.463,5.451V58.699z"/>
<g>
<path fill="#07242D" d="M200.111,30.144v8.709c0,3.041-2.465,5.518-5.505,5.518c-3.041,0-5.508-2.477-5.508-5.518v-8.709h-3.049
v8.709c0,0,0,0,0,0.007c0,4.729,3.828,8.568,8.557,8.568c4.729,0,8.561-3.827,8.561-8.556c0-0.006,0-0.019,0-0.019v-8.709H200.111
z"/>
</g>
<g>
<path fill="#07242D" d="M163.154,35.833c-3.405-8.994-16.602-6.81-16.802,2.939c0.005,2.094,0.724,3.972,1.979,5.502
c1.472,1.787,3.646,2.973,6.101,3.134c0.189,0.012,0.379,0.019,0.57,0.019h8.665c0,0,0-8.656,0-8.655
C163.666,37.773,163.493,36.772,163.154,35.833z M160.464,44.267c0,0-3.937,0-5.455,0c-3.028,0-5.482-2.468-5.482-5.496
c0-1.517,0.617-2.877,1.613-3.87l0.001,0.001c3.386-3.431,9.345-1.024,9.324,3.869C160.464,40.289,160.464,44.267,160.464,44.267z
"/>
</g>
<g>
<path fill="#07242D" d="M222.563,35.833c-3.405-8.994-16.602-6.81-16.802,2.939c0.005,2.094,0.724,3.972,1.979,5.502
c1.472,1.787,3.646,2.973,6.101,3.134c0.189,0.012,0.379,0.019,0.57,0.019h8.665c0,0,0-8.656,0-8.655
C223.075,37.773,222.902,36.772,222.563,35.833z M219.873,44.267c0,0-3.938,0-5.455,0c-3.028,0-5.482-2.468-5.482-5.496
c0-1.517,0.617-2.877,1.613-3.87l0.001,0.001c3.386-3.431,9.345-1.024,9.324,3.869C219.873,40.289,219.873,44.267,219.873,44.267z
"/>
</g>
</g>
<path fill="#FFFFFF" d="M87.645,83.488h-8.361L62.969,66.992c-0.664,0.083-1.34,0.126-2.027,0.126v16.37h-5.959V37.246h5.959
c0,0-0.011,23.984,0,23.984c2.902,0,5.558-1.198,7.443-3.125l7.132-7.286h8.545L72.467,62.333c-1.027,1.028-2.192,1.921-3.462,2.646
L87.645,83.488z"/>
</svg>

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 136 KiB

35
docs/index.md Normal file
View File

@@ -0,0 +1,35 @@
[download]: https://img.shields.io/github/downloads/aquasecurity/kube-bench/total?logo=github
[release-img]: https://img.shields.io/github/release/aquasecurity/kube-bench.svg?logo=github
[release]: https://github.com/aquasecurity/kube-bench/releases
[docker-pull]: https://img.shields.io/docker/pulls/aquasec/kube-bench?logo=docker&label=docker%20pulls%20%2F%20kube-bench
[cov-img]: https://codecov.io/github/aquasecurity/kube-bench/branch/main/graph/badge.svg
[cov]: https://codecov.io/github/aquasecurity/kube-bench
[report-card-img]: https://goreportcard.com/badge/github.com/aquasecurity/kube-bench
[report-card]: https://goreportcard.com/report/github.com/aquasecurity/kube-bench
![Kube-bench Logo](images/kube-bench.jpg)
[![GitHub Release][release-img]][release]
![Downloads][download]
![Docker Pulls][docker-pull]
[![Go Report Card][report-card-img]][report-card]
[![Build Status](https://github.com/aquasecurity/kube-bench/workflows/Build/badge.svg?branch=main)](https://github.com/aquasecurity/kube-bench/actions)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/aquasecurity/kube-bench/blob/main/LICENSE)
[![Docker image](https://images.microbadger.com/badges/image/aquasec/kube-bench.svg)](https://microbadger.com/images/aquasec/kube-bench "Get your own image badge on microbadger.com")
[![Source commit](https://images.microbadger.com/badges/commit/aquasec/kube-bench.svg)](https://microbadger.com/images/aquasec/kube-bench)
[![Coverage Status][cov-img]][cov]
# Kube-bench
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.
1. kube-bench implements the [CIS Kubernetes Benchmark](https://www.cisecurity.org/benchmark/kubernetes/) as closely as possible. Please raise issues here if kube-bench is not correctly implementing the test as described in the Benchmark. To report issues in the Benchmark itself (for example, tests that you believe are inappropriate), please join the [CIS community](https://cisecurity.org).
1. There is not a one-to-one mapping between releases of Kubernetes and releases of the CIS benchmark. See [CIS Kubernetes Benchmark support](#cis-kubernetes-benchmark-support) to see which releases of Kubernetes are covered by different releases of the benchmark.
1. It is impossible to inspect the master nodes of managed clusters, e.g. GKE, EKS, AKS and ACK, using kube-bench as one does not have access to such nodes, although it is still possible to use kube-bench to check worker node configuration in these environments.
For help and more information go to our [github discussions q&a](https://github.com/aquasecurity/kube-bench/discussions/categories/q-a)

90
docs/installation.md Normal file
View File

@@ -0,0 +1,90 @@
## Installation
You can choose to
* Run kube-bench from inside a container (sharing PID namespace with the host). See [Running inside a container](./running.md#running-inside-a-container) for additional details.
* Run a container that installs kube-bench on the host, and then run kube-bench directly on the host. See [Installing from a container](#installing-from-a-container) for additional details.
* install the latest binaries from the [Releases page](https://github.com/aquasecurity/kube-bench/releases), though please note that you also need to download the config and test files from the `cfg` directory. See [Download and Install binaries](#download-and-install-binaries) for details.
* Compile it from source. See [Installing from sources](#installing-from-sources) for details.
### Download and Install binaries
It is possible to manually install and run kube-bench release binaries. In order to do that, you must have access to your Kubernetes cluster nodes. Note that if you're using one of the managed Kubernetes services (e.g. EKS, AKS, GKE, ACK, OCP), you will not have access to the master nodes of your cluster and you cant perform any tests on the master nodes.
First, log into one of the nodes using SSH.
Install kube-bench binary for your platform using the commands below. Note that there may be newer releases available. See [releases page](https://github.com/aquasecurity/kube-bench/releases).
Ubuntu/Debian:
```
curl -L https://github.com/aquasecurity/kube-bench/releases/download/v0.6.2/kube-bench_0.6.2_linux_amd64.deb -o kube-bench_0.6.2_linux_amd64.deb
sudo apt install ./kube-bench_0.6.2_linux_amd64.deb -f
```
RHEL:
```
curl -L https://github.com/aquasecurity/kube-bench/releases/download/v0.6.2/kube-bench_0.6.2_linux_amd64.rpm -o kube-bench_0.6.2_linux_amd64.rpm
sudo yum install kube-bench_0.6.2_linux_amd64.rpm -y
```
Alternatively, you can manually download and extract the kube-bench binary:
```
curl -L https://github.com/aquasecurity/kube-bench/releases/download/v0.6.2/kube-bench_0.6.2_linux_amd64.tar.gz -o kube-bench_0.6.2_linux_amd64.tar.gz
tar -xvf kube-bench_0.6.2_linux_amd64.tar.gz
```
You can then run kube-bench directly:
```
kube-bench
```
If you manually downloaded the kube-bench binary (using curl command above), you have to specify the location of configuration directory and file. For example:
```
./kube-bench --config-dir `pwd`/cfg --config `pwd`/cfg/config.yaml
```
See previous section on [Running kube-bench](./running.md#running-kube-bench) for further details on using the kube-bench binary.
### 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)) as per this example:
```shell
# Create a target directory for the clone, inside the $GOPATH
mkdir -p $GOPATH/src/github.com/aquasecurity/kube-bench
# Clone this repository, using SSH
git clone git@github.com:aquasecurity/kube-bench.git $GOPATH/src/github.com/aquasecurity/kube-bench
# Install the pre-requisites
go get github.com/aquasecurity/kube-bench
# Change to the kube-bench directory
cd $GOPATH/src/github.com/aquasecurity/kube-bench
# Build the kube-bench binary
go build -o kube-bench .
# See all supported options
./kube-bench --help
# Run all checks
./kube-bench
```
### Installing from a container
This command copies the kube-bench binary and configuration files to your host from the Docker container:
**binaries compiled for linux-x86-64 only (so they won't run on macOS or Windows)**
```
docker run --rm -v `pwd`:/host aquasec/kube-bench:latest install
```
You can then run `./kube-bench`.

17
docs/platforms.md Normal file
View File

@@ -0,0 +1,17 @@
## CIS Kubernetes Benchmark support
kube-bench supports running tests for Kubernetes.
Most of our supported benchmarks are defined in the [CIS Kubernetes Benchmarks](https://www.cisecurity.org/benchmark/kubernetes/).
Some defined by other hardenening guides.
| Source | Kubernetes Benchmark | kube-bench config | Kubernetes versions |
|---|---|---|---|
| CIS | [1.5.1](https://workbench.cisecurity.org/benchmarks/4892) | cis-1.5 | 1.15 |
| CIS | [1.6.0](https://workbench.cisecurity.org/benchmarks/4834) | cis-1.6 | 1.16-1.18 |
| CIS | [1.20](https://workbench.cisecurity.org/benchmarks/6246) | cis-1.20 | 1.19-1.20 |
| CIS | [GKE 1.0.0](https://workbench.cisecurity.org/benchmarks/4536) | gke-1.0 | GKE |
| CIS | [EKS 1.0.0](https://workbench.cisecurity.org/benchmarks/5190) | eks-1.0 | EKS |
| CIS | [ACK 1.0.0](https://workbench.cisecurity.org/benchmarks/6467) | ack-1.0 | ACK |
| RHEL | RedHat OpenShift hardening guide | rh-0.7 | OCP 3.10-3.11 |
| CIS | [OCP4 1.1.0](https://workbench.cisecurity.org/benchmarks/6778) | rh-1.0 | OCP 4.1- |

145
docs/running.md Normal file
View File

@@ -0,0 +1,145 @@
## Running kube-bench
If you run kube-bench directly from the command line you may need to be root / sudo to have access to all the config files.
By default kube-bench attempts to auto-detect the running version of Kubernetes, and map this to the corresponding CIS Benchmark version. For example, Kubernetes version 1.15 is mapped to CIS Benchmark version `cis-1.15` which is the benchmark version valid for Kubernetes 1.15.
kube-bench also attempts to identify the components running on the node, and uses this to determine which tests to run (for example, only running the master node tests if the node is running an API server).
**Please note**
It is impossible to inspect the master nodes of managed clusters, e.g. GKE, EKS, AKS and ACK, using kube-bench as one does not have access to such nodes, although it is still possible to use kube-bench to check worker node configuration in these environments.
### Running inside a container
You can avoid installing kube-bench on the host by running it inside a container using the host PID namespace and mounting the `/etc` and `/var` directories where the configuration and other files are located on the host so that kube-bench can check their existence and permissions.
```
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -t aquasec/kube-bench:latest --version 1.18
```
> Note: the tests require either the kubelet or kubectl binary in the path in order to auto-detect the Kubernetes version. You can pass `-v $(which kubectl):/usr/local/mount-from-host/bin/kubectl` to resolve this. You will also need to pass in kubeconfig credentials. For example:
```
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -v $(which kubectl):/usr/local/mount-from-host/bin/kubectl -v ~/.kube:/.kube -e KUBECONFIG=/.kube/config -t aquasec/kube-bench:latest
```
You can use your own configs by mounting them over the default ones in `/opt/kube-bench/cfg/`
```
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -t -v path/to/my-config.yaml:/opt/kube-bench/cfg/config.yaml -v $(which kubectl):/usr/local/mount-from-host/bin/kubectl -v ~/.kube:/.kube -e KUBECONFIG=/.kube/config aquasec/kube-bench:latest
```
### Running in a Kubernetes cluster
You can run kube-bench inside a pod, but it will need access to the host's PID namespace in order to check the running processes, as well as access to some directories on the host where config files and other files are stored.
The supplied `job.yaml` file can be applied to run the tests as a job. For example:
```bash
$ kubectl apply -f job.yaml
job.batch/kube-bench created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kube-bench-j76s9 0/1 ContainerCreating 0 3s
# Wait for a few seconds for the job to complete
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kube-bench-j76s9 0/1 Completed 0 11s
# The results are held in the pod's logs
kubectl logs kube-bench-j76s9
[INFO] 1 Master Node Security Configuration
[INFO] 1.1 API Server
...
```
To run tests on the master node, the pod needs to be scheduled on that node. This involves setting a nodeSelector and tolerations in the pod spec.
The default labels applied to master nodes has changed since Kubernetes 1.11, so if you are using an older version you may need to modify the nodeSelector and tolerations to run the job on the master node.
### Running in an AKS cluster
1. Create an AKS cluster(e.g. 1.13.7) with RBAC enabled, otherwise there would be 4 failures
1. Use the [kubectl-enter plugin](https://github.com/kvaps/kubectl-enter) to shell into a node
`
kubectl-enter {node-name}
`
or ssh to one agent node
could open nsg 22 port and assign a public ip for one agent node (only for testing purpose)
1. Run CIS benchmark to view results:
```
docker run --rm -v `pwd`:/host aquasec/kube-bench:latest install
./kube-bench
```
kube-bench cannot be run on AKS master nodes
### Running in an EKS cluster
There is a `job-eks.yaml` file for running the kube-bench node checks on an EKS cluster. The significant difference on EKS is that it's not possible to schedule jobs onto the master node, so master checks can't be performed
1. To create an EKS Cluster refer to [Getting Started with Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) in the *Amazon EKS User Guide*
- Information on configuring `eksctl`, `kubectl` and the AWS CLI is within
2. Create an [Amazon Elastic Container Registry (ECR)](https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html) repository to host the kube-bench container image
```
aws ecr create-repository --repository-name k8s/kube-bench --image-tag-mutability MUTABLE
```
3. Download, build and push the kube-bench container image to your ECR repo
```
git clone https://github.com/aquasecurity/kube-bench.git
cd kube-bench
aws ecr get-login-password --region <AWS_REGION> | docker login --username AWS --password-stdin <AWS_ACCT_NUMBER>.dkr.ecr.<AWS_REGION>.amazonaws.com
docker build -t k8s/kube-bench .
docker tag k8s/kube-bench:latest <AWS_ACCT_NUMBER>.dkr.ecr.<AWS_REGION>.amazonaws.com/k8s/kube-bench:latest
docker push <AWS_ACCT_NUMBER>.dkr.ecr.<AWS_REGION>.amazonaws.com/k8s/kube-bench:latest
```
4. Copy the URI of your pushed image, the URI format is like this: `<AWS_ACCT_NUMBER>.dkr.ecr.<AWS_REGION>.amazonaws.com/k8s/kube-bench:latest`
5. Replace the `image` value in `job-eks.yaml` with the URI from Step 4
6. Run the kube-bench job on a Pod in your Cluster: `kubectl apply -f job-eks.yaml`
7. Find the Pod that was created, it *should* be in the `default` namespace: `kubectl get pods --all-namespaces`
8. Retrieve the value of this Pod and output the report, note the Pod name will vary: `kubectl logs kube-bench-<value>`
- You can save the report for later reference: `kubectl logs kube-bench-<value> > kube-bench-report.txt`
### Running on OpenShift
| OpenShift Hardening Guide | kube-bench config |
|---|---|
| ocp-3.10 +| rh-0.7 |
| ocp-4.1 +| rh-1.0 |
kube-bench includes a set of test files for Red Hat's OpenShift hardening guide for OCP 3.10 and 4.1. To run this you will need to specify `--benchmark rh-07`, or `--version ocp-3.10` or,`--version ocp-4.5` or `--benchmark rh-1.0`
`kube-bench` supports auto-detection, when you run the `kube-bench` command it will autodetect if running in openshift environment.
### Running in a GKE cluster
| CIS Benchmark | Targets |
|---|---|
| gke-1.0| master, controlplane, node, etcd, policies, managedservices |
kube-bench includes benchmarks for GKE. To run this you will need to specify `--benchmark gke-1.0` when you run the `kube-bench` command.
To run the benchmark as a job in your GKE cluster apply the included `job-gke.yaml`.
```
kubectl apply -f job-gke.yaml
```
### Running in a ACK cluster
| CIS Benchmark | Targets |
|---|---|
| ack-1.0| master, controlplane, node, etcd, policies, managedservices |
kube-bench includes benchmarks for Alibaba Cloud Container Service For Kubernetes (ACK).
To run this you will need to specify `--benchmark ack-1.0` when you run the `kube-bench` command.
To run the benchmark as a job in your ACK cluster apply the included `job-ack.yaml`.
```
kubectl apply -f job-ack.yaml
```

39
go.mod
View File

@@ -1,32 +1,19 @@
module github.com/aquasecurity/kube-bench
go 1.13
go 1.16
require (
github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 // indirect
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect
github.com/fatih/color v1.5.0
github.com/go-sql-driver/mysql v1.4.1 // indirect
github.com/aws/aws-sdk-go v1.40.51
github.com/fatih/color v1.13.0
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/imdario/mergo v0.3.5 // indirect
github.com/jinzhu/gorm v0.0.0-20160404144928-5174cc5c242a
github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d // indirect
github.com/jinzhu/now v1.0.1 // indirect
github.com/lib/pq v0.0.0-20171126050459-83612a56d3dd // indirect
github.com/mattn/go-colorable v0.0.0-20170210172801-5411d3eea597 // indirect
github.com/mattn/go-isatty v0.0.0-20170307163044-57fdcb988a5c // indirect
github.com/mattn/go-sqlite3 v1.10.0 // indirect
github.com/onsi/ginkgo v1.10.1
github.com/pkg/errors v0.8.1
github.com/spf13/cobra v0.0.3
github.com/spf13/viper v1.4.0
github.com/stretchr/testify v1.3.0
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a // indirect
google.golang.org/appengine v1.5.0 // indirect
gopkg.in/yaml.v2 v2.2.4
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d
k8s.io/client-go v11.0.0+incompatible
k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6 // indirect
sigs.k8s.io/kind v0.5.1
github.com/magiconair/properties v1.8.5
github.com/onsi/ginkgo v1.16.4
github.com/pkg/errors v0.9.1
github.com/spf13/cobra v1.2.1
github.com/spf13/viper v1.9.0
github.com/stretchr/testify v1.7.0
gopkg.in/yaml.v2 v2.4.0
gorm.io/driver/postgres v1.1.1
gorm.io/gorm v1.21.15
k8s.io/client-go v0.22.2
)

1033
go.sum

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Some files were not shown because too many files have changed in this diff Show More