diff --git a/.gitignore b/.gitignore index 9f11b75..f32e31a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea/ +.DS_Store diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9ac9f33 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +all: Compliance + +clean: + -rm ./compliance + +Compliance: + go build -o compliance + +.PHONY: clean \ No newline at end of file diff --git a/compliance b/compliance new file mode 100755 index 0000000..fb00df3 Binary files /dev/null and b/compliance differ diff --git a/config.go b/config.go index 3f12fec..9941a7b 100644 --- a/config.go +++ b/config.go @@ -1,4 +1,4 @@ -package compliance +package main import ( "encoding/json" @@ -10,9 +10,10 @@ type Script struct { Files []string `json:"files"` Name string `json:"name"` Desc string `json:"desc"` + Vars []string `json:"variables"` } -const configFile = "config.json" +const configFile = "/usr/local/bin/compliance_check/config.json" func LoadConfig() (map[string]Script, error) { configFile, err := os.Open(configFile) diff --git a/config.json b/config.json index 013fa37..353caac 100644 --- a/config.json +++ b/config.json @@ -1,32 +1,67 @@ { - "dockerCheckPrerequisites": { + + "hipaa": { "files": [ - "scripts/host.tmpl" + "/usr/local/bin/compliance_check/scripts/hipaa.sh" ], - "name": "Docker Bench Tests", - "desc": "Docker CIS benchmark tests" + "name": "HIPAA Compliance Checks", + "desc": "HIPAA Compliance Checks", + "variables": ["pathPrefix"] }, - "kubeBench1.6.0": { + "pci": { "files": [ - "kube_master_1_6_0.tmpl", - "kube_worker_1_6_0.tmpl" + "/usr/local/bin/compliance_check/scripts/pci.sh" ], - "name": "Kubernetes 1.6.0 Bench Test", - "desc": "Bench Test for Kube 1.6.0", - "conditions": { - "version": "1.6.0" - } + "name": "PCI Compliance Checks", + "desc": "PCI Compliance Checks", + "variables": ["pathPrefix"] }, - "kubeBench1.5.1": { + "gdpr": { "files": [ - "kube_master_1_5_1.tmpl", - "kube_worker_1_5_1.tmpl" + "/usr/local/bin/compliance_check/scripts/gdpr.sh" ], - "name": "Kubernetes 1.5.1 Bench Test", - "desc": "Bench Test for Kube 1.5.1", - "conditions": { - "version": "1.5.1", - "isKubeMaster": true - } + "name": "GDPR Compliance Checks", + "desc": "GDPR Compliance Checks", + "variables": ["pathPrefix"] + }, + "nist": { + "files": [ + "/usr/local/bin/compliance_check/scripts/nist.sh" + ], + "name": "NIST Compliance Checks", + "desc": "NIST Compliance Checks", + "variables": ["pathPrefix"] + }, + "hipaakube": { + "files": [ + "/usr/local/bin/compliance_check/scripts/hipaakube.sh" + ], + "name": "HIPAA Compliance Checks", + "desc": "HIPAA Compliance Checks", + "variables": ["pathPrefix", "NODE_TYPE"] + }, + "pcikube": { + "files": [ + "/usr/local/bin/compliance_check/scripts/pcikube.sh" + ], + "name": "PCI Compliance Checks", + "desc": "PCI Compliance Checks", + "variables": ["pathPrefix", "NODE_TYPE"] + }, + "gdprkube": { + "files": [ + "/usr/local/bin/compliance_check/scripts/gdprkube.sh" + ], + "name": "GDPR Compliance Checks", + "desc": "GDPR Compliance Checks", + "variables": ["pathPrefix", "NODE_TYPE"] + }, + "nistkube": { + "files": [ + "/usr/local/bin/compliance_check/scripts/nistkube.sh" + ], + "name": "NIST Compliance Checks", + "desc": "NIST Compliance Checks", + "variables": ["pathPrefix", "NODE_TYPE"] } } \ No newline at end of file diff --git a/executor.go b/executor.go index 7aabcd0..741c9e6 100644 --- a/executor.go +++ b/executor.go @@ -1,11 +1,10 @@ -package compliance +package main import ( "bufio" "bytes" + "encoding/json" "fmt" - "github.com/deepfence/compliance/global" - "github.com/deepfence/compliance/share" log "github.com/sirupsen/logrus" "io/ioutil" "os" @@ -27,85 +26,45 @@ type DockerReplaceOpts struct { } type benchItem struct { - level string - testNum string - group string - header string - profile string // level 1, 2 - scored bool - automated bool - message []string - remediation string + Level string + TestNum string + Group string + Header string + Profile string // level 1, 2 + Scored bool + Automated bool + Message string + Remediation string + RemediationImpact string + TestCategory string } -func (b *Bench) runScript() { - /*var errb, outb bytes.Buffer - args := []string{ - system.NSActRun, "-f", script, - "-m", global.SYS.GetMountNamespacePath(1), - "-n", global.SYS.GetNetNamespacePath(1), - } - log.WithFields(log.Fields{"type": bench}).Debug("Running Kubernetes CIS bench") - cmd := exec.Command(system.ExecNSTool, args...) - cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} - cmd.Stdout = &outb - cmd.Stderr = &errb - b.childCmd = cmd - err := cmd.Start() - if err != nil { - log.WithFields(log.Fields{"error": err, "msg": errb.String()}).Error("Start") - return nil, err - } - pgid := cmd.Process.Pid - global.SYS.AddToolProcess(pgid, 1, "kube-bench", script) - err = cmd.Wait() - global.SYS.RemoveToolProcess(pgid, false) - out := outb.Bytes() +func (b *Bench) RunScripts() ([]byte, error) { + for _, destPath := range b.script.Files { - b.childCmd = nil - if err != nil { - if ee, ok := err.(*exec.ExitError); ok { - status := global.SYS.GetExitStatus(ee) - if status == 2 { - // Not a master or worker node, ignore the error - log.WithFields(log.Fields{"msg": errb.String()}).Debug("Done") - return nil, fmt.Errorf("Node type not recognized") + var errb, outb bytes.Buffer + //fmt.Println(args) + cmd := exec.Command("bash", destPath) + cmd.Env = os.Environ() + for _, variable := range b.script.Vars { + value := os.Getenv(variable) + if value != "" { + fmt.Println("Applying env variable:" + variable + "with value: " + value) + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", variable, value)) } } - - log.WithFields(log.Fields{"error": err, "msg": errb.String()}).Error("") - return nil, err - } - - log.WithFields(log.Fields{"type": bench}).Debug("Finish Kubernetes CIS bench") - return out, nil*/ -} - -func (b *Bench) RunScripts() ([]byte, error) { - for _, tmplFile := range b.script.Files { - destPath := strings.Replace(tmplFile, ".tmpl", ".sh", -1) - err := b.replaceTemplateVars(tmplFile, destPath, nil) - if err != nil { - return nil, err - } - args := []string{"run", "-f", destPath, - "-m", global.SYS.GetMountNamespacePath(1), "-n", global.SYS.GetNetNamespacePath(1)} - var errb, outb bytes.Buffer - cmd := exec.Command("/usr/local/bin/nstools", args...) cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} cmd.Stdout = &outb cmd.Stderr = &errb b.childCmd = cmd - err = cmd.Start() + err := cmd.Start() if err != nil { log.WithFields(log.Fields{"error": err, "msg": errb.String()}).Error("Start") return nil, err } - pgid := cmd.Process.Pid // global.SYS.AddToolProcess(pgid, 1, "host-bench", destPath) err = cmd.Wait() - global.SYS.RemoveToolProcess(pgid, false) out := outb.Bytes() b.childCmd = nil @@ -117,9 +76,15 @@ func (b *Bench) RunScripts() ([]byte, error) { return nil, err } items := b.getBenchMsg(out) - fmt.Println("Sending items to stdout:") + // fmt.Println("Sending items to stdout:") for _, item := range items { - fmt.Println(item) + //fmt.Println(item) + s, err := json.Marshal(item) + if err == nil { + fmt.Println(string(s)) + } else { + fmt.Println(err.Error()) + } } return out, nil } @@ -160,35 +125,16 @@ func (b *Bench) replaceTemplateVars(srcPath, dstPath string, containers []string return nil } -func (b *Bench) getBenchMsg(out []byte) []*benchItem { - list := make([]*benchItem, 0) +func (b *Bench) getBenchMsg(out []byte) []benchItem { + list := make([]benchItem, 0) scanner := bufio.NewScanner(strings.NewReader(string(out))) - var last, item *benchItem for scanner.Scan() { // Read output line-by-line. Every check forms a item, // the first line is the header and the rest form the message line := scanner.Text() - if c, ok := b.parseBenchMsg(line); ok { - if c.testNum == "" && item != nil { - item.message = append(item.message, c.header) - } else { - if item != nil { - // add the last item to the result - if b.acceptBenchItem(last, item) { - list = append(list, last) - } - last = item - } - item = c - } - } - } - if item != nil { - // add the last item to the result - if b.acceptBenchItem(last, item) { - list = append(list, last) - } - if b.acceptBenchItem(item, nil) { + var item benchItem + err := json.Unmarshal([]byte(line), &item) + if err == nil && b.acceptBenchItem(&item, nil) { list = append(list, item) } } @@ -197,16 +143,16 @@ func (b *Bench) getBenchMsg(out []byte) []*benchItem { // check if last item should be accepted or ignored func (b *Bench) acceptBenchItem(last, item *benchItem) bool { - if last == nil { + /*if last == nil { return false } // 1.2 should be ignored if the next line has 1.2. prefix - if item != nil && strings.HasPrefix(item.testNum, fmt.Sprintf("%s.", last.testNum)) { + if item != nil && strings.HasPrefix(item.TestNum, fmt.Sprintf("%s.", last.TestNum)) { return false } // Ignore NOTE and INFO entries - if last.level == share.BenchLevelNote || last.level == share.BenchLevelInfo { + if last.Level == share.BenchLevelNote || last.Level == share.BenchLevelInfo { return false - } + }*/ return true } \ No newline at end of file diff --git a/go.mod b/go.mod index cf67230..c817299 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,31 @@ replace github.com/kubernetes/cri-api => k8s.io/cri-api v0.22.3 require ( github.com/aws/aws-sdk-go v1.42.22 + github.com/golang/protobuf v1.5.2 github.com/sirupsen/logrus v1.8.1 github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 + k8s.io/api v0.23.6 // github.com/zcalusic/sysinfo latest ) -require golang.org/x/sys v0.0.0-20210423082822-04245dca01da // indirect +require ( + github.com/go-logr/logr v1.2.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/go-cmp v0.5.5 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect + golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e // indirect + golang.org/x/text v0.3.7 // indirect + google.golang.org/protobuf v1.27.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + k8s.io/apimachinery v0.23.6 // indirect + k8s.io/klog/v2 v2.30.0 // indirect + k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect + sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect +) diff --git a/go.sum b/go.sum index f53884a..041d2f3 100644 --- a/go.sum +++ b/go.sum @@ -1,33 +1,261 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.42.22 h1:EwcM7/+Ytg6xK+jbeM2+f9OELHqPiEiEKetT/GgAr7I= github.com/aws/aws-sdk-go v1.42.22/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e h1:XMgFehsDnnLGtjvjOfqWSUzt0alpTR1RSEuznObga2c= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.23.6 h1:yOK34wbYECH4RsJbQ9sfkFK3O7f/DUHRlzFehkqZyVw= +k8s.io/api v0.23.6/go.mod h1:1kFaYxGCFHYp3qd6a85DAj/yW8aVD6XLZMqJclkoi9g= +k8s.io/apimachinery v0.23.6 h1:RH1UweWJkWNTlFx0D8uxOpaU1tjIOvVVWV/bu5b3/NQ= +k8s.io/apimachinery v0.23.6/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/main.go b/main.go index 428cd0a..2177ce5 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,4 @@ -package compliance +package main import ( "flag" @@ -7,6 +7,8 @@ import ( func main() { benchId := flag.String("bench-id", "", "The id of set of scripts to be run for compliance check") + flag.String("NODE_TYPE", "", "Kubernetes node role master/worker") + flag.Parse() config, err := LoadConfig() if err != nil { return diff --git a/result_parser.go b/result_parser.go index 1c828bd..6471548 100644 --- a/result_parser.go +++ b/result_parser.go @@ -1,4 +1,4 @@ -package compliance +package main import ( "github.com/deepfence/compliance/share" @@ -62,7 +62,7 @@ func (b *Bench) parseBenchMsg(line string) (*benchItem, bool) { msg = strings.TrimSpace(msg) return &benchItem{ - level: level, testNum: id, header: msg, - scored: scored, automated: automated, profile: profile, + Level: level, TestNum: id, Header: msg, + Scored: scored, Automated: automated, Profile: profile, }, true } \ No newline at end of file diff --git a/scripts/common.sh b/scripts/common.sh new file mode 100644 index 0000000..72f8a96 --- /dev/null +++ b/scripts/common.sh @@ -0,0 +1,336 @@ + +bldred='\033[1;31m' # Bold Red +bldgrn='\033[1;32m' # Bold Green +bldblu='\033[1;34m' # Bold Blue +bldylw='\033[1;33m' # Bold Yellow +txtrst='\033[0m' +logger="output.log" + +if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then + bldred='' + bldgrn='' + bldblu='' + bldylw='' + txtrst='' +fi + +logit () { + printf "%b\n" "$1" | tee -a "$logger" +} + +info () { + local infoCountCheck + local OPTIND c + while getopts c args + do + case $args in + c) infoCountCheck="true" ;; + *) exit 1 ;; + esac + done + if [ "$infoCountCheck" = "true" ]; then + printf "%b\n" "${bldblu}[INFO]${txtrst} $2" | tee -a "$logger" + totalChecks=$((totalChecks + 1)) + return + fi + printf "%b\n" "${bldblu}[INFO]${txtrst} $1" | tee -a "$logger" +} + +pass () { + local passScored + local passCountCheck + local OPTIND s c + while getopts sc args + do + case $args in + s) passScored="true" ;; + c) passCountCheck="true" ;; + *) exit 1 ;; + esac + done + if [ "$passScored" = "true" ] || [ "$passCountCheck" = "true" ]; then + printf "%b\n" "${bldgrn}[PASS]${txtrst} $2" | tee -a "$logger" + totalChecks=$((totalChecks + 1)) + fi + if [ "$passScored" = "true" ]; then + currentScore=$((currentScore + 1)) + fi + if [ "$passScored" != "true" ] && [ "$passCountCheck" != "true" ]; then + printf "%b\n" "${bldgrn}[PASS]${txtrst} $1" | tee -a "$logger" + fi +} + +warn () { + local warnScored + local OPTIND s + while getopts s args + do + case $args in + s) warnScored="true" ;; + *) exit 1 ;; + esac + done + if [ "$warnScored" = "true" ]; then + printf "%b\n" "${bldred}[WARN]${txtrst} $2" | tee -a "$logger" + totalChecks=$((totalChecks + 1)) + currentScore=$((currentScore - 1)) + return + fi + printf "%b\n" "${bldred}[WARN]${txtrst} $1" | tee -a "$logger" +} + +note () { + local noteCountCheck + local OPTIND c + while getopts c args + do + case $args in + c) noteCountCheck="true" ;; + *) exit 1 ;; + esac + done + if [ "$noteCountCheck" = "true" ]; then + printf "%b\n" "${bldylw}[NOTE]${txtrst} $2" | tee -a "$logger" + totalChecks=$((totalChecks + 1)) + return + fi + printf "%b\n" "${bldylw}[NOTE]${txtrst} $1" | tee -a "$logger" +} + +logbenchjson () { + printf "{\"Level\":\"%s\",\"TestNum\":\"%s\",\"TestCategory\":\"%s\",\"Header\":\"%s\",\"Message\":\"%s\",\"Remediation\":\"%s\",\"RemediationImpact\":\"%s\"}\n" "$1" "$2" "$3" "$4" "$5" "$6" "$7" | tee -a "$logger" +} + +yell () { + printf "%b\n" "${bldylw}$1${txtrst}\n" +} + +beginjson () { + printf "{\n \"dockerbenchsecurity\": \"%s\",\n \"start\": %s,\n \"tests\": [" "$1" "$2" | tee "$logger.json" 2>/dev/null 1>&2 +} + +endjson (){ + printf "\n ],\n \"checks\": %s,\n \"score\": %s,\n \"end\": %s\n}" "$1" "$2" "$3" | tee -a "$logger.json" 2>/dev/null 1>&2 +} + +logjson (){ + printf "\n \"%s\": \"%s\"," "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2 +} + +SSEP= +SEP= +startsectionjson() { + printf "%s\n {\n \"id\": \"%s\",\n \"desc\": \"%s\",\n \"results\": [" "$SSEP" "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2 + SEP= + SSEP="," +} + +endsectionjson() { + printf "\n ]\n }" | tee -a "$logger.json" 2>/dev/null 1>&2 +} + +starttestjson() { + printf "%s\n {\n \"id\": \"%s\",\n \"desc\": \"%s\",\n " "$SEP" "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2 + SEP="," +} + +log_to_json() { + if [ $# -eq 1 ]; then + printf "\"result\": \"%s\"" "$1" | tee -a "$logger.json" 2>/dev/null 1>&2 + return + fi + if [ $# -eq 2 ] && [ $# -ne 1 ]; then + # Result also contains details + printf "\"result\": \"%s\",\n \"details\": \"%s\"" "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2 + return + fi + # Result also includes details and a list of items. Add that directly to details and to an array property "items" + # Also limit the number of items to $limit, if $limit is non-zero + truncItems=$3 + if [ "$limit" != 0 ]; then + truncItems="" + ITEM_COUNT=0 + for item in $3; do + truncItems="$truncItems $item" + ITEM_COUNT=$((ITEM_COUNT + 1)); + if [ "$ITEM_COUNT" == "$limit" ]; then + truncItems="$truncItems (truncated)" + break; + fi + done + fi + itemsJson=$(printf "[\n "; ISEP=""; ITEMCOUNT=0; for item in $truncItems; do printf "%s\"%s\"" "$ISEP" "$item"; ISEP=","; done; printf "\n ]") + printf "\"result\": \"%s\",\n \"details\": \"%s: %s\",\n \"items\": %s" "$1" "$2" "$truncItems" "$itemsJson" | tee -a "$logger.json" 2>/dev/null 1>&2 +} + +logcheckresult() { + # Log to JSON + log_to_json "$@" + + # Log remediation measure to JSON + if [ -n "$remediation" ] && [ "$1" != "PASS" ] && [ "$printremediation" = "1" ]; then + printf ",\n \"remediation\": \"%s\"" "$remediation" | tee -a "$logger.json" 2>/dev/null 1>&2 + if [ -n "$remediationImpact" ]; then + printf ",\n \"remediation-impact\": \"%s\"" "$remediationImpact" | tee -a "$logger.json" 2>/dev/null 1>&2 + fi + fi + printf "\n }" | tee -a "$logger.json" 2>/dev/null 1>&2 + + # Save remediation measure for print log to stdout + if [ -n "$remediation" ] && [ "$1" != "PASS" ]; then + if [ -n "${checkHeader}" ]; then + if [ -n "${addSpaceHeader}" ]; then + globalRemediation="${globalRemediation}\n" + fi + globalRemediation="${globalRemediation}\n${bldblu}[INFO]${txtrst} ${checkHeader}" + checkHeader="" + addSpaceHeader="1" + fi + globalRemediation="${globalRemediation}\n${bldblu}[INFO]${txtrst} ${id} - ${remediation}" + if [ -n "${remediationImpact}" ]; then + globalRemediation="${globalRemediation} Remediation Impact: ${remediationImpact}" + fi + fi +} + + +# Compares versions of software of the format X.Y.Z +do_version_check() { + [ "$1" = "$2" ] && return 10 + + ver1front=$(printf "%s" "$1" | cut -d "." -f -1) + ver1back=$(printf "%s" "$1" | cut -d "." -f 2-) + ver2front=$(printf "%s" "$2" | cut -d "." -f -1) + ver2back=$(printf "%s" "$2" | cut -d "." -f 2-) + + if [ "$ver1front" != "$1" ] || [ "$ver2front" != "$2" ]; then + [ "$ver1front" -gt "$ver2front" ] && return 11 + [ "$ver1front" -lt "$ver2front" ] && return 9 + + [ "$ver1front" = "$1" ] || [ -z "$ver1back" ] && ver1back=0 + [ "$ver2front" = "$2" ] || [ -z "$ver2back" ] && ver2back=0 + do_version_check "$ver1back" "$ver2back" + return $? + fi + [ "$1" -gt "$2" ] && return 11 || return 9 +} + +# Extracts commandline args from the newest running processes named like the first parameter +get_command_line_args() { + PROC="$1" + + for PID in $(pgrep -f -n "$PROC"); do + tr "\0" " " < /proc/"$PID"/cmdline + done +} + +# Extract the cumulative command line arguments for the docker daemon +# +# If specified multiple times, all matches are returned. +# Accounts for long and short variants, call with short option. +# Does not account for option defaults or implicit options. +get_docker_cumulative_command_line_args() { + OPTION="$1" + + line_arg="dockerd" + if ! get_command_line_args "docker daemon" >/dev/null 2>&1 ; then + line_arg="docker daemon" + fi + + echo "<<<.Replace_docker_daemon_opts>>>" | + # normalize known long options to their short versions + sed \ + -e 's/\-\-debug/-D/g' \ + -e 's/\-\-host/-H/g' \ + -e 's/\-\-log-level/-l/g' \ + -e 's/\-\-version/-v/g' \ + | + # normalize parameters separated by space(s) to -O=VALUE + sed \ + -e 's/\-\([DHlv]\)[= ]\([^- ][^ ]\)/-\1=\2/g' \ + | + # get the last interesting option + tr ' ' "\n" | + grep "^${OPTION}" | + # normalize quoting of values + sed \ + -e 's/"//g' \ + -e "s/'//g" +} + +# Extract the effective command line arguments for the docker daemon +# +# Accounts for multiple specifications, takes the last option. +# Accounts for long and short variants, call with short option +# Does not account for option default or implicit options. +get_docker_effective_command_line_args() { + OPTION="$1" + get_docker_cumulative_command_line_args "$OPTION" | tail -n1 +} + +get_docker_configuration_file() { + FILE="$(get_docker_effective_command_line_args '--config-file' | \ + sed 's/.*=//g')" + + if [ -f "$FILE" ]; then + CONFIG_FILE="$FILE" + return + fi + if [ -f '/etc/docker/daemon.json' ]; then + CONFIG_FILE='/etc/docker/daemon.json' + return + fi + CONFIG_FILE='/dev/null' +} + +get_docker_configuration_file_args() { + OPTION="$1" + + get_docker_configuration_file + + grep "$OPTION" "$CONFIG_FILE" | sed 's/.*://g' | tr -d '" ', +} + +get_service_file() { + SERVICE="$1" + + if [ -f "/etc/systemd/system/$SERVICE" ]; then + echo "/etc/systemd/system/$SERVICE" + return + fi + if [ -f "/lib/systemd/system/$SERVICE" ]; then + echo "/lib/systemd/system/$SERVICE" + return + fi + if systemctl show -p FragmentPath "$SERVICE" 2> /dev/null 1>&2; then + systemctl show -p FragmentPath "$SERVICE" | sed 's/.*=//' + return + fi + echo "/usr/lib/systemd/system/$SERVICE" +} + +#get an argument value from command line +get_argument_value() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" | + sed \ + -e "s/^${OPTION}=//g" +} + +#check whether an argument exist in command line +check_argument() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" +} \ No newline at end of file diff --git a/scripts/docker-bench-security/.dockerignore b/scripts/docker-bench-security/.dockerignore new file mode 100644 index 0000000..8abc26a --- /dev/null +++ b/scripts/docker-bench-security/.dockerignore @@ -0,0 +1,6 @@ +* +!docker-bench-security.sh +!functions/ +!tests/ +!log/ +log/* diff --git a/scripts/docker-bench-security/.gitignore b/scripts/docker-bench-security/.gitignore new file mode 100644 index 0000000..b783cca --- /dev/null +++ b/scripts/docker-bench-security/.gitignore @@ -0,0 +1,2 @@ +log/* +*.swp* diff --git a/scripts/docker-bench-security/CONTRIBUTING.md b/scripts/docker-bench-security/CONTRIBUTING.md new file mode 100644 index 0000000..f850b01 --- /dev/null +++ b/scripts/docker-bench-security/CONTRIBUTING.md @@ -0,0 +1,58 @@ +# Contributing to Docker Bench for Security + +Want to hack on Docker Bench? Awesome! Here are instructions to get you +started. + +The Docker Bench for Security is a part of the [Docker](https://www.docker.com) +project, and follows the same rules and principles. If you're already familiar +with the way Docker does things, you'll feel right at home. + +Otherwise, go read +[Contribute to the Moby Project](https://github.com/moby/moby/blob/master/CONTRIBUTING.md). + +## Development Environment Setup + +### Start hacking + +You can build the container that wraps the docker-bench for security: + +```sh +git clone git@github.com:docker/docker-bench-security.git +cd docker-bench-security +docker build -t docker-bench-security . +``` + +Or you can simply run the shell script locally: + +```sh +git clone git@github.com:docker/docker-bench-security.git +cd docker-bench-security +sudo sh docker-bench-security.sh +``` + +The Docker Bench has the main script called `docker-bench-security.sh`. +This is the main script that checks for all the dependencies, deals with +command line arguments and loads all the tests. + +The tests are split into the following files: + +```sh +tests/ +├── 1_host_configuration.sh +├── 2_docker_daemon_configuration.sh +├── 3_docker_daemon_configuration_files.sh +├── 4_container_images.sh +├── 5_container_runtime.sh +├── 6_docker_security_operations.sh +├── 7_docker_swarm_configuration.sh +├── 8_docker_enterprise_configuration.sh +└── 99_community_checks.sh +``` + +To modify the Docker Bench for Security you should first clone the repository, +make your changes, check your code with `shellcheck`, or similar tools, and +then sign off on your commits. After that feel free to send us a pull request +with the changes. + +While this tool was inspired by the [CIS Docker 1.11.0 benchmark](https://www.cisecurity.org/benchmark/docker/) +and its successors, feel free to add new tests. diff --git a/scripts/docker-bench-security/CONTRIBUTORS.md b/scripts/docker-bench-security/CONTRIBUTORS.md new file mode 100644 index 0000000..ca9fcb6 --- /dev/null +++ b/scripts/docker-bench-security/CONTRIBUTORS.md @@ -0,0 +1,58 @@ +The following people, listed in alphabetical order, have contributed to docker-bench-security: + +* alberto +* Andreas Stieger +* Anthony Roger +* Aurélien Gasser +* binary +* Boris Gorbylev +* Cheng-Li Jerry Ma +* Csaba Palfi +* Daniele Marcocci +* Dhawal Patel +* Diogo Monica +* Diogo Mónica +* Ernst de Haan +* HuKeping +* Ivan Angelov +* J0WI +* jammasterj89 +* Jessica Frazelle +* Joachim Lusiardi +* Joachim Lusiardi +* Joachim Lusiardi +* Joe Williams +* Julien Garcia Gonzalez +* Jürgen Hermann +* kakakakakku +* Karol Babioch +* Kevin Lim +* kevinll +* Liron Levin +* liron-l +* LorensK +* lusitania +* Maik Ellerbrock +* Mark Stemm +* Matt Fellows +* Michael Crosby +* Michael Stahn +* Mike Ritter +* Mr. Secure +* MrSecure +* Nigel Brown +* Paul Czarkowski +* Paul Morgan +* Pete Sellars +* Peter +* Ravi Kumar Vadapalli +* Scott McCarty +* Sebastiaan van Stijn +* telepresencebot2 +* Thomas Sjögren +* Tom Partington +* Werner Buck +* will Farrell +* Zvi "Viz" Effron + +This list was generated Tue Nov 5 09:45:35 UTC 2019. diff --git a/scripts/docker-bench-security/Dockerfile b/scripts/docker-bench-security/Dockerfile new file mode 100644 index 0000000..5c2f48c --- /dev/null +++ b/scripts/docker-bench-security/Dockerfile @@ -0,0 +1,19 @@ +FROM alpine:3.13 + +LABEL \ + org.label-schema.name="docker-bench-security" \ + org.label-schema.url="https://dockerbench.com" \ + org.label-schema.vcs-url="https://github.com/docker/docker-bench-security.git" + +RUN apk add --no-cache iproute2 \ + docker-cli \ + dumb-init + +COPY . /usr/local/bin/ + +HEALTHCHECK CMD exit 0 + +WORKDIR /usr/local/bin + +ENTRYPOINT [ "/usr/bin/dumb-init", "/bin/sh", "docker-bench-security.sh" ] +CMD [""] diff --git a/scripts/docker-bench-security/LICENSE.md b/scripts/docker-bench-security/LICENSE.md new file mode 100644 index 0000000..34fc18b --- /dev/null +++ b/scripts/docker-bench-security/LICENSE.md @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2015 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/scripts/docker-bench-security/MAINTAINERS b/scripts/docker-bench-security/MAINTAINERS new file mode 100644 index 0000000..bd38003 --- /dev/null +++ b/scripts/docker-bench-security/MAINTAINERS @@ -0,0 +1,34 @@ +# Docker Bench for Security maintainers file +# +# This file describes who runs the docker/docker-bench-security project and how. +# This is a living document - if you see something out of date or missing, speak up! +# +# It is structured to be consumable by both humans and programs. +# To extract its contents programmatically, use any TOML-compliant parser. +# +# This file is compiled into the MAINTAINERS file in docker/opensource. +# +[Org] + [Org."Core maintainers"] + people = [ + "diogomonica", + "konstruktoid", + ] + +[people] + +# A reference list of all people associated with the project. +# All other sections should refer to people by their canonical key +# in the people section. + + # ADD YOURSELF HERE IN ALPHABETICAL ORDER + + [people.diogomonica] + Name = "Dr. Diogo Mónica" + Email = "diogo@docker.com" + GitHub = "diogomonica" + + [people.konstruktoid] + Name = "Thomas Sjögren" + Email = "thomas.sjogren@protonmail.com" + GitHub = "konstruktoid" diff --git a/scripts/docker-bench-security/README.md b/scripts/docker-bench-security/README.md new file mode 100644 index 0000000..703a544 --- /dev/null +++ b/scripts/docker-bench-security/README.md @@ -0,0 +1,138 @@ +# Docker Bench for Security + +![Docker Bench for Security running](img/benchmark_log.png) + +The Docker Bench for Security is a script that checks for dozens of common best-practices around deploying Docker containers in production. The tests are all automated, and are based on the [CIS Docker Benchmark v1.3.1](https://www.cisecurity.org/benchmark/docker/). + +We are making this available as an open-source utility so the Docker community can have an easy way to self-assess their hosts and docker containers against this benchmark. + +## Running Docker Bench for Security + +### Run from your base host + +You can simply run this script from your base host by running: + +```sh +git clone https://github.com/docker/docker-bench-security.git +cd docker-bench-security +sudo sh docker-bench-security.sh +``` + +### Run with Docker + +We packaged docker bench as a small container for your convenience. Note that this container is being run with a *lot* of privilege -- sharing the host's filesystem, pid and network namespaces, due to portions of the benchmark applying to the running host. + +The easiest way to run your hosts against the Docker Bench for Security is by running our pre-built container: + +```sh +docker run --rm --net host --pid host --userns host --cap-add audit_control \ + -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \ + -v /etc:/etc:ro \ + -v /usr/bin/containerd:/usr/bin/containerd:ro \ + -v /usr/bin/runc:/usr/bin/runc:ro \ + -v /usr/lib/systemd:/usr/lib/systemd:ro \ + -v /var/lib:/var/lib:ro \ + -v /var/run/docker.sock:/var/run/docker.sock:ro \ + --label docker_bench_security \ + docker/docker-bench-security +``` + +Don't forget to adjust the shared volumes according to your operating system. +Some examples are: + +1. On Ubuntu the `docker.service` and `docker.secret` files are located in + `/lib/systemd/system` folder by default. + +```sh +docker run --rm --net host --pid host --userns host --cap-add audit_control \ + -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \ + -v /etc:/etc:ro \ + -v /lib/systemd/system:/lib/systemd/system:ro \ + -v /usr/bin/containerd:/usr/bin/containerd:ro \ + -v /usr/bin/runc:/usr/bin/runc:ro \ + -v /usr/lib/systemd:/usr/lib/systemd:ro \ + -v /var/lib:/var/lib:ro \ + -v /var/run/docker.sock:/var/run/docker.sock:ro \ + --label docker_bench_security \ + docker/docker-bench-security +``` + +2. The /etc/hostname file is missing on macOS, so it will need to be created first. Also, `Docker Desktop` on macOS doesn't have `/usr/lib/systemd` or the above Docker + binaries. + +```sh +sudo touch /etc/hostname + +docker run --rm --net host --pid host --userns host --cap-add audit_control \ + -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \ + -v /etc:/etc \ + -v /var/lib:/var/lib:ro \ + -v /var/run/docker.sock:/var/run/docker.sock:ro \ + --label docker_bench_security \ + docker/docker-bench-security +``` + +### Note + +Docker bench requires Docker 1.13.0 or later in order to run. + +Note that when distributions don't contain `auditctl`, the audit tests will check `/etc/audit/audit.rules` to see if a rule is present instead. + +### Docker Bench for Security options + +```sh + -b optional Do not print colors + -h optional Print this help message + -l FILE optional Log output in FILE, inside container if run using docker + -u USERS optional Comma delimited list of trusted docker user(s) + -c CHECK optional Comma delimited list of specific check(s) id + -e CHECK optional Comma delimited list of specific check(s) id to exclude + -i INCLUDE optional Comma delimited list of patterns within a container or image name to check + -x EXCLUDE optional Comma delimited list of patterns within a container or image name to exclude from check + -n LIMIT optional In JSON output, when reporting lists of items (containers, images, etc.), limit the number of reported items to LIMIT. Default 0 (no limit). + -p PRINT optional Disable the printing of remediation measures. Default: print remediation measures. +``` + +By default the Docker Bench for Security script will run all available CIS tests and produce +logs in the log folder from current directory, named `docker-bench-security.log.json` and +`docker-bench-security.log`. + +If the docker container is used then the log files will be created inside the container in location `/usr/local/bin/log/`. If you wish to access them from the host after the container has been run you will need to mount a volume for storing them in. + +The CIS based checks are named `check_
_`, e.g. `check_2_6` and community contributed checks are named `check_c_`. + +`sh docker-bench-security.sh -c check_2_2` will only run check `2.2 Ensure the logging level is set to 'info'`. + +`sh docker-bench-security.sh -e check_2_2` will run all available checks except `2.2 Ensure the logging level is set to 'info'`. + +`sh docker-bench-security.sh -e docker_enterprise_configuration` will run all available checks except the docker_enterprise_configuration group + +`sh docker-bench-security.sh -e docker_enterprise_configuration,check_2_2` will run allavailable checks except the docker_enterprise_configuration group and `2.2 Ensure the logging level is set to 'info'` + +`sh docker-bench-security.sh -c container_images,container_runtime` will run just the container_images and container_runtime checks + +`sh docker-bench-security.sh -c container_images -e check_4_5` will run just the container_images checks except `4.5 Ensure Content trust for Docker is Enabled` + +Note that when submitting checks, provide information why it is a reasonable test to add and please include some kind of official documentation verifying that information. + +## Building Docker image + +You have two options if you wish to build and run this container yourself: + +1. Use Docker Build: + +```sh +git clone https://github.com/docker/docker-bench-security.git +cd docker-bench-security +docker build --no-cache -t docker-bench-security . +``` + +Followed by an appropriate `docker run` command as stated above. + +2. Use Docker Compose: + +```sh +git clone https://github.com/docker/docker-bench-security.git +cd docker-bench-security +docker-compose run --rm docker-bench-security +``` diff --git a/scripts/docker-bench-security/distros/Dockerfile.alpine b/scripts/docker-bench-security/distros/Dockerfile.alpine new file mode 100644 index 0000000..ed4596a --- /dev/null +++ b/scripts/docker-bench-security/distros/Dockerfile.alpine @@ -0,0 +1,19 @@ +FROM alpine:3.13 + +LABEL \ + org.label-schema.name="docker-bench-security" \ + org.label-schema.url="https://dockerbench.com" \ + org.label-schema.vcs-url="https://github.com/docker/docker-bench-security.git" + +RUN apk add --no-cache iproute2 \ + docker-cli \ + dumb-init + +COPY . /usr/local/bin/ + +HEALTHCHECK CMD exit 0 + +WORKDIR /usr/local/bin + +ENTRYPOINT [ "/usr/bin/dumb-init", "docker-bench-security.sh" ] +CMD [""] diff --git a/scripts/docker-bench-security/distros/Dockerfile.centos b/scripts/docker-bench-security/distros/Dockerfile.centos new file mode 100644 index 0000000..4c0dcfb --- /dev/null +++ b/scripts/docker-bench-security/distros/Dockerfile.centos @@ -0,0 +1,15 @@ +# REPOSITORY https://github.com/fatherlinux/docker-bench-security + +FROM centos + +MAINTAINER smccarty@redhat.com + +RUN yum install -y docker iproute audit procps-ng; yum clean all + +RUN mkdir /docker-bench-security + +COPY . /docker-bench-security + +WORKDIR /docker-bench-security + +ENTRYPOINT ["/bin/sh", "docker-bench-security.sh"] diff --git a/scripts/docker-bench-security/distros/Dockerfile.debian b/scripts/docker-bench-security/distros/Dockerfile.debian new file mode 100644 index 0000000..4284f54 --- /dev/null +++ b/scripts/docker-bench-security/distros/Dockerfile.debian @@ -0,0 +1,24 @@ +FROM debian:sid + +LABEL org.label-schema.name="docker-bench-security" \ + org.label-schema.url="https://github.com/konstruktoid/docker-bench-security" \ + org.label-schema.vcs-url="https://github.com/konstruktoid/docker-bench-security.git" + +RUN \ + apt-get update && \ + apt-get -y upgrade && \ + apt-get -y install auditd ca-certificates docker.io \ + gawk iproute2 procps --no-install-recommends && \ + apt-get -y clean && \ + apt-get -y autoremove && \ + rm -rf /var/lib/apt/lists/* \ + /usr/share/doc /usr/share/doc-base \ + /usr/share/man /usr/share/locale /usr/share/zoneinfo + +RUN mkdir /docker-bench-security + +COPY . /docker-bench-security + +WORKDIR /docker-bench-security + +ENTRYPOINT ["/bin/sh", "docker-bench-security.sh"] diff --git a/scripts/docker-bench-security/distros/Dockerfile.openSUSE b/scripts/docker-bench-security/distros/Dockerfile.openSUSE new file mode 100644 index 0000000..d5a0add --- /dev/null +++ b/scripts/docker-bench-security/distros/Dockerfile.openSUSE @@ -0,0 +1,13 @@ +# REPOSITORY https://github.com/docker/docker-bench-security +FROM opensuse/leap:latest + +RUN zypper -n in audit docker iproute2 && \ + mkdir /docker-bench-security && \ + rm /usr/bin/awk && \ + cp /usr/bin/gawk /usr/bin/awk + +COPY . /docker-bench-security + +WORKDIR /docker-bench-security + +ENTRYPOINT ["/bin/bash", "docker-bench-security.sh"] diff --git a/scripts/docker-bench-security/distros/Dockerfile.rhel b/scripts/docker-bench-security/distros/Dockerfile.rhel new file mode 100644 index 0000000..c1b5618 --- /dev/null +++ b/scripts/docker-bench-security/distros/Dockerfile.rhel @@ -0,0 +1,18 @@ +# REPOSITORY https://github.com/fatherlinux/docker-bench-security + +FROM rhel7 + +MAINTAINER smccarty@redhat.com + +RUN yum install -y yum-utils; yum clean all +RUN yum-config-manager --disable "*" &>/dev/null +RUN yum-config-manager --enable rhel-7-server-rpms --enable rhel-7-server-extras-rpms +RUN yum install -y docker iproute audit procps-ng; yum clean all + +RUN mkdir /docker-bench-security + +COPY . /docker-bench-security + +WORKDIR /docker-bench-security + +ENTRYPOINT ["/bin/sh", "docker-bench-security.sh"] diff --git a/scripts/docker-bench-security/distros/README.md b/scripts/docker-bench-security/distros/README.md new file mode 100644 index 0000000..be4de17 --- /dev/null +++ b/scripts/docker-bench-security/distros/README.md @@ -0,0 +1,21 @@ +# Distribution specific Dockerfiles + +## Requirements + +### Dockerfile name + +The format should be `Dockerfile.{distribution name}`. + +### Keep your images up-to-date + +Use the distribution package manager to keep your image up-to-date. + +### Labels + +Use the following labels in your Dockerfile: + +``` +LABEL org.label-schema.name="docker-bench-security" \ + org.label-schema.url="" \ + org.label-schema.vcs-url="/dev/null 2>&1; then + printf "Error connecting to docker daemon (does docker ps work?)\n" + exit 1 +fi + +usage () { + cat < +Full documentation: +Released under the Apache-2.0 License. +EOF +} + +# Default values +if [ ! -d log ]; then + mkdir log +fi + +logger="log/${myname}.log" +limit=0 +printremediation="0" +globalRemediation="" + +# Get the flags +# If you add an option here, please +# remember to update usage() above. +while getopts bhl:u:c:e:i:x:t:n:p args +do + case $args in + b) nocolor="nocolor";; + h) usage; exit 0 ;; + l) logger="$OPTARG" ;; + u) dockertrustusers="$OPTARG" ;; + c) check="$OPTARG" ;; + e) checkexclude="$OPTARG" ;; + i) include="$OPTARG" ;; + x) exclude="$OPTARG" ;; + n) limit="$OPTARG" ;; + p) printremediation="1" ;; + *) usage; exit 1 ;; + esac +done + +# Load output formating +. ./functions/output_lib.sh + +yell_info + +# Warn if not root +if [ "$(id -u)" != "0" ]; then + warn "$(yell 'Some tests might require root to run')\n" + sleep 3 +fi + +# Total Score +# Warn Scored -1, Pass Scored +1, Not Score -0 + +totalChecks=0 +currentScore=0 + +logit "Initializing $(date +%Y-%m-%dT%H:%M:%S%:z)\n" +beginjson "$version" "$(date +%s)" + +# Load all the tests from tests/ and run them +main () { + logit "\n${bldylw}Section A - Check results${txtrst}" + + # Get configuration location + get_docker_configuration_file + + # If there is a container with label docker_bench_security, memorize it: + benchcont="nil" + for c in $(docker ps | sed '1d' | awk '{print $NF}'); do + if docker inspect --format '{{ .Config.Labels }}' "$c" | \ + grep -e 'docker.bench.security' >/dev/null 2>&1; then + benchcont="$c" + fi + done + + # Get the image id of the docker_bench_security_image, memorize it: + benchimagecont="nil" + for c in $(docker images | sed '1d' | awk '{print $3}'); do + if docker inspect --format '{{ .Config.Labels }}' "$c" | \ + grep -e 'docker.bench.security' >/dev/null 2>&1; then + benchimagecont="$c" + fi + done + + if [ -n "$include" ]; then + pattern=$(echo "$include" | sed 's/,/|/g') + containers=$(docker ps | sed '1d' | awk '{print $NF}' | grep -v "$benchcont" | grep -E "$pattern") + images=$(docker images | sed '1d' | grep -E "$pattern" | awk '{print $3}' | grep -v "$benchimagecont") + elif [ -n "$exclude" ]; then + pattern=$(echo "$exclude" | sed 's/,/|/g') + containers=$(docker ps | sed '1d' | awk '{print $NF}' | grep -v "$benchcont" | grep -Ev "$pattern") + images=$(docker images | sed '1d' | grep -Ev "$pattern" | awk '{print $3}' | grep -v "$benchimagecont") + else + containers=$(docker ps | sed '1d' | awk '{print $NF}' | grep -v "$benchcont") + images=$(docker images -q | grep -v "$benchcont") + fi + + for test in tests/*.sh; do + . ./"$test" + done + + if [ -z "$check" ] && [ ! "$checkexclude" ]; then + # No options just run + cis + elif [ -z "$check" ]; then + # No check defined but excludes defined set to calls in cis() function + check=$(sed -ne "/cis() {/,/}/{/{/d; /}/d; p}" functions/functions_lib.sh) + fi + + for c in $(echo "$check" | sed "s/,/ /g"); do + if ! command -v "$c" 2>/dev/null 1>&2; then + echo "Check \"$c\" doesn't seem to exist." + continue + fi + if [ -z "$checkexclude" ]; then + # No excludes just run the checks specified + "$c" + else + # Exludes specified and check exists + checkexcluded="$(echo ",$checkexclude" | sed -e 's/^/\^/g' -e 's/,/\$|/g' -e 's/$/\$/g')" + + if echo "$c" | grep -E "$checkexcluded" 2>/dev/null 1>&2; then + # Excluded + continue + elif echo "$c" | grep -vE 'check_[0-9]|check_[a-z]' 2>/dev/null 1>&2; then + # Function not a check, fill loop_checks with all check from function + loop_checks="$(sed -ne "/$c() {/,/}/{/{/d; /}/d; p}" functions/functions_lib.sh)" + else + # Just one check + loop_checks="$c" + fi + + for lc in $loop_checks; do + if echo "$lc" | grep -vE "$checkexcluded" 2>/dev/null 1>&2; then + # Not excluded + "$lc" + fi + done + fi + done + + if [ -n "${globalRemediation}" ] && [ "$printremediation" = "1" ]; then + logit "\n\n${bldylw}Section B - Remediation measures${txtrst}" + logit "${globalRemediation}" + fi + + logit "\n\n${bldylw}Section C - Score${txtrst}\n" + info "Checks: $totalChecks" + info "Score: $currentScore\n" + + endjson "$totalChecks" "$currentScore" "$(date +%s)" +} + +main "$@" diff --git a/scripts/docker-bench-security/docker-compose.yml b/scripts/docker-bench-security/docker-compose.yml new file mode 100644 index 0000000..7a88f50 --- /dev/null +++ b/scripts/docker-bench-security/docker-compose.yml @@ -0,0 +1,21 @@ +docker-bench-security: + # use image if you have a dedicated build step: + # docker build --rm -t docker-bench-security . + # image: docker-bench-security + + # use build path to Dockerfile if docker-compose should build the image + build: . + + cap_add: + - audit_control + labels: + - docker_bench_security + net: host + pid: host + stdin_open: true + tty: true + volumes: + - /var/lib:/var/lib:ro + - /var/run/docker.sock:/var/run/docker.sock:ro + - /usr/lib/systemd:/usr/lib/systemd:ro + - /etc:/etc:ro diff --git a/scripts/docker-bench-security/functions/functions_lib.sh b/scripts/docker-bench-security/functions/functions_lib.sh new file mode 100644 index 0000000..b88ada2 --- /dev/null +++ b/scripts/docker-bench-security/functions/functions_lib.sh @@ -0,0 +1,319 @@ +#!/bin/sh + +host_configuration() { + check_1 + check_1_1 + check_1_1_1 + check_1_1_2 + check_1_1_3 + check_1_1_4 + check_1_1_5 + check_1_1_6 + check_1_1_7 + check_1_1_8 + check_1_1_9 + check_1_1_10 + check_1_1_11 + check_1_1_12 + check_1_1_13 + check_1_1_14 + check_1_1_15 + check_1_1_16 + check_1_1_17 + check_1_1_18 + check_1_2 + check_1_2_1 + check_1_2_2 + check_1_end +} + +host_configuration_level1() { + check_1 + check_1_end +} + +linux_hosts_specific_configuration() { + check_1_1 + check_1_1_1 + check_1_1_2 + check_1_1_3 + check_1_1_4 + check_1_1_5 + check_1_1_6 + check_1_1_7 + check_1_1_8 + check_1_1_9 + check_1_1_10 + check_1_1_11 + check_1_1_12 + check_1_1_13 + check_1_1_14 + check_1_1_15 + check_1_1_16 + check_1_1_17 + check_1_1_18 +} + +host_general_configuration() { + check_1 + check_1_2 + check_1_2_1 + check_1_2_2 + check_1_end +} + +docker_daemon_configuration() { + check_2 + check_2_1 + check_2_2 + check_2_3 + check_2_4 + check_2_5 + check_2_6 + check_2_7 + check_2_8 + check_2_9 + check_2_10 + check_2_11 + check_2_12 + check_2_13 + check_2_14 + check_2_15 + check_2_16 + check_2_17 + check_2_18 + check_2_end +} + +docker_daemon_configuration_level1() { + check_2 + check_2_end +} + +docker_daemon_files() { + check_3 + check_3_1 + check_3_2 + check_3_3 + check_3_4 + check_3_5 + check_3_6 + check_3_7 + check_3_8 + check_3_9 + check_3_10 + check_3_11 + check_3_12 + check_3_13 + check_3_14 + check_3_15 + check_3_16 + check_3_17 + check_3_18 + check_3_19 + check_3_20 + check_3_21 + check_3_22 + check_3_23 + check_3_24 + check_3_end +} + +docker_daemon_files_level1() { + check_3 + check_3_end +} + +container_images() { + check_4 + check_4_1 + check_4_2 + check_4_3 + check_4_4 + check_4_5 + check_4_6 + check_4_7 + check_4_8 + check_4_9 + check_4_10 + check_4_11 + check_4_end +} + +container_images_level1() { + check_4 + check_4_end +} + +container_runtime() { + check_5 + check_running_containers + check_5_1 + check_5_2 + check_5_3 + check_5_4 + check_5_5 + check_5_6 + check_5_7 + check_5_8 + check_5_9 + check_5_10 + check_5_11 + check_5_12 + check_5_13 + check_5_14 + check_5_15 + check_5_16 + check_5_17 + check_5_18 + check_5_19 + check_5_20 + check_5_21 + check_5_22 + check_5_23 + check_5_24 + check_5_25 + check_5_26 + check_5_27 + check_5_28 + check_5_29 + check_5_30 + check_5_31 + check_5_end +} + +container_runtime_level1() { + check_5 + check_5_end +} + +docker_security_operations() { + check_6 + check_6_1 + check_6_2 + check_6_end +} + +docker_security_operations_level1() { + check_6 + check_6_1 + check_6_2 + check_6_end +} + +docker_swarm_configuration() { + check_7 + check_7_1 + check_7_2 + check_7_3 + check_7_4 + check_7_5 + check_7_6 + check_7_7 + check_7_8 + check_7_9 + check_7_10 + check_7_end +} + +docker_swarm_configuration_level1() { + check_7 + check_7_end +} + +docker_enterprise_configuration() { + check_8 + check_product_license + check_8_1 + check_8_1_1 + check_8_1_2 + check_8_1_3 + check_8_1_4 + check_8_1_5 + check_8_1_6 + check_8_1_7 + check_8_2 + check_8_2_1 + check_8_end +} + +docker_enterprise_configuration_level1() { + check_8 + check_product_license + check_8_1 + check_8_1_1 + check_8_1_2 + check_8_1_3 + check_8_1_4 + check_8_1_5 + check_8_1_6 + check_8_1_7 + check_8_2 + check_8_2_1 + check_8_end +} + +universal_control_plane_configuration() { + check_8 + check_8_1 + check_8_1_1 + check_8_1_2 + check_8_1_3 + check_8_1_4 + check_8_1_5 + check_8_1_6 + check_8_1_7 + check_8_end +} + +docker_trusted_registry_configuration() { + check_8 + check_8_2 + check_8_2_1 + check_8_end +} + +community_checks() { + check_c + check_c_1 + check_c_1_1 + check_c_2 + check_c_5_3_1 + check_c_5_3_2 + check_c_5_3_3 + check_c_5_3_4 + check_c_end +} + +# CIS +cis() { + host_configuration + docker_daemon_configuration + docker_daemon_files + container_images + container_runtime + docker_security_operations + docker_swarm_configuration +} + +cis_level1() { + host_configuration_level1 + docker_daemon_configuration_level1 + docker_daemon_files_level1 + container_images_level1 + container_runtime_level1 + docker_security_operations_level1 + docker_swarm_configuration_level1 +} + +# Community contributed +community() { + community_checks +} + +# All +all() { + cis + docker_enterprise_configuration + community +} diff --git a/scripts/docker-bench-security/functions/helper_lib.sh b/scripts/docker-bench-security/functions/helper_lib.sh new file mode 100644 index 0000000..b79571f --- /dev/null +++ b/scripts/docker-bench-security/functions/helper_lib.sh @@ -0,0 +1,150 @@ +#!/bin/bash + +# Returns the absolute path of a given string +abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; } + +# Audit rules default path +auditrules="/etc/audit/audit.rules" + +# Check for required program(s) +req_programs() { + for p in $1; do + command -v "$p" >/dev/null 2>&1 || { printf "Required program not found: %s\n" "$p"; exit 1; } + done + if command -v ss >/dev/null 2>&1; then + netbin=ss + return + fi + if command -v netstat >/dev/null 2>&1; then + netbin=netstat + return + fi + echo "ss or netstat command not found." + exit 1 +} + +# Compares versions of software of the format X.Y.Z +do_version_check() { + [ "$1" = "$2" ] && return 10 + + ver1front=$(printf "%s" "$1" | cut -d "." -f -1) + ver1back=$(printf "%s" "$1" | cut -d "." -f 2-) + ver2front=$(printf "%s" "$2" | cut -d "." -f -1) + ver2back=$(printf "%s" "$2" | cut -d "." -f 2-) + + if [ "$ver1front" != "$1" ] || [ "$ver2front" != "$2" ]; then + [ "$ver1front" -gt "$ver2front" ] && return 11 + [ "$ver1front" -lt "$ver2front" ] && return 9 + + [ "$ver1front" = "$1" ] || [ -z "$ver1back" ] && ver1back=0 + [ "$ver2front" = "$2" ] || [ -z "$ver2back" ] && ver2back=0 + do_version_check "$ver1back" "$ver2back" + return $? + fi + [ "$1" -gt "$2" ] && return 11 || return 9 +} + +# Extracts commandline args from the newest running processes named like the first parameter +get_command_line_args() { + PROC="$1" + + for PID in $(pgrep -f -n "$PROC"); do + tr "\0" " " < /proc/"$PID"/cmdline + done +} + +# Extract the cumulative command line arguments for the docker daemon +# +# If specified multiple times, all matches are returned. +# Accounts for long and short variants, call with short option. +# Does not account for option defaults or implicit options. +get_docker_cumulative_command_line_args() { + OPTION="$1" + + line_arg="dockerd" + if ! get_command_line_args "docker daemon" >/dev/null 2>&1 ; then + line_arg="docker daemon" + fi + + get_command_line_args "$line_arg" | + # normalize known long options to their short versions + sed \ + -e 's/\-\-debug/-D/g' \ + -e 's/\-\-host/-H/g' \ + -e 's/\-\-log-level/-l/g' \ + -e 's/\-\-version/-v/g' \ + | + # normalize parameters separated by space(s) to -O=VALUE + sed \ + -e 's/\-\([DHlv]\)[= ]\([^- ][^ ]\)/-\1=\2/g' \ + | + # get the last interesting option + tr ' ' "\n" | + grep "^${OPTION}" | + # normalize quoting of values + sed \ + -e 's/"//g' \ + -e "s/'//g" +} + +# Extract the effective command line arguments for the docker daemon +# +# Accounts for multiple specifications, takes the last option. +# Accounts for long and short variants, call with short option +# Does not account for option default or implicit options. +get_docker_effective_command_line_args() { + OPTION="$1" + get_docker_cumulative_command_line_args "$OPTION" | tail -n1 +} + +get_docker_configuration_file() { + FILE="$(get_docker_effective_command_line_args '--config-file' | \ + sed 's/.*=//g')" + + if [ -f "$FILE" ]; then + CONFIG_FILE="$FILE" + return + fi + if [ -f '/etc/docker/daemon.json' ]; then + CONFIG_FILE='/etc/docker/daemon.json' + return + fi + CONFIG_FILE='/dev/null' +} + +get_docker_configuration_file_args() { + OPTION="$1" + + get_docker_configuration_file + + grep "$OPTION" "$CONFIG_FILE" | sed 's/.*://g' | tr -d '" ', +} + +get_service_file() { + SERVICE="$1" + + if [ -f "/etc/systemd/system/$SERVICE" ]; then + echo "/etc/systemd/system/$SERVICE" + return + fi + if [ -f "/lib/systemd/system/$SERVICE" ]; then + echo "/lib/systemd/system/$SERVICE" + return + fi + if systemctl show -p FragmentPath "$SERVICE" 2> /dev/null 1>&2; then + systemctl show -p FragmentPath "$SERVICE" | sed 's/.*=//' + return + fi + echo "/usr/lib/systemd/system/$SERVICE" +} + +yell_info() { +yell "# -------------------------------------------------------------------------------------------- +# Docker Bench for Security v$version +# +# Docker, Inc. (c) 2015-$(date +"%Y") +# +# Checks for dozens of common best-practices around deploying Docker containers in production. +# Based on the CIS Docker Benchmark 1.3.1. +# --------------------------------------------------------------------------------------------" +} diff --git a/scripts/docker-bench-security/functions/output_lib.sh b/scripts/docker-bench-security/functions/output_lib.sh new file mode 100644 index 0000000..98d448e --- /dev/null +++ b/scripts/docker-bench-security/functions/output_lib.sh @@ -0,0 +1,190 @@ +#!/bin/bash + +bldred='\033[1;31m' # Bold Red +bldgrn='\033[1;32m' # Bold Green +bldblu='\033[1;34m' # Bold Blue +bldylw='\033[1;33m' # Bold Yellow +txtrst='\033[0m' + +if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then + bldred='' + bldgrn='' + bldblu='' + bldylw='' + txtrst='' +fi + +logit () { + printf "%b\n" "$1" | tee -a "$logger" +} + +info () { + local infoCountCheck + local OPTIND c + while getopts c args + do + case $args in + c) infoCountCheck="true" ;; + *) exit 1 ;; + esac + done + if [ "$infoCountCheck" = "true" ]; then + printf "%b\n" "${bldblu}[INFO]${txtrst} $2" | tee -a "$logger" + totalChecks=$((totalChecks + 1)) + return + fi + printf "%b\n" "${bldblu}[INFO]${txtrst} $1" | tee -a "$logger" +} + +pass () { + local passScored + local passCountCheck + local OPTIND s c + while getopts sc args + do + case $args in + s) passScored="true" ;; + c) passCountCheck="true" ;; + *) exit 1 ;; + esac + done + if [ "$passScored" = "true" ] || [ "$passCountCheck" = "true" ]; then + printf "%b\n" "${bldgrn}[PASS]${txtrst} $2" | tee -a "$logger" + totalChecks=$((totalChecks + 1)) + fi + if [ "$passScored" = "true" ]; then + currentScore=$((currentScore + 1)) + fi + if [ "$passScored" != "true" ] && [ "$passCountCheck" != "true" ]; then + printf "%b\n" "${bldgrn}[PASS]${txtrst} $1" | tee -a "$logger" + fi +} + +warn () { + local warnScored + local OPTIND s + while getopts s args + do + case $args in + s) warnScored="true" ;; + *) exit 1 ;; + esac + done + if [ "$warnScored" = "true" ]; then + printf "%b\n" "${bldred}[WARN]${txtrst} $2" | tee -a "$logger" + totalChecks=$((totalChecks + 1)) + currentScore=$((currentScore - 1)) + return + fi + printf "%b\n" "${bldred}[WARN]${txtrst} $1" | tee -a "$logger" +} + +note () { + local noteCountCheck + local OPTIND c + while getopts c args + do + case $args in + c) noteCountCheck="true" ;; + *) exit 1 ;; + esac + done + if [ "$noteCountCheck" = "true" ]; then + printf "%b\n" "${bldylw}[NOTE]${txtrst} $2" | tee -a "$logger" + totalChecks=$((totalChecks + 1)) + return + fi + printf "%b\n" "${bldylw}[NOTE]${txtrst} $1" | tee -a "$logger" +} + +yell () { + printf "%b\n" "${bldylw}$1${txtrst}\n" +} + +beginjson () { + printf "{\n \"dockerbenchsecurity\": \"%s\",\n \"start\": %s,\n \"tests\": [" "$1" "$2" | tee "$logger.json" 2>/dev/null 1>&2 +} + +endjson (){ + printf "\n ],\n \"checks\": %s,\n \"score\": %s,\n \"end\": %s\n}" "$1" "$2" "$3" | tee -a "$logger.json" 2>/dev/null 1>&2 +} + +logjson (){ + printf "\n \"%s\": \"%s\"," "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2 +} + +SSEP= +SEP= +startsectionjson() { + printf "%s\n {\n \"id\": \"%s\",\n \"desc\": \"%s\",\n \"results\": [" "$SSEP" "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2 + SEP= + SSEP="," +} + +endsectionjson() { + printf "\n ]\n }" | tee -a "$logger.json" 2>/dev/null 1>&2 +} + +starttestjson() { + printf "%s\n {\n \"id\": \"%s\",\n \"desc\": \"%s\",\n " "$SEP" "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2 + SEP="," +} + +log_to_json() { + if [ $# -eq 1 ]; then + printf "\"result\": \"%s\"" "$1" | tee -a "$logger.json" 2>/dev/null 1>&2 + return + fi + if [ $# -eq 2 ] && [ $# -ne 1 ]; then + # Result also contains details + printf "\"result\": \"%s\",\n \"details\": \"%s\"" "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2 + return + fi + # Result also includes details and a list of items. Add that directly to details and to an array property "items" + # Also limit the number of items to $limit, if $limit is non-zero + truncItems=$3 + if [ "$limit" != 0 ]; then + truncItems="" + ITEM_COUNT=0 + for item in $3; do + truncItems="$truncItems $item" + ITEM_COUNT=$((ITEM_COUNT + 1)); + if [ "$ITEM_COUNT" == "$limit" ]; then + truncItems="$truncItems (truncated)" + break; + fi + done + fi + itemsJson=$(printf "[\n "; ISEP=""; ITEMCOUNT=0; for item in $truncItems; do printf "%s\"%s\"" "$ISEP" "$item"; ISEP=","; done; printf "\n ]") + printf "\"result\": \"%s\",\n \"details\": \"%s: %s\",\n \"items\": %s" "$1" "$2" "$truncItems" "$itemsJson" | tee -a "$logger.json" 2>/dev/null 1>&2 +} + +logcheckresult() { + # Log to JSON + log_to_json "$@" + + # Log remediation measure to JSON + if [ -n "$remediation" ] && [ "$1" != "PASS" ] && [ "$printremediation" = "1" ]; then + printf ",\n \"remediation\": \"%s\"" "$remediation" | tee -a "$logger.json" 2>/dev/null 1>&2 + if [ -n "$remediationImpact" ]; then + printf ",\n \"remediation-impact\": \"%s\"" "$remediationImpact" | tee -a "$logger.json" 2>/dev/null 1>&2 + fi + fi + printf "\n }" | tee -a "$logger.json" 2>/dev/null 1>&2 + + # Save remediation measure for print log to stdout + if [ -n "$remediation" ] && [ "$1" != "PASS" ]; then + if [ -n "${checkHeader}" ]; then + if [ -n "${addSpaceHeader}" ]; then + globalRemediation="${globalRemediation}\n" + fi + globalRemediation="${globalRemediation}\n${bldblu}[INFO]${txtrst} ${checkHeader}" + checkHeader="" + addSpaceHeader="1" + fi + globalRemediation="${globalRemediation}\n${bldblu}[INFO]${txtrst} ${id} - ${remediation}" + if [ -n "${remediationImpact}" ]; then + globalRemediation="${globalRemediation} Remediation Impact: ${remediationImpact}" + fi + fi +} diff --git a/scripts/docker-bench-security/img/benchmark_log.png b/scripts/docker-bench-security/img/benchmark_log.png new file mode 100644 index 0000000..7101c17 Binary files /dev/null and b/scripts/docker-bench-security/img/benchmark_log.png differ diff --git a/scripts/docker-bench-security/tests/1_host_configuration.sh b/scripts/docker-bench-security/tests/1_host_configuration.sh new file mode 100644 index 0000000..c325681 --- /dev/null +++ b/scripts/docker-bench-security/tests/1_host_configuration.sh @@ -0,0 +1,575 @@ +#!/bin/bash + +check_1() { + logit "" + local id="1" + local desc="Host Configuration" + checkHeader="$id - $desc" + info "$checkHeader" + startsectionjson "$id" "$desc" +} + +check_1_1() { + local id="1.1" + local desc="Linux Hosts Specific Configuration" + local check="$id - $desc" + info "$check" +} + +check_1_1_1() { + local id="1.1.1" + local desc="Ensure a separate partition for containers has been created (Automated)" + local remediation="For new installations, you should create a separate partition for the /var/lib/docker mount point. For systems that have already been installed, you should use the Logical Volume Manager (LVM) within Linux to create a new partition." + local remediationImpact="None." + local testCategory="Docker Configuration" + local check="$id - $desc - $testCategory" + + docker_root_dir=$(docker info -f '{{ .DockerRootDir }}') + if docker info | grep -q userns ; then + docker_root_dir=$(readlink -f "$docker_root_dir/..") + fi + + if mountpoint -q -- "$docker_root_dir" >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" +} + +check_1_1_2() { + local id="1.1.2" + local desc="Ensure only trusted users are allowed to control Docker daemon (Automated)" + local remediation="You should remove any untrusted users from the docker group using command sudo gpasswd -d docker or add trusted users to the docker group using command sudo usermod -aG docker . You should not create a mapping of sensitive directories from the host to container volumes." + local remediationImpact="Only trust user are allow to build and execute containers as normal user." + local testCategory="User Settings" + local check="$id - $desc - $testCategory" + starttestjson "$id" "$desc" + + docker_users=$(grep 'docker' /fenced/mnt/host/etc/group) + if command -v getent >/dev/null 2>&1; then + docker_users=$(getent group docker) + fi + docker_users=$(printf "%s" "$docker_users" | awk -F: '{print $4}') + + local doubtfulusers="" + if [ -n "$dockertrustusers" ]; then + for u in $(printf "%s" "$docker_users" | sed "s/,/ /g"); do + if ! printf "%s" "$dockertrustusers" | grep -q "$u" ; then + doubtfulusers="$u" + if [ -n "${doubtfulusers}" ]; then + doubtfulusers="${doubtfulusers},$u" + fi + fi + done + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* Users: $docker_users" "$remediation" "$remediationImpact" + fi + + if [ -n "${doubtfulusers}" ]; then + logbenchjson "WARN" $id "$testCategory" "$desc" " * Users: $doubtfulusers" "$remediation" "$remediationImpact" + fi + + if [ -z "${doubtfulusers}" ] && [ -n "${dockertrustusers}" ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + fi +} + +check_1_1_3() { + local id="1.1.3" + local desc="Ensure auditing is configured for the Docker daemon (Automated)" + local remediation="Install auditd. Add -w /usr/bin/dockerd -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local testCategory="Audit" + local check="$id - $desc" + starttestjson "$id" "$desc" + + file="/usr/bin/dockerd" + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep "$file" >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" +} + +check_1_1_4() { + local id="1.1.4" + local desc="Ensure auditing is configured for Docker files and directories -/run/containerd (Automated)" + local remediation="Install auditd. Add -a exit,always -F path=/run/containerd -F perm=war -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local testCategory="Audit" + local check="$id - $desc" + starttestjson "$id" "$desc" + + file="/run/containerd" + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep "$file" >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" +} + +check_1_1_5() { + local id="1.1.5" + local desc="Ensure auditing is configured for Docker files and directories - /var/lib/docker (Automated)" + local remediation="Install auditd. Add -w /var/lib/docker -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + directory="/var/lib/docker" + if [ -d "$directory" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep $directory >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$directory" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "** Directory Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_6() { + local id="1.1.6" + local desc="Ensure auditing is configured for Docker files and directories - /fenced/mnt/host/etc/docker (Automated)" + local remediation="Install auditd. Add -w /fenced/mnt/host/etc/docker -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + directory="/fenced/mnt/host/etc/docker" + if [ -d "$directory" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep $directory >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$directory" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "** Directory Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_7() { + local id="1.1.7" + local desc="Ensure auditing is configured for Docker files and directories - docker.service (Automated)" + local remediation + remediation="Install auditd. Add -w $(get_service_file docker.service) -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + file="$(get_service_file docker.service)" + if [ -f "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep "$file" >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "PASS" $id "$testCategory" "$desc" "- File Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_8() { + local id="1.1.8" + local desc="Ensure auditing is configured for Docker files and directories - containerd.sock (Automated)" + local remediation + remediation="Install auditd. Add -w $(get_service_file containerd.socket) -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + + file="$(get_service_file containerd.socket)" + if [ -e "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep "$file" >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "- File Not Found" "$remediation" "$remediationImpact" +} +check_1_1_9() { + local id="1.1.9" + local desc="Ensure auditing is configured for Docker files and directories - docker.socket (Automated)" + local remediation + remediation="Install auditd. Add -w $(get_service_file docker.socket) -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + file="$(get_service_file docker.socket)" + if [ -e "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep "$file" >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "- File Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_10() { + local id="1.1.10" + local desc="Ensure auditing is configured for Docker files and directories - /fenced/mnt/host/etc/default/docker (Automated)" + local remediation="Install auditd. Add -w /fenced/mnt/host/etc/default/docker -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + file="/fenced/mnt/host/etc/default/docker" + if [ -f "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep $file >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "- File Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_11() { + local id="1.1.11" + local desc="Ensure auditing is configured for Dockerfiles and directories - /fenced/mnt/host/etc/docker/daemon.json (Automated)" + local remediation="Install auditd. Add -w /fenced/mnt/host/etc/docker/daemon.json -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + file="/fenced/mnt/host/etc/docker/daemon.json" + if [ -f "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep $file >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "- File Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_12() { + local id="1.1.12" + local desc="1.1.12 Ensure auditing is configured for Dockerfiles and directories - /fenced/mnt/host/etc/containerd/config.toml (Automated)" + local remediation="Install auditd. Add -w /fenced/mnt/host/etc/containerd/config.toml -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + file="/fenced/mnt/host/etc/containerd/config.toml" + if [ -f "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep $file >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "- File Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_13() { + local id="1.1.13" + local desc="Ensure auditing is configured for Docker files and directories - /etc/sysconfig/docker (Automated)" + local remediation="Install auditd. Add -w /fenced/mnt/host/etc/sysconfig/docker -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + file="/fenced/mnt/host/etc/sysconfig/docker" + if [ -f "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep $file >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "** File Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_14() { + local id="1.1.14" + local desc="Ensure auditing is configured for Docker files and directories - /usr/bin/containerd (Automated)" + local remediation="Install auditd. Add -w /usr/bin/containerd -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + file="/usr/bin/containerd" + if [ -f "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep $file >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" " ** File Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_15() { + local id="1.1.15" + local desc="Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim (Automated)" + local remediation="Install auditd. Add -w /usr/bin/containerd-shim -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + file="/usr/bin/containerd-shim" + if [ -f "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep $file >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" " ** File Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_16() { + local id="1.1.16" + local desc="Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v1 (Automated)" + local remediation="Install auditd. Add -w /usr/bin/containerd-shim-runc-v1 -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + file="/usr/bin/containerd-shim-runc-v1" + if [ -f "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep $file >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "File Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_17() { + local id="1.1.17" + local desc="Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v2 (Automated)" + local remediation="Install auditd. Add -w /usr/bin/containerd-shim-runc-v2 -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + file="/usr/bin/containerd-shim-runc-v2" + if [ -f "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep $file >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" " ** File Not Found" "$remediation" "$remediationImpact" +} + +check_1_1_18() { + local id="1.1.18" + local desc="Ensure auditing is configured for Docker files and directories - /usr/bin/runc (Automated)" + local remediation="Install auditd. Add -w /usr/bin/runc -k docker to the /fenced/mnt/host/etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart." + local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions." + local check="$id - $desc" + local testCategory="Audit" + starttestjson "$id" "$desc" + + file="/usr/bin/runc" + if [ -f "$file" ]; then + if command -v auditctl >/dev/null 2>&1; then + if auditctl -l | grep $file >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "File Not Found" "$remediation" "$remediationImpact" +} + +check_1_2() { + local id="1.2" + local desc="General Configuration" + local check="$id - $desc" + info "$check" +} + +check_1_2_1() { + local id="1.2.1" + local desc="Ensure the container host has been Hardened (Manual)" + local remediation="You may consider various Security Benchmarks for your container host." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Configuration" + starttestjson "$id" "$desc" + + logbenchjson "NOTE" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" +} + +check_1_2_2() { + local id="1.2.2" + local desc="Ensure that the version of Docker is up to date (Manual)" + local remediation="You should monitor versions of Docker releases and make sure your software is updated as required." + local remediationImpact="You should perform a risk assessment regarding Docker version updates and review how they may impact your operations." + local testCategory="Docker Configuration" + local check="$id - $desc" + starttestjson "$id" "$desc" + + docker_version=$(docker version | grep -i -A2 '^server' | grep ' Version:' \ + | awk '{print $NF; exit}' | tr -d '[:alpha:]-,') + docker_current_version="$(date +%y.%m.0 -d @$(( $(date +%s) - 2592000)))" + do_version_check "$docker_current_version" "$docker_version" + if [ $? -eq 11 ]; then + logbenchjson "INFO" $id "$testCategory" "$desc" " ** Using $docker_version, verify is it up to date as deemed necessary" "$remediation" "$remediationImpact" + return + fi + logbenchjson "PASS" $id "$testCategory" "$desc" " ** Using $docker_version which is current" "$remediation" "$remediationImpact" +} + +check_1_end() { + endsectionjson +} diff --git a/scripts/docker-bench-security/tests/2_docker_daemon_configuration.sh b/scripts/docker-bench-security/tests/2_docker_daemon_configuration.sh new file mode 100644 index 0000000..ed56ba3 --- /dev/null +++ b/scripts/docker-bench-security/tests/2_docker_daemon_configuration.sh @@ -0,0 +1,408 @@ +#!/bin/bash + +check_2() { + logit "" + local id="2" + local desc="Docker daemon configuration" + checkHeader="$id - $desc" + info "$checkHeader" + startsectionjson "$id" "$desc" +} + +check_2_1() { + local id="2.1" + local desc="Run the Docker daemon as a non-root user, if possible (Manual)" + local remediation="Follow the current Docker documentation on how to install the Docker daemon as a non-root user." + local remediationImpact="There are multiple prerequisites depending on which distribution that is in use, and also known limitations regarding networking and resource limitation. Running in rootless mode also changes the location of any configuration files in use, including all containers using the daemon." + local check="$id - $desc" + local testCategory="User Settings" + starttestjson "$id" "$desc" + + logbenchjson "NOTE" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" +} + +check_2_2() { + local id="2.2" + local desc="Ensure network traffic is restricted between containers on the default bridge (Scored)" + local remediation="Edit the Docker daemon configuration file to ensure that inter-container communication is disabled: icc: false." + local remediationImpact="Inter-container communication is disabled on the default network bridge. If any communication between containers on the same host is desired, it needs to be explicitly defined using container linking or custom networks." + local check="$id - $desc" + local testCategory="Docker Configuration" + starttestjson "$id" "$desc" + + if get_docker_effective_command_line_args '--icc' | grep false >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if get_docker_configuration_file_args 'icc' | grep "false" >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" +} + +check_2_3() { + local id="2.3" + local desc="Ensure the logging level is set to 'info' (Scored)" + local remediation="Ensure that the Docker daemon configuration file has the following configuration included log-level: info. Alternatively, run the Docker daemon as following: dockerd --log-level=info" + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Logging Configuration" + starttestjson "$id" "$desc" + + if get_docker_configuration_file_args 'log-level' >/dev/null 2>&1; then + if get_docker_configuration_file_args 'log-level' | grep info >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if [ -z "$(get_docker_configuration_file_args 'log-level')" ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if get_docker_effective_command_line_args '-l'; then + if get_docker_effective_command_line_args '-l' | grep "info" >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" +} + +check_2_4() { + local id="2.4" + local desc="Ensure Docker is allowed to make changes to iptables (Scored)" + local remediation="Do not run the Docker daemon with --iptables=false option." + local remediationImpact="The Docker daemon service requires iptables rules to be enabled before it starts." + local check="$id - $desc" + local testCategory="Docker Configuration" + starttestjson "$id" "$desc" + + if get_docker_effective_command_line_args '--iptables' | grep "false" >/dev/null 2>&1; then + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if get_docker_configuration_file_args 'iptables' | grep "false" >/dev/null 2>&1; then + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" +} + +check_2_5() { + local id="2.5" + local desc="Ensure insecure registries are not used (Scored)" + local remediation="You should ensure that no insecure registries are in use." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Daemon Configuration" + starttestjson "$id" "$desc" + + if get_docker_effective_command_line_args '--insecure-registry' | grep "insecure-registry" >/dev/null 2>&1; then + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if ! [ -z "$(get_docker_configuration_file_args 'insecure-registries')" ]; then + if get_docker_configuration_file_args 'insecure-registries' | grep '\[]' >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" +} + +check_2_6() { + local id="2.6" + local desc="Ensure aufs storage driver is not used (Scored)" + local remediation="Do not start Docker daemon as using dockerd --storage-driver aufs option." + local remediationImpact="aufs is the only storage driver that allows containers to share executable and shared library memory. Its use should be reviewed in line with your organization's security policy." + local check="$id - $desc" + local testCategory="Docker Daemon Configuration" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "^\sStorage Driver:\s*aufs\s*$" >/dev/null 2>&1; then + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" +} + +check_2_7() { + local id="2.7" + local desc="Ensure TLS authentication for Docker daemon is configured (Scored)" + local remediation="Follow the steps mentioned in the Docker documentation or other references. By default, TLS authentication is not configured." + local remediationImpact="You would need to manage and guard certificates and keys for the Docker daemon and Docker clients." + local check="$id - $desc" + local testCategory="Docker Daemon Configuration" + starttestjson "$id" "$desc" + + if [ $(get_docker_configuration_file_args 'tcp://') ] || \ + [ $(get_docker_cumulative_command_line_args '-H' | grep -vE '(unix|fd)://') >/dev/null 2>&1 ]; then + if [ $(get_docker_configuration_file_args '"tlsverify":' | grep 'true') ] || \ + [ $(get_docker_cumulative_command_line_args '--tlsverify' | grep 'tlsverify') >/dev/null 2>&1 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if [ $(get_docker_configuration_file_args '"tls":' | grep 'true') ] || \ + [ $(get_docker_cumulative_command_line_args '--tls' | grep 'tls$') >/dev/null 2>&1 ]; then + logbenchjson "WARN" $id "$testCategory" "$desc" "- ** Docker daemon currently listening on TCP with TLS, but no verification" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "- ** Docker daemon currently listening on TCP without TLS" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "- ** Docker daemon not listening on TCP" "$remediation" "$remediationImpact" +} + +check_2_8() { + local id="2.8" + local desc="Ensure the default ulimit is configured appropriately (Manual)" + local remediation="Run Docker in daemon mode and pass --default-ulimit as option with respective ulimits as appropriate in your environment and in line with your security policy. Example: dockerd --default-ulimit nproc=1024:2048 --default-ulimit nofile=100:200" + local remediationImpact="If ulimits are set incorrectly this could cause issues with system resources, possibly causing a denial of service condition." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if get_docker_configuration_file_args 'default-ulimit' | grep -v '{}' >/dev/null 2>&1; then + pass -c "$check" + logcheckresult "PASS" + return + fi + if get_docker_effective_command_line_args '--default-ulimit' | grep "default-ulimit" >/dev/null 2>&1; then + pass -c "$check" + logcheckresult "PASS" + return + fi + info -c "$check" + info " * Default ulimit doesn't appear to be set" + logcheckresult "INFO" "Default ulimit doesn't appear to be set" +} + +check_2_9() { + local id="2.9" + local desc="Enable user namespace support (Scored)" + local remediation="Please consult the Docker documentation for various ways in which this can be configured depending upon your requirements. The high-level steps are: Ensure that the files /fenced/mnt/host/etc/subuid and /fenced/mnt/host/etc/subgid exist. Start the docker daemon with --userns-remap flag." + local remediationImpact="User namespace remapping is incompatible with a number of Docker features and also currently breaks some of its functionalities." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if get_docker_configuration_file_args 'userns-remap' | grep -v '""'; then + pass -s "$check" + logcheckresult "PASS" + return + fi + if get_docker_effective_command_line_args '--userns-remap' | grep "userns-remap" >/dev/null 2>&1; then + pass -s "$check" + logcheckresult "PASS" + return + fi + warn -s "$check" + logcheckresult "WARN" +} + +check_2_10() { + local id="2.10" + local desc="Ensure the default cgroup usage has been confirmed (Scored)" + local remediation="The default setting is in line with good security practice and can be left in situ." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if get_docker_configuration_file_args 'cgroup-parent' | grep -v ''; then + warn -s "$check" + info " * Confirm cgroup usage" + logcheckresult "WARN" "Confirm cgroup usage" + return + fi + if get_docker_effective_command_line_args '--cgroup-parent' | grep "cgroup-parent" >/dev/null 2>&1; then + warn -s "$check" + info " * Confirm cgroup usage" + logcheckresult "WARN" "Confirm cgroup usage" + return + fi + pass -s "$check" + logcheckresult "PASS" +} + +check_2_11() { + local id="2.11" + local desc="Ensure base device size is not changed until needed (Scored)" + local remediation="Do not set --storage-opt dm.basesize until needed." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if get_docker_configuration_file_args 'storage-opts' | grep "dm.basesize" >/dev/null 2>&1; then + warn -s "$check" + logcheckresult "WARN" + return + fi + if get_docker_effective_command_line_args '--storage-opt' | grep "dm.basesize" >/dev/null 2>&1; then + warn -s "$check" + logcheckresult "WARN" + return + fi + pass -s "$check" + logcheckresult "PASS" +} + +check_2_12() { + local id="2.12" + local desc="Ensure that authorization for Docker client commands is enabled (Scored)" + local remediation="Install/Create an authorization plugin. Configure the authorization policy as desired. Start the docker daemon using command dockerd --authorization-plugin=" + local remediationImpact="Each Docker command needs to pass through the authorization plugin mechanism. This may have a performance impact" + local check="$id - $desc" + starttestjson "$id" "$desc" + + if get_docker_configuration_file_args 'authorization-plugins' | grep -v '\[]'; then + pass -s "$check" + logcheckresult "PASS" + return + fi + if get_docker_effective_command_line_args '--authorization-plugin' | grep "authorization-plugin" >/dev/null 2>&1; then + pass -s "$check" + logcheckresult "PASS" + return + fi + warn -s "$check" + logcheckresult "WARN" +} + +check_2_13() { + local id="2.13" + local desc="Ensure centralized and remote logging is configured (Scored)" + local remediation="Set up the desired log driver following its documentation. Start the docker daemon using that logging driver. Example: dockerd --log-driver=syslog --log-opt syslog-address=tcp://192.xxx.xxx.xxx" + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info --format '{{ .LoggingDriver }}' | grep 'json-file' >/dev/null 2>&1; then + warn -s "$check" + logcheckresult "WARN" + return + fi + pass -s "$check" + logcheckresult "PASS" +} + +check_2_14() { + local id="2.14" + local desc="Ensure containers are restricted from acquiring new privileges (Scored)" + local remediation="You should run the Docker daemon using command: dockerd --no-new-privileges" + local remediationImpact="no_new_priv prevents LSMs such as SELinux from escalating the privileges of individual containers." + local check="$id - $desc" + local testCategory="Docker Daemon Configuration" + starttestjson "$id" "$desc" + + if get_docker_effective_command_line_args '--no-new-privileges' | grep "no-new-privileges" >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + if get_docker_configuration_file_args 'no-new-privileges' | grep true >/dev/null 2>&1; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" +} + +check_2_15() { + local id="2.15" + local desc="Ensure live restore is enabled (Scored)" + local remediation="Run Docker in daemon mode and pass --live-restore option." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "Live Restore Enabled:\s*true\s*" >/dev/null 2>&1; then + pass -s "$check" + logcheckresult "PASS" + return + fi + if docker info 2>/dev/null | grep -e "Swarm:*\sactive\s*" >/dev/null 2>&1; then + pass -s "$check (Incompatible with swarm mode)" + logcheckresult "PASS" + return + fi + if get_docker_effective_command_line_args '--live-restore' | grep "live-restore" >/dev/null 2>&1; then + pass -s "$check" + logcheckresult "PASS" + return + fi + warn -s "$check" + logcheckresult "WARN" +} + +check_2_16() { + local id="2.16" + local desc="Ensure Userland Proxy is Disabled (Scored)" + local remediation="You should run the Docker daemon using command: dockerd --userland-proxy=false" + local remediationImpact="Some systems with older Linux kernels may not be able to support hairpin NAT and therefore require the userland proxy service. Also, some networking setups can be impacted by the removal of the userland proxy." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if get_docker_configuration_file_args 'userland-proxy' | grep false >/dev/null 2>&1; then + pass -s "$check" + logcheckresult "PASS" + return + fi + if get_docker_effective_command_line_args '--userland-proxy=false' 2>/dev/null | grep "userland-proxy=false" >/dev/null 2>&1; then + pass -s "$check" + logcheckresult "PASS" + return + fi + warn -s "$check" + logcheckresult "WARN" +} + +check_2_17() { + local id="2.17" + local desc="Ensure that a daemon-wide custom seccomp profile is applied if appropriate (Manual)" + local remediation="By default, Docker's default seccomp profile is applied. If this is adequate for your environment, no action is necessary." + local remediationImpact="A misconfigured seccomp profile could possibly interrupt your container environment. You should therefore exercise extreme care if you choose to override the default settings." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info --format '{{ .SecurityOptions }}' | grep 'name=seccomp,profile=default' 2>/dev/null 1>&2; then + pass -c "$check" + logcheckresult "PASS" + return + fi + info -c "$check" + logcheckresult "INFO" +} + +check_2_18() { + docker_version=$(docker version | grep -i -A2 '^server' | grep ' Version:' \ + | awk '{print $NF; exit}' | tr -d '[:alpha:]-,.' | cut -c 1-4) + + local id="2.18" + local desc="Ensure that experimental features are not implemented in production (Scored)" + local remediation="You should not pass --experimental as a runtime parameter to the Docker daemon on production systems." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if [ "$docker_version" -le 1903 ]; then + if docker version -f '{{.Server.Experimental}}' | grep false 2>/dev/null 1>&2; then + pass -s "$check" + logcheckresult "PASS" + return + fi + warn -s "$check" + logcheckresult "WARN" + return + fi + local desc="$desc (Deprecated)" + local check="$id - $desc" + info -c "$desc" + logcheckresult "INFO" +} + +check_2_end() { + endsectionjson +} diff --git a/scripts/docker-bench-security/tests/3_docker_daemon_configuration_files.sh b/scripts/docker-bench-security/tests/3_docker_daemon_configuration_files.sh new file mode 100644 index 0000000..34b9de5 --- /dev/null +++ b/scripts/docker-bench-security/tests/3_docker_daemon_configuration_files.sh @@ -0,0 +1,548 @@ +#!/bin/bash + +check_3() { + logit "" + local id="3" + local desc="Docker daemon configuration files" + checkHeader="$id - $desc" + info "$checkHeader" + startsectionjson "$id" "$desc" +} + +check_3_1() { + local id="3.1" + local desc="Ensure that the docker.service file ownership is set to root:root (Automated)" + local remediation="Find out the file location: systemctl show -p FragmentPath docker.service. If the file does not exist, this recommendation is not applicable. If the file does exist, you should run the command chown root:root , in order to set the ownership and group ownership for the file to root." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file=$(get_service_file docker.service) + if [ -f "$file" ]; then + if [ "$(stat -c %u%g "$file")" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "** File Not Found" "$remediation" "$remediationImpact" +} + +check_3_2() { + local id="3.2" + local desc="Ensure that docker.service file permissions are appropriately set (Automated)" + local remediation="Find out the file location: systemctl show -p FragmentPath docker.service. If the file does not exist, this recommendation is not applicable. If the file exists, run the command chmod 644 to set the file permissions to 644." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + + file=$(get_service_file docker.service) + if [ -f "$file" ]; then + if [ "$(stat -c %a "$file")" -le 644 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" " ** File Not Found" "$remediation" "$remediationImpact" +} + +check_3_3() { + local id="3.3" + local desc="Ensure that docker.socket file ownership is set to root:root (Automated)" + local remediation="Find out the file location: systemctl show -p FragmentPath docker.socket. If the file does not exist, this recommendation is not applicable. If the file exists, run the command chown root:root to set the ownership and group ownership for the file to root." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file=$(get_service_file docker.socket) + if [ -f "$file" ]; then + if [ "$(stat -c %u%g "$file")" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_4() { + local id="3.4" + local desc="Ensure that docker.socket file permissions are set to 644 or more restrictive (Automated)" + local remediation="Find out the file location: systemctl show -p FragmentPath docker.socket. If the file does not exist, this recommendation is not applicable. If the file does exist, you should run the command chmod 644 to set the file permissions to 644." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file=$(get_service_file docker.socket) + if [ -f "$file" ]; then + if [ "$(stat -c %a "$file")" -le 644 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_5() { + local id="3.5" + local desc="Ensure that the /fenced/mnt/host/etc/docker directory ownership is set to root:root (Automated)" + local remediation="You should run the following command: chown root:root /fenced/mnt/host/etc/docker. This sets the ownership and group ownership for the directory to root." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + directory="/fenced/mnt/host/etc/docker" + if [ -d "$directory" ]; then + if [ "$(stat -c %u%g $directory)" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $directory" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_6() { + local id="3.6" + local desc="Ensure that /fenced/mnt/host/etc/docker directory permissions are set to 755 or more restrictively (Automated)" + local remediation="You should run the following command: chmod 755 /fenced/mnt/host/etc/docker. This sets the permissions for the directory to 755." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + directory="/fenced/mnt/host/etc/docker" + if [ -d "$directory" ]; then + if [ "$(stat -c %a $directory)" -le 755 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $directory" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_7() { + local id="3.7" + local desc="Ensure that registry certificate file ownership is set to root:root (Automated)" + local remediation="You should run the following command: chown root:root /fenced/mnt/host/etc/docker/certs.d//*. This would set the individual ownership and group ownership for the registry certificate files to root." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + directory="/fenced/mnt/host/etc/docker/certs.d/" + if [ -d "$directory" ]; then + fail=0 + owners=$(find "$directory" -type f -name '*.crt') + for p in $owners; do + if [ "$(stat -c %u "$p")" -ne 0 ]; then + fail=1 + fi + done + if [ $fail -eq 1 ]; then + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $directory" "$remediation" "$remediationImpact" + return + fi + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_8() { + local id="3.8" + local desc="Ensure that registry certificate file permissions are set to 444 or more restrictively (Automated)" + local remediation="You should run the following command: chmod 444 /fenced/mnt/host/etc/docker/certs.d//*. This would set the permissions for the registry certificate files to 444." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + directory="/fenced/mnt/host/etc/docker/certs.d/" + if [ -d "$directory" ]; then + fail=0 + perms=$(find "$directory" -type f -name '*.crt') + for p in $perms; do + if [ "$(stat -c %a "$p")" -gt 444 ]; then + fail=1 + fi + done + if [ $fail -eq 1 ]; then + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $directory" "$remediation" "$remediationImpact" + return + fi + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* Directory Not Found" "$remediation" "$remediationImpact" +} + +check_3_9() { + local id="3.9" + local desc="Ensure that TLS CA certificate file ownership is set to root:root (Automated)" + local remediation="You should run the following command: chown root:root . This sets the individual ownership and group ownership for the TLS CA certificate file to root." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + tlscacert=$(get_docker_effective_command_line_args '--tlscacert' | sed -n 's/.*tlscacert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -n "$(get_docker_configuration_file_args 'tlscacert')" ]; then + tlscacert=$(get_docker_configuration_file_args 'tlscacert') + fi + if [ -f "$tlscacert" ]; then + if [ "$(stat -c %u%g "$tlscacert")" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $tlscacert" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* No TLS CA certificate found" "$remediation" "$remediationImpact" +} + +check_3_10() { + local id="3.10" + local desc="Ensure that TLS CA certificate file permissions are set to 444 or more restrictively (Automated)" + local remediation="You should run the following command: chmod 444 . This sets the file permissions on the TLS CA file to 444." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + tlscacert=$(get_docker_effective_command_line_args '--tlscacert' | sed -n 's/.*tlscacert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -n "$(get_docker_configuration_file_args 'tlscacert')" ]; then + tlscacert=$(get_docker_configuration_file_args 'tlscacert') + fi + if [ -f "$tlscacert" ]; then + if [ "$(stat -c %a "$tlscacert")" -le 444 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $tlscacert" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* No TLS CA certificate found" "$remediation" "$remediationImpact" +} + +check_3_11() { + local id="3.11" + local desc="Ensure that Docker server certificate file ownership is set to root:root (Automated)" + local remediation="You should run the following command: chown root:root . This sets the individual ownership and the group ownership for the Docker server certificate file to root." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + tlscert=$(get_docker_effective_command_line_args '--tlscert' | sed -n 's/.*tlscert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -n "$(get_docker_configuration_file_args 'tlscert')" ]; then + tlscert=$(get_docker_configuration_file_args 'tlscert') + fi + if [ -f "$tlscert" ]; then + if [ "$(stat -c %u%g "$tlscert")" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $tlscert" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* No TLS Server certificate found" "$remediation" "$remediationImpact" +} + +check_3_12() { + local id="3.12" + local desc="Ensure that the Docker server certificate file permissions are set to 444 or more restrictively (Automated)" + local remediation="You should run the following command: chmod 444 . This sets the file permissions of the Docker server certificate file to 444." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + tlscert=$(get_docker_effective_command_line_args '--tlscert' | sed -n 's/.*tlscert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -n "$(get_docker_configuration_file_args 'tlscert')" ]; then + tlscert=$(get_docker_configuration_file_args 'tlscert') + fi + if [ -f "$tlscert" ]; then + if [ "$(stat -c %a "$tlscert")" -le 444 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $tlscert" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* No TLS Server certificate found" "$remediation" "$remediationImpact" +} + +check_3_13() { + local id="3.13" + local desc="Ensure that the Docker server certificate key file ownership is set to root:root (Automated)" + local remediation="You should run the following command: chown root:root . This sets the individual ownership and group ownership for the Docker server certificate key file to root." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + tlskey=$(get_docker_effective_command_line_args '--tlskey' | sed -n 's/.*tlskey=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -n "$(get_docker_configuration_file_args 'tlskey')" ]; then + tlskey=$(get_docker_configuration_file_args 'tlskey') + fi + if [ -f "$tlskey" ]; then + if [ "$(stat -c %u%g "$tlskey")" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $tlskey" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* No TLS Key Found" "$remediation" "$remediationImpact" +} + +check_3_14() { + local id="3.14" + local desc="Ensure that the Docker server certificate key file permissions are set to 400 (Automated)" + local remediation="You should run the following command: chmod 400 . This sets the Docker server certificate key file permissions to 400." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + tlskey=$(get_docker_effective_command_line_args '--tlskey' | sed -n 's/.*tlskey=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -n "$(get_docker_configuration_file_args 'tlskey')" ]; then + tlskey=$(get_docker_configuration_file_args 'tlskey') + fi + if [ -f "$tlskey" ]; then + if [ "$(stat -c %a "$tlskey")" -eq 400 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $tlskey" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "No TLS key found" "$remediation" "$remediationImpact" +} + +check_3_15() { + local id="3.15" + local desc="Ensure that the Docker socket file ownership is set to root:docker (Automated)" + local remediation="You should run the following command: chown root:docker /var/run/docker.sock. This sets the ownership to root and group ownership to docker for the default Docker socket file." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file="/var/run/docker.sock" + if [ -S "$file" ]; then + if [ "$(stat -c %U:%G $file)" = 'root:docker' ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_16() { + local id="3.16" + local desc="Ensure that the Docker socket file permissions are set to 660 or more restrictively (Automated)" + local remediation="You should run the following command: chmod 660 /var/run/docker.sock. This sets the file permissions of the Docker socket file to 660." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file="/var/run/docker.sock" + if [ -S "$file" ]; then + if [ "$(stat -c %a $file)" -le 660 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_17() { + local id="3.17" + local desc="Ensure that the daemon.json file ownership is set to root:root (Automated)" + local remediation="You should run the following command: chown root:root /fenced/mnt/host/etc/docker/daemon.json. This sets the ownership and group ownership for the file to root." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file="/fenced/mnt/host/etc/docker/daemon.json" + if [ -f "$file" ]; then + if [ "$(stat -c %U:%G $file)" = 'root:root' ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_18() { + local id="3.18" + local desc="Ensure that daemon.json file permissions are set to 644 or more restrictive (Automated)" + local remediation="You should run the following command: chmod 644 /fenced/mnt/host/etc/docker/daemon.json. This sets the file permissions for this file to 644." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + + file="/fenced/mnt/host/etc/docker/daemon.json" + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -le 644 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "*File Not Found" "$remediation" "$remediationImpact" +} + +check_3_19() { + local id="3.19" + local desc="Ensure that the /fenced/mnt/host/etc/default/docker file ownership is set to root:root (Automated)" + local remediation="You should run the following command: chown root:root /fenced/mnt/host/etc/default/docker. This sets the ownership and group ownership of the file to root." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file="/fenced/mnt/host/etc/default/docker" + if [ -f "$file" ]; then + if [ "$(stat -c %U:%G $file)" = 'root:root' ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_20() { + local id="3.20" + local desc="Ensure that the /fenced/mnt/host/etc/sysconfig/docker file permissions are set to 644 or more restrictively (Automated)" + local remediation="You should run the following command: chmod 644 /fenced/mnt/host/etc/sysconfig/docker. This sets the file permissions for this file to 644." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file="/fenced/mnt/host/etc/sysconfig/docker" + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -le 644 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_21() { + local id="3.21" + local desc="Ensure that the /fenced/mnt/host/etc/sysconfig/docker file ownership is set to root:root (Automated)" + local remediation="You should run the following command: chown root:root /fenced/mnt/host/etc/sysconfig/docker. This sets the ownership and group ownership for the file to root." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file="/fenced/mnt/host/etc/sysconfig/docker" + if [ -f "$file" ]; then + if [ "$(stat -c %U:%G $file)" = 'root:root' ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_22() { + local id="3.22" + local desc="Ensure that the /fenced/mnt/host/etc/default/docker file permissions are set to 644 or more restrictively (Automated)" + local remediation="You should run the following command: chmod 644 /fenced/mnt/host/etc/default/docker. This sets the file permissions for this file to 644." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file="/fenced/mnt/host/etc/default/docker" + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -le 644 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_23() { + local id="3.23" + local desc="Ensure that the Containerd socket file ownership is set to root:root (Automated)" + local remediation="You should run the following command: chown root:root /run/containerd/containerd.sock. This sets the ownership and group ownership for the file to root." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file="/run/containerd/containerd.sock" + if [ -S "$file" ]; then + if [ "$(stat -c %U:%G $file)" = 'root:root' ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_24() { + local id="3.24" + local desc="Ensure that the Containerd socket file permissions are set to 660 or more restrictively (Automated)" + local remediation="You should run the following command: chmod 660 /run/containerd/containerd.sock. This sets the file permissions for this file to 660." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Docker Files" + starttestjson "$id" "$desc" + + file="/run/containerd/containerd.sock" + if [ -S "$file" ]; then + if [ "$(stat -c %a $file)" -le 660 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + return + fi + logbenchjson "INFO" $id "$testCategory" "$desc" "* File Not Found" "$remediation" "$remediationImpact" +} + +check_3_end() { + endsectionjson +} diff --git a/scripts/docker-bench-security/tests/4_container_images.sh b/scripts/docker-bench-security/tests/4_container_images.sh new file mode 100644 index 0000000..ad8b7a6 --- /dev/null +++ b/scripts/docker-bench-security/tests/4_container_images.sh @@ -0,0 +1,248 @@ +#!/bin/bash + +check_4() { + logit "" + local id="4" + local desc="Container Images and Build File" + checkHeader="$id - $desc" + info "$checkHeader" + startsectionjson "$id" "$desc" +} + +check_4_1() { + local id="4.1" + local desc="Ensure that a user for the container has been created (Automated)" + local remediation="You should ensure that the Dockerfile for each container image contains the information: USER . If there is no specific user created in the container base image, then make use of the useradd command to add a specific user before the USER instruction in the Dockerfile." + local remediationImpact="Running as a non-root user can present challenges where you wish to bind mount volumes from the underlying host. In this case, care should be taken to ensure that the user running the contained process can read and write to the bound directory, according to their requirements." + local check="$id - $desc" + starttestjson "$id" "$desc" + + # If container_users is empty, there are no running containers + if [ -z "$containers" ]; then + info -c "$check" + info " * No containers running" + logcheckresult "INFO" "No containers running" + return + fi + # We have some containers running, set failure flag to 0. Check for Users. + fail=0 + # Make the loop separator be a new-line in POSIX compliant fashion + set -f; IFS=$' + ' + root_containers="" + for c in $containers; do + user=$(docker inspect --format 'User={{.Config.User}}' "$c") + + if [ "$user" = "User=0" ] || [ "$user" = "User=root" ] || [ "$user" = "User=" ] || [ "$user" = "User=[]" ] || [ "$user" = "User=" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Running as root: $c" + root_containers="$root_containers $c" + fail=1 + continue + fi + warn " * Running as root: $c" + root_containers="$root_containers $c" + fi + done + # We went through all the containers and found none running as root + if [ $fail -eq 0 ]; then + pass -s "$check" + logcheckresult "PASS" + return + fi + logcheckresult "WARN" "running as root" "$root_containers" + # Make the loop separator go back to space + set +f; unset IFS +} + +check_4_2() { + local id="4.2" + local desc="Ensure that containers use only trusted base images (Manual)" + local remediation="Configure and use Docker Content trust. View the history of each Docker image to evaluate its risk, dependent on the sensitivity of the application you wish to deploy using it. Scan Docker images for vulnerabilities at regular intervals." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "NOTE" +} + +check_4_3() { + local id="4.3" + local desc="Ensure that unnecessary packages are not installed in the container (Manual)" + local remediation="You should not install anything within the container that is not required. You should consider using a minimal base image if you can. Some of the options available include BusyBox and Alpine. Not only can this trim your image size considerably, but there would also be fewer pieces of software which could contain vectors for attack." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "NOTE" +} + +check_4_4() { + local id="4.4" + local desc="Ensure images are scanned and rebuilt to include security patches (Manual)" + local remediation="Images should be re-built ensuring that the latest version of the base images are used, to keep the operating system patch level at an appropriate level. Once the images have been re-built, containers should be re-started making use of the updated images." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "NOTE" +} + +check_4_5() { + local id="4.5" + local desc="Ensure Content trust for Docker is Enabled (Automated)" + local remediation="Add DOCKER_CONTENT_TRUST variable to the /etc/environment file using command echo DOCKER_CONTENT_TRUST=1 | sudo tee -a /etc/environment." + local remediationImpact="This prevents users from working with tagged images unless they contain a signature." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if [ "$DOCKER_CONTENT_TRUST" = "1" ]; then + pass -s "$check" + logcheckresult "PASS" + return + fi + warn -s "$check" + logcheckresult "WARN" +} + +check_4_6() { + local id="4.6" + local desc="Ensure that HEALTHCHECK instructions have been added to container images (Automated)" + local remediation="You should follow the Docker documentation and rebuild your container images to include the HEALTHCHECK instruction." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + fail=0 + no_health_images="" + for img in $images; do + if docker inspect --format='{{.Config.Healthcheck}}' "$img" 2>/dev/null | grep -e "" >/dev/null 2>&1; then + if [ $fail -eq 0 ]; then + fail=1 + warn -s "$check" + fi + imgName=$(docker inspect --format='{{.RepoTags}}' "$img" 2>/dev/null) + if ! [ "$imgName" = '[]' ]; then + warn " * No Healthcheck found: $imgName" + no_health_images="$no_health_images $imgName" + else + warn " * No Healthcheck found: $img" + no_health_images="$no_health_images $img" + fi + fi + done + if [ $fail -eq 0 ]; then + pass -s "$check" + logcheckresult "PASS" + return + fi + logcheckresult "WARN" "Images w/o HEALTHCHECK" "$no_health_images" +} + +check_4_7() { + local id="4.7" + local desc="Ensure update instructions are not used alone in the Dockerfile (Manual)" + local remediation="You should use update instructions together with install instructions and version pinning for packages while installing them. This prevent caching and force the extraction of the required versions. Alternatively, you could use the --no-cache flag during the docker build process to avoid using cached layers." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + fail=0 + update_images="" + for img in $images; do + if docker history "$img" 2>/dev/null | grep -e "update" >/dev/null 2>&1; then + if [ $fail -eq 0 ]; then + fail=1 + info -c "$check" + fi + imgName=$(docker inspect --format='{{.RepoTags}}' "$img" 2>/dev/null) + if ! [ "$imgName" = '[]' ]; then + info " * Update instruction found: $imgName" + update_images="$update_images $imgName" + fi + fi + done + if [ $fail -eq 0 ]; then + pass -c "$check" + logcheckresult "PASS" + return + fi + logcheckresult "INFO" "Update instructions found" "$update_images" +} + +check_4_8() { + local id="4.8" + local desc="Ensure setuid and setgid permissions are removed (Manual)" + local remediation="You should allow setuid and setgid permissions only on executables which require them. You could remove these permissions at build time by adding the following command in your Dockerfile, preferably towards the end of the Dockerfile: RUN find / -perm /6000 -type f -exec chmod a-s {} ; || true" + local remediationImpact="The above command would break all executables that depend on setuid or setgid permissions including legitimate ones. You should therefore be careful to modify the command to suit your requirements so that it does not reduce the permissions of legitimate programs excessively. Because of this, you should exercise a degree of caution and examine all processes carefully before making this type of modification in order to avoid outages." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "NOTE" +} + +check_4_9() { + local id="4.9" + local desc="Ensure that COPY is used instead of ADD in Dockerfiles (Manual)" + local remediation="You should use COPY rather than ADD instructions in Dockerfiles." + local remediationImpact="Care needs to be taken in implementing this control if the application requires functionality that is part of the ADD instruction, for example, if you need to retrieve files from remote URLS." + local check="$id - $desc" + starttestjson "$id" "$desc" + + fail=0 + add_images="" + for img in $images; do + if docker history --format "{{ .CreatedBy }}" --no-trunc "$img" | \ + sed '$d' | grep -q 'ADD'; then + if [ $fail -eq 0 ]; then + fail=1 + info -c "$check" + fi + imgName=$(docker inspect --format='{{.RepoTags}}' "$img" 2>/dev/null) + if ! [ "$imgName" = '[]' ]; then + info " * ADD in image history: $imgName" + add_images="$add_images $imgName" + fi + fi + done + if [ $fail -eq 0 ]; then + pass -c "$check" + logcheckresult "PASS" + return + fi + logcheckresult "INFO" "Images using ADD" "$add_images" +} + +check_4_10() { + local id="4.10" + local desc="Ensure secrets are not stored in Dockerfiles (Manual)" + local remediation="Do not store any kind of secrets within Dockerfiles. Where secrets are required during the build process, make use of a secrets management tool, such as the buildkit builder included with Docker." + local remediationImpact="A proper secrets management process will be required for Docker image building." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "NOTE" +} + +check_4_11() { + local id="4.11" + local desc="Ensure only verified packages are installed (Manual)" + local remediation="You should use a secure package distribution mechanism of your choice to ensure the authenticity of software packages." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "NOTE" +} + +check_4_end() { + endsectionjson +} diff --git a/scripts/docker-bench-security/tests/5_container_runtime.sh b/scripts/docker-bench-security/tests/5_container_runtime.sh new file mode 100644 index 0000000..6d2067b --- /dev/null +++ b/scripts/docker-bench-security/tests/5_container_runtime.sh @@ -0,0 +1,1186 @@ +#!/bin/bash + +check_5() { + logit "" + local id="5" + local desc="Container Runtime" + checkHeader="$id - $desc" + info "$checkHeader" + startsectionjson "$id" "$desc" +} + +check_running_containers() { + # If containers is empty, there are no running containers + if [ -z "$containers" ]; then + info " * No containers running, skipping Section 5" + return + fi + # Make the loop separator be a new-line in POSIX compliant fashion + set -f; IFS=$' + ' +} + +check_5_1() { + if [ -z "$containers" ]; then + return + fi + + local id="5.1" + local desc="Ensure that, if applicable, an AppArmor Profile is enabled (Automated)" + local remediation="If AppArmor is applicable for your Linux OS, you should enable it. Alternatively, Docker's default AppArmor policy can be used." + local remediationImpact="The container will have the security controls defined in the AppArmor profile. It should be noted that if the AppArmor profile is misconfigured, this may cause issues with the operation of the container." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + no_apparmor_containers="" + for c in $containers; do + policy=$(docker inspect --format 'AppArmorProfile={{ .AppArmorProfile }}' "$c") + + if [ "$policy" = "AppArmorProfile=" ] || [ "$policy" = "AppArmorProfile=[]" ] || [ "$policy" = "AppArmorProfile=" ] || [ "$policy" = "AppArmorProfile=unconfined" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * No AppArmorProfile Found: $c" + no_apparmor_containers="$no_apparmor_containers $c" + fail=1 + continue + fi + warn " * No AppArmorProfile Found: $c" + no_apparmor_containers="$no_apparmor_containers $c" + fi + done + # We went through all the containers and found none without AppArmor + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers with no AppArmorProfile" "$no_apparmor_containers" +} + +check_5_2() { + if [ -z "$containers" ]; then + return + fi + + local id="5.2" + local desc="Ensure that, if applicable, SELinux security options are set (Automated)" + local remediation="Set the SELinux State. Set the SELinux Policy. Create or import a SELinux policy template for Docker containers. Start Docker in daemon mode with SELinux enabled. Start your Docker container using the security options." + local remediationImpact="Any restrictions defined in the SELinux policy will be applied to your containers. It should be noted that if your SELinux policy is misconfigured, this may have an impact on the correct operation of the affected containers." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + no_securityoptions_containers="" + for c in $containers; do + policy=$(docker inspect --format 'SecurityOpt={{ .HostConfig.SecurityOpt }}' "$c") + + if [ "$policy" = "SecurityOpt=" ] || [ "$policy" = "SecurityOpt=[]" ] || [ "$policy" = "SecurityOpt=" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * No SecurityOptions Found: $c" + no_securityoptions_containers="$no_securityoptions_containers $c" + fail=1 + continue + fi + warn " * No SecurityOptions Found: $c" + no_securityoptions_containers="$no_securityoptions_containers $c" + fi + done + # We went through all the containers and found none without SELinux + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers with no SecurityOptions" "$no_securityoptions_containers" +} + +check_5_3() { + if [ -z "$containers" ]; then + return + fi + + local id="5.3" + local desc="Ensure that Linux kernel capabilities are restricted within containers (Automated)" + local remediation="You could remove all the currently configured capabilities and then restore only the ones you specifically use: docker run --cap-drop=all --cap-add={,} " + local remediationImpact="Restrictions on processes within a container are based on which Linux capabilities are in force. Removal of the NET_RAW capability prevents the container from creating raw sockets which is good security practice under most circumstances, but may affect some networking utilities." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + caps_containers="" + for c in $containers; do + container_caps=$(docker inspect --format 'CapAdd={{ .HostConfig.CapAdd}}' "$c") + caps=$(echo "$container_caps" | tr "[:lower:]" "[:upper:]" | \ + sed 's/CAPADD/CapAdd/' | \ + sed -r "s/AUDIT_WRITE|CHOWN|DAC_OVERRIDE|FOWNER|FSETID|KILL|MKNOD|NET_BIND_SERVICE|NET_RAW|SETFCAP|SETGID|SETPCAP|SETUID|SYS_CHROOT|\s//g") + + if [ "$caps" != 'CapAdd=' ] && [ "$caps" != 'CapAdd=[]' ] && [ "$caps" != 'CapAdd=' ] && [ "$caps" != 'CapAdd=' ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Capabilities added: $caps to $c" + caps_containers="$caps_containers $c" + fail=1 + continue + fi + warn " * Capabilities added: $caps to $c" + caps_containers="$caps_containers $c" + fi + done + # We went through all the containers and found none with extra capabilities + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Capabilities added for containers" "$caps_containers" +} + +check_5_4() { + if [ -z "$containers" ]; then + return + fi + + local id="5.4" + local desc="Ensure that privileged containers are not used (Automated)" + local remediation="You should not run containers with the --privileged flag." + local remediationImpact="If you start a container without the --privileged flag, it will not have excessive default capabilities." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + privileged_containers="" + for c in $containers; do + privileged=$(docker inspect --format '{{ .HostConfig.Privileged }}' "$c") + + if [ "$privileged" = "true" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Container running in Privileged mode: $c" + privileged_containers="$privileged_containers $c" + fail=1 + continue + fi + warn " * Container running in Privileged mode: $c" + privileged_containers="$privileged_containers $c" + fi + done + # We went through all the containers and found no privileged containers + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers running in privileged mode" "$privileged_containers" +} + +check_5_5() { + if [ -z "$containers" ]; then + return + fi + + local id="5.5" + local desc="Ensure sensitive host system directories are not mounted on containers (Automated)" + local remediation="You should not mount directories which are security sensitive on the host within containers, especially in read-write mode." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + # List of sensitive directories to test for. Script uses new-lines as a separator. + # Note the lack of identation. It needs it for the substring comparison. + sensitive_dirs='/ +/boot +/dev +/fenced/mnt/host/etc +/lib +/proc +/sys +/usr' + fail=0 + sensitive_mount_containers="" + for c in $containers; do + volumes=$(docker inspect --format '{{ .Mounts }}' "$c") + if docker inspect --format '{{ .VolumesRW }}' "$c" 2>/dev/null 1>&2; then + volumes=$(docker inspect --format '{{ .VolumesRW }}' "$c") + fi + # Go over each directory in sensitive dir and see if they exist in the volumes + for v in $sensitive_dirs; do + sensitive=0 + if echo "$volumes" | grep -e "{.*\s$v\s.*true\s.*}" 2>/tmp/null 1>&2; then + sensitive=1 + fi + if [ $sensitive -eq 1 ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Sensitive directory $v mounted in: $c" + sensitive_mount_containers="$sensitive_mount_containers $c:$v" + fail=1 + continue + fi + warn " * Sensitive directory $v mounted in: $c" + sensitive_mount_containers="$sensitive_mount_containers $c:$v" + fi + done + done + # We went through all the containers and found none with sensitive mounts + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers with sensitive directories mounted" "$sensitive_mount_containers" +} + +check_5_6() { + if [ -z "$containers" ]; then + return + fi + + local id="5.6" + local desc="Ensure sshd is not run within containers (Automated)" + local remediation="Uninstall the SSH daemon from the container and use docker exec to enter a container on the remote host." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + ssh_exec_containers="" + printcheck=0 + for c in $containers; do + + processes=$(docker exec "$c" ps -el 2>/dev/null | grep -c sshd | awk '{print $1}') + if [ "$processes" -ge 1 ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Container running sshd: $c" + ssh_exec_containers="$ssh_exec_containers $c" + fail=1 + printcheck=1 + else + warn " * Container running sshd: $c" + ssh_exec_containers="$ssh_exec_containers $c" + fi + fi + + exec_check=$(docker exec "$c" ps -el 2>/dev/null) + if [ $? -eq 255 ]; then + if [ $printcheck -eq 0 ]; then + warn -s "$check" + printcheck=1 + fi + warn " * Docker exec fails: $c" + ssh_exec_containers="$ssh_exec_containers $c" + fail=1 + fi + + done + # We went through all the containers and found none with sshd + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers with sshd/docker exec failures" "$ssh_exec_containers" +} + +check_5_7() { + if [ -z "$containers" ]; then + return + fi + + local id="5.7" + local desc="Ensure privileged ports are not mapped within containers (Automated)" + local remediation="You should not map container ports to privileged host ports when starting a container. You should also, ensure that there is no such container to host privileged port mapping declarations in the Dockerfile." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + privileged_port_containers="" + for c in $containers; do + # Port format is private port -> ip: public port + ports=$(docker port "$c" | awk '{print $0}' | cut -d ':' -f2) + + # iterate through port range (line delimited) + for port in $ports; do + if [ -n "$port" ] && [ "$port" -lt 1024 ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Privileged Port in use: $port in $c" + privileged_port_containers="$privileged_port_containers $c:$port" + fail=1 + continue + fi + warn " * Privileged Port in use: $port in $c" + privileged_port_containers="$privileged_port_containers $c:$port" + fi + done + done + # We went through all the containers and found no privileged ports + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers using privileged ports" "$privileged_port_containers" +} + +check_5_8() { + if [ -z "$containers" ]; then + return + fi + + local id="5.8" + local desc="Ensure that only needed ports are open on the container (Manual)" + local remediation="You should ensure that the Dockerfile for each container image only exposes needed ports." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + open_port_containers="" + for c in $containers; do + ports=$(docker port "$c" | awk '{print $0}' | cut -d ':' -f2) + + for port in $ports; do + if [ -n "$port" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Port in use: $port in $c" + open_port_containers="$open_port_containers $c:$port" + fail=1 + continue + fi + warn " * Port in use: $port in $c" + open_port_containers="$open_port_containers $c:$port" + fi + done + done + + # We went through all the containers and found none with open ports + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers with open ports" "$open_port_containers" +} + +check_5_9() { + if [ -z "$containers" ]; then + return + fi + + local id="5.9" + local desc="Ensure that the host's network namespace is not shared (Automated)" + local remediation="You should not pass the --net=host option when starting any container." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + net_host_containers="" + for c in $containers; do + mode=$(docker inspect --format 'NetworkMode={{ .HostConfig.NetworkMode }}' "$c") + + if [ "$mode" = "NetworkMode=host" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Container running with networking mode 'host': $c" + net_host_containers="$net_host_containers $c" + fail=1 + continue + fi + warn " * Container running with networking mode 'host': $c" + net_host_containers="$net_host_containers $c" + fi + done + # We went through all the containers and found no Network Mode host + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers running with networking mode 'host'" "$net_host_containers" +} + +check_5_10() { + if [ -z "$containers" ]; then + return + fi + + local id="5.10" + local desc="Ensure that the memory usage for containers is limited (Automated)" + local remediation="You should run the container with only as much memory as it requires by using the --memory argument." + local remediationImpact="If correct memory limits are not set on each container, one process can expand its usage and cause other containers to run out of resources." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + mem_unlimited_containers="" + for c in $containers; do + memory=$(docker inspect --format '{{ .HostConfig.Memory }}' "$c") + if docker inspect --format '{{ .Config.Memory }}' "$c" 2> /dev/null 1>&2; then + memory=$(docker inspect --format '{{ .Config.Memory }}' "$c") + fi + + if [ "$memory" = "0" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Container running without memory restrictions: $c" + mem_unlimited_containers="$mem_unlimited_containers $c" + fail=1 + continue + fi + warn " * Container running without memory restrictions: $c" + mem_unlimited_containers="$mem_unlimited_containers $c" + fi + done + # We went through all the containers and found no lack of Memory restrictions + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Container running without memory restrictions" "$mem_unlimited_containers" +} + +check_5_11() { + if [ -z "$containers" ]; then + return + fi + + local id="5.11" + local desc="Ensure that CPU priority is set appropriately on containers (Automated)" + local remediation="You should manage the CPU runtime between your containers dependent on their priority within your organization. To do so start the container using the --cpu-shares argument." + local remediationImpact="If you do not correctly assign CPU thresholds, the container process may run out of resources and become unresponsive. If CPU resources on the host are not constrainted, CPU shares do not place any restrictions on individual resources." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + cpu_unlimited_containers="" + for c in $containers; do + shares=$(docker inspect --format '{{ .HostConfig.CpuShares }}' "$c") + if docker inspect --format '{{ .Config.CpuShares }}' "$c" 2> /dev/null 1>&2; then + shares=$(docker inspect --format '{{ .Config.CpuShares }}' "$c") + fi + + if [ "$shares" = "0" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Container running without CPU restrictions: $c" + cpu_unlimited_containers="$cpu_unlimited_containers $c" + fail=1 + continue + fi + warn " * Container running without CPU restrictions: $c" + cpu_unlimited_containers="$cpu_unlimited_containers $c" + fi + done + # We went through all the containers and found no lack of CPUShare restrictions + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers running without CPU restrictions" "$cpu_unlimited_containers" +} + +check_5_12() { + if [ -z "$containers" ]; then + return + fi + + local id="5.12" + local desc="Ensure that the container's root filesystem is mounted as read only (Automated)" + local remediation="You should add a --read-only flag at a container's runtime to enforce the container's root filesystem being mounted as read only." + local remediationImpact="Enabling --read-only at container runtime may break some container OS packages if a data writing strategy is not defined. You should define what the container's data should and should not persist at runtime in order to decide which strategy to use." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + fsroot_mount_containers="" + for c in $containers; do + read_status=$(docker inspect --format '{{ .HostConfig.ReadonlyRootfs }}' "$c") + + if [ "$read_status" = "false" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Container running with root FS mounted R/W: $c" + fsroot_mount_containers="$fsroot_mount_containers $c" + fail=1 + continue + fi + warn " * Container running with root FS mounted R/W: $c" + fsroot_mount_containers="$fsroot_mount_containers $c" + fi + done + # We went through all the containers and found no R/W FS mounts + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers running with root FS mounted R/W" "$fsroot_mount_containers" +} + +check_5_13() { + if [ -z "$containers" ]; then + return + fi + + local id="5.13" + local desc="Ensure that incoming container traffic is bound to a specific host interface (Automated)" + local remediation="You should bind the container port to a specific host interface on the desired host port. Example: docker run --detach --publish 10.2.3.4:49153:80 nginx In this example, the container port 80 is bound to the host port on 49153 and would accept incoming connection only from the 10.2.3.4 external interface." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + incoming_unbound_containers="" + for c in $containers; do + for ip in $(docker port "$c" | awk '{print $3}' | cut -d ':' -f1); do + if [ "$ip" = "0.0.0.0" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Port being bound to wildcard IP: $ip in $c" + incoming_unbound_containers="$incoming_unbound_containers $c:$ip" + fail=1 + continue + fi + warn " * Port being bound to wildcard IP: $ip in $c" + incoming_unbound_containers="$incoming_unbound_containers $c:$ip" + fi + done + done + # We went through all the containers and found no ports bound to 0.0.0.0 + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers with port bound to wildcard IP" "$incoming_unbound_containers" +} + +check_5_14() { + if [ -z "$containers" ]; then + return + fi + + local id="5.14" + local desc="Ensure that the 'on-failure' container restart policy is set to '5' (Automated)" + local remediation="If you wish a container to be automatically restarted, a sample command is docker run --detach --restart=on-failure:5 nginx" + local remediationImpact="If this option is set, a container will only attempt to restart itself 5 times." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + maxretry_unset_containers="" + for c in $containers; do + policy=$(docker inspect --format MaximumRetryCount='{{ .HostConfig.RestartPolicy.MaximumRetryCount }}' "$c") + + if [ "$policy" != "MaximumRetryCount=5" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * MaximumRetryCount is not set to 5: $c" + maxretry_unset_containers="$maxretry_unset_containers $c" + fail=1 + continue + fi + warn " * MaximumRetryCount is not set to 5: $c" + maxretry_unset_containers="$maxretry_unset_containers $c" + fi + done + # We went through all the containers and they all had MaximumRetryCount=5 + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers with MaximumRetryCount not set to 5" "$maxretry_unset_containers" +} + +check_5_15() { + if [ -z "$containers" ]; then + return + fi + + local id="5.15" + local desc="Ensure that the host's process namespace is not shared (Automated)" + local remediation="You should not start a container with the --pid=host argument." + local remediationImpact="Container processes cannot see processes on the host system." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + pidns_shared_containers="" + for c in $containers; do + mode=$(docker inspect --format 'PidMode={{.HostConfig.PidMode }}' "$c") + + if [ "$mode" = "PidMode=host" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Host PID namespace being shared with: $c" + pidns_shared_containers="$pidns_shared_containers $c" + fail=1 + continue + fi + warn " * Host PID namespace being shared with: $c" + pidns_shared_containers="$pidns_shared_containers $c" + fi + done + # We went through all the containers and found none with PidMode as host + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers sharing host PID namespace" "$pidns_shared_containers" +} + +check_5_16() { + if [ -z "$containers" ]; then + return + fi + + local id="5.16" + local desc="Ensure that the host's IPC namespace is not shared (Automated)" + local remediation="You should not start a container with the --ipc=host argument." + local remediationImpact="Shared memory segments are used in order to accelerate interprocess communications, commonly in high-performance applications. If this type of application is containerized into multiple containers, you might need to share the IPC namespace of the containers in order to achieve high performance. Under these circumstances, you should still only share container specific IPC namespaces and not the host IPC namespace." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + ipcns_shared_containers="" + for c in $containers; do + mode=$(docker inspect --format 'IpcMode={{.HostConfig.IpcMode }}' "$c") + + if [ "$mode" = "IpcMode=host" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Host IPC namespace being shared with: $c" + ipcns_shared_containers="$ipcns_shared_containers $c" + fail=1 + continue + fi + warn " * Host IPC namespace being shared with: $c" + ipcns_shared_containers="$ipcns_shared_containers $c" + fi + done + # We went through all the containers and found none with IPCMode as host + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers sharing host IPC namespace" "$ipcns_shared_containers" +} + +check_5_17() { + if [ -z "$containers" ]; then + return + fi + + local id="5.17" + local desc="Ensure that host devices are not directly exposed to containers (Manual)" + local remediation="You should not directly expose host devices to containers. If you do need to expose host devices to containers, you should use granular permissions as appropriate to your organization." + local remediationImpact="You would not be able to use host devices directly within containers." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + hostdev_exposed_containers="" + for c in $containers; do + devices=$(docker inspect --format 'Devices={{ .HostConfig.Devices }}' "$c") + + if [ "$devices" != "Devices=" ] && [ "$devices" != "Devices=[]" ] && [ "$devices" != "Devices=" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + info -c "$check" + info " * Container has devices exposed directly: $c" + hostdev_exposed_containers="$hostdev_exposed_containers $c" + fail=1 + continue + fi + info " * Container has devices exposed directly: $c" + hostdev_exposed_containers="$hostdev_exposed_containers $c" + fi + done + # We went through all the containers and found none with devices + if [ $fail -eq 0 ]; then + pass -c "$check" + logcheckresult "PASS" + return + fi + logcheckresult "INFO" "Containers with host devices exposed directly" "$hostdev_exposed_containers" +} + +check_5_18() { + if [ -z "$containers" ]; then + return + fi + + local id="5.18" + local desc="Ensure that the default ulimit is overwritten at runtime if needed (Manual)" + local remediation="You should only override the default ulimit settings if needed in a specific case." + local remediationImpact="If ulimits are not set correctly, overutilization by individual containers could make the host system unusable." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + no_ulimit_containers="" + for c in $containers; do + ulimits=$(docker inspect --format 'Ulimits={{ .HostConfig.Ulimits }}' "$c") + + if [ "$ulimits" = "Ulimits=" ] || [ "$ulimits" = "Ulimits=[]" ] || [ "$ulimits" = "Ulimits=" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + info -c "$check" + info " * Container no default ulimit override: $c" + no_ulimit_containers="$no_ulimit_containers $c" + fail=1 + continue + fi + info " * Container no default ulimit override: $c" + no_ulimit_containers="$no_ulimit_containers $c" + fi + done + # We went through all the containers and found none without Ulimits + if [ $fail -eq 0 ]; then + pass -c "$check" + logcheckresult "PASS" + return + fi + logcheckresult "INFO" "Containers with no default ulimit override" "$no_ulimit_containers" +} + +check_5_19() { + if [ -z "$containers" ]; then + return + fi + + local id="5.19" + local desc="Ensure mount propagation mode is not set to shared (Automated)" + local remediation="Do not mount volumes in shared mode propagation." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + mountprop_shared_containers="" + for c in $containers; do + if docker inspect --format 'Propagation={{range $mnt := .Mounts}} {{json $mnt.Propagation}} {{end}}' "$c" | \ + grep shared 2>/dev/null 1>&2; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Mount propagation mode is shared: $c" + mountprop_shared_containers="$mountprop_shared_containers $c" + fail=1 + continue + fi + warn " * Mount propagation mode is shared: $c" + mountprop_shared_containers="$mountprop_shared_containers $c" + fi + done + # We went through all the containers and found none with shared propagation mode + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers with shared mount propagation" "$mountprop_shared_containers" +} + +check_5_20() { + if [ -z "$containers" ]; then + return + fi + + local id="5.20" + local desc="Ensure that the host's UTS namespace is not shared (Automated)" + local remediation="You should not start a container with the --uts=host argument." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + utcns_shared_containers="" + for c in $containers; do + mode=$(docker inspect --format 'UTSMode={{.HostConfig.UTSMode }}' "$c") + + if [ "$mode" = "UTSMode=host" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Host UTS namespace being shared with: $c" + utcns_shared_containers="$utcns_shared_containers $c" + fail=1 + continue + fi + warn " * Host UTS namespace being shared with: $c" + utcns_shared_containers="$utcns_shared_containers $c" + fi + done + # We went through all the containers and found none with UTSMode as host + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers sharing host UTS namespace" "$utcns_shared_containers" +} + +check_5_21() { + if [ -z "$containers" ]; then + return + fi + + local id="5.21" + local desc="Ensure the default seccomp profile is not Disabled (Automated)" + local remediation="By default, seccomp profiles are enabled. You do not need to do anything unless you want to modify and use a modified seccomp profile." + local remediationImpact="With Docker 1.10 and greater, the default seccomp profile blocks syscalls, regardless of -- cap-add passed to the container." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + seccomp_disabled_containers="" + for c in $containers; do + if docker inspect --format 'SecurityOpt={{.HostConfig.SecurityOpt }}' "$c" | \ + grep -E 'seccomp:unconfined|seccomp=unconfined' 2>/dev/null 1>&2; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Default seccomp profile disabled: $c" + seccomp_disabled_containers="$seccomp_disabled_containers $c" + fail=1 + else + warn " * Default seccomp profile disabled: $c" + seccomp_disabled_containers="$seccomp_disabled_containers $c" + fi + fi + done + # We went through all the containers and found none with default secomp profile disabled + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers with default seccomp profile disabled" "$seccomp_disabled_containers" +} + +check_5_22() { + if [ -z "$containers" ]; then + return + fi + + local id="5.22" + local desc="Ensure that docker exec commands are not used with the privileged option (Automated)" + local remediation="You should not use the --privileged option in docker exec commands." + local remediationImpact="If you need enhanced capabilities within a container, then run it with all the permissions it requires. These should be specified individually." + local check="$id - $desc" + local testCategory="Container Runtime" + + note -c "$check" + logcheckresult "NOTE" +} + +check_5_23() { + if [ -z "$containers" ]; then + return + fi + + local id="5.23" + local desc="Ensure that docker exec commands are not used with the user=root option (Manual)" + local remediation="You should not use the --user=root option in docker exec commands." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + note -c "$check" + logcheckresult "NOTE" +} + +check_5_24() { + if [ -z "$containers" ]; then + return + fi + + local id="5.24" + local desc="Ensure that cgroup usage is confirmed (Automated)" + local remediation="You should not use the --cgroup-parent option within the docker run command unless strictly required." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + unexpected_cgroup_containers="" + for c in $containers; do + mode=$(docker inspect --format 'CgroupParent={{.HostConfig.CgroupParent }}x' "$c") + + if [ "$mode" != "CgroupParent=x" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Confirm cgroup usage: $c" + unexpected_cgroup_containers="$unexpected_cgroup_containers $c" + fail=1 + continue + fi + warn " * Confirm cgroup usage: $c" + unexpected_cgroup_containers="$unexpected_cgroup_containers $c" + fi + done + # We went through all the containers and found none with UTSMode as host + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers using unexpected cgroup" "$unexpected_cgroup_containers" +} + +check_5_25() { + if [ -z "$containers" ]; then + return + fi + local id="5.25" + local desc="Ensure that the container is restricted from acquiring additional privileges (Automated)" + local remediation="You should start your container with the options: docker run --rm -it --security-opt=no-new-privileges ubuntu bash" + local remediationImpact="The no_new_priv option prevents LSMs like SELinux from allowing processes to acquire new privileges." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + addprivs_containers="" + for c in $containers; do + if ! docker inspect --format 'SecurityOpt={{.HostConfig.SecurityOpt }}' "$c" | grep 'no-new-privileges' 2>/dev/null 1>&2; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Privileges not restricted: $c" + addprivs_containers="$addprivs_containers $c" + fail=1 + continue + fi + warn " * Privileges not restricted: $c" + addprivs_containers="$addprivs_containers $c" + fi + done + # We went through all the containers and found none with capability to acquire additional privileges + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers without restricted privileges" "$addprivs_containers" +} + +check_5_26() { + if [ -z "$containers" ]; then + return + fi + + local id="5.26" + local desc="Ensure that container health is checked at runtime (Automated)" + local remediation="You should run the container using the --health-cmd parameter." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + nohealthcheck_containers="" + for c in $containers; do + if ! docker inspect --format '{{ .Id }}: Health={{ .State.Health.Status }}' "$c" 2>/dev/null 1>&2; then + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Health check not set: $c" + nohealthcheck_containers="$nohealthcheck_containers $c" + fail=1 + continue + fi + warn " * Health check not set: $c" + nohealthcheck_containers="$nohealthcheck_containers $c" + fi + done + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers without health check" "$nohealthcheck_containers" +} + +check_5_27() { + if [ -z "$containers" ]; then + return + fi + + local id="5.27" + local desc="Ensure that Docker commands always make use of the latest version of their image (Manual)" + local remediation="You should use proper version pinning mechanisms (the tag which is assigned by default is still vulnerable to caching attacks) to avoid extracting cached older versions. Version pinning mechanisms should be used for base images, packages, and entire images. You can customize version pinning rules according to your requirements." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + info -c "$check" + logcheckresult "INFO" +} + +check_5_28() { + if [ -z "$containers" ]; then + return + fi + + local id="5.28" + local desc="Ensure that the PIDs cgroup limit is used (Automated)" + local remediation="Use --pids-limit flag with an appropriate value when launching the container." + local remediationImpact="Set the PIDs limit value as appropriate. Incorrect values might leave containers unusable." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + nopids_limit_containers="" + for c in $containers; do + pidslimit="$(docker inspect --format '{{.HostConfig.PidsLimit }}' "$c")" + + if [ "$pidslimit" = "0" ] || [ "$pidslimit" = "" ] || [ "$pidslimit" = "-1" ]; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * PIDs limit not set: $c" + nopids_limit_containers="$nopids_limit_containers $c" + fail=1 + continue + fi + warn " * PIDs limit not set: $c" + nopids_limit_containers="$nopids_limit_containers $c" + fi + done + # We went through all the containers and found all with PIDs limit + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers without PIDs cgroup limit" "$nopids_limit_containers" +} + +check_5_29() { + if [ -z "$containers" ]; then + return + fi + + local id="5.29" + local desc="Ensure that Docker's default bridge 'docker0' is not used (Manual)" + local remediation="You should follow the Docker documentation and set up a user-defined network. All the containers should be run in this network." + local remediationImpact="User-defined networks need to be configured and managed in line with organizational security policy." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + docker_network_containers="" + networks=$(docker network ls -q 2>/dev/null) + for net in $networks; do + if docker network inspect --format '{{ .Options }}' "$net" 2>/dev/null | grep "com.docker.network.bridge.name:docker0" >/dev/null 2>&1; then + docker0Containers=$(docker network inspect --format='{{ range $k, $v := .Containers }} {{ $k }} {{ end }}' "$net" | \ + sed -e 's/^ //' -e 's/ /\n/g' 2>/dev/null) + + if [ -n "$docker0Containers" ]; then + if [ $fail -eq 0 ]; then + info -c "$check" + fail=1 + fi + for c in $docker0Containers; do + if [ -z "$exclude" ]; then + cName=$(docker inspect --format '{{.Name}}' "$c" 2>/dev/null | sed 's/\///g') + else + pattern=$(echo "$exclude" | sed 's/,/|/g') + cName=$(docker inspect --format '{{.Name}}' "$c" 2>/dev/null | sed 's/\///g' | grep -Ev "$pattern" ) + fi + if [ -n "$cName" ]; then + info " * Container in docker0 network: $cName" + docker_network_containers="$docker_network_containers $c:$cName" + fi + done + fi + fi + done + # We went through all the containers and found none in docker0 network + if [ $fail -eq 0 ]; then + pass -c "$check" + logcheckresult "PASS" + return + fi + logcheckresult "INFO" "Containers using docker0 network" "$docker_network_containers" +} + +check_5_30() { + if [ -z "$containers" ]; then + return + fi + + local id="5.30" + local desc="Ensure that the host's user namespaces are not shared (Automated)" + local remediation="You should not share user namespaces between host and containers." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + hostns_shared_containers="" + for c in $containers; do + if docker inspect --format '{{ .HostConfig.UsernsMode }}' "$c" 2>/dev/null | grep -i 'host' >/dev/null 2>&1; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Namespace shared: $c" + hostns_shared_containers="$hostns_shared_containers $c" + fail=1 + continue + fi + warn " * Namespace shared: $c" + hostns_shared_containers="$hostns_shared_containers $c" + fi + done + # We went through all the containers and found none with host's user namespace shared + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers sharing host user namespace" "$hostns_shared_containers" +} + +check_5_31() { + if [ -z "$containers" ]; then + return + fi + + local id="5.31" + local desc="Ensure that the Docker socket is not mounted inside any containers (Automated)" + local remediation="You should ensure that no containers mount docker.sock as a volume." + local remediationImpact="None." + local check="$id - $desc" + local testCategory="Container Runtime" + + fail=0 + docker_sock_containers="" + for c in $containers; do + if docker inspect --format '{{ .Mounts }}' "$c" 2>/dev/null | grep 'docker.sock' >/dev/null 2>&1; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * Docker socket shared: $c" + docker_sock_containers="$docker_sock_containers $c" + fail=1 + continue + fi + warn " * Docker socket shared: $c" + docker_sock_containers="$docker_sock_containers $c" + fi + done + # We went through all the containers and found none with docker.sock shared + if [ $fail -eq 0 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + return + fi + logcheckresult "WARN" "Containers sharing docker socket" "$docker_sock_containers" +} + +check_5_end() { + endsectionjson +} diff --git a/scripts/docker-bench-security/tests/6_docker_security_operations.sh b/scripts/docker-bench-security/tests/6_docker_security_operations.sh new file mode 100644 index 0000000..ed96e5d --- /dev/null +++ b/scripts/docker-bench-security/tests/6_docker_security_operations.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +check_6() { + logit "" + local id="6" + local desc="Docker Security Operations" + checkHeader="$id - $desc" + info "$checkHeader" + startsectionjson "$id" "$desc" +} + +check_6_1() { + local id="6.1" + local desc="Ensure that image sprawl is avoided (Manual)" + local remediation="You should keep only the images that you actually need and establish a workflow to remove old or stale images from the host. Additionally, you should use features such as pull-by-digest to get specific images from the registry." + local remediationImpact="docker system prune -a removes all exited containers as well as all images and volumes that are not referenced by running containers, including for UCP and DTR." + local check="$id - $desc" + starttestjson "$id" "$desc" + + images=$(docker images -q | sort -u | wc -l | awk '{print $1}') + active_images=0 + + for c in $(docker inspect --format "{{.Image}}" "$(docker ps -qa)" 2>/dev/null); do + if docker images --no-trunc -a | grep "$c" > /dev/null ; then + active_images=$(( active_images += 1 )) + fi + done + + info -c "$check" + info " * There are currently: $images images" + + if [ "$active_images" -lt "$((images / 2))" ]; then + info " * Only $active_images out of $images are in use" + fi + logcheckresult "INFO" "$active_images active/$images in use" +} + +check_6_2() { + local id="6.2" + local desc="Ensure that container sprawl is avoided (Manual)" + local remediation="You should periodically check your container inventory on each host and clean up containers which are not in active use with the command: docker container prune" + local remediationImpact="You should retain containers that are actively in use, and delete ones which are no longer needed." + local check="$id - $desc" + starttestjson "$id" "$desc" + + total_containers=$(docker info 2>/dev/null | grep "Containers" | awk '{print $2}') + running_containers=$(docker ps -q | wc -l | awk '{print $1}') + diff="$((total_containers - running_containers))" + info -c "$check" + if [ "$diff" -gt 25 ]; then + info " * There are currently a total of $total_containers containers, with only $running_containers of them currently running" + else + info " * There are currently a total of $total_containers containers, with $running_containers of them currently running" + fi + logcheckresult "INFO" "$total_containers total/$running_containers running" +} + +check_6_end() { + endsectionjson +} diff --git a/scripts/docker-bench-security/tests/7_docker_swarm_configuration.sh b/scripts/docker-bench-security/tests/7_docker_swarm_configuration.sh new file mode 100644 index 0000000..c7370f0 --- /dev/null +++ b/scripts/docker-bench-security/tests/7_docker_swarm_configuration.sh @@ -0,0 +1,225 @@ +#!/bin/bash + +check_7() { + logit "" + local id="7" + local desc="Docker Swarm Configuration" + checkHeader="$id - $desc" + info "$checkHeader" + startsectionjson "$id" "$desc" +} + +check_7_1() { + local id="7.1" + local desc="Ensure swarm mode is not Enabled, if not needed (Automated)" + local remediation="If swarm mode has been enabled on a system in error, you should run the command: docker swarm leave" + local remediationImpact="Disabling swarm mode will impact the operation of Docker Enterprise components if these are in use." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "Swarm:*\sinactive\s*" >/dev/null 2>&1; then + pass -s "$check" + logcheckresult "PASS" + return + fi + warn -s "$check" + logcheckresult "WARN" +} + +check_7_2() { + local id="7.2" + local desc="Ensure that the minimum number of manager nodes have been created in a swarm (Automated)" + local remediation="If an excessive number of managers is configured, the excess nodes can be demoted to workers using command: docker node demote " + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "Swarm:*\sactive\s*" >/dev/null 2>&1; then + managernodes=$(docker node ls | grep -c "Leader") + if [ "$managernodes" -eq 1 ]; then + pass -s "$check" + logcheckresult "PASS" + return + fi + warn -s "$check" + logcheckresult "WARN" + return + fi + pass -s "$check (Swarm mode not enabled)" + logcheckresult "PASS" +} + +check_7_3() { + local id="7.3" + local desc="Ensure that swarm services are bound to a specific host interface (Automated)" + local remediation="Resolving this issues requires re-initialization of the swarm, specifying a specific interface for the --listen-addr parameter." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "Swarm:*\sactive\s*" >/dev/null 2>&1; then + $netbin -lnt | grep -e '\[::]:2377 ' -e ':::2377' -e '*:2377 ' -e ' 0\.0\.0\.0:2377 ' >/dev/null 2>&1 + if [ $? -eq 1 ]; then + pass -s "$check" + logcheckresult "PASS" + return + fi + warn -s "$check" + logcheckresult "WARN" + return + fi + pass -s "$check (Swarm mode not enabled)" + logcheckresult "PASS" +} + +check_7_4() { + local id="7.4" + local desc="Ensure that all Docker swarm overlay networks are encrypted (Automated)" + local remediation="You should create overlay networks the with --opt encrypted flag." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + fail=0 + unencrypted_networks="" + for encnet in $(docker network ls --filter driver=overlay --quiet); do + if docker network inspect --format '{{.Name}} {{ .Options }}' "$encnet" | \ + grep -v 'encrypted:' 2>/dev/null 1>&2; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + fail=1 + fi + warn " * Unencrypted overlay network: $(docker network inspect --format '{{ .Name }} ({{ .Scope }})' "$encnet")" + unencrypted_networks="$unencrypted_networks $(docker network inspect --format '{{ .Name }} ({{ .Scope }})' "$encnet")" + fi + done + # We went through all the networks and found none that are unencrypted + if [ $fail -eq 0 ]; then + pass -s "$check" + logcheckresult "PASS" + return + fi + logcheckresult "WARN" "Unencrypted overlay networks:" "$unencrypted_networks" +} + +check_7_5() { + local id="7.5" + local desc="Ensure that Docker's secret management commands are used for managing secrets in a swarm cluster (Manual)" + local remediation="You should follow the docker secret documentation and use it to manage secrets effectively." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then + if [ "$(docker secret ls -q | wc -l)" -ge 1 ]; then + pass -c "$check" + logcheckresult "PASS" + return + fi + info -c "$check" + logcheckresult "INFO" + return + fi + pass -c "$check (Swarm mode not enabled)" + logcheckresult "PASS" +} + +check_7_6() { + local id="7.6" + local desc="Ensure that swarm manager is run in auto-lock mode (Automated)" + local remediation="If you are initializing a swarm, use the command: docker swarm init --autolock. If you want to set --autolock on an existing swarm manager node, use the command: docker swarm update --autolock." + local remediationImpact="A swarm in auto-lock mode will not recover from a restart without manual intervention from an administrator to enter the unlock key. This may not always be desirable, and should be reviewed at a policy level." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then + if ! docker swarm unlock-key 2>/dev/null | grep 'SWMKEY' 2>/dev/null 1>&2; then + warn -s "$check" + logcheckresult "WARN" + return + fi + pass -s "$check" + logcheckresult "PASS" + return + fi + pass -s "$check (Swarm mode not enabled)" + logcheckresult "PASS" +} + +check_7_7() { + local id="7.7" + local desc="Ensure that the swarm manager auto-lock key is rotated periodically (Manual)" + local remediation="You should run the command docker swarm unlock-key --rotate to rotate the keys. To facilitate auditing of this recommendation, you should maintain key rotation records and ensure that you establish a pre-defined frequency for key rotation." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then + note -c "$check" + logcheckresult "NOTE" + return + fi + pass -c "$check (Swarm mode not enabled)" + logcheckresult "PASS" +} + +check_7_8() { + local id="7.8" + local desc="Ensure that node certificates are rotated as appropriate (Manual)" + local remediation="You should run the command docker swarm update --cert-expiry 48h to set the desired expiry time on the node certificate." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then + if docker info 2>/dev/null | grep "Expiry Duration: 2 days"; then + pass -c "$check" + logcheckresult "PASS" + return + fi + info -c "$check" + logcheckresult "INFO" + return + fi + pass -c "$check (Swarm mode not enabled)" + logcheckresult "PASS" +} + +check_7_9() { + local id="7.9" + local desc="Ensure that CA certificates are rotated as appropriate (Manual)" + local remediation="You should run the command docker swarm ca --rotate to rotate a certificate." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then + info -c "$check" + logcheckresult "INFO" + return + fi + pass -c "$check (Swarm mode not enabled)" + logcheckresult "PASS" +} + +check_7_10() { + local id="7.10" + local desc="Ensure that management plane traffic is separated from data plane traffic (Manual)" + local remediation="You should initialize the swarm with dedicated interfaces for management and data planes respectively. Example: docker swarm init --advertise-addr=192.168.0.1 --data-path-addr=17.1.0.3" + local remediationImpact="This requires two network interfaces per node." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then + info -c "$check" + logcheckresult "INFO" + return + fi + pass -c "$check (Swarm mode not enabled)" + logcheckresult "PASS" +} + +check_7_end() { + endsectionjson +} diff --git a/scripts/docker-bench-security/tests/8_docker_enterprise_configuration.sh b/scripts/docker-bench-security/tests/8_docker_enterprise_configuration.sh new file mode 100644 index 0000000..9116623 --- /dev/null +++ b/scripts/docker-bench-security/tests/8_docker_enterprise_configuration.sh @@ -0,0 +1,170 @@ +#!/bin/bash + +check_8() { + logit "" + local id="8" + local desc="Docker Enterprise Configuration" + checkHeader="$id - $desc" + info "$checkHeader" + startsectionjson "$id" "$desc" +} + +check_product_license() { + enterprise_license=1 + if docker version | grep -Eqi '^Server.*Community$|Version.*-ce$'; then + info " * Community Engine license, skipping section 8" + enterprise_license=0 + fi +} + +check_8_1() { + if [ "$enterprise_license" -ne 1 ]; then + return + fi + + local id="8.1" + local desc="Universal Control Plane Configuration" + local check="$id - $desc" + info "$check" +} + +check_8_1_1() { + if [ "$enterprise_license" -ne 1 ]; then + return + fi + + local id="8.1.1" + local desc="Configure the LDAP authentication service (Automated)" + local remediation="You can configure LDAP integration via the UCP Admin Settings UI. LDAP integration can also be enabled via a configuration file" + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "INFO" +} + +check_8_1_2() { + if [ "$enterprise_license" -ne 1 ]; then + return + fi + + local id="8.1.2" + local desc="Use external certificates (Automated)" + local remediation="You can configure your own certificates for UCP either during installation or after installation via the UCP Admin Settings user interface." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "INFO" +} + +check_8_1_3() { + if [ "$enterprise_license" -ne 1 ]; then + return + fi + + local id="8.1.3" + local desc="Enforce the use of client certificate bundles for unprivileged users (Not Scored)" + local remediation="Client certificate bundles can be created in one of two ways. User Management UI: UCP Administrators can provision client certificate bundles on behalf of users. Self-Provision: Users with access to the UCP console can create client certificate bundles themselves." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "INFO" +} + +check_8_1_4() { + if [ "$enterprise_license" -ne 1 ]; then + return + fi + + local id="8.1.4" + local desc="Configure applicable cluster role-based access control policies (Not Scored)" + local remediation="UCP RBAC components can be configured as required via the UCP User Management UI." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "INFO" +} + +check_8_1_5() { + if [ "$enterprise_license" -ne 1 ]; then + return + fi + + local id="8.1.5" + local desc="Enable signed image enforcement (Automated)" + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "INFO" +} + +check_8_1_6() { + if [ "$enterprise_license" -ne 1 ]; then + return + fi + + local id="8.1.6" + local desc="Set the Per-User Session Limit to a value of '3' or lower (Automated)" + local remediation="Retrieve a UCP API token. Retrieve and save UCP config. Open the ucp-config.toml file, set the per_user_limit entry under the [auth.sessions] section to a value of 3 or lower, but greater than 0. Update UCP with the new configuration." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "INFO" +} + +check_8_1_7() { + if [ "$enterprise_license" -ne 1 ]; then + return + fi + + local id="8.1.7" + local desc="Set the 'Lifetime Minutes' and 'Renewal Threshold Minutes' values to '15' or lower and '0' respectively (Automated)" + local remediation="Retrieve a UCP API token. Retrieve and save UCP config. Open the ucp-config.toml file, set the lifetime_minutes and renewal_threshold_minutes entries under the [auth.sessions] section to values of 15 or lower and 0 respectively. Update UCP with the new configuration." + local remediationImpact="Setting the Lifetime Minutes setting to a value that is too lower would result in users having to constantly re-authenticate to their Docker Enterprise cluster." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "INFO" +} + +check_8_2() { + if [ "$enterprise_license" -ne 1 ]; then + return + fi + + local id="8.2" + local desc="Docker Trusted Registry Configuration" + local check="$id - $desc" + info "$check" +} + +check_8_2_1() { + if [ "$enterprise_license" -ne 1 ]; then + return + fi + + local id="8.2.1" + local desc="Enable image vulnerability scanning (Automated)" + local remediation="You can navigate to DTR Settings UI and select the Security tab to access the image scanning configuration. Select the Enable Scanning slider to enable this functionality." + local remediationImpact="None." + local check="$id - $desc" + starttestjson "$id" "$desc" + + note -c "$check" + logcheckresult "INFO" +} + +check_8_end() { + endsectionjson +} diff --git a/scripts/docker-bench-security/tests/99_community_checks.sh b/scripts/docker-bench-security/tests/99_community_checks.sh new file mode 100644 index 0000000..994d265 --- /dev/null +++ b/scripts/docker-bench-security/tests/99_community_checks.sh @@ -0,0 +1,234 @@ +#!/bin/bash + +check_c() { + logit "" + local id="99" + local desc="Community contributed checks" + checkHeader="$id - $desc" + info "$checkHeader" + startsectionjson "$id" "$desc" +} + +check_c_1() { + local id="C.1" + local desc="This is a example check for a Automated check" + local remediation="This is an example remediation measure for a Automated check" + local remediationImpact="This is an example remediation impact for a Automated check" + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info --format='{{ .Architecture }}' | grep 'x86_64' 2>/dev/null 1>&2; then + pass -s "$check" + logcheckresult "PASS" + return + fi + if docker info --format='{{ .Architecture }}' | grep 'aarch64' 2>/dev/null 1>&2; then + info -c "$check" + logcheckresult "INFO" + return + fi + warn -s "$check" + logcheckresult "WARN" +} + +check_c_1_1() { + local id="C.1.1" + local desc="This is a example check for a Manual check" + local remediation="This is an example remediation measure for a Manual check" + local remediationImpact="This is an example remediation impact for a Manual check" + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info --format='{{ .Architecture }}' | grep 'x86_64' 2>/dev/null 1>&2; then + pass -c "$check" + logcheckresult "PASS" + return + fi + if docker info --format='{{ .Architecture }}' | grep 'aarch64' 2>/dev/null 1>&2; then + info -c "$check" + logcheckresult "INFO" + return + fi + warn -c "$check" + logcheckresult "WARN" +} + +check_c_2() { + docker_version=$(docker version | grep -i -A2 '^server' | grep ' Version:' \ + | awk '{print $NF; exit}' | tr -d '[:alpha:]-,.' | cut -c 1-4) + + local id="C.2" + local desc="Ensure operations on legacy registry (v1) are Disabled" + local remediation="Start docker daemon with --disable-legacy-registry=false flag. Starting with Docker 17.12, support for V1 registries has been removed, and the --disable-legacy-registry flag can no longer be used." + local remediationImpact="Prevents the docker daemon from pull, push, and login operations against v1 registries." + local check="$id - $desc" + starttestjson "$id" "$desc" + + if [ "$docker_version" -lt 1712 ]; then + if get_docker_configuration_file_args 'disable-legacy-registry' | grep 'true' >/dev/null 2>&1; then + pass -s "$check" + logcheckresult "PASS" + return + fi + if get_docker_effective_command_line_args '--disable-legacy-registry' | grep "disable-legacy-registry" >/dev/null 2>&1; then + pass -s "$check" + logcheckresult "PASS" + return + fi + warn -s "$check" + logcheckresult "WARN" + return + fi + local desc="$desc (Deprecated)" + local check="$id - $desc" + info -c "$check" + logcheckresult "INFO" +} + +check_c_5_3_1() { + local id="C.5.3.1" + local desc="Ensure that CAP_DAC_READ_SEARCH Linux kernel capability is disabled (Automated)" + local remediation="Please refer to https://github.com/cdk-team/CDK/wiki/Exploit:-cap-dac-read-search for PoC." + local remediationImpact="" + local check="$id - $desc" + starttestjson "$id" "$desc" + + fail=0 + caps_containers="" + for c in $containers; do + container_caps=$(docker inspect --format 'CapAdd={{ .HostConfig.CapAdd }}' "$c") + caps=$(echo "$container_caps" | tr "[:lower:]" "[:upper:]" | \ + sed 's/CAPADD/CapAdd/') + if echo "$caps" | grep -q "DAC_READ_SEARCH"; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * CAP_DAC_READ_SEARCH added to $c" + caps_containers="$caps_containers $c" + fail=1 + continue + fi + warn " * CAP_DAC_READ_SEARCH added to $c" + caps_containers="$caps_containers $c" + fi + done + # We went through all the containers and found none with extra capabilities + if [ $fail -eq 0 ]; then + pass -s "$check" + logcheckresult "PASS" + return + fi + logcheckresult "WARN" "CAP_DAC_READ_SEARCH capability added for containers" "$caps_containers" +} + +check_c_5_3_2() { + local id="C.5.3.2" + local desc="Ensure that CAP_SYS_MODULE Linux kernel capability is disabled (Automated)" + local remediation="Please refer to https://xcellerator.github.io/posts/docker_escape/ for PoC." + local remediationImpact="" + local check="$id - $desc" + starttestjson "$id" "$desc" + + fail=0 + caps_containers="" + for c in $containers; do + container_caps=$(docker inspect --format 'CapAdd={{ .HostConfig.CapAdd }}' "$c") + caps=$(echo "$container_caps" | tr "[:lower:]" "[:upper:]" | \ + sed 's/CAPADD/CapAdd/') + if echo "$caps" | grep -q "SYS_MODULE"; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * CAP_SYS_MODULE added to $c" + caps_containers="$caps_containers $c" + fail=1 + continue + fi + warn " * CAP_SYS_MODULE added to $c" + caps_containers="$caps_containers $c" + fi + done + # We went through all the containers and found none with extra capabilities + if [ $fail -eq 0 ]; then + pass -s "$check" + logcheckresult "PASS" + return + fi + logcheckresult "WARN" "CAP_SYS_MODULE capability added for containers" "$caps_containers" +} + +check_c_5_3_3() { + local id="C.5.3.3" + local desc="Ensure that CAP_SYS_ADMIN Linux kernel capability is disabled (Automated)" + local remediation="Please refer to https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/ for PoC." + local remediationImpact="" + local check="$id - $desc" + starttestjson "$id" "$desc" + + fail=0 + caps_containers="" + for c in $containers; do + container_caps=$(docker inspect --format 'CapAdd={{ .HostConfig.CapAdd }}' "$c") + caps=$(echo "$container_caps" | tr "[:lower:]" "[:upper:]" | \ + sed 's/CAPADD/CapAdd/') + if echo "$caps" | grep -q "SYS_ADMIN"; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * CAP_SYS_ADMIN added to $c" + caps_containers="$caps_containers $c" + fail=1 + continue + fi + warn " * CAP_SYS_ADMIN added to $c" + caps_containers="$caps_containers $c" + fi + done + # We went through all the containers and found none with extra capabilities + if [ $fail -eq 0 ]; then + pass -s "$check" + logcheckresult "PASS" + return + fi + logcheckresult "WARN" "CAP_SYS_ADMIN capability added for containers" "$caps_containers" +} + +check_c_5_3_4() { + local id="C.5.3.4" + local desc="Ensure that CAP_SYS_PTRACE Linux kernel capability is disabled (Automated)" + local remediation="Please refer to https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap_sys_ptrace" + local remediationImpact="" + local check="$id - $desc" + starttestjson "$id" "$desc" + + fail=0 + caps_containers="" + for c in $containers; do + container_caps=$(docker inspect --format 'CapAdd={{ .HostConfig.CapAdd }}' "$c") + caps=$(echo "$container_caps" | tr "[:lower:]" "[:upper:]" | \ + sed 's/CAPADD/CapAdd/') + if echo "$caps" | grep -q "SYS_PTRACE"; then + # If it's the first container, fail the test + if [ $fail -eq 0 ]; then + warn -s "$check" + warn " * CAP_SYS_PTRACE added to $c" + caps_containers="$caps_containers $c" + fail=1 + continue + fi + warn " * CAP_SYS_PTRACE added to $c" + caps_containers="$caps_containers $c" + fi + done + # We went through all the containers and found none with extra capabilities + if [ $fail -eq 0 ]; then + pass -s "$check" + logcheckresult "PASS" + return + fi + logcheckresult "WARN" "CAP_SYS_PTRACE capability added for containers" "$caps_containers" +} + +check_c_end() { + endsectionjson +} diff --git a/scripts/gdpr.sh b/scripts/gdpr.sh new file mode 100644 index 0000000..85ec417 --- /dev/null +++ b/scripts/gdpr.sh @@ -0,0 +1,55 @@ +source /usr/local/bin/compliance_check/scripts/common.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/functions/helper_lib.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/1_host_configuration.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/2_docker_daemon_configuration.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/3_docker_daemon_configuration_files.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/4_container_images.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/5_container_runtime.sh + +check_1_1_3 +check_1_1_4 +check_1_1_5 +check_1_1_6 +check_1_1_7 +check_1_1_9 +check_1_1_10 +check_1_1_11 +check_1_1_12 + +check_2_5 +check_2_7 +check_2_14 + + +check_3_2 +check_3_3 +check_3_4 +check_3_5 +check_3_6 +check_3_7 +check_3_8 +check_3_9 +check_3_10 +check_3_11 +check_3_12 +check_3_13 +check_3_14 +check_3_15 +check_3_16 +check_3_17 +check_3_18 +check_3_19 +check_3_20 +check_3_21 +check_3_22 + + +#check_5_4 +#check_5_5 +#check_5_6 +#check_5_7 +#check_5_17 +#check_5_25 +#check_5_31 +#check_5_12 +#check_5_30 \ No newline at end of file diff --git a/scripts/gdprkube.sh b/scripts/gdprkube.sh new file mode 100644 index 0000000..6a41539 --- /dev/null +++ b/scripts/gdprkube.sh @@ -0,0 +1,30 @@ +source /usr/local/bin/compliance_check/scripts/common.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/functions/helper_lib.sh +source /usr/local/bin/compliance_check/scripts/kube-bench/helper1_6_0.sh +if [ -z "${NODE_TYPE}" ] +then + NODE_TYPE="master" +fi +if [ -z "$CIS_VERSION" ] +then + CIS_VERSION="1.6.0" +fi +source "/usr/local/bin/compliance_check/scripts/kube-bench/${CIS_VERSION}/${NODE_TYPE}.sh" + +if [[ $NODE_TYPE == "master" ]] +then + df_k8_1_1_1 + df_k8_1_1_2 + df_k8_1_1_3 +else + df_k8_4_1_1 + df_k8_4_1_2 + df_k8_4_1_3 + df_k8_4_1_4 + df_k8_4_1_5 + df_k8_4_1_6 + df_k8_4_1_7 + df_k8_4_1_8 + df_k8_4_1_9 + df_k8_4_1_10 +fi diff --git a/scripts/hipaa.sh b/scripts/hipaa.sh new file mode 100644 index 0000000..3bce1be --- /dev/null +++ b/scripts/hipaa.sh @@ -0,0 +1,63 @@ +source /usr/local/bin/compliance_check/scripts/common.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/functions/helper_lib.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/1_host_configuration.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/2_docker_daemon_configuration.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/3_docker_daemon_configuration_files.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/4_container_images.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/5_container_runtime.sh + +check_1_1_2 +check_1_1_3 +check_1_1_4 +check_1_1_5 +check_1_1_6 +check_1_1_7 +check_1_1_9 +check_1_1_10 +check_1_1_11 +check_1_1_12 +check_1_1_13 +check_1_1_14 +check_1_1_15 +check_1_1_16 +check_1_1_17 +check_1_1_18 + + +check_2_5 +check_2_7 +check_2_14 + + +check_3_2 +check_3_3 +check_3_4 +check_3_5 +check_3_6 +check_3_7 +check_3_8 +check_3_9 +check_3_10 +check_3_11 +check_3_12 +check_3_13 +check_3_14 +check_3_15 +check_3_16 +check_3_17 +check_3_18 +check_3_19 +check_3_20 +check_3_21 +check_3_22 + + +#check_5_4 +#check_5_5 +#check_5_6 +#check_5_7 +#check_5_17 +#check_5_25 +#check_5_31 +#check_5_12 +#check_5_30 \ No newline at end of file diff --git a/scripts/hipaakube.sh b/scripts/hipaakube.sh new file mode 100644 index 0000000..6a41539 --- /dev/null +++ b/scripts/hipaakube.sh @@ -0,0 +1,30 @@ +source /usr/local/bin/compliance_check/scripts/common.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/functions/helper_lib.sh +source /usr/local/bin/compliance_check/scripts/kube-bench/helper1_6_0.sh +if [ -z "${NODE_TYPE}" ] +then + NODE_TYPE="master" +fi +if [ -z "$CIS_VERSION" ] +then + CIS_VERSION="1.6.0" +fi +source "/usr/local/bin/compliance_check/scripts/kube-bench/${CIS_VERSION}/${NODE_TYPE}.sh" + +if [[ $NODE_TYPE == "master" ]] +then + df_k8_1_1_1 + df_k8_1_1_2 + df_k8_1_1_3 +else + df_k8_4_1_1 + df_k8_4_1_2 + df_k8_4_1_3 + df_k8_4_1_4 + df_k8_4_1_5 + df_k8_4_1_6 + df_k8_4_1_7 + df_k8_4_1_8 + df_k8_4_1_9 + df_k8_4_1_10 +fi diff --git a/scripts/host.tmpl b/scripts/host.sh similarity index 100% rename from scripts/host.tmpl rename to scripts/host.sh diff --git a/scripts/kube-bench/1.0.0/master.sh b/scripts/kube-bench/1.0.0/master.sh new file mode 100644 index 0000000..6b8920a --- /dev/null +++ b/scripts/kube-bench/1.0.0/master.sh @@ -0,0 +1,31 @@ +df_k8_1_1_1() { + local id="df_k8_1_1_1" + local desc="Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Automated)" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" + else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" + fi + if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + + +df_k8_1_1_2() { + return +} + +df_k8_1_1_3() { + return +} \ No newline at end of file diff --git a/scripts/kube-bench/1.0.0/worker.sh b/scripts/kube-bench/1.0.0/worker.sh new file mode 100644 index 0000000..127d7fd --- /dev/null +++ b/scripts/kube-bench/1.0.0/worker.sh @@ -0,0 +1,3 @@ +df_k8_4_1_1() { + return +} \ No newline at end of file diff --git a/scripts/kube-bench/1.2.0/master.sh b/scripts/kube-bench/1.2.0/master.sh new file mode 100644 index 0000000..7ce4066 --- /dev/null +++ b/scripts/kube-bench/1.2.0/master.sh @@ -0,0 +1,72 @@ +df_k8_1_1_1() { + local id="df_k8_1_1_1" + local desc="Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Automated)" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then + file="/etc/kubernetes/manifests/kube-apiserver.json" + elif [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" + else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" + fi + if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + +df_k8_1_1_2() { + local id="df_k8_1_1_2" + local desc="Ensure that the API server pod specification file ownership is set to root:root" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-apiserver.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" + else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" + fi + if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + +df_k8_1_1_3() { + local id="df_k8_1_1_3" + local desc="Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-controller-manager.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-controller-manager.json" ]; then + file="/etc/kubernetes/manifests/kube-controller-manager.json" + elif [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-controller-manager.manifest" + else + file="/etc/kubernetes/manifests/kube-controller-manager.yaml" + fi + if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} \ No newline at end of file diff --git a/scripts/kube-bench/1.2.0/worker.sh b/scripts/kube-bench/1.2.0/worker.sh new file mode 100644 index 0000000..127d7fd --- /dev/null +++ b/scripts/kube-bench/1.2.0/worker.sh @@ -0,0 +1,3 @@ +df_k8_4_1_1() { + return +} \ No newline at end of file diff --git a/scripts/kube-bench/1.4.1/master.sh b/scripts/kube-bench/1.4.1/master.sh new file mode 100644 index 0000000..7ce4066 --- /dev/null +++ b/scripts/kube-bench/1.4.1/master.sh @@ -0,0 +1,72 @@ +df_k8_1_1_1() { + local id="df_k8_1_1_1" + local desc="Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Automated)" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then + file="/etc/kubernetes/manifests/kube-apiserver.json" + elif [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" + else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" + fi + if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + +df_k8_1_1_2() { + local id="df_k8_1_1_2" + local desc="Ensure that the API server pod specification file ownership is set to root:root" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-apiserver.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" + else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" + fi + if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + +df_k8_1_1_3() { + local id="df_k8_1_1_3" + local desc="Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-controller-manager.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-controller-manager.json" ]; then + file="/etc/kubernetes/manifests/kube-controller-manager.json" + elif [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-controller-manager.manifest" + else + file="/etc/kubernetes/manifests/kube-controller-manager.yaml" + fi + if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} \ No newline at end of file diff --git a/scripts/kube-bench/1.4.1/worker.sh b/scripts/kube-bench/1.4.1/worker.sh new file mode 100644 index 0000000..051304b --- /dev/null +++ b/scripts/kube-bench/1.4.1/worker.sh @@ -0,0 +1,17 @@ +df_k8_4_1_1() { + local id="df_k8_4_1_1" + local desc="Ensure that the kubelet service file permissions are set to 644 or more restrictive" + local remediation="Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + local remediationImpact="None." + local testCategory="Worker File Mode" + file="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} \ No newline at end of file diff --git a/scripts/kube-bench/1.5.1/master.sh b/scripts/kube-bench/1.5.1/master.sh new file mode 100644 index 0000000..fe4d9ab --- /dev/null +++ b/scripts/kube-bench/1.5.1/master.sh @@ -0,0 +1,68 @@ +df_k8_1_1_1() { + local id="df_k8_1_1_1" + local desc="Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Automated)" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" + else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" + fi + if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + +df_k8_1_1_2() { + local id="df_k8_1_1_2" + local desc="Ensure that the API server pod specification file ownership is set to root:root" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-apiserver.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" + else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" + fi + if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + +df_k8_1_1_3() { + local id="df_k8_1_1_3" + local desc="Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-controller-manager.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-controller-manager.manifest" + else + file="/etc/kubernetes/manifests/kube-controller-manager.yaml" + fi + if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} \ No newline at end of file diff --git a/scripts/kube-bench/1.5.1/worker.sh b/scripts/kube-bench/1.5.1/worker.sh new file mode 100644 index 0000000..051304b --- /dev/null +++ b/scripts/kube-bench/1.5.1/worker.sh @@ -0,0 +1,17 @@ +df_k8_4_1_1() { + local id="df_k8_4_1_1" + local desc="Ensure that the kubelet service file permissions are set to 644 or more restrictive" + local remediation="Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + local remediationImpact="None." + local testCategory="Worker File Mode" + file="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} \ No newline at end of file diff --git a/scripts/kube-bench/1.6.0/master.sh b/scripts/kube-bench/1.6.0/master.sh new file mode 100644 index 0000000..eb83c62 --- /dev/null +++ b/scripts/kube-bench/1.6.0/master.sh @@ -0,0 +1,69 @@ +df_k8_1_1_1() { + local id="df_k8_1_1_1" + local desc="Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Automated)" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" + else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" + fi + if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + +df_k8_1_1_2() { + local id="df_k8_1_1_2" + local desc="Ensure that the API server pod specification file ownership is set to root:root" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-apiserver.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" + else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" + fi + if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + +df_k8_1_1_3() { + local id="df_k8_1_1_3" + local desc="Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive" + local remediation="Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-controller-manager.yaml" + local remediationImpact="None." + local testCategory="Master File Mode" + if [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-controller-manager.manifest" + else + file="/etc/kubernetes/manifests/kube-controller-manager.yaml" + fi + + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} \ No newline at end of file diff --git a/scripts/kube-bench/1.6.0/worker.sh b/scripts/kube-bench/1.6.0/worker.sh new file mode 100644 index 0000000..23775b4 --- /dev/null +++ b/scripts/kube-bench/1.6.0/worker.sh @@ -0,0 +1,219 @@ +CIS_PROXY_CMD="kube-proxy" +CIS_KUBELET_CMD="kubelet" +df_k8_4_1_1() { + local id="df_k8_4_1_1" + local desc="Ensure that the kubelet service file permissions are set to 644 or more restrictive" + local remediation="Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + local remediationImpact="None." + local testCategory="Worker File Mode" + file="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + +df_k8_4_1_2() { + local id="df_k8_4_1_2" + local desc="Ensure that the kubelet service file ownership is set to root:root" + local remediation="Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + local remediationImpact="None." + local testCategory="Worker File Mode" + file="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + + +df_k8_4_1_3() { + local id="df_k8_4_1_3" + local desc=" Ensure that the proxy kubeconfig file permissions are set to 644 or more restrictive" + local remediation="Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /dev/null 2>&1; then + file=$(get_argument_value "$CIS_PROXY_CMD" '--kubeconfig'|cut -d " " -f 1) + fi + file="${pathPrefix}${file}" + + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* kubeconfig File not found" "$remediation" "$remediationImpact" + fi +} + +df_k8_4_1_4() { + local id="df_k8_4_1_4" + local desc=" Ensure that the proxy kubeconfig file ownership is set to root:root" + local remediation="Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root " + local remediationImpact="None." + local testCategory="Worker File Mode" + if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* kubeconfig File not found" "$remediation" "$remediationImpact" + fi +} + + +df_k8_4_1_5() { + local id="df_k8_4_1_5" + local desc="Ensure that the kubelet.conf file permissions are set to 644 or more restrictive" + local remediation="Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/kubernetes/kubelet.conf" + local remediationImpact="None." + local testCategory="Worker File Mode" + if [ -f "${pathPrefix}/var/lib/kube-proxy/kubeconfig" ]; then + # kops + file="${pathPrefix}/var/lib/kube-proxy/kubeconfig" + else + file="${pathPrefix}/etc/kubernetes/proxy" + fi + + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found" "$remediation" "$remediationImpact" + fi +} + +check_4_1_6="4.1.6 - Ensure that the kubelet.conf file ownership is set to root:root (Manual)" +if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_4_1_6" + else + warn "$check_4_1_6" + warn " * Wrong ownership for $file" + fi +else + info "$check_4_1_6" +fi + +df_k8_4_1_6() { + local id="df_k8_4_1_6" + local desc="Ensure that the kubelet.conf file ownership is set to root:root" + local remediation="Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/kubernetes/kubelet.conf" + local remediationImpact="None." + local testCategory="Worker File Mode" + if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* File not found $file" "$remediation" "$remediationImpact" + fi +} + +check_4_1_7="4.1.7 - Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Manual)" +if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + pass "$check_4_1_7" + pass " * client-ca-file: $file" + else + warn "$check_4_1_7" + warn " * Wrong permissions for $file" + fi +else + info "$check_4_1_7" + info " * --client-ca-file not set" +fi + +df_k8_4_1_7() { + local id="df_k8_4_1_7" + local desc="Ensure that the certificate authorities file permissions are set to 644 or more restrictive" + local remediation="Ensure that the certificate authorities file permissions are set to 644 or more restrictive" + local remediationImpact="None." + local testCategory="Worker File Mode" + if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then + file="${pathPrefix}$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file')" + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong permissions for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* --client-ca-file not set $file" "$remediation" "$remediationImpact" + fi +} + +df_k8_4_1_8() { + local id="df_k8_4_1_8" + local desc="Ensure that the client certificate authorities file ownership is set to root:root" + local remediation="Run the following command to modify the ownership of the --client-ca-file. chown root:root " + local remediationImpact="None." + local testCategory="Worker File Mode" + if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then + file="${CIS_KUBELET_CMD}$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file')" + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "* client-ca-file: $file" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* --client-ca-file not set $file" "$remediation" "$remediationImpact" + fi +} + +df_k8_4_1_9() { + local id="df_k8_4_1_9" + local desc="Ensure that the kubelet configuration file has permissions set to 644 or more restrictive" + local remediation="Run the following command (using the config file location identied in the Audit step) chmod 644 /var/lib/kubelet/config.yaml" + local remediationImpact="None." + local testCategory="Worker File Mode" + if check_argument "$CIS_KUBELET_CMD" '--config' >/dev/null 2>&1; then + file="${pathPrefix}$(get_argument_value "$CIS_KUBELET_CMD" '--config')" + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "* kubelet configuration file: $file" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* kubelet configuration file not set $file" "$remediation" "$remediationImpact" + fi +} + +df_k8_4_1_10() { + local id="df_k8_4_1_10" + local desc="Ensure that the kubelet configuration file ownership is set to root:root" + local remediation="Run the following command (using the config file location identied in the Audit step) chown root:root /etc/kubernetes/kubelet.conf" + local remediationImpact="None." + local testCategory="Worker File Mode" + if check_argument "$CIS_KUBELET_CMD" '--config' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_KUBELET_CMD" '--config') + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + logbenchjson "PASS" $id "$testCategory" "$desc" "* kubelet configuration file: $file" "$remediation" "$remediationImpact" + else + logbenchjson "WARN" $id "$testCategory" "$desc" "* Wrong ownership for $file" "$remediation" "$remediationImpact" + fi + else + logbenchjson "INFO" $id "$testCategory" "$desc" "* kubelet configuration file not set $file" "$remediation" "$remediationImpact" + fi +} diff --git a/scripts/kube-bench/helper1_6_0.sh b/scripts/kube-bench/helper1_6_0.sh new file mode 100644 index 0000000..21205b0 --- /dev/null +++ b/scripts/kube-bench/helper1_6_0.sh @@ -0,0 +1,54 @@ +yell () { + printf "%b\n" "${bldylw}$1${txtrst}\n" +} + +yell "# ------------------------------------------------------------------------------ +# Kubernetes CIS benchmark +# +# NeuVector, Inc. (c) 2020- +# +# NeuVector delivers an application and network intelligent container security +# solution that automatically adapts to protect running containers. Don’t let +# security concerns slow down your CI/CD processes. +# ------------------------------------------------------------------------------" + +#get a process command line from /proc +get_command_line_args() { + PROC="$1" + len=${#PROC} + if [ $len -gt 15 ]; then + ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" + else + for PID in $(pgrep -n "$PROC") + do + tr "\0" " " < /proc/"$PID"/cmdline + done + fi +} + +#get an argument value from command line +get_argument_value() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" | + sed \ + -e "s/^${OPTION}=//g" +} + +#check whether an argument exist in command line +check_argument() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" +} + diff --git a/scripts/kubeBench/kube_master_1_0_0.tmpl b/scripts/kubeBench/kube_master_1_0_0.tmpl deleted file mode 100644 index 40a2892..0000000 --- a/scripts/kubeBench/kube_master_1_0_0.tmpl +++ /dev/null @@ -1,761 +0,0 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - txtrst='\033[0m' -fi - -info () { - printf "%b\n" "${bldblu}[INFO]${txtrst} $1" -} - -pass () { - printf "%b\n" "${bldgrn}[PASS]${txtrst} $1" -} - -warn () { - printf "%b\n" "${bldred}[WARN]${txtrst} $1" -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2016- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_APISERVER_CMD="<<<.Replace_apiserver_cmd>>>" -CIS_MANAGER_CMD="<<<.Replace_manager_cmd>>>" -CIS_SCHEDULER_CMD="<<<.Replace_scheduler_cmd>>>" -CIS_ETCD_CMD="<<<.Replace_etcd_cmd>>>" - -if ps -ef | grep "$CIS_APISERVER_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Master Node Security Configuration" -else - info "This node is not a Kubernetes master node" - exit 2 -fi - -info "1.1 - API Server" - -check_1_1_1="1.1.1 - Ensure that the --allow-privileged argument is set to false" -if check_argument "$CIS_APISERVER_CMD" '--allow-privileged=false' >/dev/null 2>&1; then - pass "$check_1_1_1" -else - warn "$check_1_1_1" -fi - -check_1_1_2="1.1.2 - Ensure that the --anonymous-auth argument is set to false" -if check_argument "$CIS_APISERVER_CMD" '--anonymous-auth=false' >/dev/null 2>&1; then - pass "$check_1_1_2" -else - warn "$check_1_1_2" -fi - -check_1_1_3="1.1.3 - Ensure that the --basic-auth-file argument is not set" -if check_argument "$CIS_APISERVER_CMD" '--basic-auth-file' >/dev/null 2>&1; then - warn "$check_1_1_3" -else - pass "$check_1_1_3" -fi - -check_1_1_4="1.1.4 - Ensure that the --insecure-allow-any-token argument is not set" -if check_argument "$CIS_APISERVER_CMD" '--insecure-allow-any-token' >/dev/null 2>&1; then - warn "$check_1_1_4" -else - pass "$check_1_1_4" -fi - -check_1_1_5="1.1.5 - Ensure that the --kubelet-https argument is set to true" -if check_argument "$CIS_APISERVER_CMD" '--kubelet-https=false' >/dev/null 2>&1; then - warn "$check_1_1_5" -else - pass "$check_1_1_5" -fi - -check_1_1_6="1.1.6 - Ensure that the --insecure-bind-address argument is not set" -if check_argument "$CIS_APISERVER_CMD" '--insecure-bind-address' >/dev/null 2>&1; then - address=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-bind-address'|cut -d " " -f 1) - if [ "$address" = "127.0.0.1" ]; then - pass "$check_1_1_6" - pass " * insecure-bind-address: $address" - else - warn "$check_1_1_6" - warn " * insecure-bind-address: $address" - fi -else - pass "$check_1_1_6" -fi - -check_1_1_7="1.1.7 - Ensure that the --insecure-port argument is set to 0" -if check_argument "$CIS_APISERVER_CMD" '--insecure-port' >/dev/null 2>&1; then - port=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-port'|cut -d " " -f 1) - if [ "$port" = "0" ]; then - pass "$check_1_1_7" - else - warn "$check_1_1_7" - warn " * insecure-port: $port" - fi -else - warn "$check_1_1_7" -fi - -check_1_1_8="1.1.8 - Ensure that the --secure-port argument is not set to 0" -if check_argument "$CIS_APISERVER_CMD" '--secure-port' >/dev/null 2>&1; then - port=$(get_argument_value "$CIS_APISERVER_CMD" '--secure-port'|cut -d " " -f 1) - if [ "$port" = "0" ]; then - warn "$check_1_1_8" - warn " * secure-port: $port" - else - pass "$check_1_1_8" - fi -else - pass "$check_1_1_8" -fi - -check_1_1_9="1.1.9 - Ensure that the --profiling argument is set to false" -if check_argument "$CIS_APISERVER_CMD" '--profiling=false' >/dev/null 2>&1; then - pass "$check_1_1_9" -else - warn "$check_1_1_9" -fi - -check_1_1_10="1.1.10 - Ensure that the --repair-malformed-updates argument is set to false" -if check_argument "$CIS_APISERVER_CMD" '--repair-malformed-updates=false' >/dev/null 2>&1; then - pass "$check_1_1_10" -else - warn "$check_1_1_10" -fi - -check_1_1_11="1.1.11 - Ensure that the admission control policy is not set to AlwaysAdmit" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'AlwaysAdmit' >/dev/null 2>&1; then - warn "$check_1_1_11" -else - pass "$check_1_1_11" -fi - -check_1_1_12="1.1.12 - Ensure that the admission control policy is set to AlwaysPullImages" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'AlwaysPullImages' >/dev/null 2>&1; then - pass "$check_1_1_12" -else - warn "$check_1_1_12" -fi - -check_1_1_13="1.1.13 - Ensure that the admission control policy is set to DenyEscalatingExec" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'DenyEscalatingExec' >/dev/null 2>&1; then - pass "$check_1_1_13" -else - warn "$check_1_1_13" -fi - -check_1_1_14="1.1.14 - Ensure that the admission control policy is set to SecurityContextDeny" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'SecurityContextDeny' >/dev/null 2>&1; then - pass "$check_1_1_14" -else - warn "$check_1_1_14" -fi - -check_1_1_15="1.1.15 - Ensure that the admission control policy is set to NamespaceLifecycle" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'NamespaceLifecycle' >/dev/null 2>&1; then - pass "$check_1_1_15" -else - warn "$check_1_1_15" -fi - -check_1_1_16="1.1.16 - Ensure that the --audit-log-path argument is set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-path' >/dev/null 2>&1; then - pass "$check_1_1_16" -else - warn "$check_1_1_16" -fi - -check_1_1_17="1.1.17 - Ensure that the --audit-log-maxage argument is set to 30 or as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxage' >/dev/null 2>&1; then - maxage=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxage'|cut -d " " -f 1) - if [ "$maxage" = "30" ]; then - pass "$check_1_1_17" - pass " * audit-log-maxage: $maxage" - else - warn "$check_1_1_17" - warn " * audit-log-maxage: $maxage" - fi -else - warn "$check_1_1_17" -fi - -check_1_1_18="1.1.18 - Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxbackup' >/dev/null 2>&1; then - maxbackup=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxbackup'|cut -d " " -f 1) - if [ "$maxbackup" = "10" ]; then - pass "$check_1_1_18" - pass " * audit-log-maxbackup: $maxbackup" - else - warn "$check_1_1_18" - warn " * audit-log-maxbackup: $maxbackup" - fi -else - warn "$check_1_1_18" -fi - -check_1_1_19="1.1.19 - Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxsize' >/dev/null 2>&1; then - maxsize=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxsize'|cut -d " " -f 1) - if [ "$maxsize" = "100" ]; then - pass "$check_1_1_19" - pass " * audit-log-maxsize: $maxsize" - else - warn "$check_1_1_19" - warn " * audit-log-maxsize: $maxsize" - fi -else - warn "$check_1_1_19" -fi - -check_1_1_20="1.1.20 - Ensure that the --authorization-mode argument is not set to AlwaysAllow" -if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'AlwaysAllow' >/dev/null 2>&1; then - warn "$check_1_1_20" -else - pass "$check_1_1_20" -fi - -check_1_1_21="1.1.21 - Ensure that the --token-auth-file parameter is not set" -if check_argument "$CIS_APISERVER_CMD" '--token-auth-file' >/dev/null 2>&1; then - warn "$check_1_1_21" -else - pass "$check_1_1_21" -fi - -check_1_1_22="1.1.22 - Ensure that the --kubelet-certificate-authority argument is set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--kubelet-certificate-authority' >/dev/null 2>&1; then - pass "$check_1_1_22" -else - warn "$check_1_1_22" -fi - -check_1_1_23="1.1.23 - Ensure that the --kubelet-client-certificate and --kubelet-client-key arguments are set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-certificate' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-key' >/dev/null 2>&1; then - certificate=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-certificate') - key=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-key') - pass "$check_1_1_23" - pass " * kubelet-client-certificate: $certificate" - pass " * kubelet-client-key: $key" - else - warn "$check_1_1_23" - fi -else - warn "$check_1_1_23" -fi - -check_1_1_24="1.1.24 - Ensure that the --service-account-lookup argument is set to true" -if check_argument "$CIS_APISERVER_CMD" '--service-account-lookup' >/dev/null 2>&1; then - pass "$check_1_1_24" -else - warn "$check_1_1_24" -fi - -check_1_1_25="1.1.25 - Ensure that the admission control policy is set to PodSecurityPolicy" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'PodSecurityPolicy' >/dev/null 2>&1; then - pass "$check_1_1_25" -else - warn "$check_1_1_25" -fi - -check_1_1_26="1.1.26 - Ensure that the --service-account-key-file argument is set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--service-account-key-file' >/dev/null 2>&1; then - file=$(get_argument_value "$CIS_APISERVER_CMD" '--service-account-key-file') - pass "$check_1_1_26" - pass " * service-account-key-file: $file" -else - warn "$check_1_1_26" -fi - -check_1_1_27="1.1.27 - Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--etcd-certfile' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--etcd-keyfile' >/dev/null 2>&1; then - certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-certfile') - keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-keyfile') - pass "$check_1_1_27" - pass " * etcd-certfile: $certfile" - pass " * etcd-keyfile: $keyfile" - else - warn "$check_1_1_27" - fi -else - warn "$check_1_1_27" -fi - -check_1_1_28="1.1.28 - Ensure that the admission control policy is set to ServiceAccount" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'ServiceAccount' >/dev/null 2>&1; then - pass "$check_1_1_28" -else - warn "$check_1_1_28" -fi - -check_1_1_29="1.1.29 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--tls-cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--tls-private-key-file' >/dev/null 2>&1; then - certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-cert-file') - keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-private-key-file') - pass "$check_1_1_29" - pass " * tls-cert-file: $certfile" - pass " * tls-private-key-file: $keyfile" - else - warn "$check_1_1_29" - fi -else - warn "$check_1_1_29" -fi - -check_1_1_30="1.1.30 - Ensure that the --client-ca-file argument is set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then - cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') - pass "$check_1_1_30" - pass " * client-ca-file: $cafile" -else - warn "$check_1_1_30" -fi - -check_1_1_31="1.1.31 - Ensure that the --etcd-cafile argument is set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--etcd-cafile' >/dev/null 2>&1; then - cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-cafile') - pass "$check_1_1_31" - pass " * etcd-cafile: $cafile" -else - warn "$check_1_1_31" -fi - -check_1_1_32="1.1.32 - Ensure that the admission control policy is set to NodeRestriction" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'NodeRestriction' >/dev/null 2>&1; then - pass "$check_1_1_32" -else - warn "$check_1_1_32" -fi - -check_1_1_33="1.1.33 - Ensure that the --experimental-encryption-provider-config argument is set as appropriate" -if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then - pass "$check_1_1_33" -else - warn "$check_1_1_33" -fi - -check_1_1_34="1.1.34 - Ensure that the encryption provider is set to aescbc" -if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then - encryptionConfig=$(get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config') - if sed ':a;N;$!ba;s/\n/ /g' $encryptionConfig |grep "providers:\s* - aescbc" >/dev/null 2>&1; then - pass "$check_1_1_34" - else - warn "$check_1_1_34" - fi -else - warn "$check_1_1_34" -fi -info "1.2 - Scheduler" - -check_1_2_1="1.2.1 - Ensure that the --profiling argument is set to false" -if check_argument "$CIS_SCHEDULER_CMD" '--profiling=false' >/dev/null 2>&1; then - pass "$check_1_2_1" -else - warn "$check_1_2_1" -fi - -info "1.3 - Controller Manager" - -check_1_3_1="1.3.1 - Ensure that the --terminated-pod-gc-threshold argument is set as appropriate" -if check_argument "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold' >/dev/null 2>&1; then - threshold=$(get_argument_value "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold') - pass "$check_1_3_1" - pass " * terminated-pod-gc-threshold: $threshold" -else - warn "$check_1_3_1" -fi - -check_1_3_2="1.3.2 - Ensure that the --profiling argument is set to false" -if check_argument "$CIS_MANAGER_CMD" '--profiling=false' >/dev/null 2>&1; then - pass "$check_1_3_2" -else - warn "$check_1_3_2" -fi - -check_1_3_3="1.3.3 - Ensure that the --insecure-experimental-approve-all-kubelet-csrs-for-group argument is not set" -if check_argument "$CIS_MANAGER_CMD" '--insecure-experimental-approve-all-kubelet-csrs-for-group' >/dev/null 2>&1; then - warn "$check_1_3_3" -else - pass "$check_1_3_3" -fi - -check_1_3_4="1.3.4 - Ensure that the --use-service-account-credentials argument is set to true" -if check_argument "$CIS_MANAGER_CMD" '--use-service-account-credentials' >/dev/null 2>&1; then - pass "$check_1_3_4" -else - warn "$check_1_3_4" -fi - -check_1_3_5="1.3.5 - Ensure that the --service-account-private-key-file argument is set as appropriate" -if check_argument "$CIS_MANAGER_CMD" '--service-account-private-key-file' >/dev/null 2>&1; then - keyfile=$(get_argument_value "$CIS_MANAGER_CMD" '--service-account-private-key-file') - pass "$check_1_3_5" - pass " * service-account-private-key-file: $keyfile" -else - warn "$check_1_3_5" -fi - -check_1_3_6="1.3.6 - Ensure that the --root-ca-file argument is set as appropriate" -if check_argument "$CIS_MANAGER_CMD" '--root-ca-file' >/dev/null 2>&1; then - cafile=$(get_argument_value "$CIS_MANAGER_CMD" '--root-ca-file') - pass "$check_1_3_6" - pass " * root-ca-file: $cafile" -else - warn "$check_1_3_6" -fi -info "1.4 - Configuration Files" - -check_1_4_1="1.4.1 - Ensure that the apiserver file permissions are set to 644 or more restrictive" -if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then - file="/etc/kubernetes/manifests/kube-apiserver.json" -else - file="/etc/kubernetes/manifests/kube-apiserver.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_1" - else - warn "$check_1_4_1" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_1" - info " * File not found" -fi - -check_1_4_2="1.4.2 - Ensure that the apiserver file ownership is set to root:root" -if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then - file="/etc/kubernetes/manifests/kube-apiserver.json" -else - file="/etc/kubernetes/manifests/kube-apiserver.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_2" - else - warn "$check_1_4_2" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_4_2" -fi - -check_1_4_3="1.4.3 - Ensure that the config file permissions are set to 644 or more restrictive" -file="/etc/kubernetes/admin.conf" -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_3" - else - warn "$check_1_4_3" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_3" - info " * File not found" -fi - -check_1_4_4="1.4.4 - Ensure that the config file ownership is set to root:root" -file="/etc/kubernetes/admin.conf" -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_4" - else - warn "$check_1_4_4" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_4_4" - info " * File not found" -fi - -check_1_4_5="1.4.5 - Ensure that the scheduler file permissions are set to 644 or more restrictive" -if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then - file="/etc/kubernetes/manifests/kube-scheduler.json" -else - file="/etc/kubernetes/manifests/kube-scheduler.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_5" - else - warn "$check_1_4_5" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_5" - info " * File not found" -fi - -check_1_4_6="1.4.6 - Ensure that the scheduler file ownership is set to root:root" -if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then - file="/etc/kubernetes/manifests/kube-scheduler.json" -else - file="/etc/kubernetes/manifests/kube-scheduler.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_6" - else - warn "$check_1_4_6" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_4_6" - info " * File not found" -fi - -check_1_4_7="1.4.7 - Ensure that the etcd.conf file permissions are set to 644 or more restrictive" -if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then - file="/etc/kubernetes/manifests/etcd.json" -else - file="/etc/kubernetes/manifests/etcd.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_7" - else - warn "$check_1_4_7" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_7" - info " * File not found" -fi - -check_1_4_8="1.4.8 - Ensure that the etcd.conf file ownership is set to root:root" -if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then - file="/etc/kubernetes/manifests/etcd.json" -else - file="/etc/kubernetes/manifests/etcd.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_8" - else - warn "$check_1_4_8" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_4_8" -fi - -#TODO -check_1_4_9="1.4.9 - Ensure that the flanneld file permissions are set to 644 or more restrictive" -check_1_4_10="1.4.10 - Ensure that the flanneld file ownership is set to root:root" -check_1_4_11="1.4.11 - Ensure that the etcd data directory permissions are set to 700 or more restrictive" -directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') -if [ -d $directory ]; then - if [ "$(stat -c %a $directory)" -eq 700 ]; then - pass "$check_1_4_11" - else - warn "$check_1_4_11" - perm=$(stat -c %a $directory) - warn " * Wrong permissions for $directory:$perm" - fi -else - warn "$check_1_4_11" - warn " * Directory not found:$directory" -fi - -check_1_4_12="1.4.12 - Ensure that the etcd data directory ownership is set to etcd:etcd" -directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') -if [ -d $directory ]; then - if [ "$(stat -c %U:%G $directory)" = "etcd:etcd" ]; then - pass "$check_1_4_12" - else - warn "$check_1_4_12" - owner=$(stat -c %U:%G $directory) - warn " * Wrong ownership for $directory:$owner" - fi -else - warn "$check_1_4_12" - warn " * Directory not found:$directory" -fi -info "1.5 - etcd" - -check_1_5_1="1.5.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)" -if check_argument "$CIS_ETCD_CMD" '--cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_ETCD_CMD" '--key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_ETCD_CMD" '--cert-file') - kfile=$(get_argument_value "$CIS_ETCD_CMD" '--key-file') - pass "$check_1_5_1" - pass " * cert-file: $cfile" - pass " * key-file: $kfile" - else - warn "$check_1_5_1" - fi -else - warn "$check_1_5_1" -fi - -check_1_5_2="1.5.2 - Ensure that the --client-cert-auth argument is set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--client-cert-auth' >/dev/null 2>&1; then - pass "$check_1_5_2" -else - warn "$check_1_5_2" -fi - -check_1_5_3="1.5.3 - Ensure that the --auto-tls argument is not set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--auto-tls=tru' >/dev/null 2>&1; then - warn "$check_1_5_3" -else - pass "$check_1_5_3" -fi - -check_1_5_4="1.5.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_ETCD_CMD" '--peer-key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-cert-file') - kfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-key-file') - pass "$check_1_5_4" - pass " * peer-cert-file: $cfile" - pass " * peer-key-file: $kfile" - else - warn "$check_1_5_4" - fi -else - warn "$check_1_5_4" -fi - -check_1_5_5="1.5.5 - Ensure that the --peer-client-cert-auth argument is set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-client-cert-auth' >/dev/null 2>&1; then - pass "$check_1_5_5" -else - warn "$check_1_5_5" -fi - -check_1_5_6="1.5.6 - Ensure that the --peer-auto-tls argument is not set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-auto-tls=true' >/dev/null 2>&1; then - warn "$check_1_5_6" -else - pass "$check_1_5_6" -fi - -check_1_5_7="1.5.7 - Ensure that the --wal-dir argument is set as appropriate (Scored)" -if check_argument "$CIS_ETCD_CMD" '--wal-dir' >/dev/null 2>&1; then - wdir=$(get_argument_value "$CIS_ETCD_CMD" '--wal-dir') - pass "$check_1_5_7" - pass " * wal-dir: $wdir" -else - warn "$check_1_5_7" -fi - -check_1_5_8="1.5.8 - Ensure that the --max-wals argument is set to 0 (Scored)" -if check_argument "$CIS_ETCD_CMD" '--max-wals=0' >/dev/null 2>&1; then - pass "$check_1_5_8" -else - warn "$check_1_5_8" -fi - -#TODO -check_1_5_9="1.5.9 - Ensure that a unique Certificate Authority is used for etcd (Not Scored)" -info "1.6 - General Security Primitives" - -# Make the loop separator be a new-line in POSIX compliant fashion -set -f; IFS=$' -' - -check_1_6_1="1.6.1 - Ensure that the cluster-admin role is only used where required(Not Scored)" -cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) -info $check_1_6_1 -for admin in $cluster_admins; do - info " * $admin" -done - -check_1_6_2="1.6.2 - Create Pod Security Policies for your cluster (Not Scored)" -policies=$(kubectl get psp) -info $check_1_6_2 -for policy in $policies; do - info " * $policy" -done - -check_1_6_3="1.6.3 - Create administrative boundaries between resources using namespaces (Not Scored)" -namespaces=$(kubectl get namespaces) -info $check_1_6_3 -for namespace in $namespaces; do - info " * $namespace" -done - -check_1_6_4="1.6.4 - Create network segmentation using Network Policies (Not Scored)" -policies=$(kubectl get pods --namespace=kube-system) -info $check_1_6_4 -for policy in $policies; do - info " * $policy" -done - -check_1_6_5="1.6.5 - Avoid using Kubernetes Secrets (Not Scored)" -secrets=$(kubectl get secrets) -info $check_1_6_5 -for secret in $secrets; do - info " * $secret" -done - -#TODO -check_1_6_6="1.6.6 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)" -info $check_1_6_6 -check_1_6_7="1.6.7 - Apply Security Context to Your Pods and Containers (Not Scored)" -info $check_1_6_7 -check_1_6_8="1.6.8 - Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)" -info $check_1_6_8 -exit 0; diff --git a/scripts/kubeBench/kube_master_1_2_0.tmpl b/scripts/kubeBench/kube_master_1_2_0.tmpl deleted file mode 100644 index 93ca222..0000000 --- a/scripts/kubeBench/kube_master_1_2_0.tmpl +++ /dev/null @@ -1,910 +0,0 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - txtrst='\033[0m' -fi - -info () { - printf "%b\n" "${bldblu}[INFO]${txtrst} $1" -} - -pass () { - printf "%b\n" "${bldgrn}[PASS]${txtrst} $1" -} - -warn () { - printf "%b\n" "${bldred}[WARN]${txtrst} $1" -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2016- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_APISERVER_CMD="<<<.Replace_apiserver_cmd>>>" -CIS_MANAGER_CMD="<<<.Replace_manager_cmd>>>" -CIS_SCHEDULER_CMD="<<<.Replace_scheduler_cmd>>>" -CIS_ETCD_CMD="<<<.Replace_etcd_cmd>>>" - -if ps -ef | grep "$CIS_APISERVER_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Master Node Security Configuration" -else - info "This node is not a Kubernetes master node" - exit 2 -fi - -info "1.1 - API Server" - -check_1_1_1="1.1.1 - Ensure that the --anonymous-auth argument is set to false" -if check_argument "$CIS_APISERVER_CMD" '--anonymous-auth=false' >/dev/null 2>&1; then - pass "$check_1_1_1" -else - warn "$check_1_1_1" -fi - -check_1_1_2="1.1.2 - Ensure that the --basic-auth-file argument is not set" -if check_argument "$CIS_APISERVER_CMD" '--basic-auth-file' >/dev/null 2>&1; then - warn "$check_1_1_2" -else - pass "$check_1_1_2" -fi - -check_1_1_3="1.1.3 - Ensure that the --insecure-allow-any-token argument is not set" -if check_argument "$CIS_APISERVER_CMD" '--insecure-allow-any-token' >/dev/null 2>&1; then - warn "$check_1_1_3" -else - pass "$check_1_1_3" -fi - -check_1_1_4="1.1.4 - Ensure that the --kubelet-https argument is set to true" -if check_argument "$CIS_APISERVER_CMD" '--kubelet-https=false' >/dev/null 2>&1; then - warn "$check_1_1_4" -else - pass "$check_1_1_4" -fi - -check_1_1_5="1.1.5 - Ensure that the --insecure-bind-address argument is not set" -if check_argument "$CIS_APISERVER_CMD" '--insecure-bind-address' >/dev/null 2>&1; then - address=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-bind-address'|cut -d " " -f 1) - if [ "$address" = "127.0.0.1" ]; then - pass "$check_1_1_5" - pass " * insecure-bind-address: $address" - else - warn "$check_1_1_5" - warn " * insecure-bind-address: $address" - fi -else - pass "$check_1_1_5" -fi - -check_1_1_6="1.1.6 - Ensure that the --insecure-port argument is set to 0" -if check_argument "$CIS_APISERVER_CMD" '--insecure-port' >/dev/null 2>&1; then - port=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-port'|cut -d " " -f 1) - if [ "$port" = "0" ]; then - pass "$check_1_1_6" - else - warn "$check_1_1_6" - warn " * insecure-port: $port" - fi -else - warn "$check_1_1_6" -fi - -check_1_1_7="1.1.7 - Ensure that the --secure-port argument is not set to 0" -if check_argument "$CIS_APISERVER_CMD" '--secure-port' >/dev/null 2>&1; then - port=$(get_argument_value "$CIS_APISERVER_CMD" '--secure-port'|cut -d " " -f 1) - if [ "$port" = "0" ]; then - warn "$check_1_1_7" - warn " * secure-port: $port" - else - pass "$check_1_1_7" - fi -else - pass "$check_1_1_7" -fi - -check_1_1_8="1.1.8 - Ensure that the --profiling argument is set to false" -if check_argument "$CIS_APISERVER_CMD" '--profiling=false' >/dev/null 2>&1; then - pass "$check_1_1_8" -else - warn "$check_1_1_8" -fi - -check_1_1_9="1.1.9 - Ensure that the --repair-malformed-updates argument is set to false" -if check_argument "$CIS_APISERVER_CMD" '--repair-malformed-updates=false' >/dev/null 2>&1; then - pass "$check_1_1_9" -else - warn "$check_1_1_9" -fi - -check_1_1_10="1.1.10 - Ensure that the admission control policy is not set to AlwaysAdmit" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'AlwaysAdmit' >/dev/null 2>&1; then - warn "$check_1_1_10" -else - pass "$check_1_1_10" -fi - -check_1_1_11="1.1.11 - Ensure that the admission control policy is set to AlwaysPullImages" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'AlwaysPullImages' >/dev/null 2>&1; then - pass "$check_1_1_11" -else - warn "$check_1_1_11" -fi - -check_1_1_12="1.1.12 - Ensure that the admission control policy is set to DenyEscalatingExec" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'DenyEscalatingExec' >/dev/null 2>&1; then - pass "$check_1_1_12" -else - warn "$check_1_1_12" -fi - -check_1_1_13="1.1.13 - Ensure that the admission control policy is set to SecurityContextDeny" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'SecurityContextDeny' >/dev/null 2>&1; then - pass "$check_1_1_13" -else - warn "$check_1_1_13" -fi - -check_1_1_14="1.1.14 - Ensure that the admission control policy is set to NamespaceLifecycle" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'NamespaceLifecycle' >/dev/null 2>&1; then - pass "$check_1_1_14" -else - warn "$check_1_1_14" -fi - -check_1_1_15="1.1.15 - Ensure that the --audit-log-path argument is set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-path' >/dev/null 2>&1; then - pass "$check_1_1_15" -else - warn "$check_1_1_15" -fi - -check_1_1_16="1.1.16 - Ensure that the --audit-log-maxage argument is set to 30 or as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxage' >/dev/null 2>&1; then - maxage=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxage'|cut -d " " -f 1) - if [ "$maxage" = "30" ]; then - pass "$check_1_1_16" - pass " * audit-log-maxage: $maxage" - else - warn "$check_1_1_16" - warn " * audit-log-maxage: $maxage" - fi -else - warn "$check_1_1_16" -fi - -check_1_1_17="1.1.17 - Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxbackup' >/dev/null 2>&1; then - maxbackup=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxbackup'|cut -d " " -f 1) - if [ "$maxbackup" = "10" ]; then - pass "$check_1_1_17" - pass " * audit-log-maxbackup: $maxbackup" - else - warn "$check_1_1_17" - warn " * audit-log-maxbackup: $maxbackup" - fi -else - warn "$check_1_1_17" -fi - -check_1_1_18="1.1.18 - Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxsize' >/dev/null 2>&1; then - maxsize=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxsize'|cut -d " " -f 1) - if [ "$maxsize" = "100" ]; then - pass "$check_1_1_18" - pass " * audit-log-maxsize: $maxsize" - else - warn "$check_1_1_18" - warn " * audit-log-maxsize: $maxsize" - fi -else - warn "$check_1_1_18" -fi - -check_1_1_19="1.1.19 - Ensure that the --authorization-mode argument is not set to AlwaysAllow" -if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'AlwaysAllow' >/dev/null 2>&1; then - warn "$check_1_1_19" -else - pass "$check_1_1_19" -fi - -check_1_1_20="1.1.20 - Ensure that the --token-auth-file parameter is not set" -if check_argument "$CIS_APISERVER_CMD" '--token-auth-file' >/dev/null 2>&1; then - warn "$check_1_1_20" -else - pass "$check_1_1_20" -fi - -check_1_1_21="1.1.21 - Ensure that the --kubelet-certificate-authority argument is set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--kubelet-certificate-authority' >/dev/null 2>&1; then - pass "$check_1_1_21" -else - warn "$check_1_1_21" -fi - -check_1_1_22="1.1.22 - Ensure that the --kubelet-client-certificate and --kubelet-client-key arguments are set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-certificate' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-key' >/dev/null 2>&1; then - certificate=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-certificate') - key=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-key') - pass "$check_1_1_22" - pass " * kubelet-client-certificate: $certificate" - pass " * kubelet-client-key: $key" - else - warn "$check_1_1_22" - fi -else - warn "$check_1_1_22" -fi - -check_1_1_23="1.1.23 - Ensure that the --service-account-lookup argument is set to true" -if check_argument "$CIS_APISERVER_CMD" '--service-account-lookup' >/dev/null 2>&1; then - pass "$check_1_1_23" -else - warn "$check_1_1_23" -fi - -check_1_1_24="1.1.24 - Ensure that the admission control policy is set to PodSecurityPolicy" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'PodSecurityPolicy' >/dev/null 2>&1; then - pass "$check_1_1_24" -else - warn "$check_1_1_24" -fi - -check_1_1_25="1.1.25 - Ensure that the --service-account-key-file argument is set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--service-account-key-file' >/dev/null 2>&1; then - file=$(get_argument_value "$CIS_APISERVER_CMD" '--service-account-key-file') - pass "$check_1_1_25" - pass " * service-account-key-file: $file" -else - warn "$check_1_1_25" -fi - -check_1_1_26="1.1.26 - Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--etcd-certfile' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--etcd-keyfile' >/dev/null 2>&1; then - certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-certfile') - keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-keyfile') - pass "$check_1_1_26" - pass " * etcd-certfile: $certfile" - pass " * etcd-keyfile: $keyfile" - else - warn "$check_1_1_26" - fi -else - warn "$check_1_1_26" -fi - -check_1_1_27="1.1.27 - Ensure that the admission control policy is set to ServiceAccount" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'ServiceAccount' >/dev/null 2>&1; then - pass "$check_1_1_27" -else - warn "$check_1_1_27" -fi - -check_1_1_28="1.1.28 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--tls-cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--tls-private-key-file' >/dev/null 2>&1; then - certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-cert-file') - keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-private-key-file') - pass "$check_1_1_28" - pass " * tls-cert-file: $certfile" - pass " * tls-private-key-file: $keyfile" - else - warn "$check_1_1_28" - fi -else - warn "$check_1_1_28" -fi - -check_1_1_29="1.1.29 - Ensure that the --client-ca-file argument is set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then - cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') - pass "$check_1_1_29" - pass " * client-ca-file: $cafile" -else - warn "$check_1_1_29" -fi - -check_1_1_30="1.1.30 - Ensure that the --etcd-cafile argument is set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--etcd-cafile' >/dev/null 2>&1; then - cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-cafile') - pass "$check_1_1_30" - pass " * etcd-cafile: $cafile" -else - warn "$check_1_1_30" -fi - -check_1_1_31="1.1.31 - Ensure that the --authorization-mode argument is set to Node" -if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'Node' >/dev/null 2>&1; then - pass "$check_1_1_31" -else - warn "$check_1_1_31" -fi - -check_1_1_32="1.1.32 - Ensure that the admission control policy is set to NodeRestriction" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'NodeRestriction' >/dev/null 2>&1; then - pass "$check_1_1_32" -else - warn "$check_1_1_32" -fi - -check_1_1_33="1.1.33 - Ensure that the --experimental-encryption-provider-config argument is set as appropriate" -if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then - pass "$check_1_1_33" -else - warn "$check_1_1_33" -fi - -check_1_1_34="1.1.34 - Ensure that the encryption provider is set to aescbc" -if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then - encryptionConfig=$(get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config') - if sed ':a;N;$!ba;s/\n/ /g' $encryptionConfig |grep "providers:\s* - aescbc" >/dev/null 2>&1; then - pass "$check_1_1_34" - else - warn "$check_1_1_34" - fi -else - warn "$check_1_1_34" -fi - -check_1_1_35="1.1.35 - Ensure that the admission control policy is set to EventRateLimit" -if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'EventRateLimit' >/dev/null 2>&1; then - pass "$check_1_1_35" - admissionctrl=$(get_argument_value "$CIS_APISERVER_CMD" '--admission-control') - pass " * : $admissionctrl" -else - warn "$check_1_1_35" -fi - -check_1_1_36="1.1.36 - Ensure that the AdvancedAuditing argument is not set to false" -if get_argument_value "$CIS_APISERVER_CMD" '--feature-gates'| grep 'AdvancedAuditing=false' >/dev/null 2>&1; then - warn "$check_1_1_36" -else - pass "$check_1_1_36" -fi - -check_1_1_37="1.1.37 - Ensure that the --request-timeout argument is set as appropriate" -if check_argument "$CIS_APISERVER_CMD" '--request-timeout' >/dev/null 2>&1; then - requestTimeout=$(get_argument_value "$CIS_APISERVER_CMD" '--request-timeout') - warn "$check_1_1_37" - warn " * request-timeout: $requestTimeout" -else - pass "$check_1_1_37" -fi - -info "1.2 - Scheduler" - -check_1_2_1="1.2.1 - Ensure that the --profiling argument is set to false" -if check_argument "$CIS_SCHEDULER_CMD" '--profiling=false' >/dev/null 2>&1; then - pass "$check_1_2_1" -else - warn "$check_1_2_1" -fi - -info "1.3 - Controller Manager" - -check_1_3_1="1.3.1 - Ensure that the --terminated-pod-gc-threshold argument is set as appropriate" -# Filter out processes like "/bin/tee -a /var/log/kube-controller-manager.log" -# which exist on kops-managed clusters. -if check_argument "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold' >/dev/null 2>&1; then - threshold=$(get_argument_value "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold') - pass "$check_1_3_1" - pass " * terminated-pod-gc-threshold: $threshold" -else - echo "done" - warn "$check_1_3_1" -fi - -check_1_3_2="1.3.2 - Ensure that the --profiling argument is set to false" -if check_argument "$CIS_MANAGER_CMD" '--profiling=false' >/dev/null 2>&1; then - pass "$check_1_3_2" -else - warn "$check_1_3_2" -fi - -check_1_3_3="1.3.3 - Ensure that the --use-service-account-credentials argument is set to true" -if check_argument "$CIS_MANAGER_CMD" '--use-service-account-credentials' >/dev/null 2>&1; then - pass "$check_1_3_3" -else - warn "$check_1_3_3" -fi - -check_1_3_4="1.3.4 - Ensure that the --service-account-private-key-file argument is set as appropriate" -if check_argument "$CIS_MANAGER_CMD" '--service-account-private-key-file' >/dev/null 2>&1; then - keyfile=$(get_argument_value "$CIS_MANAGER_CMD" '--service-account-private-key-file') - pass "$check_1_3_4" - pass " * service-account-private-key-file: $keyfile" -else - warn "$check_1_3_4" -fi - -check_1_3_5="1.3.5 - Ensure that the --root-ca-file argument is set as appropriate" -if check_argument "$CIS_MANAGER_CMD" '--root-ca-file' >/dev/null 2>&1; then - cafile=$(get_argument_value "$CIS_MANAGER_CMD" '--root-ca-file') - pass "$check_1_3_5" - pass " * root-ca-file: $cafile" -else - warn "$check_1_3_5" -fi -info "1.4 - Configuration Files" - -check_1_4_1="1.4.1 - Ensure that the API server pod specification file permissions are set to 644 or more restrictive" -if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then - file="/etc/kubernetes/manifests/kube-apiserver.json" -elif [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-apiserver.manifest" -else - file="/etc/kubernetes/manifests/kube-apiserver.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_1" - else - warn "$check_1_4_1" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_1" - info " * File not found" -fi - -check_1_4_2="1.4.2 - Ensure that the API server pod specification file ownership is set to root:root" -if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then - file="/etc/kubernetes/manifests/kube-apiserver.json" -elif [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-apiserver.manifest" -else - file="/etc/kubernetes/manifests/kube-apiserver.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_2" - else - warn "$check_1_4_2" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_4_2" -fi - -check_1_4_3="1.4.3 - Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive" -if [ -f "/etc/kubernetes/manifests/kube-controller-manager.json" ]; then - file="/etc/kubernetes/manifests/kube-controller-manager.json" -elif [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-controller-manager.manifest" -else - file="/etc/kubernetes/manifests/kube-controller-manager.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_3" - else - warn "$check_1_4_3" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_3" - info " * File not found" -fi - -check_1_4_4="1.4.4 - Ensure that the controller manager pod specification file ownership is set to root:root" -if [ -f "/etc/kubernetes/manifests/kube-controller-manager.json" ]; then - file="/etc/kubernetes/manifests/kube-controller-manager.json" -elif [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-controller-manager.manifest" -else - file="/etc/kubernetes/manifests/kube-controller-manager.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_4" - else - warn "$check_1_4_4" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_4_4" - info " * File not found" -fi - -check_1_4_5="1.4.5 - Ensure that the scheduler pod specification file permissions are set to 644 or more restrictive" -if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then - file="/etc/kubernetes/manifests/kube-scheduler.json" -elif [ -f "/etc/kubernetes/manifests/kube-scheduler.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-scheduler.manifest" -else - file="/etc/kubernetes/manifests/kube-scheduler.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_5" - else - warn "$check_1_4_5" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_5" - info " * File not found" -fi - -check_1_4_6="1.4.6 - Ensure that the scheduler pod specification file ownership is set to root:root" -if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then - file="/etc/kubernetes/manifests/kube-scheduler.json" -elif [ -f "/etc/kubernetes/manifests/kube-scheduler.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-scheduler.manifest" -else - file="/etc/kubernetes/manifests/kube-scheduler.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %U:%G $file)" = "root:root" ]; then - pass "$check_1_4_6" - else - warn "$check_1_4_6" - owner=$(stat -c %U:%G $file) - warn " * Wrong ownership for $file:$owner" - fi -else - info "$check_1_4_6" - info " * File not found" -fi - -check_1_4_7="1.4.7 - Ensure that the etcd pod specification file permissions are set to 644 or more restrictive" -if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then - file="/etc/kubernetes/manifests/etcd.json" -elif [ -f "/etc/kubernetes/manifests/etcd.manifest" ]; then - # kops - # Also this file is a symlink, hence 'stat -L' below. - file="/etc/kubernetes/manifests/etcd.manifest" -else - file="/etc/kubernetes/manifests/etcd.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -L -c %a $file)" -eq 644 -o "$(stat -L -c %a $file)" -eq 640 -o "$(stat -L -c %a $file)" -eq 600 ]; then - pass "$check_1_4_7" - else - warn "$check_1_4_7" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_7" - info " * File not found" -fi - -check_1_4_8="1.4.8 - Ensure that the etcd pod specification file ownership is set to root:root" -if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then - file="/etc/kubernetes/manifests/etcd.json" -elif [ -f "/etc/kubernetes/manifests/etcd.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/etcd.manifest" -else - file="/etc/kubernetes/manifests/etcd.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %U:%G $file)" = "root:root" ]; then - pass "$check_1_4_8" - else - warn "$check_1_4_8" - owner=$(stat -c %U:%G $directory) - warn " * Wrong ownership for $file:$owner" - fi -else - info "$check_1_4_8" -fi - -#TODO -check_1_4_9="1.4.9 - Ensure that the Container Network Interface file permissions are set to 644 or more restrictive" -check_1_4_10="1.4.10 - Ensure that the Container Network Interface file ownership is set to root:root" -check_1_4_11="1.4.11 - Ensure that the etcd data directory permissions are set to 700 or more restrictive" -directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') -if [ -d "$directory" ]; then - if [ "$(stat -c %a $directory)" -eq 700 ]; then - pass "$check_1_4_11" - else - warn "$check_1_4_11" - perm=$(stat -c %a $directory) - warn " * Wrong permissions for $directory:$perm" - fi -else - warn "$check_1_4_11" - warn " * Directory not found:$directory" -fi - -check_1_4_12="1.4.12 - Ensure that the etcd data directory ownership is set to etcd:etcd" -directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') -if [ -d "$directory" ]; then - if [ "$(stat -c %U:%G $directory)" = "etcd:etcd" ]; then - pass "$check_1_4_12" - else - warn "$check_1_4_12" - owner=$(stat -c %U:%G $directory) - warn " * Wrong ownership for $directory:$owner" - fi -else - warn "$check_1_4_12" - warn " * Directory not found:$directory" -fi - -check_1_4_13="1.4.13 - Ensure that the admin.conf file permissions are set to 644 or more restrictive" -file="/etc/kubernetes/admin.conf" -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_13" - else - warn "$check_1_4_13" - perm=$(stat -c %a $file) - warn " * Wrong permissions for $file:$perm" - fi -else - warn "$check_1_4_13" - warn " * File not found:$file" -fi - -check_1_4_14="1.4.14 - Ensure that the admin.conf file ownership is set to root:root" -file="/etc/kubernetes/admin.conf" -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_14" - else - warn "$check_1_4_14" - owner=$(stat -c %U:%G $file) - warn " * Wrong ownership for $file:$owner" - fi -else - warn "$check_1_4_14" - warn " * File not found:$file" -fi - -check_1_4_15="1.4.15 - Ensure that the scheduler.conf file permissions are set to 644 or more restrictive" -file="/etc/kubernetes/scheduler.conf" -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_15" - else - warn "$check_1_4_15" - perm=$(stat -c %a $file) - warn " * Wrong permissions for $file:$perm" - fi -else - warn "$check_1_4_15" - warn " * File not found:$file" -fi - -check_1_4_16="1.4.16 - Ensure that the scheduler.conf file ownership is set to root:root" -file="/etc/kubernetes/scheduler.conf" -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_16" - else - warn "$check_1_4_16" - owner=$(stat -c %U:%G $file) - warn " * Wrong ownership for $file:$owner" - fi -else - warn "$check_1_4_16" - warn " * File not found:$file" -fi - -check_1_4_17="1.4.17 - Ensure that the controller-manager.conf file permissions are set to 644 or more restrictive" -file="/etc/kubernetes/controller-manager.conf" -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_17" - else - warn "$check_1_4_17" - perm=$(stat -c %a $file) - warn " * Wrong permissions for $file:$perm" - fi -else - warn "$check_1_4_17" - warn " * File not found:$file" -fi - -check_1_4_18="1.4.18 - Ensure that the controller-manager.conf file ownership is set to root:root" -file="/etc/kubernetes/controller-manager.conf" -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_18" - else - warn "$check_1_4_18" - owner=$(stat -c %U:%G $file) - warn " * Wrong ownership for $file:$owner" - fi -else - warn "$check_1_4_18" - warn " * File not found:$file" -fi -info "1.5 - etcd" - -check_1_5_1="1.5.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)" -if check_argument "$CIS_ETCD_CMD" '--cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_ETCD_CMD" '--key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_ETCD_CMD" '--cert-file') - kfile=$(get_argument_value "$CIS_ETCD_CMD" '--key-file') - pass "$check_1_5_1" - pass " * cert-file: $cfile" - pass " * key-file: $kfile" - else - warn "$check_1_5_1" - fi -else - warn "$check_1_5_1" -fi - -check_1_5_2="1.5.2 - Ensure that the --client-cert-auth argument is set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--client-cert-auth' >/dev/null 2>&1; then - pass "$check_1_5_2" -else - warn "$check_1_5_2" -fi - -check_1_5_3="1.5.3 - Ensure that the --auto-tls argument is not set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--auto-tls=tru' >/dev/null 2>&1; then - warn "$check_1_5_3" -else - pass "$check_1_5_3" -fi - -check_1_5_4="1.5.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_ETCD_CMD" '--peer-key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-cert-file') - kfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-key-file') - pass "$check_1_5_4" - pass " * peer-cert-file: $cfile" - pass " * peer-key-file: $kfile" - else - warn "$check_1_5_4" - fi -else - warn "$check_1_5_4" -fi - -check_1_5_5="1.5.5 - Ensure that the --peer-client-cert-auth argument is set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-client-cert-auth' >/dev/null 2>&1; then - pass "$check_1_5_5" -else - warn "$check_1_5_5" -fi - -check_1_5_6="1.5.6 - Ensure that the --peer-auto-tls argument is not set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-auto-tls=true' >/dev/null 2>&1; then - warn "$check_1_5_6" -else - pass "$check_1_5_6" -fi - -check_1_5_7="1.5.7 - Ensure that the --wal-dir argument is set as appropriate (Scored)" -if check_argument "$CIS_ETCD_CMD" '--wal-dir' >/dev/null 2>&1; then - wdir=$(get_argument_value "$CIS_ETCD_CMD" '--wal-dir') - pass "$check_1_5_7" - pass " * wal-dir: $wdir" -else - warn "$check_1_5_7" -fi - -check_1_5_8="1.5.8 - Ensure that the --max-wals argument is set to 0 (Scored)" -if check_argument "$CIS_ETCD_CMD" '--max-wals=0' >/dev/null 2>&1; then - pass "$check_1_5_8" -else - warn "$check_1_5_8" -fi - -#TODO -check_1_5_9="1.5.9 - Ensure that a unique Certificate Authority is used for etcd (Not Scored)" -info "1.6 - General Security Primitives" - -# Make the loop separator be a new-line in POSIX compliant fashion -set -f; IFS=$' -' - -check_1_6_1="1.6.1 - Ensure that the cluster-admin role is only used where required(Not Scored)" -cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) -info $check_1_6_1 -for admin in $cluster_admins; do - info " * $admin" -done - -check_1_6_2="1.6.2 - Create Pod Security Policies for your cluster (Not Scored)" -policies=$(kubectl get psp) -info $check_1_6_2 -for policy in $policies; do - info " * $policy" -done - -check_1_6_3="1.6.3 - Create administrative boundaries between resources using namespaces (Not Scored)" -namespaces=$(kubectl get namespaces) -info $check_1_6_3 -for namespace in $namespaces; do - info " * $namespace" -done - -check_1_6_4="1.6.4 - Create network segmentation using Network Policies (Not Scored)" -policies=$(kubectl get pods --namespace=kube-system) -info $check_1_6_4 -for policy in $policies; do - info " * $policy" -done - -check_1_6_5="1.6.5 - Avoid using Kubernetes Secrets (Not Scored)" -secrets=$(kubectl get secrets) -info $check_1_6_5 -for secret in $secrets; do - info " * $secret" -done - -#TODO -check_1_6_6="1.6.6 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)" -info $check_1_6_6 -check_1_6_7="1.6.7 - Apply Security Context to Your Pods and Containers (Not Scored)" -info $check_1_6_7 -check_1_6_8="1.6.8 - Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)" -info $check_1_6_8 -check_1_6_9="1.6.9 - Place compensating controls in the form of PSP and RBAC for privileged containers usage" -info $check_1_6_9 -exit 0; diff --git a/scripts/kubeBench/kube_master_1_4_1.tmpl b/scripts/kubeBench/kube_master_1_4_1.tmpl deleted file mode 100644 index 47f8f8c..0000000 --- a/scripts/kubeBench/kube_master_1_4_1.tmpl +++ /dev/null @@ -1,1159 +0,0 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -notScored="1.1.1, 1.1.12, 1.1.13, 1.1.31, 1.4.9, 1.4.10, 1.5.7, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.6.5, 1.6.6, 1.6.7, 1.6.8, -1.7.1, 1.7.6, 1.7.7, 2.1.11, 2.1.14" -level2="1.3.6, 1.5.7, 1.6.1, 1.6.4, 1.6.5, 1.6.6, 1.6.7, 1.6.8, - 1.7.6, 1.7.7" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_APISERVER_CMD="<<<.Replace_apiserver_cmd>>>" -CIS_MANAGER_CMD="<<<.Replace_manager_cmd>>>" -CIS_SCHEDULER_CMD="<<<.Replace_scheduler_cmd>>>" -CIS_ETCD_CMD="<<<.Replace_etcd_cmd>>>" -CIS_PROXY_CMD="<<<.Replace_proxy_cmd>>>" - -if ps -ef | grep "$CIS_APISERVER_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Master Node Security Configuration" -else - info "This node is not a Kubernetes master node" - exit 2 -fi - -info "1.1 - API Server" - -check_1_1_1="1.1.1 - Ensure that the --anonymous-auth argument is set to false (Not Scored)" -if check_argument "$CIS_APISERVER_CMD" '--anonymous-auth=false' >/dev/null 2>&1; then - pass "$check_1_1_1" -else - warn "$check_1_1_1" -fi - -check_1_1_2="1.1.2 - Ensure that the --basic-auth-file argument is not set (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--basic-auth-file' >/dev/null 2>&1; then - warn "$check_1_1_2" -else - pass "$check_1_1_2" -fi - -check_1_1_3="1.1.3 - Ensure that the --insecure-allow-any-token argument is not set (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--insecure-allow-any-token' >/dev/null 2>&1; then - warn "$check_1_1_3" -else - pass "$check_1_1_3" -fi - -check_1_1_4="1.1.4 - Ensure that the --kubelet-https argument is set to true (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--kubelet-https=false' >/dev/null 2>&1; then - warn "$check_1_1_4" -else - pass "$check_1_1_4" -fi - -check_1_1_5="1.1.5 - Ensure that the --insecure-bind-address argument is not set (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--insecure-bind-address' >/dev/null 2>&1; then - address=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-bind-address'|cut -d " " -f 1) - if [ "$address" = "127.0.0.1" ]; then - pass "$check_1_1_5" - pass " * insecure-bind-address: $address" - else - warn "$check_1_1_5" - warn " * insecure-bind-address: $address" - fi -else - pass "$check_1_1_5" -fi - -check_1_1_6="1.1.6 - Ensure that the --insecure-port argument is set to 0 (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--insecure-port' >/dev/null 2>&1; then - port=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-port'|cut -d " " -f 1) - if [ "$port" = "0" ]; then - pass "$check_1_1_6" - else - warn "$check_1_1_6" - warn " * insecure-port: $port" - fi -else - warn "$check_1_1_6" -fi - -check_1_1_7="1.1.7 - Ensure that the --secure-port argument is not set to 0 (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--secure-port' >/dev/null 2>&1; then - port=$(get_argument_value "$CIS_APISERVER_CMD" '--secure-port'|cut -d " " -f 1) - if [ "$port" = "0" ]; then - warn "$check_1_1_7" - warn " * secure-port: $port" - else - pass "$check_1_1_7" - fi -else - pass "$check_1_1_7" -fi - -check_1_1_8="1.1.8 - Ensure that the --profiling argument is set to false (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--profiling=false' >/dev/null 2>&1; then - pass "$check_1_1_8" -else - warn "$check_1_1_8" -fi - -check_1_1_9="1.1.9 - Ensure that the --repair-malformed-updates argument is set to false (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--repair-malformed-updates=false' >/dev/null 2>&1; then - pass "$check_1_1_9" -else - warn "$check_1_1_9" -fi - -check_1_1_10="1.1.10 - Ensure that the admission control plugin AlwaysAdmit is not set (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'AlwaysAdmit' >/dev/null 2>&1; then - warn "$check_1_1_10" -else - pass "$check_1_1_10" -fi - -check_1_1_11="1.1.11 - Ensure that the admission control plugin AlwaysPullImages is set (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'AlwaysPullImages' >/dev/null 2>&1; then - pass "$check_1_1_11" -else - warn "$check_1_1_11" -fi - -check_1_1_12="1.1.12 - [DEPRECATED] Ensure that the admission control plugin DenyEscalatingExec is set (Not Scored)" -pass "$check_1_1_12" - -check_1_1_13="1.1.13 - Ensure that the admission control plugin SecurityContextDeny is set (Not Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'SecurityContextDeny' >/dev/null 2>&1; then - pass "$check_1_1_13" -else - warn "$check_1_1_13" -fi - -check_1_1_14="1.1.14 - Ensure that the admission control plugin NamespaceLifecycle is set (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--disable-admission-plugins'| grep 'NamespaceLifecycle' >/dev/null 2>&1; then - warn "$check_1_1_14" -else - pass "$check_1_1_14" -fi - -check_1_1_15="1.1.15 - Ensure that the --audit-log-path argument is set as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-path' >/dev/null 2>&1; then - pass "$check_1_1_15" -else - warn "$check_1_1_15" -fi - -check_1_1_16="1.1.16 - Ensure that the --audit-log-maxage argument is set to 30 or as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxage' >/dev/null 2>&1; then - maxage=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxage'|cut -d " " -f 1) - if [ "$maxage" = "30" ]; then - pass "$check_1_1_16" - pass " * audit-log-maxage: $maxage" - else - warn "$check_1_1_16" - warn " * audit-log-maxage: $maxage" - fi -else - warn "$check_1_1_16" -fi - -check_1_1_17="1.1.17 - Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxbackup' >/dev/null 2>&1; then - maxbackup=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxbackup'|cut -d " " -f 1) - if [ "$maxbackup" = "10" ]; then - pass "$check_1_1_17" - pass " * audit-log-maxbackup: $maxbackup" - else - warn "$check_1_1_17" - warn " * audit-log-maxbackup: $maxbackup" - fi -else - warn "$check_1_1_17" -fi - -check_1_1_18="1.1.18 - Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxsize' >/dev/null 2>&1; then - maxsize=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxsize'|cut -d " " -f 1) - if [ "$maxsize" = "100" ]; then - pass "$check_1_1_18" - pass " * audit-log-maxsize: $maxsize" - else - warn "$check_1_1_18" - warn " * audit-log-maxsize: $maxsize" - fi -else - warn "$check_1_1_18" -fi - -check_1_1_19="1.1.19 - Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'AlwaysAllow' >/dev/null 2>&1; then - warn "$check_1_1_19" -else - pass "$check_1_1_19" -fi - -check_1_1_20="1.1.20 - Ensure that the --token-auth-file parameter is not set (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--token-auth-file' >/dev/null 2>&1; then - warn "$check_1_1_20" -else - pass "$check_1_1_20" -fi - -check_1_1_21="1.1.21 - Ensure that the --kubelet-certificate-authority argument is set as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--kubelet-certificate-authority' >/dev/null 2>&1; then - pass "$check_1_1_21" -else - warn "$check_1_1_21" -fi - -check_1_1_22="1.1.22 - Ensure that the --kubelet-client-certificate and --kubelet-client- key arguments are set as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-certificate' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-key' >/dev/null 2>&1; then - certificate=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-certificate') - key=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-key') - pass "$check_1_1_22" - pass " * kubelet-client-certificate: $certificate" - pass " * kubelet-client-key: $key" - else - warn "$check_1_1_22" - fi -else - warn "$check_1_1_22" -fi - -check_1_1_23="1.1.23 - Ensure that the --service-account-lookup argument is set to true (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--service-account-lookup' >/dev/null 2>&1; then - pass "$check_1_1_23" -else - warn "$check_1_1_23" -fi - -check_1_1_24="1.1.24 - Ensure that the admission control plugin PodSecurityPolicy is set (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'PodSecurityPolicy' >/dev/null 2>&1; then - pass "$check_1_1_24" -else - warn "$check_1_1_24" -fi - -check_1_1_25="1.1.25 - Ensure that the --service-account-key-file argument is set as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--service-account-key-file' >/dev/null 2>&1; then - file=$(get_argument_value "$CIS_APISERVER_CMD" '--service-account-key-file') - pass "$check_1_1_25" - pass " * service-account-key-file: $file" -else - warn "$check_1_1_25" -fi - -check_1_1_26="1.1.26 - Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--etcd-certfile' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--etcd-keyfile' >/dev/null 2>&1; then - certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-certfile') - keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-keyfile') - pass "$check_1_1_26" - pass " * etcd-certfile: $certfile" - pass " * etcd-keyfile: $keyfile" - else - warn "$check_1_1_26" - fi -else - warn "$check_1_1_26" -fi - -check_1_1_27="1.1.27 - Ensure that the admission control plugin ServiceAccount is set (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--disable-admission-plugins'| grep 'ServiceAccount' >/dev/null 2>&1; then - warn "$check_1_1_27" -else - pass "$check_1_1_27" -fi - -check_1_1_28="1.1.28 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--tls-cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--tls-private-key-file' >/dev/null 2>&1; then - certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-cert-file') - keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-private-key-file') - pass "$check_1_1_28" - pass " * tls-cert-file: $certfile" - pass " * tls-private-key-file: $keyfile" - else - warn "$check_1_1_28" - fi -else - warn "$check_1_1_28" -fi - -check_1_1_29="1.1.29 - Ensure that the --client-ca-file argument is set as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then - cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') - pass "$check_1_1_29" - pass " * client-ca-file: $cafile" -else - warn "$check_1_1_29" -fi - -check_1_1_30="1.1.30 - Ensure that the --etcd-cafile argument is set as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--etcd-cafile' >/dev/null 2>&1; then - cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-cafile') - pass "$check_1_1_30" - pass " * etcd-cafile: $cafile" -else - warn "$check_1_1_30" -fi - -check_1_1_31="1.1.31 - Ensure that the API Server only makes use of Strong Cryptographic Ciphers (Not Scored)" -if check_argument "$CIS_APISERVER_CMD" '--tls-cipher-suites' >/dev/null 2>&1; then - ciphers=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-cipher-suites'|cut -d " " -f 1) - found=$(echo $ciphers| sed -rn '/(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)/p') - if [ ! -z "$found" ]; then - pass "$check_1_1_31" - else - warn "$check_1_1_31" - fi -else - warn "$check_1_1_31" -fi - -check_1_1_32="1.1.32 - Ensure that the --authorization-mode argument includes Node (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'Node' >/dev/null 2>&1; then - pass "$check_1_1_32" -else - warn "$check_1_1_32" -fi - -check_1_1_33="1.1.33 - Ensure that the admission control plugin NodeRestriction is set (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'NodeRestriction' >/dev/null 2>&1; then - pass "$check_1_1_33" -else - warn "$check_1_1_33" -fi - -check_1_1_34="1.1.34 - Ensure that the --encryption-provider-config argument is set as appropriate (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then - pass "$check_1_1_34" -else - warn "$check_1_1_34" -fi - -check_1_1_35="1.1.35 - Ensure that the encryption provider is set to aescbc (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then - encryptionConfig=$(get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config') - if sed ':a;N;$!ba;s/\n/ /g' $encryptionConfig |grep "providers:\s* - aescbc" >/dev/null 2>&1; then - pass "$check_1_1_35" - else - warn "$check_1_1_35" - fi -else - warn "$check_1_1_35" -fi - -check_1_1_36="1.1.36 - Ensure that the admission control plugin EventRateLimit is set (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'EventRateLimit' >/dev/null 2>&1; then - pass "$check_1_1_36" - admissionctrl=$(get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins') - pass " * : $admissionctrl" -else - warn "$check_1_1_36" -fi - -check_1_1_37="1.1.37 - Ensure that the AdvancedAuditing argument is not set to false (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--feature-gates'| grep 'AdvancedAuditing=false' >/dev/null 2>&1; then - warn "$check_1_1_37" -else - pass "$check_1_1_37" -fi - -check_1_1_38="1.1.38 - Ensure that the --request-timeout argument is set as appropriate (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--request-timeout' >/dev/null 2>&1; then - requestTimeout=$(get_argument_value "$CIS_APISERVER_CMD" '--request-timeout') - warn "$check_1_1_38" - warn " * request-timeout: $requestTimeout" -else - pass "$check_1_1_38" -fi - -check_1_1_39="1.1.39 - Ensure that the --authorization-mode argument includes RBAC (Scored)" -if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'RBAC' >/dev/null 2>&1; then - pass "$check_1_1_39" -else - warn "$check_1_1_39" -fi - -info "1.2 - Scheduler" - -check_1_2_1="1.2.1 - Ensure that the --profiling argument is set to false (Scored)" -if check_argument "$CIS_SCHEDULER_CMD" '--profiling=false' >/dev/null 2>&1; then - pass "$check_1_2_1" -else - warn "$check_1_2_1" -fi - -check_1_2_2="1.2.2 - Ensure that the --address argument is set to 127.0.0.1 (Scored)" -if get_argument_value "$CIS_SCHEDULER_CMD" '--address'| grep '127.0.0.1' >/dev/null 2>&1; then - pass "$check_1_2_2" -else - warn "$check_1_2_2" -fi -info "1.3 - Controller Manager" - -check_1_3_1="1.3.1 - Ensure that the --terminated-pod-gc-threshold argument is set as appropriate (Scored)" -# Filter out processes like "/bin/tee -a /var/log/kube-controller-manager.log" -# which exist on kops-managed clusters. -if check_argument "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold' >/dev/null 2>&1; then - threshold=$(get_argument_value "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold') - pass "$check_1_3_1" - pass " * terminated-pod-gc-threshold: $threshold" -else - warn "$check_1_3_1" -fi - -check_1_3_2="1.3.2 - Ensure that the --profiling argument is set to false (Scored)" -if check_argument "$CIS_MANAGER_CMD" '--profiling=false' >/dev/null 2>&1; then - pass "$check_1_3_2" -else - warn "$check_1_3_2" -fi - -check_1_3_3="1.3.3 - Ensure that the --use-service-account-credentials argument is set to true (Scored)" -if check_argument "$CIS_MANAGER_CMD" '--use-service-account-credentials' >/dev/null 2>&1; then - pass "$check_1_3_3" -else - warn "$check_1_3_3" -fi - -check_1_3_4="1.3.4 - Ensure that the --service-account-private-key-file argument is set as appropriate (Scored)" -if check_argument "$CIS_MANAGER_CMD" '--service-account-private-key-file' >/dev/null 2>&1; then - keyfile=$(get_argument_value "$CIS_MANAGER_CMD" '--service-account-private-key-file') - pass "$check_1_3_4" - pass " * service-account-private-key-file: $keyfile" -else - warn "$check_1_3_4" -fi - -check_1_3_5="1.3.5 - Ensure that the --root-ca-file argument is set as appropriate (Scored)" -if check_argument "$CIS_MANAGER_CMD" '--root-ca-file' >/dev/null 2>&1; then - cafile=$(get_argument_value "$CIS_MANAGER_CMD" '--root-ca-file') - pass "$check_1_3_5" - pass " * root-ca-file: $cafile" -else - warn "$check_1_3_5" -fi - -check_1_3_6="1.3.6 - Ensure that the RotateKubeletServerCertificate argument is set to true (Scored)" -if check_argument "$CIS_MANAGER_CMD" '--feature-gates' >/dev/null 2>&1; then - serverCert=$(get_argument_value "$CIS_MANAGER_CMD" '--feature-gates') - found=$(echo $serverCert| grep 'RotateKubeletServerCertificate=true') - if [ ! -z $found ]; then - pass "$check_1_3_6" - else - warn "$check_1_3_6" - fi -else - warn "$check_1_3_6" -fi - -check_1_3_7="1.3.7 - Ensure that the --address argument is set to 127.0.0.1 (Scored)" -if get_argument_value "$CIS_MANAGER_CMD" '--address'| grep '127.0.0.1' >/dev/null 2>&1; then - pass "$check_1_3_7" -else - warn "$check_1_3_7" -fi -info "1.4 - Configuration Files" - -check_1_4_1="1.4.1 - Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Scored)" -if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then - file="/etc/kubernetes/manifests/kube-apiserver.json" -elif [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-apiserver.manifest" -else - file="/etc/kubernetes/manifests/kube-apiserver.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_1" - else - warn "$check_1_4_1" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_1" - info " * File not found" -fi - -check_1_4_2="1.4.2 - Ensure that the API server pod specification file ownership is set to root:root (Scored)" -if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then - file="/etc/kubernetes/manifests/kube-apiserver.json" -elif [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-apiserver.manifest" -else - file="/etc/kubernetes/manifests/kube-apiserver.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_2" - else - warn "$check_1_4_2" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_4_2" -fi - -check_1_4_3="1.4.3 - Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive (Scored)" -if [ -f "/etc/kubernetes/manifests/kube-controller-manager.json" ]; then - file="/etc/kubernetes/manifests/kube-controller-manager.json" -elif [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-controller-manager.manifest" -else - file="/etc/kubernetes/manifests/kube-controller-manager.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_3" - else - warn "$check_1_4_3" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_3" - info " * File not found" -fi - -check_1_4_4="1.4.4 - Ensure that the controller manager pod specification file ownership is set to root:root (Scored)" -if [ -f "/etc/kubernetes/manifests/kube-controller-manager.json" ]; then - file="/etc/kubernetes/manifests/kube-controller-manager.json" -elif [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-controller-manager.manifest" -else - file="/etc/kubernetes/manifests/kube-controller-manager.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_4" - else - warn "$check_1_4_4" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_4_4" - info " * File not found" -fi - -check_1_4_5="1.4.5 - Ensure that the scheduler pod specification file permissions are set to 644 or more restrictive (Scored)" -if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then - file="/etc/kubernetes/manifests/kube-scheduler.json" -elif [ -f "/etc/kubernetes/manifests/kube-scheduler.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-scheduler.manifest" -else - file="/etc/kubernetes/manifests/kube-scheduler.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_5" - else - warn "$check_1_4_5" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_5" - info " * File not found" -fi - -check_1_4_6="1.4.6 - Ensure that the scheduler pod specification file ownership is set to root:root (Scored)" -if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then - file="/etc/kubernetes/manifests/kube-scheduler.json" -elif [ -f "/etc/kubernetes/manifests/kube-scheduler.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/kube-scheduler.manifest" -else - file="/etc/kubernetes/manifests/kube-scheduler.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %U:%G $file)" = "root:root" ]; then - pass "$check_1_4_6" - else - warn "$check_1_4_6" - owner=$(stat -c %U:%G $file) - warn " * Wrong ownership for $file:$owner" - fi -else - info "$check_1_4_6" - info " * File not found" -fi - -check_1_4_7="1.4.7 - Ensure that the etcd pod specification file permissions are set to 644 or more restrictive (Scored)" -if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then - file="/etc/kubernetes/manifests/etcd.json" -elif [ -f "/etc/kubernetes/manifests/etcd.manifest" ]; then - # kops - # Also this file is a symlink, hence 'stat -L' below. - file="/etc/kubernetes/manifests/etcd.manifest" -else - file="/etc/kubernetes/manifests/etcd.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -L -c %a $file)" -eq 644 -o "$(stat -L -c %a $file)" -eq 640 -o "$(stat -L -c %a $file)" -eq 600 ]; then - pass "$check_1_4_7" - else - warn "$check_1_4_7" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_4_7" - info " * File not found" -fi - -check_1_4_8="1.4.8 - Ensure that the etcd pod specification file ownership is set to root:root (Scored)" -if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then - file="/etc/kubernetes/manifests/etcd.json" -elif [ -f "/etc/kubernetes/manifests/etcd.manifest" ]; then - # kops - file="/etc/kubernetes/manifests/etcd.manifest" -else - file="/etc/kubernetes/manifests/etcd.yaml" -fi -if [ -f $file ]; then - if [ "$(stat -c %U:%G $file)" = "root:root" ]; then - pass "$check_1_4_8" - else - warn "$check_1_4_8" - owner=$(stat -c %U:%G $directory) - warn " * Wrong ownership for $file:$owner" - fi -else - info "$check_1_4_8" -fi - -#TODO -check_1_4_9="1.4.9 - Ensure that the Container Network Interface file permissions are set to 644 or more restrictive (Not Scored)" -info "$check_1_4_9" - -check_1_4_10="1.4.10 - Ensure that the Container Network Interface file ownership is set to root:root (Not Scored)" -info "$check_1_4_10" - -check_1_4_11="1.4.11 - Ensure that the etcd data directory permissions are set to 700 or more restrictive (Scored)" -directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') -if [ -d "$directory" ]; then - if [ "$(stat -c %a $directory)" -eq 700 ]; then - pass "$check_1_4_11" - else - warn "$check_1_4_11" - perm=$(stat -c %a $directory) - warn " * Wrong permissions for $directory:$perm" - fi -else - warn "$check_1_4_11" - warn " * Directory not found:$directory" -fi - -check_1_4_12="1.4.12 - Ensure that the etcd data directory ownership is set to etcd:etcd (Scored)" -directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') -if [ -d "$directory" ]; then - if [ "$(stat -c %U:%G $directory)" = "etcd:etcd" ]; then - pass "$check_1_4_12" - else - warn "$check_1_4_12" - owner=$(stat -c %U:%G $directory) - warn " * Wrong ownership for $directory:$owner" - fi -else - warn "$check_1_4_12" - warn " * Directory not found:$directory" -fi - -check_1_4_13="1.4.13 - Ensure that the admin.conf file permissions are set to 644 or more restrictive (Scored)" -file="/etc/kubernetes/admin.conf" -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_13" - else - warn "$check_1_4_13" - perm=$(stat -c %a $file) - warn " * Wrong permissions for $file:$perm" - fi -else - warn "$check_1_4_13" - warn " * File not found:$file" -fi - -check_1_4_14="1.4.14 - Ensure that the admin.conf file ownership is set to root:root (Scored)" -file="/etc/kubernetes/admin.conf" -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_14" - else - warn "$check_1_4_14" - owner=$(stat -c %U:%G $file) - warn " * Wrong ownership for $file:$owner" - fi -else - warn "$check_1_4_14" - warn " * File not found:$file" -fi - -check_1_4_15="1.4.15 - Ensure that the scheduler.conf file permissions are set to 644 or more restrictive (Scored)" -file="/etc/kubernetes/scheduler.conf" -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_15" - else - warn "$check_1_4_15" - perm=$(stat -c %a $file) - warn " * Wrong permissions for $file:$perm" - fi -else - warn "$check_1_4_15" - warn " * File not found:$file" -fi - -check_1_4_16="1.4.16 - Ensure that the scheduler.conf file ownership is set to root:root (Scored)" -file="/etc/kubernetes/scheduler.conf" -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_16" - else - warn "$check_1_4_16" - owner=$(stat -c %U:%G $file) - warn " * Wrong ownership for $file:$owner" - fi -else - warn "$check_1_4_16" - warn " * File not found:$file" -fi - -check_1_4_17="1.4.17 - Ensure that the controller-manager.conf file permissions are set to 644 or more restrictive (Scored)" -file="/etc/kubernetes/controller-manager.conf" -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_4_17" - else - warn "$check_1_4_17" - perm=$(stat -c %a $file) - warn " * Wrong permissions for $file:$perm" - fi -else - warn "$check_1_4_17" - warn " * File not found:$file" -fi - -check_1_4_18="1.4.18 - Ensure that the controller-manager.conf file ownership is set to root:root (Scored)" -file="/etc/kubernetes/controller-manager.conf" -if [ -f $file ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_4_18" - else - warn "$check_1_4_18" - owner=$(stat -c %U:%G $file) - warn " * Wrong ownership for $file:$owner" - fi -else - warn "$check_1_4_18" - warn " * File not found:$file" -fi - -check_1_4_19="1.4.19 - Ensure that the Kubernetes PKI directory and file ownership is set to root:root (Scored)" -file="/etc/kubernetes/pki/" -files=$(find $file) -pass=true -for f in ${files}; do - if [ "$(stat -c %u%g $f)" != 00 ]; then - pass=false; - break; - fi -done - -if [ "$pass" = "true" ]; then - pass "$check_1_4_19" -else - warn "$check_1_4_19" -fi - -check_1_4_20="1.4.20 - Ensure that the Kubernetes PKI certificate file permissions are set to 644 or more restrictive (Scored)" -files=$(find $file -name "*.crt") -pass=true -for f in ${files}; do - if ! [ "$(stat -c %a $f)" -eq 644 -o "$(stat -c %a $f)" -eq 600 -o "$(stat -c %a $f)" -eq 400 ]; then - pass=false; - break; - fi -done - -if [ "$pass" = "true" ]; then - pass "$check_1_4_20" -else - warn "$check_1_4_20" -fi - -check_1_4_21="1.4.21 - Ensure that the Kubernetes PKI key file permissions are set to 600 (Scored)" -files=$(find $file -name "*.key") -pass=true -for f in ${files}; do - if ! [ "$(stat -c %a $f)" -eq 600 ]; then - pass=false; - break; - fi -done - -if [ "$pass" = "true" ]; then - pass "$check_1_4_21" -else - warn "$check_1_4_21" -fi -info "1.5 - etcd" - -check_1_5_1="1.5.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)" -if check_argument "$CIS_ETCD_CMD" '--cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_ETCD_CMD" '--key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_ETCD_CMD" '--cert-file') - kfile=$(get_argument_value "$CIS_ETCD_CMD" '--key-file') - pass "$check_1_5_1" - pass " * cert-file: $cfile" - pass " * key-file: $kfile" - else - warn "$check_1_5_1" - fi -else - warn "$check_1_5_1" -fi - -check_1_5_2="1.5.2 - Ensure that the --client-cert-auth argument is set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--client-cert-auth' >/dev/null 2>&1; then - pass "$check_1_5_2" -else - warn "$check_1_5_2" -fi - -check_1_5_3="1.5.3 - Ensure that the --auto-tls argument is not set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--auto-tls=true' >/dev/null 2>&1; then - warn "$check_1_5_3" -else - pass "$check_1_5_3" -fi - -check_1_5_4="1.5.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_ETCD_CMD" '--peer-key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-cert-file') - kfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-key-file') - pass "$check_1_5_4" - pass " * peer-cert-file: $cfile" - pass " * peer-key-file: $kfile" - else - warn "$check_1_5_4" - fi -else - warn "$check_1_5_4" -fi - -check_1_5_5="1.5.5 - Ensure that the --peer-client-cert-auth argument is set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-client-cert-auth' >/dev/null 2>&1; then - pass "$check_1_5_5" -else - warn "$check_1_5_5" -fi - -check_1_5_6="1.5.6 - Ensure that the --peer-auto-tls argument is not set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-auto-tls=true' >/dev/null 2>&1; then - warn "$check_1_5_6" -else - pass "$check_1_5_6" -fi - -check_1_5_7="1.5.7 - Ensure that a unique Certificate Authority is used for etcd (Not Scored)" -if check_argument "$CIS_ETCD_CMD" '--trusted-ca-file' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then - tfile=$(get_argument_value "$CIS_ETCD_CMD" '--trusted-ca-file') - cfile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') - if [ "$tfile" = "$cfile" ]; then - pass "$check_1_5_7" - pass " * trusted-ca-file: $tfile" - pass " * client-ca-file: $cfile" - else - warn "$check_1_5_7" - fi - else - warn "$check_1_5_7" - warn " * client-ca-file doesn't exist" - fi -else - warn "$check_1_5_7" - warn " * trusted-ca-file doesn't exist" -fi -info "1.6 - General Security Primitives" - -# Make the loop separator be a new-line in POSIX compliant fashion -set -f; IFS=$' -' -check_1_6_1="1.6.1 - Place compensating controls in the form of PSP and RBAC for privileged containers usage (Not Scored)" -info "$check_1_6_1" - -check_1_6_2="1.6.2 - Ensure that the cluster-admin role is only used where required(Not Scored)" -cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) -info $check_1_6_2 -for admin in $cluster_admins; do - info " * $admin" -done - -check_1_6_3="1.6.3 - Create administrative boundaries between resources using namespaces (Not Scored)" -namespaces=$(kubectl get namespaces) -info $check_1_6_3 -for namespace in $namespaces; do - info " * $namespace" -done - -check_1_6_4="1.6.4 - Create network segmentation using Network Policies (Not Scored)" -policies=$(kubectl get pods --namespace=kube-system) -info $check_1_6_4 -for policy in $policies; do - info " * $policy" -done - -check_1_6_5="1.6.5 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)" -info "$check_1_6_5" - -check_1_6_6="1.6.6 - Apply Security Context to Your Pods and Containers (Not Scored)" -info $check_1_6_6 -check_1_6_7="1.6.7 - Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)" -info $check_1_6_7 -check_1_6_8="1.6.8 - Configure Network policies as appropriate (Not Scored)" -info $check_1_6_8 - -check_1_7_1="1.7.1 - Do not admit privileged containers (Not Scored)" -names=$(kubectl get psp 2>/dev/null | sed 1,1d | cut -d " " -f 1) -result="" -for name in $names; do - result=$(kubectl get psp $name -o=jsonpath='{.spec.privileged}'|grep true) - if [ -z "$result" ]; then - break; - fi -done -if [ -z "$result" ]; then - pass "$check_1_7_1" -else - warn "$check_1_7_1" -fi - -check_1_7_2="1.7.2 - Do not admit containers wishing to share the host process ID namespace (Scored)" -result="" -for name in $names; do - result=$(kubectl get psp $name -o=jsonpath='{.spec.hostPID}'|grep true) - if [ -z "$result" ]; then - break; - fi -done -if [ -z "$result" ]; then - pass "$check_1_7_2" -else - warn "$check_1_7_2" -fi - -check_1_7_3="1.7.3 - Do not admit containers wishing to share the host IPC namespace (Scored)" -result="" -for name in $names; do - result=$(kubectl get psp $name -o=jsonpath='{.spec.hostIPC}'|grep true) - if [ -z "$result" ]; then - break; - fi -done -if [ -z "$result" ]; then - pass "$check_1_7_3" -else - warn "$check_1_7_3" -fi - -check_1_7_4="1.7.4 - Do not admit containers wishing to share the host network namespace (Scored)" -result="" -for name in $names; do - result=$(kubectl get psp $name -o=jsonpath='{.spec.hostNetwork}'|grep true) - if [ -z "$result" ]; then - break; - fi -done -if [ -z "$result" ]; then - pass "$check_1_7_4" -else - warn "$check_1_7_4" -fi - -check_1_7_5="1.7.5 - Do not admit containers with allowPrivilegeEscalation (Scored)" -result="" -for name in $names; do - result=$(kubectl get psp $name -o=jsonpath='{.spec.allowPrivilegeEscalation}'|grep true) - if [ -z "$result" ]; then - break; - fi -done -if [ -z "$result" ]; then - pass "$check_1_7_5" -else - warn "$check_1_7_5" -fi - -check_1_7_6="1.7.6 - Do not admit root containers (Not Scored)" -result="" -for name in $names; do - result=$(kubectl get psp $name -o=jsonpath='{.spec.runAsUser.rule}' | grep -v -E '(\<0\>)|(MustRunAsNonRoot)') - if [ -z "$result" ]; then - break; - fi -done -if [ -z "$result" ]; then - pass "$check_1_7_6" -else - warn "$check_1_7_6" -fi - -check_1_7_7="1.7.7 - Do not admit containers with dangerous capabilities (Not Scored)" -result="" -for name in $names; do - result=$(kubectl get psp $name -o=jsonpath='{.spec.allowPrivilegeEscalation}'|grep true) - if [ -z "$result" ]; then - break; - fi -done -if [ -z "$result" ]; then - pass "$check_1_7_7" -else - warn "$check_1_7_7" -fi - -exit 0; diff --git a/scripts/kubeBench/kube_master_ocp_4_3.tmpl b/scripts/kubeBench/kube_master_ocp_4_3.tmpl deleted file mode 100644 index eb98edc..0000000 --- a/scripts/kubeBench/kube_master_ocp_4_3.tmpl +++ /dev/null @@ -1,1243 +0,0 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.6, 5.2.9, 5.3.2, 5.4.2, 5.5.1, 5.6.2, 5.6.3, 5.6.4" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -info "1 - Control Plane Components" - -info "1.1 - Master Node Configuration Files" - -check_1_1_1="1.1.1 - Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Scored)" - -file="/etc/kubernetes/manifests/kube-apiserver-pod.yaml" -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_1_1" - else - warn "$check_1_1_1" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_1_1" - info " * File not found" -fi - -check_1_1_2="1.1.2 - Ensure that the API server pod specification file ownership is set to root:root (Scored)" - -file="/etc/kubernetes/manifests/kube-apiserver-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_2" - else - warn "$check_1_1_2" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_2" -fi - -check_1_1_3="1.1.3 - Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive (Scored)" - -file="/etc/kubernetes/manifests/kube-controller-manager-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_1_1_3" - else - warn "$check_1_1_3" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_1_3" - info " * File not found" -fi - -check_1_1_4="1.1.4 - Ensure that the controller manager pod specification file ownership is set to root:root (Scored)" - -file="/etc/kubernetes/manifests/kube-controller-manager-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_4" - else - warn "$check_1_1_4" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_4" -fi - -check_1_1_5="1.1.5 - Ensure that the scheduler pod specification file permissions are set to 644 or more restrictive (Scored)" - -file="/etc/kubernetes/manifests/kube-scheduler-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_1_1_5" - else - warn "$check_1_1_5" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_1_5" - info " * File not found" -fi - -check_1_1_6="1.1.6 - Ensure that the scheduler pod specification file ownership is set to root:root (Scored)" - -file="/etc/kubernetes/manifests/kube-scheduler-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_6" - else - warn "$check_1_1_6" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_6" -fi - -check_1_1_7="1.1.7 - Ensure that the etcd pod specification file permissions are set to 644 or more restrictive (Scored)" - -file="/etc/kubernetes/manifests/etcd-member.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_1_1_7" - else - warn "$check_1_1_7" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_1_7" - info " * File not found" -fi - -check_1_1_8="1.1.8 - Ensure that the etcd pod specification file ownership is set to root:root (Scored)" - -file="/etc/kubernetes/manifests/etcd-member.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_8" - else - warn "$check_1_1_8" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_8" -fi - -#todo find CNI file location -check_1_1_9="1.1.9 - Ensure that the Container Network Interface file permissions are set to 644 or more restrictive (Not Scored)" - -valid_permission=true -path_cni_netd="/etc/cni/net.d" -path_cni_bin="/opt/cni/bin" -path_sdn_lib_ocpsdn="/var/lib/cni/networks/openshift-sdn" -path_sdn_run_ocpsdn="/var/run/openshift-sdn" -path_ovs_openv="/var/run/openvswitch" -path_ovs_k8s="/var/run/kubernetes" -path_ovs_etc_openv="/etc/openvswitch" -path_ovs_run_openv="/run/openvswitch" -path_ovs_var_openv="/var/run/openvswitch" - -invalid_file_list="" - -for p in "$path_cni_netd" "$path_cni_bin" "$path_sdn_lib_ocpsdn" "$path_sdn_run_ocpsdn" "$path_ovs_openv" "$path_ovs_k8s" "$path_ovs_etc_openv" "$path_ovs_run_openv" "$path_ovs_var_openv" -do - if [ -d "$p" ]; then - files=$(find $p -type f) - for i in $files - do - if [ $(stat -c %a "$i") -gt 644 ]; then - valid_permission=false - invalid_file_list+=" $i" - fi - done - fi -done - -if [ "$valid_permission" = "true" ]; then - pass "$check_1_1_9" -else - warn "$check_1_1_9" - for p in $invalid_file_list - do - warn " *Wrong ownership for $p " - done -fi - -check_1_1_10="1.1.10 - Ensure that the Container Network Interface file ownership is set to root:root (Not Scored)" - -valid_ownership=true -path_cni_netd="/etc/cni/net.d" -path_cni_bin="/opt/cni/bin" - -path_sdn_lib_ocpsdn="/var/lib/cni/networks/openshift-sdn" -path_sdn_run_ocpsdn="/var/run/openshift-sdn" - -path_ovs_openv="/var/run/openvswitch" -path_ovs_k8s="/var/run/kubernetes" -path_ovs_etc_openv="/etc/openvswitch" -path_ovs_run_openv="/run/openvswitch" -path_ovs_var_openv="/var/run/openvswitch" - -invalid_file_list="" - -for p in "$path_cni_netd" "$path_cni_bin" "$path_sdn_lib_ocpsdn" "$path_sdn_run_ocpsdn" "$path_ovs_k8s" -do - if [ -d "$p" ]; then - files=$(find $p -type f) - for i in $files - do - if [ $(stat -c %U:%G "$i") != "root:root" ]; then - valid_ownership=false - invalid_file_list+=" $i" - fi - done - fi -done - -for p in "$path_ovs_openv" "$path_ovs_etc_openv" "$path_ovs_run_openv" "$path_ovs_var_openv" -do - if [ -d "$p" ]; then - files=$(find $p -type f) - for i in $files - do - if [ $(stat -c %U:%G "$i") != "openvswitch:openvswitch" ]; then - valid_ownership=false - invalid_file_list+=" $i" - fi - done - fi -done - -if [ "$valid_ownership" = "true" ]; then - pass "$check_1_1_10" -else - warn "$check_1_1_10" - for p in $invalid_file_list - do - warn " *Wrong ownership for $p " - done -fi - -check_1_1_11="1.1.11 - Ensure that the etcd data directory permissions are set to 700 or more restrictive (Scored)" - -file="/var/lib/etcd" -if [ -d "$file" ]; then - if [ "$(stat -c %a $file)" -eq 700 ]; then - pass "$check_1_1_11" - else - warn "$check_1_1_11" - warn " * Wrong permission for $file" - fi -else - info "$check_1_1_11" -fi - -check_1_1_12="1.1.12 - Ensure that the etcd data directory ownership is set to etcd:etcd (Scored)" - -file="/var/lib/etcd" -if [ -d "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_12" - else - warn "$check_1_1_12" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_12" -fi - -check_1_1_13="1.1.13 - Ensure that the admin.conf file permissions are set to 644 or more restrictive (Scored)" - -file="/etc/kubernetes/kubeconfig" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_1_1_13" - else - warn "$check_1_1_13" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_1_13" - info " * File not found" -fi - -check_1_1_14="1.1.14 - Ensure that the admin.conf file ownership is set to root:root (Scored)" - -file="/etc/kubernetes/kubeconfig" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_14" - else - warn "$check_1_1_14" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_14" -fi - -check_1_1_15="1.1.15 - Ensure that the scheduler.conf file permissions are set to 644 or more restrictive (Scored)" - -files=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*/configmaps/scheduler-kubeconfig/kubeconfig') - -valid_permission=false -for i in $files -do - if [ $(stat -c %a "$i") -eq 644 -o $(stat -c %a "$i") -eq 600 -o $(stat -c %a "$i") -eq 400 ]; then - valid_permission=true - else - valid_permission=false - break - fi -done - -if [ "$valid_permission" = "true" ]; then - pass "$check_1_1_15" -else - warn "$check_1_1_15" -fi - -check_1_1_16="1.1.16 - Ensure that the scheduler.conf file ownership is set to root:root (Scored)" - -files=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*/configmaps/scheduler-kubeconfig/kubeconfig') - -valid_permission=false -for i in $files -do - if [ $(stat -c %u%g "$i") -eq 00 ]; then - valid_permission=true - else - valid_permission=false - break - fi -done - -if [ "$valid_permission" = "true" ]; then - pass "$check_1_1_16" -else - warn "$check_1_1_16" -fi - -check_1_1_17="1.1.17 - Ensure that the controller-manager.conf file permissions are set to 644 or more restrictive (Scored)" - -files=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*/configmaps/controller-manager-kubeconfig/kubeconfig') - -valid_permission=false -for i in $files -do - if [ $(stat -c %a "$i") -eq 644 -o $(stat -c %a "$i") -eq 600 -o $(stat -c %a "$i") -eq 400 ]; then - valid_permission=true - else - valid_permission=false - break - fi -done - -if [ "$valid_permission" = "true" ]; then - pass "$check_1_1_17" -else - warn "$check_1_1_17" -fi - -check_1_1_18="1.1.18 - Ensure that the controller-manager.conf file ownership is set to root:root (Scored)" - -files=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*/configmaps/controller-manager-kubeconfig/kubeconfig') - -valid_permission=false -for i in $files -do - if [ $(stat -c %u%g "$i") -eq 00 ]; then - valid_permission=true - else - valid_permission=false - break - fi -done - -if [ "$valid_permission" = "true" ]; then - pass "$check_1_1_18" -else - warn "$check_1_1_18" -fi - -check_1_1_19="1.1.19 - Ensure that the Kubernetes PKI directory and file ownership is set to root:root (Scored)" - -directories=$(find /etc/kubernetes/static-pod-resources -type d -wholename '*/secrets*') -files=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*/secrets*') - -valid_perm_dir=false -for i in $directories -do - if [ $(stat -c %u%g "$i") -eq 00 ]; then - valid_perm_dir=true - else - valid_perm_dir=false - break - fi -done - -valid_perm_file=false -for i in $files -do - if [ $(stat -c %u%g "$i") -eq 00 ]; then - valid_perm_file=true - else - valid_perm_file=false - break - fi -done - -if [ "$valid_perm_file" = "true" ] && [ "$valid_perm_dir" = "true" ]; then - pass "$check_1_1_19" -else - warn "$check_1_1_19" -fi - -check_1_1_20="1.1.20 - Ensure that the Kubernetes PKI certificate file permissions are set to 644 or more restrictive (Not Scored)" -files=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*/secrets/*.crt') -valid_perm_file=false -for i in $files -do - if [ $(stat -c %a "$i") -eq 600 ]; then - valid_perm_file=true - else - valid_perm_file=false - break - fi -done - -if [ "$valid_perm_file" = "true" ]; then - pass "$check_1_1_20" -else - warn "$check_1_1_20" -fi - -check_1_1_21="1.1.21 - Ensure that the Kubernetes PKI key file permissions are set to 600 (Not Scored)" -files=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*/secrets/*.key') -valid_perm_file=false -for i in $files -do - if [ $(stat -c %a "$i") -eq 600 ]; then - valid_perm_file=true - else - valid_perm_file=false - break - fi -done - -if [ "$valid_perm_file" = "true" ]; then - pass "$check_1_1_21" -else - warn "$check_1_1_21" -fi - -info "1.2 - API Server" - -#todo oc -check_1_2_1="1.2.1 - Allows anonymous requests to the API server to support information discovery and webhook integrations. Anonymous requests are assigned the system:unauthenticated group, which is bound to cluster-scoped roles (Not Scored)" -output_kube=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | \ - jq -r '.data["config.yaml"]' | \ - jq '.auditConfig.policyConfiguration.rules' | \ - grep 'system:unauthenticated' ) -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | \ - jq -r '.data["config.yaml"]' | \ - jq '.auditConfig.policyConfiguration.rules' | \ - grep 'system:unauthenticated' ) - -if [ -z "$output_kube" ] || [ -z "$output" ]; then - warn "$check_1_2_1" -else - pass "$check_1_2_1" -fi - -check_1_2_2="1.2.2 - Ensure that the basic-auth-file method is not enabled (Scored)" -output_ocp=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | grep --color "basic-auth") -output_api=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | grep --color "basic-auth" ) -running=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/config.openshift.io/v1/clusteroperators/authentication ) -if [ -z "$output_ocp" ] && [ -z "$output_api" ] && [ -n "$running" ] ; then - pass "$check_1_2_2" -else - warn "$check_1_2_2" -fi - -check_1_2_3="1.2.3 - Ensure that the token-auth-file flag is not used (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig.apiServerArguments //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty') -output_4=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/config.openshift.io/v1/clusteroperators/authentication) -if [ -z "$output_1" ] || [ -z "$output_2" ] || [ -z "$output_3" ] || [ -z "$output_4" ]; then - warn "$check_1_2_3" -else - pass "$check_1_2_3" -fi - -check_1_2_4="1.2.4 - Ensure that control-plane components utilize X.509 certificates for authentication (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.kubeletClientInfo //empty' ) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/secrets/serving-cert ) -if [ -z "$output_1" ] || [ -z "$output_2" ]; then - warn "$check_1_2_4" -else - pass "$check_1_2_4" -fi - -check_1_2_5="1.2.5 - Ensure that X.509 certificates are utilized for the secure connections between API server and node/kubelet (Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.kubeletClientInfo //empty' ) -if [ -z "$output" ]; then - warn "$check_1_2_5" -else - pass "$check_1_2_5" -fi - -check_1_2_6="1.2.6 - Ensure that X.509 certificates are utilized for authentication of the control-plane components (Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.kubeletClientInfo //empty' ) -if [ -z "$output" ]; then - warn "$check_1_2_6" -else - pass "$check_1_2_6" -fi - -check_1_2_7="1.2.7 - Ensure to use RBAC to authorize requests and actions a user is allowed to perform in an OpenShift cluster (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig.apiServerArguments //empty' ) -if [ -z "$output_1" ] || [ -z "$output_2" ] || [ -z "$output_3" ]; then - warn "$check_1_2_7" -else - pass "$check_1_2_7" -fi - -check_1_2_8="1.2.8 - Ensure that the Node authorizer is enabled (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig.apiServerArguments //empty' ) -if [ -z "$output_1" ] || [ -z "$output_2" ] || [ -z "$output_3" ]; then - warn "$check_1_2_8" -else - pass "$check_1_2_8" -fi - -check_1_2_9="1.2.9 - Ensure to use RBAC to authorize requests and actions a user is allowed to perform in an OpenShift cluster (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -if [ -z "$output_1" ] || [ -z "$output_2" ]; then - warn "$check_1_2_9" -else - pass "$check_1_2_9" -fi - -check_1_2_10="1.2.10 - Ensure that the kubelet sends fewer events for preventing requests flooding at the API server (Not Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_10" -else - warn "$check_1_2_10" -fi - -check_1_2_11="1.2.11 - Ensure that AlwaysAdmit admission control plugin is not enabled (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_11" -else - warn "$check_1_2_11" -fi - -check_1_2_12="1.2.12 - Ensure that the admission control plugin AlwaysPullImages is set (Not Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_12" -else - warn "$check_1_2_12" -fi - -check_1_2_13="1.2.13 - Ensure that the admission control plugin SecurityContextDeny is set if PodSecurityPolicy is not used (Not Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/security.openshift.io/v1/securitycontextconstraints/restricted | grep "SecurityContextDeny") -output_4=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/security.openshift.io/v1/securitycontextconstraints/restricted | grep 'Allow Privileged:'| grep false) -if [ -z "$output_1" ] && [ -z "$output_2" ] && [ -z "$output_3" ] && [ -n "$output_4" ]; then - pass "$check_1_2_13" -else - warn "$check_1_2_13" -fi - -check_1_2_14="1.2.14 - Ensure that the admission control plugin ServiceAccount is set (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_14" -else - warn "$check_1_2_14" -fi - -#todo review with Andson "Verify that NamespaceLifecycle is in place" -check_1_2_15="1.2.15 - Ensure that the admission control plugin NamespaceLifecycle is set (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_15" -else - warn "$check_1_2_15" -fi - -#todo the same audit script as 1.2.13 -check_1_2_16="1.2.16 - Ensure that the admission control plugin PodSecurityPolicy is set (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/security.openshift.io/v1/securitycontextconstraints/restricted | grep "SecurityContextDeny") -output_4=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/security.openshift.io/v1/securitycontextconstraints/restricted | grep 'Allow Privileged:'| grep false) -if [ -z "$output_1" ] && [ -z "$output_2" ] && [ -z "$output_3" ] && [ -n "$output_4" ]; then - pass "$check_1_2_16" -else - warn "$check_1_2_16" -fi - -#todo reivew with Andson "need a command to verify NodeRestriction" -check_1_2_17="1.2.17 - Ensure that the admission control plugin NodeRestriction is set (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_17" -else - warn "$check_1_2_17" -fi - -check_1_2_18="1.2.18 - Ensure that the --insecure-bind-address argument is not set (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig' | grep bind) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/kube-apiserver-pod | grep --color "insecure-bind-address") - -if [ -n "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_18" -else - warn "$check_1_2_18" -fi - -#todo review with Andson "insecure-port" -check_1_2_19="1.2.19 - Ensure that the --insecure-port argument is set to 0 (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig' | grep insecure) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/kube-apiserver-pod | grep --color "insecure-port") -if [ -z "$output" ] && [ -n "$output_2" ]; then - pass "$check_1_2_19" -else - warn "$check_1_2_19" -fi - -check_1_2_20="1.2.20 - Ensure that the --secure-port argument is not set to 0 (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | grep --color "bindAddress") -if [ -z "$output_1" ] || [ -z "$output_2" ]; then - warn "$check_1_2_20" -else - pass "$check_1_2_20" -fi - -#todo review by Andson "default port value 10248, bindAddress is 127.0.0.1" -check_1_2_21="1.2.21 - Ensure that the --profiling argument is set to false (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig.apiServerArguments //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/kube-apiserver-pod | grep --color healthz) -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/endpoints/api) -if [ -n "$output_1" ] && [ -n "$output_2" ] && [ -n "$output_3" ]; then - pass "$check_1_2_21" -else - warn "$check_1_2_21" -fi - -check_1_2_22="1.2.22 - Ensure that the --audit-log-path argument is set (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig.apiServerArguments') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.auditFilePath //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.auditFilePath //empty') -if [ -z "$output_1" ] || [ -z "$output_2" ] || [ -z "$output_3" ]; then - warn "$check_1_2_22" -else - pass "$check_1_2_22" -fi - -check_1_2_23="1.2.23 - Ensure that the --audit-log-maxage argument is set to 30 or as appropriate (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig //empty') -if [ -n "$output_1" ]; then - pass "$check_1_2_23" -else - warn "$check_1_2_23" -fi - -check_1_2_24="1.2.24 - Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.maximumRetainedFiles //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.maximumRetainedFiles //empty') -if [ "$output_1" -eq 10 -a "$output_2" -eq 10 ] > /dev/null 2>&1; then - pass "$check_1_2_24" -else - warn "$check_1_2_24" -fi - -check_1_2_25="1.2.25 - Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.maximumFileSizeMegabytes //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.maximumFileSizeMegabytes //empty') -if [ "$output_1" -eq 100 -a "$output_2" -eq 100 ] > /dev/null 2>&1; then - pass "$check_1_2_25" -else - warn "$check_1_2_25" -fi - -check_1_2_26="1.2.26 - Ensure that the --request-timeout argument is set as appropriate (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.servingInfo.requestTimeoutSeconds //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.servingInfo.requestTimeoutSeconds //empty') -if [ "$output_1" -eq 3600 -a -z "$output_2" ]; then - pass "$check_1_2_26" -else - warn "$check_1_2_26" -fi - -#todo review with Andson -check_1_2_27="1.2.27 - Ensure that the --service-account-lookup argument is set to true (Scored)" -info "$check_1_2_27 - OpenShift denies access for any OAuth Access token that does not exist in its etcd data store. - OpenShift does not use the service-account-lookup flag." - -check_1_2_28="1.2.28 - Ensure that the --service-account-key-file argument is set as appropriate (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.serviceAccountPublicKeyFiles //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.serviceAccountPublicKeyFiles //empty') -if [ -z "$output_1" ] || [ -z "$output_2" ]; then - warn "$check_1_2_28" -else - pass "$check_1_2_28" -fi - -check_1_2_29="1.2.29 - Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate (Scored)" -output_cert=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.storageConfig.certFile //empty') -output_key=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.storageConfig.keyFile //empty') -if [ -z "$output_cert" ] || [ -z "$output_key" ]; then - warn "$check_1_2_29" -else - pass "$check_1_2_29" -fi - -check_1_2_30="1.2.30 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)" -output_cert=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.servingInfo.certFile //empty') -output_key=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.servingInfo.keyFile //empty') -if [ -z "$output_cert" ] || [ -z "$output_key" ]; then - warn "$check_1_2_30" -else - pass "$check_1_2_30" -fi - -check_1_2_31="1.2.31 - Ensure that the --client-ca-file argument is set as appropriate (Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.servingInfo.clientCA //empty') -if [ -z "$output" ]; then - warn "$check_1_2_31" -else - pass "$check_1_2_31" -fi - -check_1_2_32="1.2.32 - Ensure that the --etcd-cafile argument is set as appropriate (Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.storageConfig.ca //empty') -if [ -z "$output" ]; then - warn "$check_1_2_32" -else - pass "$check_1_2_32" -fi - -#todo review with Andson -check_1_2_33="1.2.33 - Ensure that the --encryption-provider-config argument is set as appropriate (Not Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/openshiftapiservers/cluster -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}') -if [ -z "$output" ]; then - warn "$check_1_2_33" -else - pass "$check_1_2_33" -fi -#if get_argument_value "$CIS_APISERVER_CMD" '--encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then -# pass "$check_1_2_33" -#else -# warn "$check_1_2_33" -#fi - -#todo review with Andson -check_1_2_34="1.2.34 - Ensure that encryption providers are appropriately configured (Not Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/openshiftapiservers/cluster -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}') -if [ -z "$output" ]; then - warn "$check_1_2_34" -else - pass "$check_1_2_34" -fi -#if check_argument "$CIS_APISERVER_CMD" '--encryption-provider-config' >/dev/null 2>&1; then -# encryptionConfig=$(get_argument_value "$CIS_APISERVER_CMD" '--encryption-provider-config') -# if [ -f "$encryptionConfig" ]; then -# if [ $(grep -c "\- aescbc:\|\- kms:\|\- secretbox:" $encryptionConfig) -ne 0 ]; then -# pass "$check_1_2_34" -# else -# warn "$check_1_2_34" -# fi -# else -# warn "$check_1_2_34" -# fi -#else -# warn "$check_1_2_34" -#fi -#if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then -# encryptionConfig=$(get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config') -# if sed ':a;N;$!ba;s/\n/ /g' $encryptionConfig |grep "providers:\s* - aescbc" >/dev/null 2>&1; then -# pass "$check_1_2_34" -# else -# warn "$check_1_2_34" -# fi -#else -# warn "$check_1_2_34" -#fi - -#todo review with Andson -check_1_2_35="1.2.35 - Ensure that the API Server only makes use of Strong Cryptographic Ciphers (Not Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-authentication/configmaps/v4-0-config-system-cliconfig -o jsonpath='{.data.v4\-0\-config\-system\-cliconfig}' | jq '.servingInfo //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster |jq '.spec.observedConfig.servingInfo //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/openshiftapiservers/cluster |jq '.spec.observedConfig.servingInfo //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/namespaces/openshift-ingress-operator/ingresscontrollers/default ) - -if [ -z "$output_1" ] || [ -z "$output_2" ] || [ -z "$output_3" ] || [ -z "$output_4" ]; then - warn "$check_1_2_35" -else - pass "$check_1_2_35" -fi - -info "1.3 - Controller Manager" - -#todo review with Andson -check_1_3_1="1.3.1 - Ensure that imageMinimumGCAge, imageGCHighThresholdPercent, imageGCLowThresholdPercent are set as appropriate (Not Scored)" -info "$check_1_3_1" -info "Container garbage collection is enabled by default and happens automatically in response to eviction thresholds being reached. OpenShift does not set the terminated-pod-gc-threshold value differently from the Kubernetes default of 12500. You may need to adjust this value based on your cluster resources. -Need to confirm the above. Try checking the default machine config pool for worker nodes" - - -## Filter out processes like "/bin/tee -a /var/log/kube-controller-manager.log" -## which exist on kops-managed clusters. -#if check_argument "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold' >/dev/null 2>&1; then -# threshold=$(get_argument_value "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold') -# pass "$check_1_3_1" -# pass " * terminated-pod-gc-threshold: $threshold" -#else -# warn "$check_1_3_1" -#fi - -check_1_3_2="1.3.2 - Ensure that the profiling is secured with RBAC and is only available to cluster administrators (Scored)" - -info "$check_1_3_2" -info "OpenShift uses profiling by default but it is secured with authentication and authorization and is only available to cluster administrators.The Kubernetes Controller Manager operator manages and updates the Kubernetes Controller Manager deployed on top of OpenShift. This operator is configured via KubeControllerManager custom resource. By default, the operator exposes Prometheus metrics via metrics service. The metrics are collected from the Kubernetes Controller Manager operator." -#if check_argument "$CIS_MANAGER_CMD" '--profiling=false' >/dev/null 2>&1; then -# pass "$check_1_3_2" -#else -# warn "$check_1_3_2" -#fi - -check_1_3_3="1.3.3 - Ensure that the --use-service-account-credentials argument is set to true (Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.extendedArguments["use-service-account-credentials"]' | grep true) -if [ -n "$output" ]; then - pass "$check_1_3_3" -else - warn "$check_1_3_3" -fi - -check_1_3_4="1.3.4 - Ensure that the --service-account-private-key-file argument is set as appropriate (Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.extendedArguments["service-account-private-key-file"] //empty') -if [ -z "$output" ]; then - warn "$check_1_3_4" -else - pass "$check_1_3_4" -fi - -check_1_3_5="1.3.5 - Ensure that the --root-ca-file argument is set as appropriate (Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.extendedArguments["root-ca-file"] //empty') -if [ -z "$output" ]; then - warn "$check_1_3_5" -else - pass "$check_1_3_5" -fi - -check_1_3_6="1.3.6 - Ensure that the RotateKubeletServerCertificate argument is set to true (Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq '.extendedArguments["feature-gates"]' | grep "RotateKubeletServerCertificate=true") -if [ -z "$output" ]; then - warn "$check_1_3_6" -else - pass "$check_1_3_6" -fi - - -check_1_3_7="1.3.7 - Ensure that the --bind-address argument is set to 127.0.0.1 (Scored)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq '.extendedArguments["secure-port"] //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq '.extendedArguments["port"] //empty') -if [ -z "$output_1" ] || [ -z "$output_2" ]; then - warn "$check_1_3_7" -else - pass "$check_1_3_7" -fi - -info "1.4 - Scheduler" - -#todo not implemented -check_1_4_1="1.4.1 - Ensure the profiling endpoint is protected with RBAC (Scored)" -#info "$check_1_4_1" -#if check_argument "$CIS_SCHEDULER_CMD" '--profiling=false' >/dev/null 2>&1; then -# pass "$check_1_4_1" -#else -# warn "$check_1_4_1" -#fi - -#todo review -check_1_4_2="1.4.2 - Ensure that the --bind-address argument is set to 127.0.0.1 (Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-scheduler/configmaps/config | jq -r '.data["config.yaml"]' | jq '.extendedArguments["secure-port"] //empty' ) -if [ -z "$output" ]; then - pass "$check_1_4_2" -else - warn "$check_1_4_2" -fi -#if get_argument_value "$CIS_SCHEDULER_CMD" '--bind-address'| grep '127.0.0.1' >/dev/null 2>&1; then -# pass "$check_1_4_2" -#else -# warn "$check_1_4_2" -#fi - -info "2 - etcd" - -check_2_1="2.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)" -file="/etc/kubernetes/manifests/etcd-member.yaml" -output_cert=$(grep "\(--cert-file=\)" $file) -output_key=$(grep "\(--key-file=\)" $file) -if [ -z "$output_cert" ] || [ -z "$output_key" ]; then - warn "$check_2_1" -else - pass "$check_2_1" -fi - -check_2_2="2.2 - Ensure that the --client-cert-auth argument is set to true (Scored)" -file="/etc/kubernetes/manifests/etcd-member.yaml" -output=$(grep "\(--client-cert-auth=true\)" $file) -if [ -z "$output" ]; then - warn "$check_2_2" -else - pass "$check_2_2" -fi - -check_2_3="2.3 - Ensure that the --auto-tls argument is not set to true (Scored)" -file="/etc/kubernetes/manifests/etcd-member.yaml" -output=$(grep "\(--auto-tls=true\)" $file) -if [ -z "$output" ]; then - pass "$check_2_3" -else - warn "$check_2_3" -fi - -check_2_4="2.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Scored)" -file="/etc/kubernetes/manifests/etcd-member.yaml" -output_cert=$(grep "\(--peer-cert-file=\)" $file) -output_key=$(grep "\(--peer-key-file=\)" $file) -if [ -z "$output_cert" ] || [ -z "$output_key" ]; then - warn "$check_2_4" -else - pass "$check_2_4" -fi - -check_2_5="2.5 - Ensure that the --peer-client-cert-auth argument is set to true (Scored)" -file="/etc/kubernetes/manifests/etcd-member.yaml" -output=$(grep "\(--peer-client-cert-auth=true\)" $file) -if [ -z "$output" ]; then - warn "$check_2_5" -else - pass "$check_2_5" -fi - -check_2_6="2.6 - Ensure that the --peer-auto-tls argument is not set to true (Scored)" -file="/etc/kubernetes/manifests/etcd-member.yaml" -output=$(grep "\(--peer-auto-tls=true\)" $file) -if [ -z "$output" ]; then - pass "$check_2_6" -else - warn "$check_2_6" -fi - -check_2_7="2.7 - Ensure that a unique Certificate Authority is used for etcd (Not Scored)" -file="/etc/kubernetes/manifests/etcd-member.yaml" -output=$(grep "\(--trusted-ca-file=/etc/ssl/etcd/ca.crt\)" $file) -if [ -z "$output" ]; then - warn "$check_2_7" -else - pass "$check_2_7" -fi -info "3 - Control Plane Configuration" - -info "3.1 - Authentication and Authorization" - -#todo review -check_3_1_1="3.1.1 - Client certificate authentication should not be used for users (Not Scored)" -output=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*configmaps/client-ca/ca-bundle.crt') -if [ -z "$output" ]; then - warn "$check_3_1_1" -else - pass "check_3_1_1" -fi - -info "3.2 - Logging" - -#todo review with Andson (check recommended audit scripts) -check_3_2_1="3.2.1 - Ensure that a minimal audit policy is created (Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.auditConfig.auditFilePath','.auditConfig.enabled','.auditConfig.logFormat','.auditConfig.maximumFileSizeMegabytes','.auditConfig.maximumRetainedFiles') -if [ -z "$output" ]; then - warn "$check_3_2_1" -else - pass "$check_3_2_1" -fi - -#todo review with Andson (Compliance TBD) -check_3_2_2="3.2.2 - Ensure that the audit policy covers key security concerns (Not Scored)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.auditConfig.auditFilePath','.auditConfig.enabled','.auditConfig.logFormat','.auditConfig.maximumFileSizeMegabytes','.auditConfig.maximumRetainedFiles','.auditConfig.policyConfiguration') -if [ -z "$output" ]; then - warn "$check_3_2_2" -else - pass "$check_3_2_2" -fi -info "5 - Policies" -info "5.1 - RBAC and Service Accounts" - -# Make the loop separator be a new-line in POSIX compliant fashion -set -f; IFS=$' -' - -check_5_1_1="5.1.1 - Ensure that the cluster-admin role is only used where required (Not Scored)" -cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) -info "$check_5_1_1" -for admin in $cluster_admins; do - info " * $admin" -done - -check_5_1_2="5.1.2 - Minimize access to secrets (Not Scored)" -policies=$(kubectl get psp) -info "$check_5_1_2" -for policy in $policies; do - info " * $policy" -done - -check_5_1_3="5.1.3 - Create administrative boundaries between resources using namespaces (Not Scored)" -namespaces=$(kubectl get namespaces) -info "$check_5_1_3" -for namespace in $namespaces; do - info " * $namespace" -done - -check_5_1_4="5.1.4 - Create network segmentation using Network Policies (Not Scored)" -policies=$(kubectl get pods --namespace=kube-system) -info "$check_5_1_4" -for policy in $policies; do - info " * $policy" -done - -check_5_1_5="5.1.5 - Avoid using Kubernetes Secrets (Not Scored)" -secrets=$(kubectl get secrets) -info "$check_5_1_5" -for secret in $secrets; do - info " * $secret" -done - -#TODO -check_5_1_6="5.1.6 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)" -info "$check_5_1_6" -check_5_1_7="5.1.7 - Apply Security Context to Your Pods and Containers (Not Scored)" -info "$check_5_1_7" -check_5_1_8="5.1.8 - Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)" -info "$check_5_1_8" -check_5_1_9="5.1.9 - Place compensating controls in the form of PSP and RBAC for privileged containers usage (Not Scored)" -info "$check_5_1_9" - -info "5.2 - Pod Security Policies" - -check_5_2_1="5.2.1 - Minimize the admission of privileged containers (Not Scored)" -info "$check_5_2_1" -check_5_2_2="5.2.2 - Minimize the admission of containers wishing to share the host process ID namespace (Scored)" -info "$check_5_2_2" -check_5_2_3="5.2.3 - Minimize the admission of containers wishing to share the host IPC namespace (Scored)" -info "$check_5_2_3" -check_5_2_4="5.2.4 - Minimize the admission of containers wishing to share the host network namespace (Scored)" -info "$check_5_2_4" -check_5_2_5="5.2.5 - Minimize the admission of containers with allowPrivilegeEscalation (Scored)" -info "$check_5_2_5" -check_5_2_6="5.2.6 - Minimize the admission of root containers (Not Scored)" -info "$check_5_2_6" -check_5_2_7="5.2.7 - Minimize the admission of containers with the NET_RAW capability (Not Scored)" -info "$check_5_2_7" -check_5_2_8="5.2.8 - Minimize the admission of containers with added capabilities (Not Scored)" -info "$check_5_2_8" -check_5_2_9="5.2.9 - Minimize the admission of containers with capabilities assigned (Not Scored)" -info "$check_5_2_9" - -info "5.3 - Network Policies and CNI" -check_5_3_1="5.3.1 - Ensure that the CNI in use supports Network Policies (Not Scored)" -info "$check_5_3_1" -check_5_3_2="5.3.2 - Ensure that all Namespaces have Network Policies defined (Scored)" -info "$check_5_3_2" - -info "5.4 - Secrets Management" -check_5_4_1="5.4.1 - Prefer using secrets as files over secrets as environment variables (Not Scored)" -info "$check_5_4_1" -check_5_4_2="5.4.2 - Consider external secret storage (Not Scored)" -info "$check_5_4_2" - -info "5.5 - Extensible Admission Control" -check_5_5_1="5.5.1 - Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)" -info "$check_5_5_1" - -info "5.6 - General Policies" -check_5_6_1="5.6.1 - Create administrative boundaries between resources using namespaces (Not Scored)" -info "$check_5_6_1" -#todo remedition -check_5_6_2="5.6.2 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)" -info "$check_5_6_2" -check_5_6_3="5.6.3 - Apply Security Context to Your Pods and Containers (Not Scored)" -info "$check_5_6_3" -check_5_6_4="5.6.4 - The default namespace should not be used (Scored)" -info "$check_5_6_4" -exit 0; diff --git a/scripts/kubeBench/kube_master_ocp_4_5.tmpl b/scripts/kubeBench/kube_master_ocp_4_5.tmpl deleted file mode 100644 index 072c777..0000000 --- a/scripts/kubeBench/kube_master_ocp_4_5.tmpl +++ /dev/null @@ -1,1275 +0,0 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.6, 5.2.9, 5.3.2, 5.4.2, 5.5.1, 5.6.2, 5.6.3, 5.6.4" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -info "1 - Control Plane Components" - -info "1.1 - Master Node Configuration Files" - -check_1_1_1="1.1.1 - Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Manual)" - -file="/etc/kubernetes/manifests/kube-apiserver-pod.yaml" -if [ -f $file ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_1_1_1" - else - warn "$check_1_1_1" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_1_1" - info " * File not found" -fi - -check_1_1_2="1.1.2 - Ensure that the API server pod specification file ownership is set to root:root (Manual)" - -file="/etc/kubernetes/manifests/kube-apiserver-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_2" - else - warn "$check_1_1_2" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_2" -fi - -check_1_1_3="1.1.3 - Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive (Manual)" - -file="/etc/kubernetes/manifests/kube-controller-manager-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_1_1_3" - else - warn "$check_1_1_3" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_1_3" - info " * File not found" -fi - -check_1_1_4="1.1.4 - Ensure that the controller manager pod specification file ownership is set to root:root (Manual)" - -file="/etc/kubernetes/manifests/kube-controller-manager-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_4" - else - warn "$check_1_1_4" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_4" -fi - -check_1_1_5="1.1.5 - Ensure that the scheduler pod specification file permissions are set to 644 or more restrictive (Manual)" - -file="/etc/kubernetes/manifests/kube-scheduler-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_1_1_5" - else - warn "$check_1_1_5" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_1_5" - info " * File not found" -fi - -check_1_1_6="1.1.6 - Ensure that the scheduler pod specification file ownership is set to root:root (Manual)" - -file="/etc/kubernetes/manifests/kube-scheduler-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_6" - else - warn "$check_1_1_6" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_6" -fi - -#todo file name changes to "etcd-pod" -check_1_1_7="1.1.7 - Ensure that the etcd pod specification file permissions are set to 644 or more restrictive (Manual)" - -file="/etc/kubernetes/manifests/etcd-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_1_1_7" - else - warn "$check_1_1_7" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_1_7" - info " * File not found" -fi - -check_1_1_8="1.1.8 - Ensure that the etcd pod specification file ownership is set to root:root (Manual)" - -file="/etc/kubernetes/manifests/etcd-pod.yaml" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_8" - else - warn "$check_1_1_8" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_8" -fi - -check_1_1_9="1.1.9 - Ensure that the Container Network Interface file permissions are set to 644 or more restrictive (Manual)" - -valid_permission=true -path_cni_netd="/etc/cni/net.d" -path_cni_bin="/opt/cni/bin" -path_cni_multus="/var/run/multus/cni/net.d" -path_sdn_lib_ocpsdn="/var/lib/cni/networks/openshift-sdn" -path_sdn_run_ocpsdn="/var/run/openshift-sdn" -path_ovs_openv="/var/run/openvswitch" -path_ovs_k8s="/var/run/kubernetes" -path_ovs_etc_openv="/etc/openvswitch" -path_ovs_run_openv="/run/openvswitch" -path_ovs_var_openv="/var/run/openvswitch" - -invalid_file_list="" - -for p in "$path_cni_netd" "$path_cni_bin" "$path_cni_multus" "$path_sdn_lib_ocpsdn" "$path_sdn_run_ocpsdn" "$path_ovs_openv" "$path_ovs_k8s" "$path_ovs_etc_openv" "$path_ovs_run_openv" "$path_ovs_var_openv" -do - if [ -d "$p" ]; then - files=$(find $p -type f) - for i in $files - do - if [ $(stat -c %a "$i") -gt 644 ]; then - valid_permission=false - invalid_file_list+=" $i" - fi - done - fi -done - -if [ "$valid_permission" = "true" ]; then - pass "$check_1_1_9" -else - warn "$check_1_1_9" - for p in $invalid_file_list - do - warn " *Wrong ownership for $p " - done -fi - -check_1_1_10="1.1.10 - Ensure that the Container Network Interface file ownership is set to root:root (Manual)" - -valid_ownership=true -path_cni_netd="/etc/cni/net.d" -path_cni_bin="/opt/cni/bin" -path_cni_multus="/var/run/multus/cni/net.d" - -path_sdn_lib_ocpsdn="/var/lib/cni/networks/openshift-sdn" -path_sdn_run_ocpsdn="/var/run/openshift-sdn" - -path_ovs_openv="/var/run/openvswitch" -path_ovs_k8s="/var/run/kubernetes" -path_ovs_etc_openv="/etc/openvswitch" -path_ovs_run_openv="/run/openvswitch" -path_ovs_var_openv="/var/run/openvswitch" - -invalid_file_list="" - -for p in "$path_cni_netd" "$path_cni_bin" "$path_cni_multus" "$path_sdn_lib_ocpsdn" "$path_sdn_run_ocpsdn" -do - if [ -d "$p" ]; then - files=$(find $p -type f) - for i in $files - do - if [ $(stat -c %U:%G "$i") != "root:root" ]; then - valid_ownership=false - invalid_file_list+=" $i" - fi - done - fi -done - -for p in "$path_ovs_openv" "$path_ovs_k8s" "$path_ovs_etc_openv" "$path_ovs_run_openv" "$path_ovs_var_openv" -do - if [ -d "$p" ]; then - files=$(find $p -type f) - for i in $files - do - if [ $(stat -c %U:%G "$i") != "openvswitch:openvswitch" ]; then - valid_ownership=false - invalid_file_list+=" $i" - fi - done - fi -done - -if [ "$valid_ownership" = "true" ]; then - pass "$check_1_1_10" -else - warn "$check_1_1_10" - for p in $invalid_file_list - do - warn " *Wrong ownership for $p " - done -fi - -check_1_1_11="1.1.11 - Ensure that the etcd data directory permissions are set to 700 or more restrictive (Manual)" - -file="/var/lib/etcd" -if [ -d "$file" ]; then - if [ "$(stat -c %a $file)" -eq 700 ]; then - pass "$check_1_1_11" - else - warn "$check_1_1_11" - warn " * Wrong permission for $file" - fi -else - info "$check_1_1_11" -fi - -#todo review -check_1_1_12="1.1.12 - Ensure that the etcd data directory ownership is set to root:root (Manual)" - -file="/var/lib/etcd" -if [ -d "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_12" - else - warn "$check_1_1_12" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_12" -fi - -check_1_1_13="1.1.13 - Ensure that the admin.conf file permissions are set to 644 or more restrictive (Manual)" - -file="/etc/kubernetes/kubeconfig" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -le 644 ]; then - pass "$check_1_1_13" - else - warn "$check_1_1_13" - warn " * Wrong permissions for $file" - fi -else - info "$check_1_1_13" - info " * File not found" -fi - -check_1_1_14="1.1.14 - Ensure that the admin.conf file ownership is set to root:root (Manual)" - -file="/etc/kubernetes/kubeconfig" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_1_1_14" - else - warn "$check_1_1_14" - warn " * Wrong ownership for $file" - fi -else - info "$check_1_1_14" -fi - -check_1_1_15="1.1.15 - Ensure that the scheduler.conf file permissions are set to 644 or more restrictive (Manual)" - -files=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*/configmaps/scheduler-kubeconfig/kubeconfig') - -valid_permission=false -for i in $files -do - if [ $(stat -c %a "$i") -eq 644 -o $(stat -c %a "$i") -eq 600 -o $(stat -c %a "$i") -eq 400 ]; then - valid_permission=true - else - valid_permission=false - break - fi -done - -if [ "$valid_permission" = "true" ]; then - pass "$check_1_1_15" -else - warn "$check_1_1_15" -fi - -check_1_1_16="1.1.16 - Ensure that the scheduler.conf file ownership is set to root:root (Manual)" - -files=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*/configmaps/scheduler-kubeconfig/kubeconfig') - -valid_permission=false -for i in $files -do - if [ $(stat -c %u%g "$i") -eq 00 ]; then - valid_permission=true - else - valid_permission=false - break - fi -done - -if [ "$valid_permission" = "true" ]; then - pass "$check_1_1_16" -else - warn "$check_1_1_16" -fi - -check_1_1_17="1.1.17 - Ensure that the controller-manager.conf file permissions are set to 644 or more restrictive (Manual)" - -files=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*/configmaps/controller-manager-kubeconfig/kubeconfig') - -valid_permission=false -for i in $files -do - if [ $(stat -c %a "$i") -eq 644 -o $(stat -c %a "$i") -eq 600 -o $(stat -c %a "$i") -eq 400 ]; then - valid_permission=true - else - valid_permission=false - break - fi -done - -if [ "$valid_permission" = "true" ]; then - pass "$check_1_1_17" -else - warn "$check_1_1_17" -fi - -check_1_1_18="1.1.18 - Ensure that the controller-manager.conf file ownership is set to root:root (Manual)" - -files=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*/configmaps/controller-manager-kubeconfig/kubeconfig') - -valid_permission=false -for i in $files -do - if [ $(stat -c %u%g "$i") -eq 00 ]; then - valid_permission=true - else - valid_permission=false - break - fi -done - -if [ "$valid_permission" = "true" ]; then - pass "$check_1_1_18" -else - warn "$check_1_1_18" -fi - -check_1_1_19="1.1.19 - Ensure that the Kubernetes PKI directory and file ownership is set to root:root (Manual)" - -cert_path="/etc/kubernetes/static-pod-certs" -valid_perm_dir=false -valid_perm_file=false - -if [ -f "$cert_path" ]; then - - directories=$(find $cert_path -type d -wholename '*/secrets*') - files=$(find $cert_path -type f -wholename '*/secrets*') - - for i in $directories - do - if [ $(stat -c %u%g "$i") -eq 00 ]; then - valid_perm_dir=true - else - valid_perm_dir=false - break - fi - done - - for i in $files - do - if [ $(stat -c %u%g "$i") -eq 00 ]; then - valid_perm_file=true - else - valid_perm_file=false - break - fi - done - - if [ "$valid_perm_file" = "true" ] && [ "$valid_perm_dir" = "true" ]; then - pass "$check_1_1_19" - else - warn "$check_1_1_19" - fi -else - warn "$check_1_1_19" - warn "$cert_path doesn't exist." -fi - -check_1_1_20="1.1.20 - Ensure that the Kubernetes PKI certificate file permissions are set to 644 or more restrictive (Manual)" - -cert_path="/etc/kubernetes/static-pod-certs" -if [ -f "$cert_path" ]; then - files=$(find $cert_path -type f -wholename '*/secrets/*.crt') - valid_perm_file=false - for i in $files - do - if [ $(stat -c %a "$i") -eq 600 ]; then - valid_perm_file=true - else - valid_perm_file=false - break - fi - done - - if [ "$valid_perm_file" = "true" ]; then - pass "$check_1_1_20" - else - warn "$check_1_1_20" - fi -else - warn "$check_1_1_20" - warn "$cert_path doesn't exist." -fi - -check_1_1_21="1.1.21 - Ensure that the Kubernetes PKI key file permissions are set to 600 (Manual)" - -cert_path="/etc/kubernetes/static-pod-certs" - -if [ -f "$cert_path" ]; then - files=$(find $cert_path -type f -wholename '*/secrets/*.key') - valid_perm_file=false - for i in $files - do - if [ $(stat -c %a "$i") -eq 600 ]; then - valid_perm_file=true - else - valid_perm_file=false - break - fi - done - - if [ "$valid_perm_file" = "true" ]; then - pass "$check_1_1_21" - else - warn "$check_1_1_21" - fi -else - warn "$check_1_1_21" - warn "$cert_path doesn't exist." -fi - -info "1.2 - API Server" - -#todo oc -check_1_2_1="1.2.1 - Ensure that anonymous requests are authorized (Manual)" -output_kube=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | \ - jq -r '.data["config.yaml"]' | \ - jq '.auditConfig.policyConfiguration.rules' | \ - grep 'system:unauthenticated' ) -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | \ - jq -r '.data["config.yaml"]' | \ - jq '.auditConfig.policyConfiguration.rules' | \ - grep 'system:unauthenticated' ) - -if [ -z "$output_kube" ] || [ -z "$output" ]; then - warn "$check_1_2_1" -else - pass "$check_1_2_1" -fi - -check_1_2_2="1.2.2 - Ensure that the --basic-auth-file argument is not set (Manual)" -output_ocp=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | grep --color "basic-auth") -output_api=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | grep --color "basic-auth" ) -running=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/config.openshift.io/v1/clusteroperators/authentication ) -if [ -z "$output_ocp" ] && [ -z "$output_api" ] && [ -n "$running" ] ; then - pass "$check_1_2_2" -else - warn "$check_1_2_2" -fi - -check_1_2_3="1.2.3 - Ensure that the --token-auth-file parameter is not set (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig.apiServerArguments //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty') -output_4=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/config.openshift.io/v1/clusteroperators/authentication) -if [ -z "$output_1" ] || [ -z "$output_2" ] || [ -z "$output_3" ] || [ -z "$output_4" ]; then - warn "$check_1_2_3" -else - pass "$check_1_2_3" -fi - -check_1_2_4="1.2.4 - Use https for kubelet connections (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.kubeletClientInfo //empty' ) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/secrets/serving-cert ) -if [ -z "$output_1" ] || [ -z "$output_2" ]; then - warn "$check_1_2_4" -else - pass "$check_1_2_4" -fi - -check_1_2_5="1.2.5 - Ensure that the kubelet uses certificates to authenticate (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.kubeletClientInfo //empty' ) -if [ -z "$output" ]; then - warn "$check_1_2_5" -else - pass "$check_1_2_5" -fi - -check_1_2_6="1.2.6 - Verify that the kubelet certificate authority is set as appropriate (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.kubeletClientInfo //empty' ) -if [ -z "$output" ]; then - warn "$check_1_2_6" -else - pass "$check_1_2_6" -fi - -check_1_2_7="1.2.7 - Ensure that the --authorization-mode argument is not set to AlwaysAllow (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig.apiServerArguments //empty' ) -if [ -z "$output_1" ] || [ -z "$output_2" ] || [ -z "$output_3" ]; then - warn "$check_1_2_7" -else - pass "$check_1_2_7" -fi - -check_1_2_8="1.2.8 - Verify that the Node authorizer is enabled (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig.apiServerArguments //empty' ) -if [ -z "$output_1" ] || [ -z "$output_2" ] || [ -z "$output_3" ]; then - warn "$check_1_2_8" -else - pass "$check_1_2_8" -fi - -check_1_2_9="1.2.9 - Verify that RBAC is enabled (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.apiServerArguments //empty' ) -if [ -z "$output_1" ] || [ -z "$output_2" ]; then - warn "$check_1_2_9" -else - pass "$check_1_2_9" -fi - -check_1_2_10="1.2.10 - Ensure that the APIPriorityAndFairness feature gate is enabled (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_10" -else - warn "$check_1_2_10" -fi - -check_1_2_11="1.2.11 - Ensure that the admission control plugin AlwaysAdmit is not set (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_11" -else - warn "$check_1_2_11" -fi - -check_1_2_12="1.2.12 - Ensure that the admission control plugin AlwaysPullImages is set (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_12" -else - warn "$check_1_2_12" -fi - -check_1_2_13="1.2.13 - Ensure that the admission control plugin SecurityContextDeny is not set (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/security.openshift.io/v1/securitycontextconstraints/restricted | grep "SecurityContextDeny") -output_4=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/security.openshift.io/v1/securitycontextconstraints/restricted | grep 'Allow Privileged:'| grep false) -if [ -z "$output_1" ] && [ -z "$output_2" ] && [ -z "$output_3" ] && [ -n "$output_4" ]; then - pass "$check_1_2_13" -else - warn "$check_1_2_13" -fi - -check_1_2_14="1.2.14 - Ensure that the admission control plugin ServiceAccount is set (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_14" -else - warn "$check_1_2_14" -fi - -#todo review with Andson "Verify that NamespaceLifecycle is in place" -check_1_2_15="1.2.15 - Ensure that the admission control plugin NamespaceLifecycle is set (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_15" -else - warn "$check_1_2_15" -fi - -#todo the same audit script as 1.2.13 -check_1_2_16="1.2.16 - Ensure that the admission control plugin SecurityContextConstraint is set (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/security.openshift.io/v1/securitycontextconstraints/restricted | grep "SecurityContextDeny") -output_4=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/security.openshift.io/v1/securitycontextconstraints/restricted | grep 'Allow Privileged:'| grep false) -if [ -z "$output_1" ] && [ -z "$output_2" ] && [ -z "$output_3" ] && [ -n "$output_4" ]; then - pass "$check_1_2_16" -else - warn "$check_1_2_16" -fi - -#todo reivew with Andson "need a command to verify NodeRestriction" -check_1_2_17="1.2.17 - Ensure that the admission control plugin NodeRestriction is set (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data."config.yaml"' | jq '.apiServerArguments."enable-admission-plugins" //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq -r '.spec.unsupportedConfigOverrides //empty') -if [ -z "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_17" -else - warn "$check_1_2_17" -fi - -check_1_2_18="1.2.18 - Ensure that the --insecure-bind-address argument is not set (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig' | grep bind) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/kube-apiserver-pod | grep --color "insecure-bind-address") - -if [ -n "$output_1" ] && [ -z "$output_2" ]; then - pass "$check_1_2_18" -else - warn "$check_1_2_18" -fi - -#todo review with Andson "insecure-port" -check_1_2_19="1.2.19 - Ensure that the --insecure-port argument is set to 0 (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig' | grep insecure) -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/kube-apiserver-pod | grep --color "insecure-port") -if [ -z "$output" ] && [ -n "$output_2" ]; then - pass "$check_1_2_19" -else - warn "$check_1_2_19" -fi - -check_1_2_20="1.2.20 - Ensure that the --secure-port argument is not set to 0 (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | grep --color "bindAddress") -if [ -z "$output_1" ] || [ -z "$output_2" ]; then - warn "$check_1_2_20" -else - pass "$check_1_2_20" -fi - -#todo review by Andson "default port value 10248, bindAddress is 127.0.0.1" -check_1_2_21="1.2.21 - Ensure that the healthz endpoint is protected by RBAC (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig.apiServerArguments //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/kube-apiserver-pod | grep --color healthz) -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/endpoints/api) -if [ -n "$output_1" ] && [ -n "$output_2" ] && [ -n "$output_3" ]; then - pass "$check_1_2_21" -else - warn "$check_1_2_21" -fi - -check_1_2_22="1.2.22 - Ensure that the --audit-log-path argument is set (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig.apiServerArguments') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.auditFilePath //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.auditFilePath //empty') -if [ -z "$output_1" ] || [ -z "$output_2" ] || [ -z "$output_3" ]; then - warn "$check_1_2_22" -else - pass "$check_1_2_22" -fi - -check_1_2_23="1.2.23 - Ensure that the audit logs are forwarded off the cluster for retention (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster | jq '.spec.observedConfig //empty') -if [ -n "$output_1" ]; then - pass "$check_1_2_23" -else - warn "$check_1_2_23" -fi - -check_1_2_24="1.2.24 - Ensure that the maximumRetainedFiles argument is set to 10 or as appropriate (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.maximumRetainedFiles //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.maximumRetainedFiles //empty') -if [ "$output_1" -eq 10 -a "$output_2" -eq 10 ] > /dev/null 2>&1; then - pass "$check_1_2_24" -else - warn "$check_1_2_24" -fi - -check_1_2_25="1.2.25 - Ensure that the maximumFileSizeMegabytes argument is set to 100 or as appropriate (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.maximumFileSizeMegabytes //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.auditConfig.maximumFileSizeMegabytes //empty') -if [ "$output_1" -eq 100 -a "$output_2" -eq 100 ] > /dev/null 2>&1; then - pass "$check_1_2_25" -else - warn "$check_1_2_25" -fi - -check_1_2_26="1.2.26 - Ensure that the --request-timeout argument is set as appropriate (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.servingInfo.requestTimeoutSeconds //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.servingInfo.requestTimeoutSeconds //empty') -if [ "$output_1" -eq 3600 -a -z "$output_2" ]; then - pass "$check_1_2_26" -else - warn "$check_1_2_26" -fi - -#todo review with Andson -check_1_2_27="1.2.27 - Ensure that the --service-account-lookup argument is set to true (Manual)" -info "$check_1_2_27 - OpenShift denies access for any OAuth Access token that does not exist in its etcd data store. - OpenShift does not use the service-account-lookup flag." - -check_1_2_28="1.2.28 - Ensure that the --service-account-key-file argument is set as appropriate (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.serviceAccountPublicKeyFiles //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.serviceAccountPublicKeyFiles //empty') -if [ -z "$output_1" ] || [ -z "$output_2" ]; then - warn "$check_1_2_28" -else - pass "$check_1_2_28" -fi - -check_1_2_29="1.2.29 - Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate (Manual)" -output_cert=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.storageConfig.certFile //empty') -output_key=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.storageConfig.keyFile //empty') -if [ -z "$output_cert" ] || [ -z "$output_key" ]; then - warn "$check_1_2_29" -else - pass "$check_1_2_29" -fi - -check_1_2_30="1.2.30 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Manual)" -output_cert=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.servingInfo.certFile //empty') -output_key=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.servingInfo.keyFile //empty') -if [ -z "$output_cert" ] || [ -z "$output_key" ]; then - warn "$check_1_2_30" -else - pass "$check_1_2_30" -fi - -check_1_2_31="1.2.31 - Ensure that the --client-ca-file argument is set as appropriate (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.servingInfo.clientCA //empty') -if [ -z "$output" ]; then - warn "$check_1_2_31" -else - pass "$check_1_2_31" -fi - -check_1_2_32="1.2.32 - Ensure that the --etcd-cafile argument is set as appropriate (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.storageConfig.ca //empty') -if [ -z "$output" ]; then - warn "$check_1_2_32" -else - pass "$check_1_2_32" -fi - -#todo review with Andson -check_1_2_33="1.2.33 - Ensure that the --encryption-provider-config argument is set as appropriate (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/openshiftapiservers/cluster -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}') -if [ -z "$output" ]; then - warn "$check_1_2_33" -else - pass "$check_1_2_33" -fi -#if get_argument_value "$CIS_APISERVER_CMD" '--encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then -# pass "$check_1_2_33" -#else -# warn "$check_1_2_33" -#fi - -#todo review with Andson -check_1_2_34="1.2.34 - Ensure that encryption providers are appropriately configured (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/openshiftapiservers/cluster -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}') -if [ -z "$output" ]; then - warn "$check_1_2_34" -else - pass "$check_1_2_34" -fi -#if check_argument "$CIS_APISERVER_CMD" '--encryption-provider-config' >/dev/null 2>&1; then -# encryptionConfig=$(get_argument_value "$CIS_APISERVER_CMD" '--encryption-provider-config') -# if [ -f "$encryptionConfig" ]; then -# if [ $(grep -c "\- aescbc:\|\- kms:\|\- secretbox:" $encryptionConfig) -ne 0 ]; then -# pass "$check_1_2_34" -# else -# warn "$check_1_2_34" -# fi -# else -# warn "$check_1_2_34" -# fi -#else -# warn "$check_1_2_34" -#fi -#if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then -# encryptionConfig=$(get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config') -# if sed ':a;N;$!ba;s/\n/ /g' $encryptionConfig |grep "providers:\s* - aescbc" >/dev/null 2>&1; then -# pass "$check_1_2_34" -# else -# warn "$check_1_2_34" -# fi -#else -# warn "$check_1_2_34" -#fi - -#todo review with Andson -check_1_2_35="1.2.35 - Ensure that the API Server only makes use of Strong Cryptographic Ciphers (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-authentication/configmaps/v4-0-config-system-cliconfig -o jsonpath='{.data.v4\-0\-config\-system\-cliconfig}' | jq '.servingInfo //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/kubeapiservers/cluster |jq '.spec.observedConfig.servingInfo //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/openshiftapiservers/cluster |jq '.spec.observedConfig.servingInfo //empty') -output_3=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/apis/operator.openshift.io/v1/namespaces/openshift-ingress-operator/ingresscontrollers/default ) - -if [ -z "$output_1" ] || [ -z "$output_2" ] || [ -z "$output_3" ] || [ -z "$output_4" ]; then - warn "$check_1_2_35" -else - pass "$check_1_2_35" -fi - -info "1.3 - Controller Manager" - -#todo review with Andson -check_1_3_1="1.3.1 - Ensure that garbage collection is configured as appropriate (Manual)" -info "$check_1_3_1" -info "Garbage collection is important to ensure sufficient resource availability and avoiding degraded performance and availability. In the worst case, the system might crash or just be unusable for a long period of time. The current setting for garbage collection is 12,500 terminated pods which might be too high for your system to sustain. Based on your system resources and tests, choose an appropriate threshold value to activate garbage collection." - - -## Filter out processes like "/bin/tee -a /var/log/kube-controller-manager.log" -## which exist on kops-managed clusters. -#if check_argument "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold' >/dev/null 2>&1; then -# threshold=$(get_argument_value "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold') -# pass "$check_1_3_1" -# pass " * terminated-pod-gc-threshold: $threshold" -#else -# warn "$check_1_3_1" -#fi - -check_1_3_2="1.3.2 - Ensure that controller manager healthz endpoints are protected by RBAC (Manual)" - -info "$check_1_3_2" -info "Profiling allows for the identification of specific performance bottlenecks. It generates a significant amount of program data that could potentially be exploited to uncover system and program details. If you are not experiencing any bottlenecks and do not need the profiler for troubleshooting purposes, it is recommended to turn it off to reduce the potential attack surface." -#if check_argument "$CIS_MANAGER_CMD" '--profiling=false' >/dev/null 2>&1; then -# pass "$check_1_3_2" -#else -# warn "$check_1_3_2" -#fi - -check_1_3_3="1.3.3 - Ensure that the --use-service-account-credentials argument is set to true (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.extendedArguments["use-service-account-credentials"]' | grep true) -if [ -n "$output" ]; then - pass "$check_1_3_3" -else - warn "$check_1_3_3" -fi - -check_1_3_4="1.3.4 - Ensure that the --service-account-private-key-file argument is set as appropriate (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.extendedArguments["service-account-private-key-file"] //empty') -if [ -z "$output" ]; then - warn "$check_1_3_4" -else - pass "$check_1_3_4" -fi - -check_1_3_5="1.3.5 - Ensure that the --root-ca-file argument is set as appropriate (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq -r '.extendedArguments["root-ca-file"] //empty') -if [ -z "$output" ]; then - warn "$check_1_3_5" -else - pass "$check_1_3_5" -fi - -check_1_3_6="1.3.6 - Ensure that the RotateKubeletServerCertificate argument is set to true (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq '.extendedArguments["feature-gates"]' | grep "RotateKubeletServerCertificate=true") -if [ -z "$output" ]; then - warn "$check_1_3_6" -else - pass "$check_1_3_6" -fi - - -check_1_3_7="1.3.7 - Ensure that the --bind-address argument is set to 127.0.0.1 (Manual)" -output_1=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq '.extendedArguments["secure-port"] //empty') -output_2=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-controller-manager/configmaps/config | jq -r '.data["config.yaml"]' | jq '.extendedArguments["port"] //empty') -if [ -z "$output_1" ] || [ -z "$output_2" ]; then - warn "$check_1_3_7" -else - pass "$check_1_3_7" -fi - -info "1.4 - Scheduler" - -#todo not implemented -check_1_4_1="1.4.1 - Ensure that the healthz endpoints for the scheduler are protected by RBAC (Manual)" -info "$check_1_4_1" -info "Disable profiling, if not needed." -#if check_argument "$CIS_SCHEDULER_CMD" '--profiling=false' >/dev/null 2>&1; then -# pass "$check_1_4_1" -#else -# warn "$check_1_4_1" -#fi - -#todo review -check_1_4_2="1.4.2 - Verify that the scheduler API service is protected by authentication and authorization (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-scheduler/configmaps/config | jq -r '.data["config.yaml"]' | jq '.extendedArguments["secure-port"] //empty' ) -if [ -z "$output" ]; then - pass "$check_1_4_2" -else - warn "$check_1_4_2" -fi -#if get_argument_value "$CIS_SCHEDULER_CMD" '--bind-address'| grep '127.0.0.1' >/dev/null 2>&1; then -# pass "$check_1_4_2" -#else -# warn "$check_1_4_2" -#fiinfo "2 - etcd" - -check_2_1="2.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Manual)" -file="/etc/kubernetes/manifests/etcd-pod.yaml" -output_cert=$(grep "\(--cert-file=\)" $file) -output_key=$(grep "\(--key-file=\)" $file) -if [ -z "$output_cert" ] || [ -z "$output_key" ]; then - warn "$check_2_1" -else - pass "$check_2_1" -fi - -check_2_2="2.2 - Ensure that the --client-cert-auth argument is set to true (Manual)" -file="/etc/kubernetes/manifests/etcd-pod.yaml" -output=$(grep "\(--client-cert-auth=true\)" $file) -if [ -z "$output" ]; then - warn "$check_2_2" -else - pass "$check_2_2" -fi - -#todo review with Andson (OCP doesn't use auto-tls) -check_2_3="2.3 - Ensure that the --auto-tls argument is not set to true (Manual)" -file="/etc/kubernetes/manifests/etcd-pod.yaml" -output=$(grep "\(--auto-tls=true\)" $file) -if [ -z "$output" ]; then - pass "$check_2_3" -else - warn "$check_2_3" -fi - -check_2_4="2.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Manual)" -file="/etc/kubernetes/manifests/etcd-pod.yaml" -output_cert=$(grep "\(--peer-cert-file=\)" $file) -output_key=$(grep "\(--peer-key-file=\)" $file) -if [ -z "$output_cert" ] || [ -z "$output_key" ]; then - warn "$check_2_4" -else - pass "$check_2_4" -fi - -check_2_5="2.5 - Ensure that the --peer-client-cert-auth argument is set to true (Manual)" -file="/etc/kubernetes/manifests/etcd-pod.yaml" -output=$(grep "\(--peer-client-cert-auth=true\)" $file) -if [ -z "$output" ]; then - warn "$check_2_5" -else - pass "$check_2_5" -fi - -check_2_6="2.6 - Ensure that the --peer-auto-tls argument is not set to true (Manual)" -file="/etc/kubernetes/manifests/etcd-pod.yaml" -output=$(grep "\(--peer-auto-tls=true\)" $file) -if [ -z "$output" ]; then - pass "$check_2_6" -else - warn "$check_2_6" -fi - -check_2_7="2.7 - Ensure that a unique Certificate Authority is used for etcd (Manual)" -file="/etc/kubernetes/manifests/etcd-pod.yaml" -output_1=$(grep "\(--trusted-ca-file=\)" $file) -output_2=$(grep "\(--peer-trusted-ca-file=\)" $file) -if [ -z "$output_1" ] || [ -z "$output_2" ]; then - warn "$check_2_7" -else - pass "$check_2_7" -fi -info "3 - Control Plane Configuration" - -info "3.1 - Authentication and Authorization" - -#todo review -check_3_1_1="3.1.1 - Client certificate authentication should not be used for users (Manual)" -output=$(find /etc/kubernetes/static-pod-resources -type f -wholename '*configmaps/client-ca/ca-bundle.crt') -if [ -z "$output" ]; then - warn "$check_3_1_1" -else - pass "check_3_1_1" -fi - -info "3.2 - Logging" - -#todo review with Andson (check recommended audit scripts) -check_3_2_1="3.2.1 - Ensure that a minimal audit policy is created (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.auditConfig.auditFilePath','.auditConfig.enabled','.auditConfig.logFormat','.auditConfig.maximumFileSizeMegabytes','.auditConfig.maximumRetainedFiles') -if [ -z "$output" ]; then - warn "$check_3_2_1" -else - pass "$check_3_2_1" -fi - -#todo review with Andson (Compliance TBD) -check_3_2_2="3.2.2 - Ensure that the audit policy covers key security concerns (Manual)" -output=$(curl -ks -H "Authorization: Bearer $OC_TOKEN" https://kubernetes.default/api/v1/namespaces/openshift-kube-apiserver/configmaps/config | jq -r '.data["config.yaml"]' | jq '.auditConfig.auditFilePath','.auditConfig.enabled','.auditConfig.logFormat','.auditConfig.maximumFileSizeMegabytes','.auditConfig.maximumRetainedFiles','.auditConfig.policyConfiguration') -if [ -z "$output" ]; then - warn "$check_3_2_2" -else - pass "$check_3_2_2" -fi -info "5 - Policies" -info "5.1 - RBAC and Service Accounts" - -# Make the loop separator be a new-line in POSIX compliant fashion -set -f; IFS=$' -' - -check_5_1_1="5.1.1 - Ensure that the cluster-admin role is only used where required (Manual)" -cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) -info "$check_5_1_1" -for admin in $cluster_admins; do - info " * $admin" -done - -check_5_1_2="5.1.2 - Minimize access to secrets (Manual)" -policies=$(kubectl get psp) -info "$check_5_1_2" -for policy in $policies; do - info " * $policy" -done - -check_5_1_3="5.1.3 - Minimize wildcard use in Roles and ClusterRoles (Manual)" -info "$check_5_1_3" - -check_5_1_4="5.1.4 - Minimize access to create pods (Manual)" -policies=$(kubectl get pods --namespace=kube-system) -info "$check_5_1_4" -for policy in $policies; do - info " * $policy" -done - -check_5_1_5="5.1.5 - Ensure that default service accounts are not actively used. (Manual)" -info "check_5_1_5" -info "The default service account should not be used to ensure that rights granted to applications can be more easily audited and reviewed." - -#TODO -check_5_1_6="5.1.6 - Ensure that Service Account Tokens are only mounted where necessary (Manual)" -info "$check_5_1_6" -info "Service accounts tokens should not be mounted in pods except where the workload running in the pod explicitly needs to communicate with the API server" - -info "5.2 - Pod Security Policies" - -check_5_2_1="5.2.1 - Minimize the admission of privileged containers (Manual)" -info "$check_5_2_1" -info "Do not generally permit containers to be run with the securityContext.privileged flag set to true." -check_5_2_2="5.2.2 - Minimize the admission of containers wishing to share the host process ID namespace (Manual)" -info "$check_5_2_2" -info "Do not generally permit containers to be run with the hostPID flag set to true." -check_5_2_3="5.2.3 - Minimize the admission of containers wishing to share the host IPC namespace (Manual)" -info "$check_5_2_3" -info "Do not generally permit containers to be run with the hostIPC flag set to true." -check_5_2_4="5.2.4 - Minimize the admission of containers wishing to share the host network namespace (Manual)" -info "$check_5_2_4" -info "Do not generally permit containers to be run with the hostNetwork flag set to true." -check_5_2_5="5.2.5 - Minimize the admission of containers with allowPrivilegeEscalation (Manual)" -info "$check_5_2_5" -info "Do not generally permit containers to be run with the allowPrivilegeEscalation flag set to true." -check_5_2_6="5.2.6 - Minimize the admission of root containers (Manual)" -info "$check_5_2_6" -info "Do not generally permit containers to be run as the root user." -check_5_2_7="5.2.7 - Minimize the admission of containers with the NET_RAW capability (Manual)" -info "$check_5_2_7" -info "Do not generally permit containers with the potentially dangerous NET_RAW capability." -check_5_2_8="5.2.8 - Minimize the admission of containers with added capabilities (Manual)" -info "$check_5_2_8" -info "Do not generally permit containers with capabilities assigned beyond the default set." -check_5_2_9="5.2.9 - Minimize the admission of containers with capabilities assigned (Manual)" -info "$check_5_2_9" -info "Do not generally permit containers with capabilities" - -info "5.3 - Network Policies and CNI" -check_5_3_1="5.3.1 - Ensure that the CNI in use supports Network Policies (Manual)" -info "$check_5_3_1" -info "There are a variety of CNI plugins available for Kubernetes. If the CNI in use does not support Network Policies it may not be possible to effectively restrict traffic in the cluster." -check_5_3_2="5.3.2 - Ensure that all Namespaces have Network Policies defined (Manual)" -info "$check_5_3_2" -info "Use network policies to isolate traffic in your cluster network." - -info "5.4 - Secrets Management" -check_5_4_1="5.4.1 - Prefer using secrets as files over secrets as environment variables (Manual)" -info "$check_5_4_1" -info "Kubernetes supports mounting secrets as data volumes or as environment variables. Minimize the use of environment variable secrets." -check_5_4_2="5.4.2 - Consider external secret storage (Manual)" -info "$check_5_4_2" -info "Consider the use of an external secrets storage and management system, instead of using Kubernetes Secrets directly, if you have more complex secret management needs. Ensure the solution requires authentication to access secrets, has auditing of access to and use of secrets, and encrypts secrets. Some solutions also make it easier to rotate secrets." - -info "5.5 - Extensible Admission Control" -check_5_5_1="5.5.1 - Configure Image Provenance using image controller configuration parameters (Manual)" -info "$check_5_5_1" -info "Configure Image Provenance for your deployment." - -info "5.6 - General Policies" -check_5_6_1="5.6.1 - Create administrative boundaries between resources using namespaces (Manual)" -info "$check_5_6_1" -info "Use namespaces to isolate your Kubernetes objects." -#todo remedition -check_5_6_2="5.6.2 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Manual)" -info "$check_5_6_2" -info "Enable default seccomp profile in your pod definitions." -check_5_6_3="5.6.3 - Apply Security Context to Your Pods and Containers (Manual)" -info "$check_5_6_3" -info "A security context defines the operating system security settings (uid, gid, capabilities, SELinux role, etc..) applied to a container. When designing your containers and pods, make sure that you configure the security context for your pods, containers, and volumes. A security context is a property defined in the deployment yaml. It controls the security parameters that will be assigned to the pod/container/volume. There are two levels of security context: pod level security context, and container level security context." -check_5_6_4="5.6.4 - The default namespace should not be used (Manual)" -info "$check_5_6_4" -info "Resources in a Kubernetes cluster should be segregated by namespace, to allow for security controls to be applied at that level and to make it easier to manage resources." -exit 0; diff --git a/scripts/kubeBench/kube_worker_1_2_0.tmpl b/scripts/kubeBench/kube_worker_1_2_0.tmpl deleted file mode 100644 index b6d2ea1..0000000 --- a/scripts/kubeBench/kube_worker_1_2_0.tmpl +++ /dev/null @@ -1,346 +0,0 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - txtrst='\033[0m' -fi - -info () { - printf "%b\n" "${bldblu}[INFO]${txtrst} $1" -} - -pass () { - printf "%b\n" "${bldgrn}[PASS]${txtrst} $1" -} - -warn () { - printf "%b\n" "${bldred}[WARN]${txtrst} $1" -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2016- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_KUBELET_CMD="<<<.Replace_kubelet_cmd>>>" - -if ps -ef | grep "$CIS_KUBELET_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Worker Node Security Configuration" -else - info "This node is not a Kubernetes worker node" - exit 2 -fi - -info "2.1 - Kubelet" - -check_2_1_1="2.1.1 - Ensure that the --allow-privileged argument is set to false" -if check_argument "$CIS_KUBELET_CMD" '--allow-privileged=false' >/dev/null 2>&1; then - pass "$check_2_1_1" -else - warn "$check_2_1_1" -fi - -check_2_1_2="2.1.2 - Ensure that the --anonymous-auth argument is set to false" -if check_argument "$CIS_KUBELET_CMD" '--anonymous-auth=false' >/dev/null 2>&1; then - pass "$check_2_1_2" -else - warn "$check_2_1_2" -fi - -check_2_1_3="2.1.3 - Ensure that the --authorization-mode argument is not set to AlwaysAllow" -if check_argument "$CIS_KUBELET_CMD" '--authorization-mode=AlwaysAllow' >/dev/null 2>&1; then - warn "$check_2_1_3" -else - pass "$check_2_1_3" -fi - -check_2_1_4="2.1.4 - Ensure that the --client-ca-file argument is set as appropriate" -if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then - cafile=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') - pass "$check_2_1_4" - pass " * client-ca-file: $cafile" -else - warn "$check_2_1_4" -fi - -check_2_1_5="2.1.5 - Ensure that the --read-only-port argument is set to 0" -if check_argument "$CIS_KUBELET_CMD" '--read-only-port' >/dev/null 2>&1; then - port=$(get_argument_value "$CIS_KUBELET_CMD" '--read-only-port' | cut -d " " -f 1) - if [ $port = "0" ]; then - pass "$check_2_1_5" - else - warn "$check_2_1_5" - warn " * read-only-port: $port" - fi -else - warn "$check_2_1_5" -fi - -check_2_1_6="2.1.6 - Ensure that the --streaming-connection-idle-timeout argument is not set to 0" -if check_argument "$CIS_KUBELET_CMD" '--streaming-connection-idle-timeout=0' >/dev/null 2>&1; then - timeout=$(get_argument_value "$CIS_KUBELET_CMD" '--streaming-connection-idle-timeout') - warn "$check_2_1_6" - warn " * streaming-connection-idle-timeout: $timeout" -else - pass "$check_2_1_6" -fi - -check_2_1_7="2.1.7 - Ensure that the --protect-kernel-defaults argument is set to true" -if check_argument "$CIS_KUBELET_CMD" '--protect-kernel-defaults=true' >/dev/null 2>&1; then - pass "$check_2_1_7" -else - warn "$check_2_1_7" -fi - -check_2_1_8="2.1.8 - Ensure that the --make-iptables-util-chains argument is set to true" -if check_argument "$CIS_KUBELET_CMD" '--make-iptables-util-chains=true' >/dev/null 2>&1; then - pass "$check_2_1_8" -else - warn "$check_2_1_8" -fi - -check_2_1_9="2.1.9 - Ensure that the --keep-terminated-pod-volumes argument is set to false" -if check_argument "$CIS_KUBELET_CMD" '--keep-terminated-pod-volumes=false' >/dev/null 2>&1; then - pass "$check_2_1_9" -else - warn "$check_2_1_9" -fi - -check_2_1_10="2.1.10 - Ensure that the --hostname-override argument is not set" -if check_argument "$CIS_KUBELET_CMD" '--hostname-override' >/dev/null 2>&1; then - warn "$check_2_1_10" -else - pass "$check_2_1_10" -fi - -check_2_1_11="2.1.11 - Ensure that the --event-qps argument is set to 0" -if check_argument "$CIS_KUBELET_CMD" '--event-qps' >/dev/null 2>&1; then - event=$(get_argument_value "$CIS_KUBELET_CMD" '--event-qps' | cut -d " " -f 1) - if [ $event = "0" ]; then - pass "$check_2_1_11" - else - warn "$check_2_1_11" - warn " * event-qps: $event" - fi -else - warn "$check_2_1_11" -fi - -check_2_1_12="2.1.12 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate" -if check_argument "$CIS_KUBELET_CMD" '--tls-cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_KUBELET_CMD" '--tls-private-key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-cert-file') - kfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-private-key-file') - pass "$check_2_1_12" - pass " * tls-cert-file: $cfile" - pass " * tls-private-key-file: $kfile" - else - warn "$check_2_1_12" - fi -else - warn "$check_2_1_12" -fi - -check_2_1_13="2.1.13 - Ensure that the --cadvisor-port argument is set to 0" -if check_argument "$CIS_KUBELET_CMD" '--cadvisor-port' >/dev/null 2>&1; then - port=$(get_argument_value "$CIS_KUBELET_CMD" '--cadvisor-port' | cut -d " " -f 1) - if [ $port = "0" ]; then - pass "$check_2_1_13" - else - warn "$check_2_1_13" - warn " * cadvisor-port: $port" - fi -else - warn "$check_2_1_13" -fi - -info "2.2 - Configuration Files" - -check_2_2_1="2.2.1 - Ensure that the config file permissions are set to 644 or more restrictive" -if [ -f "/etc/kubernetes/config" ]; then - file="/etc/kubernetes/config" -elif [ -f "/var/lib/kubelet/kubeconfig" ]; then - # kops - file="/var/lib/kubelet/kubeconfig" -else - file="/etc/kubernetes/kubelet.conf" -fi - -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_2_2_1" - else - warn "$check_2_2_1" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_1" - info " * File not found" -fi - -check_2_2_2="2.2.2 - Ensure that the config file ownership is set to root:root" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_2" - else - warn "$check_2_2_2" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_2" -fi - -check_2_2_3="2.2.3 - Ensure that the kubelet file permissions are set to 644 or more restrictive" -if [ -f "/etc/kubernetes/kubelet" ]; then - file="/etc/kubernetes/kubelet" -elif [ -f "/etc/sysconfig/kubelet" ]; then - # kops - file="/etc/sysconfig/kubelet" -else - file="/etc/kubernetes/kubelet.conf" -fi - -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_2_2_3" - else - warn "$check_2_2_3" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_3" - info " * File not found" -fi - -check_2_2_4="2.2.4 - Ensure that the kubelet file ownership is set to root:root" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_4" - else - warn "$check_2_2_4" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_4" -fi - -check_2_2_5="2.2.5 - Ensure that the proxy file permissions are set to 644 or more restrictive" -if [ -f "/var/lib/kube-proxy/kubeconfig" ]; then - # kops - file="/var/lib/kube-proxy/kubeconfig" -else - file="/etc/kubernetes/proxy" -fi - -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_2_2_5" - else - warn "$check_2_2_5" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_5" - info " * File not found" -fi - -check_2_2_6="2.2.6 - Ensure that the proxy file ownership is set to root:root" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_6" - else - warn "$check_2_2_6" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_6" -fi - -check_2_2_7="2.2.7 - Ensure that the certificate authorities file permissions are set to 644 or more restrictive" -if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then - file=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_2_2_7" - pass " * client-ca-file: $file" - else - warn "$check_2_2_7" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_7" - info " * --client-ca-file not set" -fi - -check_2_2_8="2.2.8 - Ensure that the client certificate authorities file ownership is set to root:root" -if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then - file=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_8" - pass " * client-ca-file: $file" - else - warn "$check_2_2_8" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_8" - info " * --client-ca-file not set" -fi -exit 0; diff --git a/scripts/kubeBench/kube_worker_1_4_1.tmpl b/scripts/kubeBench/kube_worker_1_4_1.tmpl deleted file mode 100644 index acfedad..0000000 --- a/scripts/kubeBench/kube_worker_1_4_1.tmpl +++ /dev/null @@ -1,436 +0,0 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -notScored="1.1.1, 1.1.12, 1.1.13, 1.1.31, 1.4.9, 1.4.10, 1.5.7, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.6.5, 1.6.6, 1.6.7, 1.6.8, -1.7.1, 1.7.6, 1.7.7, 2.1.11, 2.1.14" -level2="1.3.6, 1.5.7, 1.6.1, 1.6.4, 1.6.5, 1.6.6, 1.6.7, 1.6.8, - 1.7.6, 1.7.7" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_KUBELET_CMD="<<<.Replace_kubelet_cmd>>>" -CIS_PROXY_CMD="<<<.Replace_proxy_cmd>>>" - -if ps -ef | grep "$CIS_KUBELET_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Worker Node Security Configuration" -else - info "This node is not a Kubernetes worker node" - exit 2 -fi - -info "2.1 - Kubelet" - -check_2_1_1="2.1.1 - Ensure that the --anonymous-auth argument is set to false (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--anonymous-auth=false' >/dev/null 2>&1; then - pass "$check_2_1_1" -else - warn "$check_2_1_1" -fi - -check_2_1_2="2.1.2 - Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--authorization-mode=AlwaysAllow' >/dev/null 2>&1; then - warn "$check_2_1_2" -else - pass "$check_2_1_2" -fi - -check_2_1_3="2.1.3 - Ensure that the --client-ca-file argument is set as appropriate (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then - cafile=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') - pass "$check_2_1_3" - pass " * client-ca-file: $cafile" -else - warn "$check_2_1_3" -fi - -check_2_1_4="2.1.4 - Ensure that the --read-only-port argument is set to 0 (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--read-only-port' >/dev/null 2>&1; then - port=$(get_argument_value "$CIS_KUBELET_CMD" '--read-only-port' | cut -d " " -f 1) - if [ $port = "0" ]; then - pass "$check_2_1_4" - else - warn "$check_2_1_4" - warn " * read-only-port: $port" - fi -else - warn "$check_2_1_4" -fi - -check_2_1_5="2.1.5 - Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--streaming-connection-idle-timeout=0' >/dev/null 2>&1; then - timeout=$(get_argument_value "$CIS_KUBELET_CMD" '--streaming-connection-idle-timeout') - warn "$check_2_1_5" - warn " * streaming-connection-idle-timeout: $timeout" -else - pass "$check_2_1_5" -fi - -check_2_1_6="2.1.6 - Ensure that the --protect-kernel-defaults argument is set to true (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--protect-kernel-defaults=true' >/dev/null 2>&1; then - pass "$check_2_1_6" -else - warn "$check_2_1_6" -fi - -check_2_1_7="2.1.7 - Ensure that the --make-iptables-util-chains argument is set to true (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--make-iptables-util-chains=true' >/dev/null 2>&1; then - pass "$check_2_1_7" -else - warn "$check_2_1_7" -fi - -check_2_1_8="2.1.8 - Ensure that the --hostname-override argument is not set (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--hostname-override' >/dev/null 2>&1; then - warn "$check_2_1_8" -else - pass "$check_2_1_8" -fi - -check_2_1_9="2.1.9 - Ensure that the --event-qps argument is set to 0 (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--event-qps' >/dev/null 2>&1; then - event=$(get_argument_value "$CIS_KUBELET_CMD" '--event-qps' | cut -d " " -f 1) - if [ $event = "0" ]; then - pass "$check_2_1_9" - else - warn "$check_2_1_9" - warn " * event-qps: $event" - fi -else - warn "$check_2_1_9" -fi - -check_2_1_10="2.1.10 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--tls-cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_KUBELET_CMD" '--tls-private-key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-cert-file') - kfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-private-key-file') - pass "$check_2_1_10" - pass " * tls-cert-file: $cfile" - pass " * tls-private-key-file: $kfile" - else - warn "$check_2_1_10" - fi -else - warn "$check_2_1_10" -fi - -check_2_1_11="2.1.11 - [DEPRECATED] Ensure that the --cadvisor-port argument is set to 0 (Not Scored)" -pass "$check_2_1_11" - -check_2_1_12="2.1.12 - Ensure that the --rotate-certificates argument is not set to false (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--rotate-certificates=true' >/dev/null 2>&1; then - pass "$check_2_1_12" -else - warn "$check_2_1_12" -fi - -check_2_1_13="2.1.13 - Ensure that the RotateKubeletServerCertificate argument is set to true (Scored)" -file="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" -found=$(sed -rn '/--feature-gates=RotateKubeletServerCertificate=true/p' $file) -if [ -z "$found" ]; then - warn "$check_2_1_13" -else - pass "$check_2_1_13" -fi - -check_2_1_14="2.1.14 - Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Not Scored)" -if check_argument "$CIS_KUBELET_CMD" '--tls-cipher-suites' >/dev/null 2>&1; then - ciphers=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-cipher-suites'|cut -d " " -f 1) - found=$(echo $ciphers| sed -rn '/(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)/p') - if [ ! -z "$found" ]; then - pass "$check_2_1_14" - else - warn "$check_2_1_14" - fi -else - warn "$check_2_1_14" -fi -info "2.2 - Configuration Files" - -check_2_2_1="2.2.1 - Ensure that the kubelet service file permissions are set to 644 or more restrictive (Scored)" -file="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" - -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_2_2_1" - else - warn "$check_2_2_1" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_1" - info " * File not found" -fi - -check_2_2_2="2.2.2 - Ensure that the kubelet.conf file permissions are set to 644 or more restrictive (Scored)" -file="/etc/kubernetes/kubelet.conf" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_2_2_2" - else - warn "$check_2_2_2" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_2" - info " * File not found" -fi - - -check_2_2_3="2.2.3 - Ensure that the kubelet.conf file ownership is set to root:root (Scored)" -file="/etc/kubernetes/kubelet.conf" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_3" - else - warn "$check_2_2_3" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_3" -fi - -check_2_2_4="2.2.4 - Ensure that the kubelet service file ownership is set to root:root (Scored)" -file="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_4" - else - warn "$check_2_2_4" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_4" -fi - -check_2_2_5="2.2.5 - Ensure that the proxy kubeconfig file permissions are set to 644 or more restrictive (Scored)" -file="" -if check_argument "$CIS_PROXY_CMD" '--kubeconfig' >/dev/null 2>&1; then - file=$(get_argument_value "$CIS_PROXY_CMD" '--kubeconfig'|cut -d " " -f 1) -fi - -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_2_2_5" - else - warn "$check_2_2_5" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_5" - info " * --kubeconfig not set" -fi - -check_2_2_6="2.2.6 - Ensure that the proxy kubeconfig file ownership is set to root:root (Scored)" -file="" -if check_argument "$CIS_PROXY_CMD" '--kubeconfig' >/dev/null 2>&1; then - file=$(get_argument_value "$CIS_PROXY_CMD" '--kubeconfig'|cut -d " " -f 1) -fi -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_6" - else - warn "$check_2_2_6" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_6" - info " * --kubeconfig not set" -fi - -check_2_2_7="2.2.7 - Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then - file=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_2_2_7" - pass " * client-ca-file: $file" - else - warn "$check_2_2_7" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_7" - info " * --client-ca-file not set" -fi - -check_2_2_8="2.2.8 - Ensure that the client certificate authorities file ownership is set to root:root (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then - file=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_8" - pass " * client-ca-file: $file" - else - warn "$check_2_2_8" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_8" - info " * --client-ca-file not set" -fi - -check_2_2_9="2.2.9 - Ensure that the kubelet configuration file has permissions set to 644 or more restrictive (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--config' >/dev/null 2>&1; then - file=$(get_argument_value "$CIS_KUBELET_CMD" '--config') - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_2_2_9" - pass " * config: $file" - else - warn "$check_2_2_9" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_9" - info " * --config not set" -fi - -check_2_2_10="2.2.10 - Ensure that the kubelet configuration file ownership is set to root:root (Scored)" -if check_argument "$CIS_KUBELET_CMD" '--config' >/dev/null 2>&1; then - file=$(get_argument_value "$CIS_KUBELET_CMD" '--config') - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_10" - pass " * client: $file" - else - warn "$check_2_2_10" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_10" - info " * --config not set" -fi -exit 0; diff --git a/scripts/kubeBench/kube_worker_ocp_4_3.tmpl b/scripts/kubeBench/kube_worker_ocp_4_3.tmpl deleted file mode 100644 index ca77772..0000000 --- a/scripts/kubeBench/kube_worker_ocp_4_3.tmpl +++ /dev/null @@ -1,383 +0,0 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.6, 5.2.9, 5.3.2, 5.4.2, 5.5.1, 5.6.2, 5.6.3, 5.6.4" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -info "4.1 - Worker Node Configuration Files" - -check_4_1_1="4.1.1 - Ensure that the kubelet service file permissions are set to 644 or more restrictive (Scored)" -file="/etc/systemd/system/kubelet.service" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_4_1_1" - else - warn "$check_4_1_1" - warn " * Wrong permissions for $file" - fi -else - info "$check_4_1_1" - info " * The kubelet service file not found" -fi - -check_4_1_2="4.1.2 - Ensure that the kubelet service file ownership is set to root:root (Scored)" -file="/etc/systemd/system/kubelet.service" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_4_1_2" - else - warn "$check_4_1_2" - warn " * Wrong ownership for $file" - fi -else - info "$check_4_1_2" -fi - -#todo review -#check_4_1_3="4.1.3 - Ensure that the proxy kubeconfig file permissions are set to 644 or more restrictive (Scored)" -#check_4_1_4="4.1.4 - Ensure that the proxy kubeconfig file ownership is set to root:root (Scored)" - -check_4_1_5="4.1.5 - Ensure that the kubelet.conf file permissions are set to 644 or more restrictive (Scored)" -file="/etc/kubernetes/kubelet.conf" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_4_1_5" - else - warn "$check_4_1_5" - warn " * Wrong permissions for $file" - fi -else - info "$check_4_1_5" - info " * File not found" -fi - -check_4_1_6="4.1.6 - Ensure that the kubelet.conf file ownership is set to root:root (Scored)" -file="/etc/kubernetes/kubelet.conf" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_4_1_6" - else - warn "$check_4_1_6" - warn " * Wrong ownership for $file" - fi -else - info "$check_4_1_6" -fi - -check_4_1_7="4.1.7 - Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Scored)" -file="/etc/kubernetes/kubelet-ca.crt" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_4_1_7" - else - warn "$check_4_1_7" - warn " * Wrong permissions for $file" - fi -else - info "$check_4_1_7" - info " * File not found" -fi - -check_4_1_8="4.1.8 - Ensure that the client certificate authorities file ownership is set to root:root (Scored)" -file="/etc/kubernetes/kubelet-ca.crt" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_4_1_8" - else - warn "$check_4_1_8" - warn " * Wrong ownership for $file" - fi -else - info "$check_4_1_8" -fi - -check_4_1_9="4.1.9 - Ensure that the kubelet configuration file has permissions set to 644 or more restrictive (Scored)" -file="/var/lib/kubelet/kubeconfig" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_4_1_9" - else - warn "$check_4_1_9" - warn " * Wrong permissions for $file" - fi -else - info "$check_4_1_9" - info " * File not found" -fi - -check_4_1_10="4.1.10 - Ensure that the kubelet configuration file ownership is set to root:root (Scored)" -file="/var/lib/kubelet/kubeconfig" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_4_1_10" - else - warn "$check_4_1_10" - warn " * Wrong ownership for $file" - fi -else - info "$check_4_1_10" -fi - -info "4.2 - Kubelet" - -#todo review all audits -check_4_2_1="4.2.1 - Ensure that the anonymous-auth argument is set to false (Scored)" -file="/etc/kubernetes/kubelet.conf" -output_ca=$(grep '\(clientCAFile: /etc/kubernetes/kubelet-ca.crt\)' $file) -output_auth=$(grep '\(enabled: false\)' $file) -if [ -z "$output_ca" ] || [ -z "$output_auth" ] ; then - warn "$check_4_2_1" -else - pass "$check_4_2_1" -fi - -check_4_2_2="4.2.2 - Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(authorization-mode\)' $file) -if [ -z "$output" ]; then - pass "$check_4_2_2" -else - warn "$check_4_2_2" -fi - -check_4_2_3="4.2.3 - Ensure that the --client-ca-file argument is set as appropriate (Scored)" -file="/etc/kubernetes/kubelet.conf" -output_ca=$(grep '\(clientCAFile: /etc/kubernetes/kubelet-ca.crt\)' $file) -if [ -z "$output_ca" ]; then - warn "$check_4_2_3" -else - pass "$check_4_2_3" -fi - -#todo review (ocp by default setting) -check_4_2_4="4.2.4 - Ensure that the --read-only-port argument is set to 0 (Scored)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(read-only-port\)' $file) -if [ -z "$output" ]; then - pass "$check_4_2_4" -else - warn "$check_4_2_4" -fi - -check_4_2_5="4.2.5 - Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Scored)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(streaming-connection-idle-timeout\)' $file) -if [ -z "$output" ]; then - pass "$check_4_2_5" -else - warn "$check_4_2_5" -fi - -check_4_2_7="4.2.7 - Ensure that the --make-iptables-util-chains argument is set to true (Scored)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(make-iptables-util-chains\)' $file) -if [ -z "$output" ]; then - pass "$check_4_2_7" -else - warn "$check_4_2_7" -fi - -check_4_2_9="4.2.9 - Ensure that the --event-qps argument is set to 0 or a level which ensures appropriate event capture (Not Scored)" -info "$check_4_2_9" - -check_4_2_10="4.2.10 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)" -file="/etc/kubernetes/kubelet.conf" -output_cert=$(grep '\(tls-cert-file\)' $file) -output_key=$(grep '\(tls-private-key-file\)' $file) -if [ -z "$output_cert" ] && [ -z "$output_key" ]; then - pass "$check_4_2_10" -else - warn "$check_4_2_10" -fi -#if check_argument "$CIS_KUBELET_CMD" '--tls-cert-file' >/dev/null 2>&1; then -# if check_argument "$CIS_KUBELET_CMD" '--tls-private-key-file' >/dev/null 2>&1; then -# cfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-cert-file') -# kfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-private-key-file') -# pass "$check_4_2_10" -# pass " * tls-cert-file: $cfile" -# pass " * tls-private-key-file: $kfile" -# else -# warn "$check_4_2_10" -# fi -#else -# warn "$check_4_2_10" -#fi - -check_4_2_11="4.2.11 - Ensure that the RotateKubeletClientCertificate argument is not set to false (Scored)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(RotateKubeletClientCertificate\)' $file) -if [ -z "$output" ]; then - pass "$check_4_2_11" -else - warn "$check_4_2_11" -fi -#if check_argument "$CIS_KUBELET_CMD" '--event-qps' >/dev/null 2>&1; then -# event=$(get_argument_value "$CIS_KUBELET_CMD" '--event-qps' | cut -d " " -f 1) -# if [ $event = "0" ]; then -# pass "$check_4_2_11" -# else -# warn "$check_4_2_11" -# warn " * event-qps: $event" -# fi -#else -# warn "$check_4_2_11" -#fi - -check_4_2_12="4.2.12 - Ensure that the RotateKubeletServerCertificate argument is set to true (Scored)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(RotateKubeletServerCertificate: true\)' $file) -if [ -z "$output" ]; then - warn "$check_4_2_12" -else - pass "$check_4_2_12" -fi - diff --git a/scripts/kubeBench/kube_worker_ocp_4_5.tmpl b/scripts/kubeBench/kube_worker_ocp_4_5.tmpl deleted file mode 100644 index 90e5f3e..0000000 --- a/scripts/kubeBench/kube_worker_ocp_4_5.tmpl +++ /dev/null @@ -1,415 +0,0 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.6, 5.2.9, 5.3.2, 5.4.2, 5.5.1, 5.6.2, 5.6.3, 5.6.4" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - elif echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -info "4.1 - Worker Node Configuration Files" - -check_4_1_1="4.1.1 - Ensure that the kubelet service file permissions are set to 644 or more restrictive (Automated)" -file="/etc/systemd/system/kubelet.service" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_4_1_1" - else - warn "$check_4_1_1" - warn " * Wrong permissions for $file" - fi -else - info "$check_4_1_1" - info " * The kubelet service file not found" -fi - -check_4_1_2="4.1.2 - Ensure that the kubelet service file ownership is set to root:root (Automated)" -file="/etc/systemd/system/kubelet.service" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_4_1_2" - else - warn "$check_4_1_2" - warn " * Wrong ownership for $file" - fi -else - info "$check_4_1_2" -fi - -#todo review with Andson (/config/kube-proxy-config.yaml find / -name "kube-proxy-config.yaml") -check_4_1_3="4.1.3 - If proxy kubeconfig file exists ensure permissions are set to 644 or more restrictive (Manual)" -info "$check_4_1_3" - -check_4_1_4="4.1.4 - If proxy kubeconfig file exists ensure ownership is set to root:root (Manual)" -info "$check_4_1_4" - -check_4_1_5="4.1.5 - Ensure that the kubelet.conf file permissions are set to 644 or more restrictive (Manual)" -file="/etc/kubernetes/kubelet.conf" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_4_1_5" - else - warn "$check_4_1_5" - warn " * Wrong permissions for $file" - fi -else - info "$check_4_1_5" - info " * File not found" -fi - -check_4_1_6="4.1.6 - Ensure that the --kubeconfig kubelet.conf file ownership is set to root:root (Manual)" -file="/etc/kubernetes/kubelet.conf" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_4_1_6" - else - warn "$check_4_1_6" - warn " * Wrong ownership for $file" - fi -else - info "$check_4_1_6" -fi - -check_4_1_7="4.1.7 - Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Automated)" -file="/etc/kubernetes/kubelet-ca.crt" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then - pass "$check_4_1_7" - else - warn "$check_4_1_7" - warn " * Wrong permissions for $file" - fi -else - info "$check_4_1_7" - info " * File not found" -fi - -check_4_1_8="4.1.8 - Ensure that the client certificate authorities file ownership is set to root:root (Automated)" -file="/etc/kubernetes/kubelet-ca.crt" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_4_1_8" - else - warn "$check_4_1_8" - warn " * Wrong ownership for $file" - fi -else - info "$check_4_1_8" -fi - -check_4_1_9="4.1.9 - Ensure that the kubelet --config configuration file has permissions set to 644 or more restrictive (Automated)" -file="/var/lib/kubelet/kubeconfig" -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_4_1_9" - else - warn "$check_4_1_9" - warn " * Wrong permissions for $file" - fi -else - info "$check_4_1_9" - info " * File not found" -fi - -check_4_1_10="4.1.10 - Ensure that the kubelet configuration file ownership is set to root:root (Automated)" -file="/var/lib/kubelet/kubeconfig" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_4_1_10" - else - warn "$check_4_1_10" - warn " * Wrong ownership for $file" - fi -else - info "$check_4_1_10" -fi - -info "4.2 - Kubelet" - -#todo review all audits -check_4_2_1="4.2.1 - Ensure that the anonymous-auth argument is set to false (Automated)" -file="/etc/kubernetes/kubelet.conf" -output_ca=$(grep '\(clientCAFile: /etc/kubernetes/kubelet-ca.crt\)' $file) -output_auth=$(grep '\(enabled: false\)' $file) -if [ -z "$output_ca" ] || [ -z "$output_auth" ] ; then - warn "$check_4_2_1" -else - pass "$check_4_2_1" -fi - -check_4_2_2="4.2.2 - Ensure that the --authorization-mode argument is not set to AlwaysAllow (Automated)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(authorization-mode\)' $file) -if [ -z "$output" ]; then - pass "$check_4_2_2" -else - warn "$check_4_2_2" -fi - -check_4_2_3="4.2.3 - Ensure that the --client-ca-file argument is set as appropriate (Automated)" -file="/etc/kubernetes/kubelet.conf" -output_ca=$(grep '\(clientCAFile: /etc/kubernetes/kubelet-ca.crt\)' $file) -if [ -z "$output_ca" ]; then - warn "$check_4_2_3" -else - pass "$check_4_2_3" -fi - -#todo review (ocp by default setting) -check_4_2_4="4.2.4 - Verify that the read only port is not used or is set to 0 (Automated)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(read-only-port\)' $file) -if [ -z "$output" ]; then - pass "$check_4_2_4" -else - warn "$check_4_2_4" -fi - -check_4_2_5="4.2.5 - Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Automated)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(streaming-connection-idle-timeout\)' $file) -if [ -z "$output" ]; then - pass "$check_4_2_5" -else - warn "$check_4_2_5" -fi - -check_4_2_6="4.2.6 - Ensure that the --protect-kernel-defaults argument is not set (Manual)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(protectKernelDefaults\)' $file) -if [ -z "$output" ]; then - pass "$check_4_2_5" -else - warn "$check_4_2_5" -fi - -check_4_2_7="4.2.7 - Ensure that the --make-iptables-util-chains argument is set to true (Manual)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(make-iptables-util-chains\)' $file) -if [ -z "$output" ]; then - pass "$check_4_2_7" -else - warn "$check_4_2_7" -fi - -check_4_2_8="4.2.8 - Ensure that the --hostname-override argument is not set (Manual)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(hostname-override\)' $file) -if [ -z "$output" ]; then - pass "$check_4_2_7" -else - warn "$check_4_2_7" -fi - -check_4_2_9="4.2.9 - Ensure that the kubeAPIQPS [--event-qps] argument is set to 0 or a level which ensures appropriate event capture (Automated)" -file="/etc/kubernetes/kubelet.conf" -output=$(grep '\(kubeAPIQPS: 50\)' $file) -if [ -z "$output" ]; then - warn "$check_4_2_9" -else - pass "$check_4_2_9" -fi - -check_4_2_10="4.2.10 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Automated)" -file="/etc/kubernetes/kubelet.conf" -output_cert=$(grep '\(tls-cert-file\)' $file) -output_key=$(grep '\(tls-private-key-file\)' $file) -if [ -z "$output_cert" ] && [ -z "$output_key" ]; then - pass "$check_4_2_10" -else - warn "$check_4_2_10" -fi -#if check_argument "$CIS_KUBELET_CMD" '--tls-cert-file' >/dev/null 2>&1; then -# if check_argument "$CIS_KUBELET_CMD" '--tls-private-key-file' >/dev/null 2>&1; then -# cfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-cert-file') -# kfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-private-key-file') -# pass "$check_4_2_10" -# pass " * tls-cert-file: $cfile" -# pass " * tls-private-key-file: $kfile" -# else -# warn "$check_4_2_10" -# fi -#else -# warn "$check_4_2_10" -#fi - -check_4_2_11="4.2.11 - Ensure that the --rotate-certificates argument is not set to false (Manual)" -file="/etc/kubernetes/kubelet.conf" -output1=$(grep '\(rotateKubeletClientCertificates: false\)' $file) -output2=$(grep '\(rotateCertificates: true\)' $file) -if [ -z "$output1"] && [ -n "$output2" ]; then - pass "$check_4_2_11" -else - warn "$check_4_2_11" -fi -#if check_argument "$CIS_KUBELET_CMD" '--event-qps' >/dev/null 2>&1; then -# event=$(get_argument_value "$CIS_KUBELET_CMD" '--event-qps' | cut -d " " -f 1) -# if [ $event = "0" ]; then -# pass "$check_4_2_11" -# else -# warn "$check_4_2_11" -# warn " * event-qps: $event" -# fi -#else -# warn "$check_4_2_11" -#fi - -check_4_2_12="4.2.12 - Verify that the RotateKubeletServerCertificate argument is set to true (Manual)" -file="/etc/kubernetes/kubelet.conf" -output1=$(grep '\(RotateKubeletServerCertificate: true\)' $file) -output2=$(grep '\(rotateCertificates: true\)' $file) -if [ -n "$output1" ] && [ -n "$output2" ] ; then - pass "$check_4_2_12" -else - warn "$check_4_2_12" -fi - -check_4_2_13="4.2.13 - Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Manual)" -info "$check_4_2_13" -info "TLS ciphers have had a number of known vulnerabilities and weaknesses, which can reduce the protection provided by them. By default Kubernetes supports a number of TLS ciphersuites including some that have security concerns, weakening the protection provided." diff --git a/scripts/kubeBench/kubecis_1_0_0.rem b/scripts/kubeBench/kubecis_1_0_0.rem deleted file mode 100644 index 34d0baf..0000000 --- a/scripts/kubeBench/kubecis_1_0_0.rem +++ /dev/null @@ -1,106 +0,0 @@ -1.1.1 : Edit the /etc/kubernetes/config file on the master node and set the KUBE_ALLOW_PRIV parameter to "--allow-privileged=false" : KUBE_ALLOW_PRIV="--allow-privileged=false" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.2 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to "--anonymous-auth=false" : KUBE_API_ARGS="--anonymous-auth=false" Based on your system, restart the kube-apiserver service. For example, systemctl restart kube-apiserver.service -1.1.3 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the /etc/kubernetes/apiserver file on the master node and remove the "--basic- auth-file=" argument from the KUBE_API_ARGS parameter. Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.4 : Edit the /etc/kubernetes/apiserver file on the master node and remove the --insecure- allow-any-token argument from the KUBE_API_ARGS parameter. Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.5 : Edit the /etc/kubernetes/apiserver file on the master node and remove the --kubelet- https argument from the KUBE_API_ARGS parameter. Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.6 : Edit the /etc/kubernetes/apiserver file on the master node and remove the --insecure- bind-address argument from the KUBE_API_ADDRESS parameter. Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.7 : Edit the /etc/kubernetes/apiserver file on the master node and set --insecure-port=0 in the KUBE_API_PORT parameter. Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.8 : Edit the /etc/kubernetes/apiserver file on the master node and either remove the -- secure-port argument from the KUBE_API_ARGS parameter or set it to a different desired port. Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.9 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to "--profiling=false" : KUBE_API_ARGS="--profiling=false" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.10 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to "--repair-malformed-updates=false" : KUBE_API_ARGS="--repair-malformed-updates=false" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.11 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_ADMISSION_CONTROL parameter to a value that does not include AlwaysAdmit . Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.12 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_ADMISSION_CONTROL parameter to "--admission- control=...,AlwaysPullImages,..." : KUBE_ADMISSION_CONTROL="--admission-control=...,AlwaysPullImages,..." Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.13 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_ADMISSION_CONTROL parameter to "--admission- control=...,DenyEscalatingExec,..." : KUBE_ADMISSION_CONTROL="--admission-control=...,DenyEscalatingExec,..." Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.14 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_ADMISSION_CONTROL parameter to "--admission- control=...,SecurityContextDeny,..." : KUBE_ADMISSION_CONTROL="--admission-control=...,SecurityContextDeny,..." Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.15 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_ADMISSION_CONTROL parameter to "--admission- control=NamespaceLifecycle,..." : KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,..." Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.16 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to "--audit-log-path=" : KUBE_API_ARGS="--audit-log-path=/var/log/apiserver/audit.log" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.17 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to "--audit-log-maxage=30" : KUBE_API_ARGS="--audit-log-maxage=30" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.18 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to "--audit-log-maxbackup=10" : KUBE_API_ARGS="--audit-log-maxbackup=10" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.19 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to "--audit-log-maxsize=100" : KUBE_API_ARGS="--audit-log-maxsize=100" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.20 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to values other than --authorization-mode=AlwaysAllow . One such example could be as below: KUBE_API_ARGS="--authorization-mode=RBAC" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.21 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the /etc/kubernetes/apiserver file on the master node and remove the "--token- auth-file=" argument from the KUBE_API_ARGS parameter. Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.22 : Follow the Kubernetes documentation and setup the TLS connection between the apiserver and kubelets. Then, edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to "--kubelet-certificate-authority=" : KUBE_API_ARGS="--kubelet-certificate-authority=" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.23 : Follow the Kubernetes documentation and set up the TLS connection between the apiserver and kubelets. Then, edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to "--kubelet-client- certificate=" and "--kubelet-client- key=" : KUBE_API_ARGS="--kubelet-client-certificate= --kubelet-client-key=" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.24 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to "--service-account-lookup=true" : KUBE_API_ARGS="--service-account-lookup=true" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.25 : Follow the documentation and create Pod Security Policy objects as per your environment. Then, edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_ADMISSION_CONTROL parameter to "--admission- control=...,PodSecurityPolicy,..." : KUBE_ADMISSION_CONTROL="--admission-control=...,PodSecurityPolicy,..." Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.26 : Edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to "--service-account-key-file=" : KUBE_API_ARGS="--service-account-key-file=" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.27 : Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to include "--etcd-certfile=" and "--etcd-keyfile=" : KUBE_API_ARGS="... --etcd-certfile= --etcd- keyfile= ..." Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.28 : Follow the documentation and create ServiceAccount objects as per your environment. Then, edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_ADMISSION_CONTROL parameter to "--admission- control=...,ServiceAccount,..." : KUBE_ADMISSION_CONTROL="--admission-control=...,ServiceAccount,..." Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.29 : Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to include "--tls-cert-file=" and "--tls-private-key-file=" : KUBE_API_ARGS="--tls-cert-file= --tls-private- key-file=" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.30 : Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to include "--client-ca-file=" : KUBE_API_ARGS="--client-ca-file=" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.1.31 : Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the /etc/kubernetes/apiserver file on the master node and set the KUBE_API_ARGS parameter to include "--etcd-cafile=" : KUBE_API_ARGS="--etcd-cafile=" Based on your system, restart the kube-apiserver service. For example: systemctl restart kube-apiserver.service -1.2.1 : Edit the /etc/kubernetes/scheduler file on the master node and set the KUBE_SCHEDULER_ARGS parameter to "--profiling=false" : KUBE_SCHEDULER_ARGS="--profiling=false" Based on your system, restart the kube-scheduler service. For example: systemctl restart kube-scheduler.service -1.3.1 : Edit the /etc/kubernetes/controller-manager file on the master node and set the KUBE_CONTROLLER_MANAGER_ARGS parameter to "--terminated-pod-gc- threshold=" : KUBE_CONTROLLER_MANAGER_ARGS="--terminated-pod-gc-threshold=10" Based on your system, restart the kube-controller-manager service. For example: systemctl restart kube-controller-manager.service -1.3.2 : Edit the /etc/kubernetes/controller-manager file on the master node and set the KUBE_CONTROLLER_MANAGER_ARGS parameter to "--profiling=false" : KUBE_CONTROLLER_MANAGER_ARGS="--profiling=false" Based on your system, restart the kube-controller-manager service. For example: systemctl restart kube-controller-manager.service -1.3.3 : Edit the /etc/kubernetes/controller-manager file on the master node and remove the -- insecure-experimental-approve-all-kubelet-csrs-for-group argument from the KUBE_CONTROLLER_MANAGER_ARGS parameter. Based on your system, restart the kube-controller-manager service. For example: systemctl restart kube-controller-manager.service -1.3.4 : Edit the /etc/kubernetes/controller-manager file on the master node and set the KUBE_CONTROLLER_MANAGER_ARGS parameter to --use-service-account- credentials=true : KUBE_CONTROLLER_MANAGER_ARGS="--use-service-account-credentials=true" Based on your system, restart the kube-controller-manager service. For example: systemctl restart kube-controller-manager.service -1.3.5 : Edit the /etc/kubernetes/controller-manager file on the master node and set the KUBE_CONTROLLER_MANAGER_ARGS parameter to --service-account-private-key- file= : KUBE_CONTROLLER_MANAGER_ARGS="--service-account-private-key-file=" Based on your system, restart the kube-controller-manager service. For example: systemctl restart kube-controller-manager.service -1.3.6 : Edit the /etc/kubernetes/controller-manager file on the master node and set the KUBE_CONTROLLER_MANAGER_ARGS parameter to include --root-ca-file= : KUBE_CONTROLLER_MANAGER_ARGS="--root-ca-file=" Based on your system, restart the kube-controller-manager service. For example: systemctl restart kube-controller-manager.service -1.4.1 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/apiserver -1.4.2 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/apiserver -1.4.3 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/config -1.4.4 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/config -1.4.5 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/scheduler -1.4.6 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/scheduler -1.4.7 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/etcd/etcd.conf -1.4.8 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/etcd/etcd.conf -1.4.9 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/sysconfig/flanneld -1.4.10 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/sysconfig/flanneld -1.4.11 : 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/default.etcd -1.4.12 : 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/default.etcd -1.5.1 : Follow the etcd service documentation and configure TLS encryption. -1.5.2 : Edit the etcd envrironment file (for example, /etc/etcd/etcd.conf ) on the etcd server node and set the ETCD_CLIENT_CERT_AUTH parameter to "true" : ETCD_CLIENT_CERT_AUTH="true" Edit the etcd startup file (for example, /etc/systemd/system/multi- user.target.wants/etcd.service ) and configure the startup parameter for --client- cert-auth and set it to \"${ETCD_CLIENT_CERT_AUTH}\" : ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd -- name=\"${ETCD_NAME}\" --data-dir=\"${ETCD_DATA_DIR}\" --listen-client- urls=\"${ETCD_LISTEN_CLIENT_URLS}\" --client-cert- auth=\"${ETCD_CLIENT_CERT_AUTH}\"" Based on your system, reload the daemon and restart the etcd service. For example, systemctl daemon-reload systemctl restart etcd.service -1.5.3 : Edit the etcd environment file (for example, /etc/etcd/etcd.conf ) on the etcd server node and comment out the ETCD_AUTO_TLS parameter. #ETCD_AUTO_TLS="true" Edit the etcd startup file (for example, /etc/systemd/system/multi- user.target.wants/etcd.service ) and remove the startup parameter for --auto-tls . Based on your system, reload the daemon and restart the etcd service. For example, systemctl daemon-reload systemctl restart etcd.service -1.5.4 : Follow the etcd service documentation and configure peer TLS encryption as appropriate for your etcd cluster. -1.5.5 : Edit the etcd environment file (for example, /etc/etcd/etcd.conf ) on the etcd server node and set the ETCD_PEER_CLIENT_CERT_AUTH parameter to "true" : ETCD_PEER_CLIENT_CERT_AUTH="true" Edit the etcd startup file (for example, /etc/systemd/system/multi- user.target.wants/etcd.service ) and configure the startup parameter for --peer- client-cert-auth and set it to \"${ETCD_PEER_CLIENT_CERT_AUTH}\" : ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd -- name=\"${ETCD_NAME}\" --data-dir=\"${ETCD_DATA_DIR}\" --listen-client- urls=\"${ETCD_LISTEN_CLIENT_URLS}\" --peer-client-cert- auth=\"${ETCD_PEER_CLIENT_CERT_AUTH}\"" Based on your system, reload the daemon and restart the etcd service. For example, systemctl daemon-reload systemctl restart etcd.service -1.5.6 : Edit the etcd environment file (for example, /etc/etcd/etcd.conf ) on the etcd server node and comment out the ETCD_PEER_AUTO_TLS parameter: #ETCD_PEER_AUTO_TLS="true" Edit the etcd startup file (for example, /etc/systemd/system/multi- user.target.wants/etcd.service ) and remove the startup parameter for --peer-auto- tls . Based on your system, reload the daemon and restart the etcd service. For example, systemctl daemon-reload systemctl restart etcd.service -1.5.7 : Edit the etcd environment file (for example, /etc/etcd/etcd.conf ) on the etcd server node and set the ETCD_WAL_DIR parameter as appropriate: ETCD_WAL_DIR="" Edit the etcd startup file (for example, /etc/systemd/system/multi- user.target.wants/etcd.service ) and configure the startup parameter for --wal-dir and set it to \"${ETCD_WAL_DIR}\" : ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd -- name=\"${ETCD_NAME}\" --data-dir=\"${ETCD_DATA_DIR}\" --listen-client- urls=\"${ETCD_LISTEN_CLIENT_URLS}\" --wal-dir=\"${ETCD_WAL_DIR}\"" Based on your system, reload the daemon and restart the etcd service. For example, systemctl daemon-reload systemctl restart etcd.service -1.5.8 : Edit the etcd environment file (for example, /etc/etcd/etcd.conf ) on the etcd server node and set the ETCD_MAX_WALS parameter to 0 : ETCD_MAX_WALS="0" Edit the etcd startup file (for example, /etc/systemd/system/multi- user.target.wants/etcd.service ) and configure the startup parameter for --max-wals and set it to \"${ETCD_MAX_WALS}\" : ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd -- name=\"${ETCD_NAME}\" --data-dir=\"${ETCD_DATA_DIR}\" --listen-client- urls=\"${ETCD_LISTEN_CLIENT_URLS}\" --max-walsr=\"${ETCD_MAX_WALS}\"" Based on your system, reload the daemon and restart the etcd service. For example, systemctl daemon-reload systemctl restart etcd.service -1.5.9 : Follow the etcd documentation and create a dedicated certificate authority setup for the etcd service. -1.6.1 : Remove any unneeded clusterrolebindings : 130 | P a g ekubectl delete clusterrolebinding [name] -1.6.2 : Follow the documentation and create and enforce Pod Security Policies for your cluster. Additionally, you could refer the "CIS Security Benchmark for Docker" and follow the suggested Pod Security Policies for your environment. -1.6.3 : Follow the documentation and create namespaces for objects in your deployment as you need them. -1.6.4 : Follow the documentation and create NetworkPolicy objects as you need them. -1.6.5 : Use other mechanisms such as vaults to manage your cluster secrets. -1.6.6 : 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: 140 | P a g ename: trustworthy-pod annotations: seccomp.security.alpha.kubernetes.io/pod: docker/default spec: containers: - name: trustworthy-container image: sotrustworthy:latest -1.6.7 : 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. -1.6.8 : Follow the Kubernetes documentation and setup image provenance. -2.1.1 : Edit the /etc/kubernetes/config file on each node and set the KUBE_ALLOW_PRIV parameter to "--allow-privileged=false" : KUBE_ALLOW_PRIV="--allow-privileged=false" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.2 : Edit the /etc/kubernetes/kubelet file on each node and set the KUBELET_ARGS parameter to "--anonymous-auth=false" : KUBELET_ARGS="--anonymous-auth=false" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.3 : Edit the /etc/kubernetes/kubelet file on each node and set the KUBELET_ARGS parameter to "--authorization-mode=Webhook" : KUBELET_ARGS="--authorization-mode=Webhook" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.4 : Follow the Kubernetes documentation and setup the TLS connection between the apiserver and kubelets. Then, edit the /etc/kubernetes/kubelet file on each node and set the KUBELET_ARGS parameter to "--client-ca-file=" : KUBELET_ARGS="--client-ca-file=" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.5 : Edit the /etc/kubernetes/kubelet file on each node and set the KUBELET_ARGS parameter to "--read-only-port=0" KUBELET_ARGS="--read-only-port=0" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.6 : Edit the /etc/kubernetes/kubelet file on each node and set the KUBELET_ARGS parameter to "--streaming-connection-idle-timeout=" KUBELET_ARGS="--streaming-connection-idle-timeout=5m" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.7 : Edit the /etc/kubernetes/kubelet file on each node and set the KUBELET_ARGS parameter to "--protect-kernel-defaults=true" KUBELET_ARGS="--protect-kernel-defaults=true" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.8 : Edit the /etc/kubernetes/kubelet file on each node and remove the --make-iptables- util-chains argument from the KUBELET_ARGS parameter. Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.9 : Edit the /etc/kubernetes/kubelet file on each node and set the KUBELET_ARGS parameter to "--keep-terminated-pod-volumes=false" : KUBELET_ARGS="--keep-terminated-pod-volumes=false" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.10 : Edit the /etc/kubernetes/kubelet file on each node and set the KUBELET_HOSTNAME parameter to "" : KUBELET_HOSTNAME="" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.11 : Edit the /etc/kubernetes/kubelet file on each node and set the KUBELET_ARGS parameter to "--event-qps=0" : KUBELET_ARGS="--event-qps=0" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.12 : Follow the Kubernetes documentation and set up the TLS connection on the Kubelet. Then, edit the /etc/kubernetes/kubelet file on the master node and set the KUBELET_ARGS parameter to include "--tls-cert-file=" and "--tls- private-key-file=" : KUBELET_ARGS="--tls-cert-file= --tls-private- key-file=" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.1.13 : Edit the /etc/kubernetes/kubelet file on each node and set the KUBELET_ARGS parameter to "--cadvisor-port=0" : KUBELET_ARGS="--cadvisor-port=0" Based on your system, restart the kubelet service. For example: systemctl restart kubelet.service -2.2.1 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/kubernetes/config -2.2.2 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/kubernetes/config -2.2.3 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/kubernetes/kubelet -2.2.4 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/kubernetes/kubelet -2.2.5 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/kubernetes/proxy -2.2.6 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/kubernetes/proxy -3.1.1 : Edit the deployment specs and set --anonymous-auth=false . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.2 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the deployment specs and remove "--basic-auth-file=" . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.3 : Edit the deployment specs and remove --insecure-allow-any-token . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.4 : Edit the deployment specs and remove --insecure-bind-address . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.5 : Edit the deployment specs and set --insecure-port=0 . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.6 : Edit the deployment specs and set the --secure-port argument to the desired port. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.7 : Edit the deployment specs and set "--profiling=false" : kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.8 : Edit the deployment specs and set --admission-control argument to a value that does not include AlwaysAdmit . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.9 : Edit the deployment specs and set --admission-control argument to a value that includes NamespaceLifecycle . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.10 : Edit the deployment specs and set --audit-log-path argument as appropriate. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.11 : Edit the deployment specs and set --audit-log-maxage to 30 or as appropriate. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.12 : Edit the deployment specs and set --audit-log-maxbackup to 10 or as appropriate. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.13 : Edit the deployment specs and set --audit-log-maxsize=100 to 100 or as appropriate. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.14 : Edit the deployment specs and set --authorization-mode argument to a value other than AlwaysAllow kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.15 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the deployment specs and remove the --token-auth-file= argument. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.16 : Edit the deployment specs and set "--service-account-lookup=true" . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.17 : Edit the deployment specs and set --service-account-key-file argument as appropriate. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.18 : Follow the Kubernetes documentation and set up the TLS connection between the federation apiserver and etcd. Then, edit the deployment specs and set "--etcd- certfile=" and "--etcd- keyfile=" arguments. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.19 : Follow the Kubernetes documentation and set up the TLS connection on the federation apiserver. Then, edit the deployment specs and set "--tls-cert-file=" and "--tls-private-key-file=" : kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.2.1 : Edit the deployment specs and set "--profiling=false" : kubectl edit deployments federation-controller-manager-deployment -- namespace=federation-system diff --git a/scripts/kubeBench/kubecis_1_2_0.rem b/scripts/kubeBench/kubecis_1_2_0.rem deleted file mode 100644 index d2a0e40..0000000 --- a/scripts/kubeBench/kubecis_1_2_0.rem +++ /dev/null @@ -1,123 +0,0 @@ -1.1.1 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the below parameter. --anonymous-auth=false -1.1.2 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and remove the --basic-auth-file= parameter. -1.1.3 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and remove the --insecure-allow-any-token parameter. -1.1.4 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and remove the --kubelet-https parameter. -1.1.5 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and remove the --insecure-bind-address parameter. -1.1.6 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the below parameter. --insecure-port=0 -1.1.7 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and either remove the --secure-port parameter or set it to a different (non-zero) desired port. -1.1.8 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the below parameter. --profiling=false -1.1.9 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the below parameter. --repair-malformed-updates=false -1.1.10 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --admission-control parameter to a value that does not include AlwaysAdmit . -1.1.11 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --admission-control parameter to include AlwaysPullImages . --admission-control=...,AlwaysPullImages,... -1.1.12 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --admission-control parameter to a value that includes DenyEscalatingExec . --admission-control=...,DenyEscalatingExec,... -1.1.13 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --admission-control parameter to include SecurityContextDeny . --admission-control=...,SecurityContextDeny,... -1.1.14 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --admission-control parameter to include NamespaceLifecycle . --admission-control=...,NamespaceLifecycle,... -1.1.15 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml 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 -1.1.16 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --audit-log-maxage parameter to 30 or as an appropriate number of days: --audit-log-maxage=30 -1.1.17 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --audit-log-maxbackup parameter to 10 or to an appropriate value. --audit-log-maxbackup=10 -1.1.18 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml 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 -1.1.19 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml 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 -1.1.20 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and remove the --token-auth-file= parameter. -1.1.21 : Follow the Kubernetes documentation and setup the TLS connection between the apiserver and kubelets. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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= -1.1.22 : Follow the Kubernetes documentation and set up the TLS connection between the apiserver and kubelets. Then, edit API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the kubelet client certificate and key parameters as below. --kubelet-client-certificate= --kubelet-client-key= -1.1.23 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the below parameter. --service-account-lookup=true -1.1.24 : Follow the documentation and create Pod Security Policy objects as per your environment. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --admission-control parameter to a value that includes PodSecurityPolicy : --admission-control=...,PodSecurityPolicy,... Then restart the API Server. -1.1.25 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --service-account-key-file parameter to the public key file for service accounts: --service-account-key-file= -1.1.26 : Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the etcd certificate and key file parameters. --etcd-certfile= --etcd-keyfile= -1.1.27 : Follow the documentation and create ServiceAccount objects as per your environment. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --admission-control parameter to a value that includes ServiceAccount . --admission-control=...,ServiceAccount,... -1.1.28 : Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the TLS certificate and private key file parameters. --tls-cert-file= --tls-private-key-file= -1.1.29 : Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the client certificate authority file. --client-ca-file= -1.1.30 : Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the etcd certificate authority file parameter. --etcd-cafile= -1.1.31 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --authorization-mode parameter to a value that includes Node . --authorization-mode=Node,RBAC -1.1.32 : Follow the Kubernetes documentation and configure NodeRestriction plug-in on kubelets. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --admission-control parameter to a value that includes NodeRestriction . --admission-control=...,NodeRestriction,... -1.1.33 : Follow the Kubernetes documentation and configure a EncryptionConfig file. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --experimental-encryption-provider-config parameter to the path of that file: --experimental-encryption-provider-config= -1.1.34 : Follow the Kubernetes documentation and configure a EncryptionConfig file. In this file, choose aescbc as the encryption provider. For example, kind: EncryptionConfig apiVersion: v1 resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: <32-byte base64-encoded secret> -1.1.35 : Follow the Kubernetes documentation and set the desired limits in a configuration file. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml and set the below parameters. --admission-control=EventRateLimit --admission-control-config-file= -1.1.36 : Follow the Kubernetes documentation and set the desired audit policy in the /etc/kubernetes/audit-policy.yaml file. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml and set the below parameters. 85 | P a g e--audit-policy-file=/etc/kubernetes/audit-policy.yaml -1.1.37 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml and set the below parameter as appropriate and if needed. For example, --request-timeout=300 -1.2.1 : Edit the Scheduler pod specification file /etc/kubernetes/manifests/kube- scheduler.yaml file on the master node and set the below parameter. --profiling=false -1.3.1 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml on the master node and set the --terminated-pod-gc- threshold to an appropriate threshold, for example: --terminated-pod-gc-threshold=10 -1.3.2 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml on the master node and set the below parameter. --profiling=false -1.3.3 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml on the master node to set the below parameter. --use-service-account-credentials=true -1.3.4 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml 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= -1.3.5 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml on the master node and set the --root-ca-file parameter to the certificate bundle file`. --root-ca-file= -1.3.6 : 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. -1.3.7 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml on the master node and set the --feature-gates parameter to include RotateKubeletServerCertificate=true . --feature-gates=RotateKubeletServerCertificate=true -1.4.1 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml -1.4.2 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-apiserver.yaml -1.4.3 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-controller-manager.yaml -1.4.4 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-controller-manager.yaml -1.4.5 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-scheduler.yaml -1.4.6 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-scheduler.yaml -1.4.7 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/etcd.yaml -1.4.8 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/etcd.yaml -1.4.9 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 -1.4.10 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root -1.4.11 : 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 -1.4.12 : 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 -1.4.13 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/admin.conf -1.4.14 : 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 -1.4.15 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/scheduler.conf -1.4.16 : 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 -1.4.17 : 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 -1.4.18 : 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 -1.5.1 : 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. --ca-file= --key-file= -1.5.2 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --client-cert-auth="true" -1.5.3 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and either remove the --auto-tls parameter or set it to false . --auto-tls=false -1.5.4 : Follow the etcd service documentation and configure peer TLS encryption as appropriate for your etcd cluster. Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameters. --peer-client-file= --peer-key-file= -1.5.5 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --peer-client-cert-auth=true -1.5.6 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and either remove the --peer-auto-tls parameter or set it to false . --peer-auto-tls=false -1.5.7 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --wal-dir= -1.5.8 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --max-wals=0 -1.5.9 : Follow the etcd documentation and create a dedicated certificate authority setup for the etcd service. 157 | P a g eThen, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --trusted-ca-file= -1.6.2 : Follow the documentation and create and enforce Pod Security Policies for your cluster. Additionally, you could refer the "CIS Security Benchmark for Docker" and follow the suggested Pod Security Policies for your environment. -1.6.3 : Follow the documentation and create namespaces for objects in your deployment as you need them. -1.6.4 : Follow the documentation and create NetworkPolicy objects as you need them. -1.6.5 : 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: 167 | P a g eapiVersion: v1 kind: Pod metadata: name: trustworthy-pod annotations: seccomp.security.alpha.kubernetes.io/pod: docker/default spec: containers: - name: trustworthy-container image: sotrustworthy:latest -1.6.6 : 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. -1.6.7 : Follow the Kubernetes documentation and setup image provenance. -1.6.8 : Follow the Kubernetes documentation and setup network policies as appropriate. For example, you could create a "default" isolation policy for a Namespace by creating a NetworkPolicy that selects all pods but does not allow any traffic: apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: -1.6.9 : Follow Kubernetes documentation and setup PSP and RBAC authorization for your cluster. -2.1.1 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable. --allow-privileged=false Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -2.1.2 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.3 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.4 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameter in KUBELET_AUTHZ_ARGS variable. --client-ca-file= Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -2.1.5 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.6 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.7 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.8 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.9 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable. --keep-terminated-pod-volumes=false Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -2.1.10 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.11 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable. --event-qps=0 Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -2.1.12 : Follow the Kubernetes documentation and set up the TLS connection on the Kubelet. Then edit the kubelet service file /etc/systemd/system/kubelet.service.d/10- kubeadm.conf on each worker node and set the below parameters in KUBELET_CERTIFICATE_ARGS variable. --tls-cert-file= file= --tls-private-key- Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -2.1.13 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameter in KUBELET_CADVISOR_ARGS variable. --cadvisor-port=0 Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -2.1.14 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and remove the --feature- gates=RotateKubeletClientCertificate=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 -2.1.15 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.2.1 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/kubernetes/kubelet.conf -2.2.2 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/kubernetes/kubelet.conf -2.2.3 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 755 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf -2.2.4 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/systemd/system/kubelet.service.d/10-kubeadm.conf -2.2.5 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 -2.2.6 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root -2.2.7 : Run the following command to modify the file permissions of the --client-ca-file chmod 644 -2.2.8 : Run the following command to modify the ownership of the --client-ca-file . chown root:root -3.1.1 : Edit the deployment specs and set --anonymous-auth=false . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.2 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the deployment specs and remove "--basic-auth-file=" . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.3 : Edit the deployment specs and remove --insecure-allow-any-token . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.4 : Edit the deployment specs and remove --insecure-bind-address . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.5 : Edit the deployment specs and set --insecure-port=0 . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.6 : Edit the deployment specs and set the --secure-port argument to the desired port. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.7 : Edit the deployment specs and set "--profiling=false" : kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.8 : Edit the deployment specs and set --admission-control argument to a value that does not include AlwaysAdmit . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.9 : Edit the deployment specs and set --admission-control argument to a value that includes NamespaceLifecycle . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.10 : Edit the deployment specs and set --audit-log-path argument as appropriate. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.11 : Edit the deployment specs and set --audit-log-maxage to 30 or as appropriate. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.12 : Edit the deployment specs and set --audit-log-maxbackup to 10 or as appropriate. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.13 : Edit the deployment specs and set --audit-log-maxsize=100 to 100 or as appropriate. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.14 : Edit the deployment specs and set --authorization-mode argument to a value other than AlwaysAllow kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.15 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the deployment specs and remove the --token-auth-file= argument. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.16 : Edit the deployment specs and set "--service-account-lookup=true" . kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.17 : Edit the deployment specs and set --service-account-key-file argument as appropriate. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.18 : Follow the Kubernetes documentation and set up the TLS connection between the federation apiserver and etcd. Then, edit the deployment specs and set "--etcd- certfile=" and "--etcd- keyfile=" arguments. kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.1.19 : Follow the Kubernetes documentation and set up the TLS connection on the federation apiserver. Then, edit the deployment specs and set "--tls-cert-file=" and "--tls-private-key-file=" : kubectl edit deployments federation-apiserver-deployment -- namespace=federation-system -3.2.1 : Edit the deployment specs and set "--profiling=false" : kubectl edit deployments federation-controller-manager-deployment -- namespace=federation-system diff --git a/scripts/kubeBench/kubecis_1_4_1.rem b/scripts/kubeBench/kubecis_1_4_1.rem deleted file mode 100644 index ea92042..0000000 --- a/scripts/kubeBench/kubecis_1_4_1.rem +++ /dev/null @@ -1,115 +0,0 @@ -1.1.1 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the below parameter. --anonymous-auth=false -1.1.2 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and remove the --basic-auth-file= parameter. -1.1.3 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and remove the --insecure-allow-any-token parameter. -1.1.4 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and remove the --kubelet-https parameter. -1.1.5 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and remove the --insecure-bind-address parameter. -1.1.6 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the below parameter. --insecure-port=0 -1.1.7 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and either remove the --secure-port parameter or set it to a different (non-zero) desired port. -1.1.8 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the below parameter. --profiling=false -1.1.9 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the below parameter. --repair-malformed-updates=false -1.1.10 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --enable-admission-plugins parameter to a value that does not include AlwaysAdmit. -1.1.11 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --enable-admission-plugins parameter to include AlwaysPullImages. --enable-admission-plugins=...,AlwaysPullImages,... -1.1.12 : None -1.1.13 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --enable-admission-plugins parameter to include SecurityContextDeny. --enable-admission-plugins=...,SecurityContextDeny,... -1.1.14 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --disable-admission-plugins parameter to ensure it does not include NamespaceLifecycle. -1.1.15 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml 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 -1.1.16 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --audit-log-maxage parameter to 30 or as an appropriate number of days: --audit-log-maxage=30 -1.1.17 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --audit-log-maxbackup parameter to 10 or to an appropriate value. --audit-log-maxbackup=10 -1.1.18 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml 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 -1.1.19 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml 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 -1.1.20 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and remove the --token-auth-file= parameter. -1.1.21 : Follow the Kubernetes documentation and setup the TLS connection between the apiserver and kubelets. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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= -1.1.22 : Follow the Kubernetes documentation and set up the TLS connection between the apiserver and kubelets. Then, edit API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the kubelet client certificate and key parameters as below. --kubelet-client-certificate= --kubelet-client-key= -1.1.23 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml 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. -1.1.24 : Follow the documentation and create Pod Security Policy objects as per your environment. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml 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. -1.1.25 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --service-account-key-file parameter to the public key file for service accounts: --service-account-key-file= -1.1.26 : Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the etcd certificate and key file parameters. --etcd-certfile= --etcd-keyfile= -1.1.27 : Follow the documentation and create ServiceAccount objects as per your environment. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and ensure that the --disable-admission-plugins parameter is set to a value that does not include ServiceAccount. -1.1.28 : Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the TLS certificate and private key file parameters. --tls-cert-file= --tls-private-key-file= -1.1.29 : Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the client certificate authority file. --client-ca-file= -1.1.30 : Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the etcd certificate authority file parameter. --etcd-cafile= -1.1.31 : 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,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256 -1.1.32 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --authorization-mode parameter to a value that includes Node. --authorization-mode=Node,RBAC -1.1.33 : Follow the Kubernetes documentation and configure NodeRestriction plug-in on kubelets. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --enable-admission-plugins parameter to a value that includes NodeRestriction. --enable-admission-plugins=...,NodeRestriction,... -1.1.34 : Follow the Kubernetes documentation and configure a EncryptionConfig file. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --encryption-provider-config parameter to the path of that file: --encryption-provider-config= -1.1.35 : Follow the Kubernetes documentation and configure a EncryptionConfig file. In this file, choose aescbc as the encryption provider. For example, kind: EncryptionConfig apiVersion: v1 resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: <32-byte base64-encoded secret> -1.1.36 : Follow the Kubernetes documentation and set the desired limits in a configuration file. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml and set the below parameters. --enable-admission-plugins=...,EventRateLimit,... --admission-control-config-file= -1.1.37 : Follow the Kubernetes documentation and set the desired audit policy in the /etc/kubernetes/audit-policy.yaml file. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml and set the below parameters. --audit-policy-file=/etc/kubernetes/audit-policy.yaml In the same API server pod specification file ensure that if the --feature-gates argument is present, it does not include AdvancedAuditing=false. -1.1.38 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml and set the below parameter as appropriate and if needed. For example, --request-timeout=300s -1.1.39 : Edit the API server pod specification file /etc/kubernetes/manifests/kube- apiserver.yaml on the master node and set the --authorization-mode parameter to a value that includes RBAC, for example: --authorization-mode=Node,RBAC -1.2.1 : Edit the Scheduler pod specification file /etc/kubernetes/manifests/kube- scheduler.yaml file on the master node and set the below parameter. --profiling=false -1.2.2 : Edit the Scheduler pod specification file /etc/kubernetes/manifests/kube- scheduler.yaml on the master node and ensure the correct value for the --address parameter -1.3.1 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml on the master node and set the --terminated-pod-gc- threshold to an appropriate threshold, for example: --terminated-pod-gc-threshold=10 -1.3.2 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml on the master node and set the below parameter. --profiling=false -1.3.3 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml on the master node to set the below parameter. --use-service-account-credentials=true -1.3.4 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml 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= -1.3.5 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml on the master node and set the --root-ca-file parameter to the certificate bundle file`. --root-ca-file= -1.3.6 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml on the master node and set the --feature-gates parameter to include RotateKubeletServerCertificate=true. --feature-gates=RotateKubeletServerCertificate=true -1.3.7 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube- controller-manager.yaml on the master node and ensure the correct value for the -- address parameter -1.4.1 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml -1.4.2 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-apiserver.yaml -1.4.3 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-controller-manager.yaml -1.4.4 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-controller-manager.yaml -1.4.5 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-scheduler.yaml -1.4.6 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-scheduler.yaml -1.4.7 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/etcd.yaml -1.4.8 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/etcd.yaml -1.4.9 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 -1.4.10 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root -1.4.11 : 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 -1.4.12 : 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 -1.4.13 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/admin.conf -1.4.14 : 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 -1.4.15 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/scheduler.conf -1.4.16 : 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 -1.4.17 : 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 -1.4.18 : 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 -1.4.19 : 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/ -1.4.20 : 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 -1.4.21 : 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 -1.5.1 : 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= --key-file= -1.5.2 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --client-cert-auth="true" -1.5.3 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and either remove the --auto-tls parameter or set it to false . --auto-tls=false -1.5.4 : Follow the etcd service documentation and configure peer TLS encryption as appropriate for your etcd cluster. Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameters. --peer-client-file= --peer-key-file= -1.5.5 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --peer-client-cert-auth=true -1.5.6 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and either remove the --peer-auto-tls parameter or set it to false . --peer-auto-tls=false -1.5.7 : Follow the etcd documentation and create a dedicated certificate authority setup for the etcd service. Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --trusted-ca-file= -1.6.1 : Follow Kubernetes documentation and setup PSP and RBAC authorization for your cluster. -1.6.2 : 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] -1.6.3 : Follow the documentation and create namespaces for objects in your deployment as you need them. -1.6.4 : Follow the documentation and create NetworkPolicy objects as you need them. -1.6.5 : 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 -1.6.6 : 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. -1.6.7 : Follow the Kubernetes documentation and setup image provenance. -1.6.8 : Follow the Kubernetes documentation and setup network policies as appropriate. For example, you could create a "default" isolation policy for a Namespace by creating a NetworkPolicy that selects all pods but does not allow any traffic: apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: -1.7.1 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.privileged field is omitted or set to false. -1.7.2 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostPID field is omitted or set to false. -1.7.3 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostIPC field is omitted or set to false. -1.7.4 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostNetwork field is omitted or set to false. -1.7.5 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.allowPrivilegeEscalation field is omitted or set to false. -1.7.6 : 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. -1.7.7 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.requiredDropCapabilities is set to include either NET_RAW or ALL. -2.1.1 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.2 : If using a Kubelet config file, edit the file to set authorization: mode to Webhook. If using executable arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the 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 -2.1.3 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameter in KUBELET_AUTHZ_ARGS variable. --client-ca-file= Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -2.1.4 : If using a Kubelet config file, edit the file to set readOnlyPort to 0. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.5 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.6 : If using a Kubelet config file, edit the file to set protectKernelDefaults: true. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.7 : If using a Kubelet config file, edit the file to set makeIPTablesUtilChains: true. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.8 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -2.1.9 : If using a Kubelet config file, edit the file to set eventRecordQPS: 0. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameter in KUBELET_SYSTEM_PODS_ARGS variable. --event-qps=0 Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -2.1.10 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameters in KUBELET_CERTIFICATE_ARGS variable. --tls-cert-file= --tls-private-key- file= Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -2.1.11 : None -2.1.12 : If using a Kubelet config file, edit the file to add the line rotateCertificates: true. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and add --rotate-certificates=true argument to the KUBELET_CERTIFICATE_ARGS variable. Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -2.1.13 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameter in KUBELET_CADVISOR_ARGS variable. --cadvisor-port=0 Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -2.1.14 : If using a Kubelet config file, edit the file to set TLSCipherSuites: to TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 ,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256 or to a subset of these values. If using executable arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below 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 -2.2.1 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf -2.2.2 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/kubernetes/kubelet.conf -2.2.3 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/kubernetes/kubelet.conf -2.2.4 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/systemd/system/kubelet.service.d/10-kubeadm.conf -2.2.5 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 -2.2.6 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root -2.2.7 : Run the following command to modify the file permissions of the --client-ca-file. chmod 644 -2.2.8 : Run the following command to modify the ownership of the --client-ca-file. chown root:root -2.2.9 : Run the following command (using the config file location identified in the Audit step) chmod 644 /var/lib/kubelet/config.yaml -2.2.10 : Run the following command (using the config file location identified in the Audit step) chown root:root /var/lib/kubelet/config.yaml diff --git a/scripts/kubeBench/kubecis_1_5_1.rem b/scripts/kubeBench/kubecis_1_5_1.rem deleted file mode 100644 index 41f6500..0000000 --- a/scripts/kubeBench/kubecis_1_5_1.rem +++ /dev/null @@ -1,122 +0,0 @@ -1.1.1 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml -1.1.2 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-apiserver.yaml -1.1.3 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-controller-manager.yaml -1.1.4 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-controller-manager.yaml -1.1.5 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-scheduler.yaml -1.1.6 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-scheduler.yaml -1.1.7 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/etcd.yaml -1.1.8 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/etcd.yaml -1.1.9 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 -1.1.10 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root -1.1.11 : 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 -1.1.12 : 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 -1.1.13 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/admin.conf -1.1.14 : 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 -1.1.15 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/scheduler.conf -1.1.16 : 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 -1.1.17 : 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 -1.1.18 : 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 -1.1.19 : 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/ -1.1.20 : 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 -1.1.21 : 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 -1.2.1 : Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the below parameter. --anonymous-auth=false -1.2.2 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and remove the --basic-auth-file= parameter. -1.2.3 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and remove the --token-auth-file= parameter. -1.2.4 : Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and remove the --kubelet-https parameter. -1.2.5 : Follow the Kubernetes documentation and set up the TLS connection between the apiserver and kubelets. Then, edit API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the kubelet client certificate and key parameters as below. --kubelet-client-certificate= --kubelet-client-key= -1.2.6 : Follow the Kubernetes documentation and setup the TLS connection between the apiserver and kubelets. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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= -1.2.7 : Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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 -1.2.8 : Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --authorization-mode parameter to a value that includes Node . --authorization-mode=Node,RBAC -1.2.9 : Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --authorization-mode parameter to a value that includes RBAC, for example:--authorization-mode=Node,RBAC -1.2.10: Follow the Kubernetes documentation and set the desired limits in a configuration file. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml and set the below parameters. --enable-admission-plugins=...,EventRateLimit,... --admission-control-config-file= -1.2.11: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and either remove the --enable-admission-plugins parameter, or set it to a value that does not include AlwaysAdmit. -1.2.12: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --enable-admission-plugins parameter to include AlwaysPullImages. --enable-admission-plugins=...,AlwaysPullImages,... -1.2.13: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --enable-admission-plugins parameter to include SecurityContextDeny, unless PodSecurityPolicy is already in place. --enable-admission-plugins=...,SecurityContextDeny,... -1.2.14: Follow the documentation and create ServiceAccount objects as per your environment. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and ensure that the --disable-admission-plugins parameter is set to a value that does not include ServiceAccount. -1.2.15: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --disable-admission-plugins parameter to ensure it does not include NamespaceLifecycle. -1.2.16: Follow the documentation and create Pod Security Policy objects as per your environment. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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. -1.2.17: Follow the Kubernetes documentation and configure NodeRestriction plug-in on kubelets. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --enable-admission-plugins parameter to a value that includes NodeRestriction. --enable-admission-plugins=...,NodeRestriction,... -1.2.18: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and remove the --insecure-bind-address parameter. -1.2.19: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the below parameter. --insecure-port=0 -1.2.20: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and either remove the --secure-port parameter or set it to a different (non-zero) desired port. -1.2.21: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the below parameter. --profiling=false -1.2.22: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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 -1.2.23: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --audit-log-maxage parameter to 30 or as an appropriate number of days: --audit-log-maxage=30 -1.2.24: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --audit-log-maxbackup parameter to 10 or to an appropriate value. --audit-log-maxbackup=10 -1.2.25: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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 -1.2.26: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml and set the below parameter as appropriate and if needed. For example, --request-timeout=300s -1.2.27: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the below parameter. --service-account-lookup=true -1.2.28: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --service-account-key-file parameter to the public key file for service accounts: --service-account-key-file= -1.2.29: Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the etcd certificate and key file parameters. --etcd-certfile= --etcd-keyfile= -1.2.30: Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the TLS certificate and private key file parameters. --tls-cert-file= --tls-private-key-file= -1.2.31: Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the client certificate authority file. --client-ca-file= -1.2.32: Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the etcd certificate authority file parameter. --etcd-cafile= -1.2.33: Follow the Kubernetes documentation and configure a EncryptionConfig file. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --encryption-provider-config parameter to the path of that file: --encryption-provider-config= -1.2.34: Follow the Kubernetes documentation and configure a EncryptionConfig file. In this file, choose aescbc, kms or secretbox as the encryption provider. -1.2.35: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the below 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 -1.3.1 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node and set the --terminated-pod-gc-threshold to an appropriate threshold, for example: --terminated-pod-gc-threshold=10 -1.3.2 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node and set the below parameter. --profiling=false -1.3.3 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node to set the below parameter. --use-service-account-credentials=true -1.3.4 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml 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= -1.3.5 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node and set the --root-ca-file parameter to the certificate bundle file`. --root-ca-file= -1.3.6 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node and set the --feature-gates parameter to include RotateKubeletServerCertificate=true. --feature-gates=RotateKubeletServerCertificate=true -1.3.7 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node and ensure the correct value for the --bind-address parameter. -1.4.1 : Edit the Scheduler pod specification file /etc/kubernetes/manifests/kube-scheduler.yaml file on the master node and set the below parameter. --profiling=false -1.4.2 : Edit the Scheduler pod specification file /etc/kubernetes/manifests/kube-scheduler.yaml on the master node and ensure the correct value for the --bind-address parameter -2.1 : 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= --key-file= -2.2 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --client-cert-auth="true" -2.3 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and either remove the --auto-tls parameter or set it to false. --auto-tls=false -2.4 : Follow the etcd service documentation and configure peer TLS encryption as appropriate for your etcd cluster. Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameters. --peer-cert-file= --peer-key-file= -2.5 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --peer-client-cert-auth=true -2.6 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and either remove the --peer-auto-tls parameter or set it to false. --peer-auto-tls=false -2.7 : Follow the etcd documentation and create a dedicated certificate authority setup for the etcd service. Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --trusted-ca-file= -3.1.1 : Alternative mechanisms provided by Kubernetes such as the use of OIDC should be implemented in place of client certificates. -3.2.1 : Create an audit policy file for your cluster. -3.2.2 : Consider modification of the audit policy in use on the cluster to include these items, at a minimum. -4.1.1 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf -4.1.2 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/systemd/system/kubelet.service.d/10-kubeadm.conf -4.1.3 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 -4.1.5 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/kubernetes/kubelet.conf -4.1.6 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/kubernetes/kubelet.conf -4.1.7 : Run the following command to modify the file permissions of the --client-ca-file chmod 644 -4.1.8 : Run the following command to modify the ownership of the --client-ca-file. chown root:root -4.1.9 : Run the following command (using the config file location identied in the Audit step) chmod 644 /var/lib/kubelet/config.yaml -4.1.10 : Run the following command (using the config file location identied in the Audit step) chown root:root /etc/kubernetes/kubelet.conf -4.2.1 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.2 : If using a Kubelet config file, edit the file to set authorization: mode to Webhook. If using executable arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the 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 -4.2.3 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameter in KUBELET_AUTHZ_ARGS variable. --client-ca-file= Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -4.2.4 : If using a Kubelet config file, edit the file to set readOnlyPort to 0. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.5 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.6 : If using a Kubelet config file, edit the file to set protectKernelDefaults: true. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.7 : If using a Kubelet config file, edit the file to set makeIPTablesUtilChains: true. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.8 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.9 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.10 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameters in KUBELET_CERTIFICATE_ARGS variable. --tls-cert-file= --tls-private-key- file= Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -4.2.11 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.12 : On the master edit /var/lib/kubelet/kubeadm-flags.env and set the parameter KUBELET_CERTIFICATE_ARGS --feature-gates=RotateKubeletServerCertificate=true or as an alternative, and suggested as a last resort, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.13 : If using a Kubelet config file, edit the file to set TLSCipherSuites: to TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256 or to a subset of these values. If using executable arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the --tls-cipher-suites parameter as follows, or to a subset of these values. --tls-cipher- suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM _SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM _SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM _SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256 Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -5.1.1 : 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] -5.1.2 : Where possible, remove get, list and watch access to secret objects in the cluster. -5.1.3 : Where possible replace any use of wildcards in clusterroles and roles with specific objects or actions. -5.1.4 : Where possible, remove create access to pod objects in the cluster. -5.1.5 : 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 -5.1.6 : Modify the definition of pods and service accounts which do not need to mount service account tokens to disable it. -5.2.1 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.privileged field is omitted or set to false. -5.2.2 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostPID field is omitted or set to false. -5.2.3 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostIPC field is omitted or set to false. -5.2.4 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostNetwork field is omitted or set to false. -5.2.5 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.allowPrivilegeEscalation field is omitted or set to false. -5.2.6 : 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. -5.2.7 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.requiredDropCapabilities is set to include either NET_RAW or ALL. -5.2.8 : Ensure that allowedCapabilities is not present in PSPs for the cluster unless it is set to an empty array. -5.2.9 : 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. -5.3.1 : 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. -5.3.2 : Follow the documentation and create NetworkPolicy objects as you need them. -5.4.1 : If possible, rewrite application code to read secrets from mounted secret files, rather than from environment variables. -5.4.2 : Refer to the secrets management options offered by your cloud provider or a third-party secrets management solution. -5.5.1 : Follow the Kubernetes documentation and setup image provenance. -5.7.1 : Follow the documentation and create namespaces for objects in your deployment as you need them. -5.7.2 : 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 -5.7.3 : 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. -5.7.4 : Ensure that namespaces are created to allow for appropriate segregation of Kubernetes resources and that all new resources are created in a specific namespace. diff --git a/scripts/kubeBench/kubecis_1_6_0.rem b/scripts/kubeBench/kubecis_1_6_0.rem deleted file mode 100644 index 41f6500..0000000 --- a/scripts/kubeBench/kubecis_1_6_0.rem +++ /dev/null @@ -1,122 +0,0 @@ -1.1.1 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml -1.1.2 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-apiserver.yaml -1.1.3 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-controller-manager.yaml -1.1.4 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-controller-manager.yaml -1.1.5 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/kube-scheduler.yaml -1.1.6 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/kube-scheduler.yaml -1.1.7 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/manifests/etcd.yaml -1.1.8 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root /etc/kubernetes/manifests/etcd.yaml -1.1.9 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 -1.1.10 : Run the below command (based on the file location on your system) on the master node. For example, chown root:root -1.1.11 : 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 -1.1.12 : 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 -1.1.13 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/admin.conf -1.1.14 : 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 -1.1.15 : Run the below command (based on the file location on your system) on the master node. For example, chmod 644 /etc/kubernetes/scheduler.conf -1.1.16 : 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 -1.1.17 : 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 -1.1.18 : 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 -1.1.19 : 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/ -1.1.20 : 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 -1.1.21 : 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 -1.2.1 : Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the below parameter. --anonymous-auth=false -1.2.2 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and remove the --basic-auth-file= parameter. -1.2.3 : Follow the documentation and configure alternate mechanisms for authentication. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and remove the --token-auth-file= parameter. -1.2.4 : Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and remove the --kubelet-https parameter. -1.2.5 : Follow the Kubernetes documentation and set up the TLS connection between the apiserver and kubelets. Then, edit API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the kubelet client certificate and key parameters as below. --kubelet-client-certificate= --kubelet-client-key= -1.2.6 : Follow the Kubernetes documentation and setup the TLS connection between the apiserver and kubelets. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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= -1.2.7 : Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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 -1.2.8 : Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --authorization-mode parameter to a value that includes Node . --authorization-mode=Node,RBAC -1.2.9 : Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --authorization-mode parameter to a value that includes RBAC, for example:--authorization-mode=Node,RBAC -1.2.10: Follow the Kubernetes documentation and set the desired limits in a configuration file. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml and set the below parameters. --enable-admission-plugins=...,EventRateLimit,... --admission-control-config-file= -1.2.11: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and either remove the --enable-admission-plugins parameter, or set it to a value that does not include AlwaysAdmit. -1.2.12: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --enable-admission-plugins parameter to include AlwaysPullImages. --enable-admission-plugins=...,AlwaysPullImages,... -1.2.13: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --enable-admission-plugins parameter to include SecurityContextDeny, unless PodSecurityPolicy is already in place. --enable-admission-plugins=...,SecurityContextDeny,... -1.2.14: Follow the documentation and create ServiceAccount objects as per your environment. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and ensure that the --disable-admission-plugins parameter is set to a value that does not include ServiceAccount. -1.2.15: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --disable-admission-plugins parameter to ensure it does not include NamespaceLifecycle. -1.2.16: Follow the documentation and create Pod Security Policy objects as per your environment. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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. -1.2.17: Follow the Kubernetes documentation and configure NodeRestriction plug-in on kubelets. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --enable-admission-plugins parameter to a value that includes NodeRestriction. --enable-admission-plugins=...,NodeRestriction,... -1.2.18: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and remove the --insecure-bind-address parameter. -1.2.19: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the below parameter. --insecure-port=0 -1.2.20: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and either remove the --secure-port parameter or set it to a different (non-zero) desired port. -1.2.21: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the below parameter. --profiling=false -1.2.22: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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 -1.2.23: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --audit-log-maxage parameter to 30 or as an appropriate number of days: --audit-log-maxage=30 -1.2.24: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --audit-log-maxbackup parameter to 10 or to an appropriate value. --audit-log-maxbackup=10 -1.2.25: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml 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 -1.2.26: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml and set the below parameter as appropriate and if needed. For example, --request-timeout=300s -1.2.27: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the below parameter. --service-account-lookup=true -1.2.28: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --service-account-key-file parameter to the public key file for service accounts: --service-account-key-file= -1.2.29: Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the etcd certificate and key file parameters. --etcd-certfile= --etcd-keyfile= -1.2.30: Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the TLS certificate and private key file parameters. --tls-cert-file= --tls-private-key-file= -1.2.31: Follow the Kubernetes documentation and set up the TLS connection on the apiserver. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the client certificate authority file. --client-ca-file= -1.2.32: Follow the Kubernetes documentation and set up the TLS connection between the apiserver and etcd. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the etcd certificate authority file parameter. --etcd-cafile= -1.2.33: Follow the Kubernetes documentation and configure a EncryptionConfig file. Then, edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the --encryption-provider-config parameter to the path of that file: --encryption-provider-config= -1.2.34: Follow the Kubernetes documentation and configure a EncryptionConfig file. In this file, choose aescbc, kms or secretbox as the encryption provider. -1.2.35: Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml on the master node and set the below 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 -1.3.1 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node and set the --terminated-pod-gc-threshold to an appropriate threshold, for example: --terminated-pod-gc-threshold=10 -1.3.2 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node and set the below parameter. --profiling=false -1.3.3 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node to set the below parameter. --use-service-account-credentials=true -1.3.4 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml 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= -1.3.5 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node and set the --root-ca-file parameter to the certificate bundle file`. --root-ca-file= -1.3.6 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node and set the --feature-gates parameter to include RotateKubeletServerCertificate=true. --feature-gates=RotateKubeletServerCertificate=true -1.3.7 : Edit the Controller Manager pod specification file /etc/kubernetes/manifests/kube-controller-manager.yaml on the master node and ensure the correct value for the --bind-address parameter. -1.4.1 : Edit the Scheduler pod specification file /etc/kubernetes/manifests/kube-scheduler.yaml file on the master node and set the below parameter. --profiling=false -1.4.2 : Edit the Scheduler pod specification file /etc/kubernetes/manifests/kube-scheduler.yaml on the master node and ensure the correct value for the --bind-address parameter -2.1 : 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= --key-file= -2.2 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --client-cert-auth="true" -2.3 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and either remove the --auto-tls parameter or set it to false. --auto-tls=false -2.4 : Follow the etcd service documentation and configure peer TLS encryption as appropriate for your etcd cluster. Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameters. --peer-cert-file= --peer-key-file= -2.5 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --peer-client-cert-auth=true -2.6 : Edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and either remove the --peer-auto-tls parameter or set it to false. --peer-auto-tls=false -2.7 : Follow the etcd documentation and create a dedicated certificate authority setup for the etcd service. Then, edit the etcd pod specification file /etc/kubernetes/manifests/etcd.yaml on the master node and set the below parameter. --trusted-ca-file= -3.1.1 : Alternative mechanisms provided by Kubernetes such as the use of OIDC should be implemented in place of client certificates. -3.2.1 : Create an audit policy file for your cluster. -3.2.2 : Consider modification of the audit policy in use on the cluster to include these items, at a minimum. -4.1.1 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf -4.1.2 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/systemd/system/kubelet.service.d/10-kubeadm.conf -4.1.3 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 -4.1.5 : Run the below command (based on the file location on your system) on the each worker node. For example, chmod 644 /etc/kubernetes/kubelet.conf -4.1.6 : Run the below command (based on the file location on your system) on the each worker node. For example, chown root:root /etc/kubernetes/kubelet.conf -4.1.7 : Run the following command to modify the file permissions of the --client-ca-file chmod 644 -4.1.8 : Run the following command to modify the ownership of the --client-ca-file. chown root:root -4.1.9 : Run the following command (using the config file location identied in the Audit step) chmod 644 /var/lib/kubelet/config.yaml -4.1.10 : Run the following command (using the config file location identied in the Audit step) chown root:root /etc/kubernetes/kubelet.conf -4.2.1 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.2 : If using a Kubelet config file, edit the file to set authorization: mode to Webhook. If using executable arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the 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 -4.2.3 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameter in KUBELET_AUTHZ_ARGS variable. --client-ca-file= Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -4.2.4 : If using a Kubelet config file, edit the file to set readOnlyPort to 0. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.5 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.6 : If using a Kubelet config file, edit the file to set protectKernelDefaults: true. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.7 : If using a Kubelet config file, edit the file to set makeIPTablesUtilChains: true. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.8 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.9 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.10 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameters in KUBELET_CERTIFICATE_ARGS variable. --tls-cert-file= --tls-private-key- file= Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -4.2.11 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.12 : On the master edit /var/lib/kubelet/kubeadm-flags.env and set the parameter KUBELET_CERTIFICATE_ARGS --feature-gates=RotateKubeletServerCertificate=true or as an alternative, and suggested as a last resort, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.13 : If using a Kubelet config file, edit the file to set TLSCipherSuites: to TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256 or to a subset of these values. If using executable arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the --tls-cipher-suites parameter as follows, or to a subset of these values. --tls-cipher- suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM _SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM _SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM _SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256 Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -5.1.1 : 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] -5.1.2 : Where possible, remove get, list and watch access to secret objects in the cluster. -5.1.3 : Where possible replace any use of wildcards in clusterroles and roles with specific objects or actions. -5.1.4 : Where possible, remove create access to pod objects in the cluster. -5.1.5 : 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 -5.1.6 : Modify the definition of pods and service accounts which do not need to mount service account tokens to disable it. -5.2.1 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.privileged field is omitted or set to false. -5.2.2 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostPID field is omitted or set to false. -5.2.3 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostIPC field is omitted or set to false. -5.2.4 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostNetwork field is omitted or set to false. -5.2.5 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.allowPrivilegeEscalation field is omitted or set to false. -5.2.6 : 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. -5.2.7 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.requiredDropCapabilities is set to include either NET_RAW or ALL. -5.2.8 : Ensure that allowedCapabilities is not present in PSPs for the cluster unless it is set to an empty array. -5.2.9 : 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. -5.3.1 : 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. -5.3.2 : Follow the documentation and create NetworkPolicy objects as you need them. -5.4.1 : If possible, rewrite application code to read secrets from mounted secret files, rather than from environment variables. -5.4.2 : Refer to the secrets management options offered by your cloud provider or a third-party secrets management solution. -5.5.1 : Follow the Kubernetes documentation and setup image provenance. -5.7.1 : Follow the documentation and create namespaces for objects in your deployment as you need them. -5.7.2 : 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 -5.7.3 : 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. -5.7.4 : Ensure that namespaces are created to allow for appropriate segregation of Kubernetes resources and that all new resources are created in a specific namespace. diff --git a/scripts/kubeBench/kubecis_gke_1_0_0.rem b/scripts/kubeBench/kubecis_gke_1_0_0.rem deleted file mode 100644 index 6cb38b6..0000000 --- a/scripts/kubeBench/kubecis_gke_1_0_0.rem +++ /dev/null @@ -1,548 +0,0 @@ -1.1.1 : This control cannot be modified in GKE. -1.1.2 : This control cannot be modified in GKE. -1.1.3 : This control cannot be modified in GKE. -1.1.4 : This control cannot be modified in GKE. -1.1.5 : This control cannot be modified in GKE. -1.1.6 : This control cannot be modified in GKE. -1.1.7 : This control cannot be modified in GKE. -1.1.8 : This control cannot be modified in GKE. -1.1.9 : This control cannot be modified in GKE. -1.1.10 : This control cannot be modified in GKE. -1.1.11 : This control cannot be modified in GKE. -1.1.12 : This control cannot be modified in GKE. -1.1.13 : This control cannot be modified in GKE. -1.1.14 : This control cannot be modified in GKE. -1.1.15 : This control cannot be modified in GKE. -1.1.16 : This control cannot be modified in GKE. -1.1.17 : This control cannot be modified in GKE. -1.1.18 : This control cannot be modified in GKE. -1.1.19 : This control cannot be modified in GKE. -1.1.20 : This control cannot be modified in GKE. -1.1.21 : This control cannot be modified in GKE. -1.2.1 : This control cannot be modified in GKE. -1.2.2 : This control cannot be modified in GKE. -1.2.3 : This control cannot be modified in GKE. -1.2.4 : This control cannot be modified in GKE. -1.2.5 : This control cannot be modified in GKE. -1.2.6 : This control cannot be modified in GKE. -1.2.7 : This control cannot be modified in GKE. -1.2.8 : This control cannot be modified in GKE. -1.2.9 : This control cannot be modified in GKE. -1.2.10: This control cannot be modified in GKE. -1.2.11: This control cannot be modified in GKE. -1.2.12: This control cannot be modified in GKE. -1.2.13: This control cannot be modified in GKE. -1.2.14: This control cannot be modified in GKE. -1.2.15: This control cannot be modified in GKE. -1.2.16: This control cannot be modified in GKE. -1.2.17: This control cannot be modified in GKE. -1.2.18: This control cannot be modified in GKE. -1.2.19: This control cannot be modified in GKE. -1.2.20: This control cannot be modified in GKE. -1.2.21: This control cannot be modified in GKE. -1.2.22: This control cannot be modified in GKE. -1.2.23: This control cannot be modified in GKE. -1.2.24: This control cannot be modified in GKE. -1.2.25: This control cannot be modified in GKE. -1.2.26: This control cannot be modified in GKE. -1.2.27: This control cannot be modified in GKE. -1.2.28: This control cannot be modified in GKE. -1.2.29: This control cannot be modified in GKE. -1.2.30: This control cannot be modified in GKE. -1.2.31: This control cannot be modified in GKE. -1.2.32: This control cannot be modified in GKE. -1.2.33: This control cannot be modified in GKE. -1.2.34: This control cannot be modified in GKE. -1.2.35: This control cannot be modified in GKE. -1.3.1 : This control cannot be modified in GKE. -1.3.2 : This control cannot be modified in GKE. -1.3.3 : This control cannot be modified in GKE. -1.3.4 : This control cannot be modified in GKE. -1.3.5 : This control cannot be modified in GKE. -1.3.6 : This control cannot be modified in GKE. -1.3.7 : This control cannot be modified in GKE. -1.4.1 : This control cannot be modified in GKE. -1.4.2 : This control cannot be modified in GKE. -2.1 : This control cannot be modified in GKE. -2.2 : This control cannot be modified in GKE. -2.3 : This control cannot be modified in GKE. -2.4 : This control cannot be modified in GKE. -2.5 : This control cannot be modified in GKE. -2.6 : This control cannot be modified in GKE. -2.7 : This control cannot be modified in GKE. -3.1.1 : Alternative mechanisms provided by Kubernetes such as the use of OIDC should be implemented in place of client certificates. You can remediate the availability of client certificates in your GKE cluster. See Recommendation 6.8.2. -3.2.1 : This control cannot be modified in GKE. -3.2.2 : This control cannot be modified in GKE. -4.1.1 : This control cannot be modified in GKE. -4.1.2 : This control cannot be modified in GKE. -4.1.3 : Run the below command (based on the file location on your system) on each worker node. For example, chmod 644 -4.1.4 : Run the below command (based on the file location on your system) on each worker node. For example, chown root:root -4.1.5 : This control cannot be modified in GKE. -4.1.6 : This control cannot be modified in GKE. -4.1.7 : This control cannot be modified in GKE. -4.1.8 : This control cannot be modified in GKE. -4.1.9 : Run the following command (using the config file location identified in the Audit step) chmod 644 /var/lib/kubelet/config.yaml -4.1.10 : Run the following command (using the config file location identied in the Audit step) chown root:root /etc/kubernetes/kubelet.conf -4.2.1 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.2 : If using a Kubelet config file, edit the file to set authorization: mode to Webhook. If using executable arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the 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 -4.2.3 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameter in KUBELET_AUTHZ_ARGS variable. --client-ca-file= Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -4.2.4 : If using a Kubelet config file, edit the file to set readOnlyPort to 0. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.5 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.6 : If using a Kubelet config file, edit the file to set protectKernelDefaults: true. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.7 : If using a Kubelet config file, edit the file to set makeIPTablesUtilChains: true. If using command line arguments, edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.8 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.9 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.10 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf on each worker node and set the below parameters in KUBELET_CERTIFICATE_ARGS variable. --tls-cert-file= --tls-private-key- file= Based on your system, restart the kubelet service. For example: systemctl daemon-reload systemctl restart kubelet.service -4.2.11 : 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 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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 -4.2.12 : Edit the kubelet service file /etc/systemd/system/kubelet.service.d/10-kubeadm.conf 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: -4.2.13 : This control cannot be modified in GKE. -5.1.1 : 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] -5.1.2 : Where possible, remove get, list and watch access to secret objects in the cluster. -5.1.3 : Where possible replace any use of wildcards in clusterroles and roles with specific objects or actions. -5.1.4 : Where possible, remove create access to pod objects in the cluster. -5.1.5 : 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 -5.1.6 : Modify the definition of pods and service accounts which do not need to mount service account tokens to disable it. -5.2.1 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.privileged field is omitted or set to false. -5.2.2 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostPID field is omitted or set to false. -5.2.3 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostIPC field is omitted or set to false. -5.2.4 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.hostNetwork field is omitted or set to false. -5.2.5 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.allowPrivilegeEscalation field is omitted or set to false. -5.2.6 : 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. -5.2.7 : Create a PSP as described in the Kubernetes documentation, ensuring that the .spec.requiredDropCapabilities is set to include either NET_RAW or ALL. -5.2.8 : Ensure that allowedCapabilities is not present in PSPs for the cluster unless it is set to an empty array. -5.2.9 : 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. -5.3.1 : 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. -5.3.2 : Follow the documentation and create NetworkPolicy objects as you need them. -5.4.1 : If possible, rewrite application code to read secrets from mounted secret files, rather than from environment variables. -5.4.2 : Refer to the secrets management options offered by your cloud provider or a third-party secrets management solution. -5.5.1 : Follow the Kubernetes documentation and setup image provenance. -5.6.1 : Follow the documentation and create namespaces for objects in your deployment as you need them. -5.6.2 : 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 -5.6.3 : 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. -5.6.4 : Ensure that namespaces are created to allow for appropriate segregation of Kubernetes resources and that all new resources are created in a specific namespace. -6.1.1 : Using Command Line: gcloud services enable containerscanning.googleapis.com -6.1.2 : Using Command Line: - To change roles at the GCR bucket level: - Firstly, run the following if read permissions are required: - - gsutil iam ch [TYPE]:[EMAIL-ADDRESS]:objectViewer - gs://artifacts.[PROJECT_ID].appspot.com - - Then remove the excessively privileged role (Storage Admin / Storage Object Admin / - Storage Object Creator) using: - - gsutil iam ch -d [TYPE]:[EMAIL-ADDRESS]:[ROLE] - gs://artifacts.[PROJECT_ID].appspot.com - - where: - [TYPE] can be one of the following: - o user, if the [EMAIL-ADDRESS] is a Google account - o serviceAccount, if [EMAIL-ADDRESS] specifies a Service account - [EMAIL-ADDRESS] can be one of the following: - o a Google account (for example, someone@example.com) - o a Cloud IAM service account - To modify roles defined at the project level and subsequently inherited within the GCR - bucket, or the Service Account User role, extract the IAM policy file, modify it accordingly - and apply it using: - - gcloud projects set-iam-policy [PROJECT_ID] [POLICY_FILE] -6.1.3 : Using Command Line: - For an account explicitly granted to the bucket. First, add read access to the Kubernetes - Service Account - - gsutil iam ch [TYPE]:[EMAIL-ADDRESS]:objectViewer - gs://artifacts.[PROJECT_ID].appspot.com - - where: - [TYPE] can be one of the following: - o user, if the [EMAIL-ADDRESS] is a Google account - o serviceAccount, if [EMAIL-ADDRESS] specifies a Service account [EMAIL-ADDRESS] can be one of the following: o a Google account (for example, someone@example.com) o a Cloud IAM service account Then remove the excessively privileged role (Storage Admin / Storage Object Admin / Storage Object Creator) using: gsutil iam ch -d [TYPE]:[EMAIL-ADDRESS]:[ROLE] gs://artifacts.[PROJECT_ID].appspot.com For an account that inherits access to the GCR Bucket through Project level permissions, modify the Projects IAM policy file accordingly, then upload it using: gcloud projects set-iam-policy [PROJECT_ID] [POLICY_FILE] -6.1.4 : Using Command Line: - First, update the cluster to enable Binary Authorization: - - gcloud container cluster update [CLUSTER_NAME] \ - --enable-binauthz - - Create a Binary Authorization Policy using the Binary Authorization Policy Reference - (https://cloud.google.com/binary-authorization/docs/policy-yaml-reference) for guidance. - Import the policy file into Binary Authorization: - - gcloud container binauthz policy import [YAML_POLICY] -6.2.1 : Using Command Line: - Firstly, create a minimally privileged service account: - - gcloud iam service-accounts create [SA_NAME] \ - --display-name "GKE Node Service Account" - export NODE_SA_EMAIL=`gcloud iam service-accounts list \ - --format='value(email)' \ - --filter='displayName:GKE Node Service Account'` - - Grant the following roles to the service account: - - export PROJECT_ID=`gcloud config get-value project` - gcloud projects add-iam-policy-binding $PROJECT_ID \ - --member serviceAccount:$NODE_SA_EMAIL \ - --role roles/monitoring.metricWriter - gcloud projects add-iam-policy-binding $PROJECT_ID \ - --member serviceAccount:$NODE_SA_EMAIL \ - --role roles/monitoring.viewer - gcloud projects add-iam-policy-binding $PROJECT_ID \ - --member serviceAccount:$NODE_SA_EMAIL \ - --role roles/logging.logWriter - - To create a new Node pool using the Service account, run the following command: - - gcloud container node-pools create [NODE_POOL] \ - --service-account=[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com \ - --cluster=[CLUSTER_NAME] --zone [COMPUTE_ZONE] - - You will need to migrate your workloads to the new Node pool, and delete Node pools that - use the default service account to complete the remediation. -6.2.2 : Using Command Line: - - gcloud beta container clusters update [CLUSTER_NAME] --zone [CLUSTER_ZONE] \ - --identity-namespace=[PROJECT_ID].svc.id.goog - - Note that existing Node pools are unaffected. New Node pools default to --workload- - metadata-from-node=GKE_METADATA_SERVER . - - Then, modify existing Node pools to enable GKE_METADATA_SERVER: - - gcloud beta container node-pools update [NODEPOOL_NAME] \ - --cluster=[CLUSTER_NAME] --zone [CLUSTER_ZONE] \ - --workload-metadata-from-node=GKE_METADATA_SERVER - - You may also need to modify workloads in order for them to use Workload Identity as - described within https://cloud.google.com/kubernetes-engine/docs/how-to/workload- - identity. Also consider the effects on the availability of your hosted workloads as Node - pools are updated, it may be more appropriate to create new Node Pools. -6.3.1 : Using Command Line: - To create a key - - Create a key ring: - - gcloud kms keyrings create [RING_NAME] \ - --location [LOCATION] \ - --project [KEY_PROJECT_ID] - - Create a key: - - gcloud kms keys create [KEY_NAME] \ - --location [LOCATION] \ - --keyring [RING_NAME] \ - --purpose encryption \ - --project [KEY_PROJECT_ID] - - Grant the Kubernetes Engine Service Agent service account the Cloud KMS CryptoKey - Encrypter/Decrypter role: - - gcloud kms keys add-iam-policy-binding [KEY_NAME] \ - --location [LOCATION] \ - --keyring [RING_NAME] \ - --member serviceAccount:[SERVICE_ACCOUNT_NAME] \ - --role roles/cloudkms.cryptoKeyEncrypterDecrypter \ - --project [KEY_PROJECT_ID] - - To create a new cluster with Application-layer Secrets Encryption: - - gcloud container clusters create [CLUSTER_NAME] \ - --cluster-version=latest \ - --zone [ZONE] \ - --database-encryption-key projects/[KEY_PROJECT_ID]/locations/[LOCATION]/keyRings/[RING_NAME]/cryptoKey s/[KEY_NAME] \ - --project [CLUSTER_PROJECT_ID] - - To enable on an existing cluster: - - gcloud container clusters update [CLUSTER_NAME] \ - --zone [ZONE] \ - --database-encryption-key projects/[KEY_PROJECT_ID]/locations/[LOCATION]/keyRings/[RING_NAME]/cryptoKey s/[KEY_NAME] \ - --project [CLUSTER_PROJECT_ID] -6.4.1 : Using Command Line: - To update an existing cluster, create a new Node pool with the legacy GCE metadata - endpoint disabled: - - gcloud container node-pools create [POOL_NAME] \ - --metadata disable-legacy-endpoints=true \ - --cluster [CLUSTER_NAME] \ - --zone [COMPUTE_ZONE] - - You will need to migrate workloads from any existing non-conforming Node pools, to the - new Node pool, then delete non-conforming Node pools to complete the remediation. -6.4.2 : Using Command Line: - gcloud beta container clusters update [CLUSTER_NAME] \ - --identity-namespace=[PROJECT_ID].svc.id.goog - Note that existing Node pools are unaffected. New Node pools default to --workload- - metadata-from-node=GKE_METADATA_SERVER . - - To modify an existing Node pool to enable GKE Metadata Server: - - gcloud beta container node-pools update [NODEPOOL_NAME] \ - --cluster=[CLUSTER_NAME] \ - --workload-metadata-from-node=GKE_METADATA_SERVER - - You may also need to modify workloads in order for them to use Workload Identity as - described within https://cloud.google.com/kubernetes-engine/docs/how-to/workload- - identity. -6.5.1 : Using Command Line: - To set the node image to cos for an existing cluster's Node pool: - - gcloud container clusters upgrade [CLUSTER_NAME]\ - --image-type cos \ - --zone [COMPUTE_ZONE] --node-pool [POOL_NAME] -6.5.2 : Using Command Line: - To enable node auto-repair for an existing cluster with Node pool, run the following - command: - - gcloud container node-pools update [POOL_NAME] \ - --cluster [CLUSTER_NAME] --zone [COMPUTE_ZONE] \ - --enable-autorepair -6.5.3 : Using Command Line: - To enable node auto-upgrade for an existing cluster's Node pool, run the following - command: - - gcloud container node-pools update [NODE_POOL] \ - --cluster [CLUSTER_NAME] --zone [COMPUTE_ZONE] \ - --enable-autoupgrade -6.5.4 : Using Command Line: - Create a new cluster by running the following command: - - gcloud beta container clusters create [CLUSTER_NAME] \ - --zone [COMPUTE_ZONE] \ - --release-channel [RELEASE_CHANNEL] - - where [RELEASE_CHANNEL] is stable or regular according to your needs. -6.5.5 : Using Command Line: - To create a Node pool within the cluster with Integrity Monitoring enabled, run the - following command: - - gcloud beta container node-pools create [NODEPOOL_NAME] \ - --cluster [CLUSTER_NAME] --zone [COMPUTE_ZONE] \ - --shielded-integrity-monitoring - - You will also need to migrate workloads from existing non-conforming Node pools to the - newly created Node pool, then delete the non-conforming pools. -6.5.6 : Using Command Line: - To migrate an existing cluster, you will need to specify the --enable-shielded-nodes flag - on a cluster update command: - - gcloud beta container clusters update [CLUSTER_NAME] \ - --zone [CLUSTER_ZONE] \ - --enable-shielded-nodes -6.5.7 : Using Command Line: - To create a Node pool within the cluster with Secure Boot enabled, run the following - command: - - gcloud beta container node-pools create [NODEPOOL_NAME] \ - --cluster [CLUSTER_NAME] --zone [COMPUTE_ZONE] \ - --shielded-secure-boot - - You will also need to migrate workloads from existing non-conforming Node pools to the - newly created Node pool, then delete the non-conforming pools. -6.6.1 : Using Command Line: - To enable intranode visibility on an existing cluster, run the following command: - - gcloud beta container clusters update [CLUSTER_NAME] \ - --enable-intra-node-visibility -6.6.2 : Using Command Line: - To enable Alias IP on a new cluster, run the following command: - - gcloud container clusters create [CLUSTER_NAME] \ - --zone [COMPUTE_ZONE] \ - --enable-ip-alias -6.6.3 : Using Command Line: - To check Master Authorized Networks status for an existing cluster, run the following - command; - - gcloud container clusters describe [CLUSTER_NAME] \ - --zone [COMPUTE_ZONE] \ - --format json | jq '.masterAuthorizedNetworksConfig' - - The output should return - - { - "enabled": true - } - - if Master Authorized Networks is enabled. - - If Master Authorized Networks is disabled, the - above command will return null ( { } ). -6.6.4 : Using Command Line: - Create a cluster with a Private Endpoint enabled and Public Access disabled by including - the --enable-private-endpoint flag within the cluster create command: - - gcloud container clusters create [CLUSTER_NAME] \ - --enable-private-endpoint - - Setting this flag also requires the setting of --enable-private-nodes , --enable-ip-alias - and --master-ipv4-cidr=[MASTER_CIDR_RANGE] . -6.6.5 : Using Command Line: - To create a cluster with Private Nodes enabled, include the --enable-private-nodes flag - within the cluster create command: - - gcloud container clusters create [CLUSTER_NAME] \ - --enable-private-nodes - - Setting this flag also requires the setting of --enable-ip-alias and --master-ipv4- - cidr=[MASTER_CIDR_RANGE] . -6.6.6 : Using Command Line: - Use the following command to generate firewall rules, setting the variables as appropriate. - You may want to use the target [TAG] and [SERVICE_ACCOUNT] previously identified. - - gcloud compute firewall-rules create FIREWALL_RULE_NAME \ - --network [NETWORK] \ - --priority [PRIORITY] \ - --direction [DIRECTION] \ - --action [ACTION] \ - --target-tags [TAG] \ - --target-service-accounts [SERVICE_ACCOUNT] \ - --source-ranges [SOURCE_CIDR-RANGE] \ - --source-tags [SOURCE_TAGS] \ - --source-service-accounts=[SOURCE_SERVICE_ACCOUNT] \ - --destination-ranges [DESTINATION_CIDR_RANGE] \ - --rules [RULES] -6.6.7 : Using Command Line: - To enable Network Policy for an existing cluster, firstly enable the Network Policy add-on: - - gcloud container clusters update [CLUSTER_NAME] \ - --zone [COMPUTE_ZONE] \ - --update-addons NetworkPolicy=ENABLED - - Then, enable Network Policy: - - gcloud container clusters update [CLUSTER_NAME] \ - --zone [COMPUTE_ZONE] \ - --enable-network-policy -6.6.8 : If services of type:LoadBalancer are discovered, consider replacing the Service with an Ingress. - - To configure the Ingress and use Google-managed SSL certificates, follow the instructions - as listed at https://cloud.google.com/kubernetes-engine/docs/how-to/managed-certs. -6.7.1 : Using Command Line: - - STACKDRIVER KUBERNETES ENGINE MONITORING SUPPORT (PREFERRED): - To enable Stackdriver Kubernetes Engine Monitoring for an existing cluster, run the - following command: - - gcloud container clusters update [CLUSTER_NAME] \ - --zone [COMPUTE_ZONE] \ - --enable-stackdriver-kubernetes - - LEGACY STACKDRIVER SUPPORT: - Both Logging and Monitoring support must be enabled. - To enable Legacy Stackdriver Logging for an existing cluster, run the following command: - - gcloud container clusters update [CLUSTER_NAME] --zone [COMPUTE_ZONE] \ - --logging-service logging.googleapis.com - - To enable Legacy Stackdriver Monitoring for an existing cluster, run the following - command: - - gcloud container clusters update [CLUSTER_NAME] --zone [COMPUTE_ZONE] \ - --monitoring-service monitoring.googleapis.com -6.7.2 : Using Command Line: - Download the example manifests: - - curl https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-node-tools/master/os-audit/cos-auditd-logging.yaml \ - > cos-auditd-logging.yaml - - Edit the example manifests if needed. Then, deploy them: - - kubectl apply -f cos-auditd-logging.yaml - - Verify that the logging Pods have started. If you defined a different Namespace in your - manifests, replace cos-auditd with the name of the namespace you're using: - - kubectl get pods --namespace=cos-auditd -6.8.1 : Using Command Line: - To update an existing cluster and disable Basic Authentication by removing the static - password: - - gcloud container clusters update [CLUSTER_NAME] \ - --no-enable-basic-auth -6.8.2 : Using Command Line: - Create a new cluster without a Client Certificate: - - gcloud container clusters create [CLUSTER_NAME] \ - --no-issue-client-certificate -6.8.3 : Using Command Line: - Follow the G Suite Groups instructions at https://cloud.google.com/kubernetes- - engine/docs/how-to/role-based-access-control#google-groups-for-gke. - - Then, create a cluster with - - gcloud beta container clusters create my-cluster \ - --security-group="gke-security-groups@[yourdomain.com]" - - Finally create Roles, ClusterRoles, RoleBindings, and ClusterRoleBindings that - reference your G Suite Groups. -6.8.4 : Using Command Line: - To disable Legacy Authorization for an existing cluster, run the following command: - - gcloud container clusters update [CLUSTER_NAME] \ - --zone [COMPUTE_ZONE] \ - --no-enable-legacy-authorization -6.9.1 : Using Command Line: - FOR NODE BOOT DISKS: - Create a new node pool using customer-managed encryption keys for the node boot disk, of - [DISK_TYPE] either pd-standard or pd-ssd : - - gcloud beta container node-pools create [CLUSTER_NAME] \ - --disk-type [DISK_TYPE] \ - --boot-disk-kms-key \ - projects/[KEY_PROJECT_ID]/locations/[LOCATION]/keyRings/[RING_NAME]/cryptoKeys/[KEY_NAME] - - Create a cluster using customer-managed encryption keys for the node boot disk, of - [DISK_TYPE] either pd-standard or pd-ssd : - - gcloud beta container clusters create [CLUSTER_NAME] \ - --disk-type [DISK_TYPE] \ - --boot-disk-kms-key \ - projects/[KEY_PROJECT_ID]/locations/[LOCATION]/keyRings/[RING_NAME]/cryptoKeys/[KEY_NAME] - - FOR ATTACHED DISKS: - Follow the instructions detailed at https://cloud.google.com/kubernetes- - engine/docs/how-to/using-cmek. -6.10.1 : Using Command Line: - To disable the Kubernetes Dashboard on an existing cluster, run the following command: - - gcloud container clusters update [CLUSTER_NAME] \ - --zone [ZONE] \ - --update-addons=KubernetesDashboard=DISABLED -6.10.2 : Using Command Line: - Upon creating a new cluster - - gcloud container clusters create [CLUSTER_NAME] \ - --zone [COMPUTE_ZONE] - - Do not use the --enable-kubernetes-alpha argument. -6.10.3 : Using Command Line: - To enable Pod Security Policy for an existing cluster, run the following command: - - gcloud beta container clusters update [CLUSTER_NAME] \ - --zone [COMPUTE_ZONE] \ - --enable-pod-security-policy -6.10.4 : Using Command Line: - To enable GKE Sandbox on an existing cluster, a new Node pool must be created. - - gcloud container node-pools create [NODE_POOL_NAME] \ - --zone=[COMPUTE-ZONE] \ - --cluster=[CLUSTER_NAME] \ - --image-type=cos_containerd \ - --sandbox type=gvisor -6.10.5 : Using Command Line: - Firstly, update the cluster to enable Binary Authorization: - - gcloud container cluster update [CLUSTER_NAME] \ - --zone [COMPUTE-ZONE] \ - --enable-binauthz - - Create a Binary Authorization Policy using the Binary Authorization Policy Reference - (https://cloud.google.com/binary-authorization/docs/policy-yaml-reference) for - guidance. - - Import the policy file into Binary Authorization: - - gcloud container binauthz policy import [YAML_POLICY] -6.10.6 : Using Command Line: - Follow the instructions at https://cloud.google.com/security-command- - center/docs/quickstart-scc-setup. diff --git a/scripts/kubeBench/kubecis_ocp_4_3.rem b/scripts/kubeBench/kubecis_ocp_4_3.rem deleted file mode 100644 index 4135186..0000000 --- a/scripts/kubeBench/kubecis_ocp_4_3.rem +++ /dev/null @@ -1,243 +0,0 @@ -1.1.1 : In OpenShift 4 the kube-apiserver is deployed as a static pod and its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/kube-apiserver-pod.yaml. It is mounted via hostpath to the kube-apiserver pods via /etc/kubernetes/static-pod-resources/kube-apiserver-pod.yaml with permissions 0644. -1.1.2 : In OpenShift 4 the kube-apiserver is deployed as a static pod and its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/kube-apiserver-pod.yaml. It is mounted via hostpath to the kube-apiserver pods via /etc/kubernetes/static-pod-resources/kube-apiserver-pod.yaml with ownership root:root. -1.1.3 : In OpenShift 4 the kube-controller-manager is deployed as a static pod and its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/kube-controller-manager-pod.yaml. It is mounted via hostpath to the kube-controller-manager pods via /etc/kubernetes/static-pod-resources/kube-controller-manager-pod.yaml with permissions 0644. -1.1.4 : In OpenShift 4 the kube-controller-manager is deployed as a static pod and its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/kube-controller-manager-pod.yaml. It is mounted via hostpath to the kube-controller-manager pods via /etc/kubernetes/static-pod-resources/kube-controller-manager-pod.yaml with ownership root:root. -1.1.5 : In OpenShift 4 the kube-scheduler is deployed as a static pod and its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/kube-scheduler-pod.yaml. It is mounted via hostpath to the kube-controller-manager pods via /etc/kubernetes/static-pod-resources/kube-scheduler-pod.yaml with permissions 0644. -1.1.6 : In OpenShift 4 the kube-scheduler is deployed as a static pod and its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/kube-scheduler-pod.yaml. It is mounted via hostpath to the kube-controller-manager pods via /etc/kubernetes/static-pod-resources/kube-scheduler-pod.yaml with ownership root:root. -1.1.7 : In OpenShift 4 etcd is deployed as a static pod and its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/etcd-member.yaml with permissions 0644. -1.1.8 : In OpenShift 4 etcd is deployed as a static pod and its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/etcd-member.yaml with ownership root:root. -1.1.9 : Ensure that the Container Network Interface file permissions, openshift-sdn and Open vSwitch file permissions are set to 644 or more restrictive. OpenShift deploys OVS as a network overlay by default. The SDN components are deployed as DaemonSets across the master/worker nodes with controllers limited to control plane nodes. Various configurations (ConfigMaps and other files managed by the operator via hostpath but stored on the container hosts) are stored in the following locations: - - CNI: - /etc/cni/net.d (all files <= 0644) - /host/opt/cni/bin (all files <= 0644, executables 0755) - - SDN: - /var/lib/cni/networks/openshift-sdn (all files <= 0644) - /var/run/openshift-sdn (all files <= 0644) - - OVS: - /var/run/openvswitch (all files <= 0644) - /var/run/kubernetes (no files) - /etc/openvswitch (all files <= 0644) - /run/openvswitch (all files <= 0644) - /var/run/openvswitch (all files <= 0644) -1.1.10 : Ensure that the Container Network Interface file ownership is set to root:root. Ensure that the openshift-sdn file ownership is set to root:root and the Open vSwitch (OVS) file ownership is set to openvswitch:openvswitch. OpenShift deploys OVS as a network overlay by default. The SDN components are deployed as DaemonSets across the master/worker nodes with controllers limited to control plane nodes. Various configurations (ConfigMaps and other files managed by the operator via hostpath but stored on the container hosts) are stored in the following locations: - - CNI: - /etc/cni/net.d (ownership is 0:0) - /host/opt/cni/bin (ownership is 0:0) - - SDN: - /var/lib/cni/networks/openshift-sdn (ownership is 0:0) - /var/run/openshift-sdn (ownership is 0:0) - - OVS: - /var/run/openvswitch (ownership is 998:996 or openvswitch:openvswitch) - /var/run/kubernetes (ownership is 0:0) - /etc/openvswitch (ownership is 998:996 or openvswitch:openvswitch) - /run/openvswitch (ownership is 998:996 or openvswitch:openvswitch) - /var/run/openvswitch (ownership is 998:996 or openvswitch:openvswitch) -1.1.11 : In OpenShift 4 etcd runs as a static pod on each control plane node. The etcd database is stored on the container host in /var/lib/etcd and mounted to the etcd-member container via the host path mount data-dir with the same filesystem path. The permissions for this directory on the etcd-member container is 755 and on the container host is 0700 (check on this). -1.1.12 : In OpenShift 4 etcd runs as a static pod on each control plane node. The etcd database is stored on the master nodes in /var/lib/etcd and mounted to the etcd-member container via the host path mount data-dir with the same filesystem path. The ownership for this directory (on the etcd-member container and on the container host) is root:root. In OCP 4, etcd cannot be deployed on separate nodes. For this reason, etcd ownership is managed in the same way as all other master components. This is not expected to change. - - Furthermore, OCP 4.4 includes a new etcd operator. The etcd operator will help to automate restoration of master nodes. There is also a new etcdctl container in the etcd static pod for quick debugging. cluster-admin rights are required to exec into etcd containers. -1.1.13 : In OpenShift 4 the kubeconfig file for system:admin (admin.conf) is stored in /etc/kubernetes/kubeconfig with permissions 0644. -1.1.14 : In OpenShift 4 the kubeconfig file for system:admin (admin.conf) is stored in /etc/kubernetes/kubeconfig with ownership root:root. -1.1.15 : The kubeconfig file for kube-scheduler is stored in the ConfigMap scheduler-kubeconfig in the namespace openshift-kube-scheduler. The file kubeconfig (scheduler.conf) is referenced in the pod via hostpath and is stored in /etc/kubernetes/static-pod-resources/configmaps/scheduler-kubeconfig/kubeconfig with permissions 0644. -1.1.16 : The kubeconfig file for kube-scheduler is stored in the ConfigMap scheduler-kubeconfig in the namespace openshift-kube-scheduler. The file kubeconfig (scheduler.conf) is referenced in the pod via hostpath and is stored in /etc/kubernetes/static-pod-resources/configmaps/scheduler-kubeconfig/kubeconfig with ownership root:root. -1.1.17 : The kubeconfig file for kube-controller-manager is stored in the ConfigMap controller-manager-kubeconfig in the namespace openshift-kube-controller-manager. The file kubeconfig (controller-manager.conf) is referenced in the pod via hostpath and is stored in /etc/kubernetes/static-pod-resources/configmaps/controller-manager-kubeconfig/kubeconfig with permissions 0644. -1.1.18 : The kubeconfig file for kube-controller-manager is stored in the ConfigMap controller-manager-kubeconfig in the namespace openshift-kube-controller-manager. The file kubeconfig (controller-manager.conf) is referenced in the pod via hostpath and is stored in /etc/kubernetes/static-pod-resources/configmaps/controller-manager-kubeconfig/kubeconfig with ownership root:root. -1.1.19 : Keys for control plane components like kube-apiserver, kube-controller-manager, kube-scheduler and etcd are stored with their respective static pod configurations in the directory /etc/kubernetes/static-pod-resources/*/secrets. The directory and file ownership are set to root:root. -1.1.20 : Certificates for control plane components like kube-apiserver, kube-controller-manager, kube-scheduler and etcd are stored with their respective static pod configurations in the directory /etc/kubernetes/static-pod-resources/*/secrets. Certificate files all have permissions 0600. -1.1.21 : Keys for control plane components like kube-apiserver, kube-controller-manager, kube-scheduler and etcd are stored with their respective static pod configurations in the directory /etc/kubernetes/static-pod-resources/*/secrets. Key files all have permissions 0600. -1.2.1 : OpenShift provides it's own fully integrated authentication and authorization mechanism. OpenShift allows anonymous requests to the API server to support information discovery and webhook integrations. Anonymous requests are assigned the system:unauthenticated group, which is bound to cluster-scoped roles. Verify that the default behavior is maintained. If the default behavior is changed, platform components will not work properly, in particular Elasticsearch and Prometheus. The oauth-proxy deployed as part of these components makes anonymous use of /.well-known/oauth-authorization-server endpoint, granted by system:discovery role. -1.2.2 : OpenShift provides it's own fully integrated authentication and authorization mechanism. The apiserver is protected by either requiring an OAuth token issued by the platform's integrated OAuth server or signed certificates. By default the basic-auth-file method is not enabled in OpenShift. -1.2.3 : OpenShift does not use token-auth-file flag. OpenShift includes a built-in OAuth server rather than relying on a static token file. The OAuth server is integrated with the API server. -1.2.4 : OpenShift utilizes X.509 certificates for authentication of the control-plane components. OpenShift configures the API server to use an internal certificate authority (CA) to validate the user certificate sent during TLS negotiation. If the CA validation of the certificate is successful, the request is authenticated and user information is derived from the certificate subject fields. Certificates for control plane components like kube-apiserver, kube-controller-manager, kube-scheduler and etcd are stored with their respective static pod configurations in the directory /etc/kubernetes/static-pod-resources/*/secrets. -1.2.5 : OpenShift uses X.509 certificates to provide secure connections between API server and node/kubelet. OpenShift does not use kubelet-certificate-authority flag. The platform includes multiple certificate authorities (CAs) providing independent chains of trust, increasing the security posture of the cluster. The certificates generated by each CA are used to identify a particular OpenShift platform component to another OpenShift platform component. Communication between the API server and the kubelet is secured by the kubelet serving CA. -1.2.6 : OpenShift uses X.509 certificates to provide secure connections between API server and node/kubelet. OpenShift does not use kubelet-certificate-authority flag. The platform includes multiple certificate authorities (CAs) providing independent chains of trust, increasing the security posture of the cluster. The certificates generated by each CA are used to identify a particular OpenShift platform component to another OpenShift platform component. Communication between the API server and the kubelet is secured by the kubelet serving CA -1.2.7 : When the --authorization-mode argument is set to AlwaysAllow, the API Server allows all requests. It is not possible to configure an OpenShift cluster this way. The --authorization-mode flag is not used by OpenShift API Server. OpenShift is configured to use RBAC to authorize requests. See https://docs.openshift.com/container-platform/4.3/authentication/using-rbac.html - - Additional notes: - Requests to the API server are authenticated by X.509 certificates. External access to the API server is through the Ingress controller. A custom certificate can be added to the ingress controller. - - Role-based access control (RBAC) objects determine what actions a user is allowed to perform on what objects in an OpenShift cluster. Cluster administrators manage RBAC for the cluster. Project owners can manage RBAC for their individual OpenShift projects. -1.2.8 : In OpenShift, the Node authorizer is enabled by default. The authorization-mode argument is not configurable for the API server. The OpenShift API server does not use the values assigned to the flag authorization-mode. -1.2.9 : OpenShift supports RBAC. The --authorization-mode flag is not used by OpenShift API Server. -1.2.10: EventRateLimit admission plugin is alpha and cannot be enabled in Openshift. It was developed to alleviate the potential issue of flooding the API server with requests. However, the kubelet has since been fixed to send fewer events. In future Kubernetes releases, api priority and fairness will be used to limit the rate at which the API server accepts requests. -1.2.11: OpenShift does not enable the AlwaysAdmit admission control plugin. It cannot be enabled. -1.2.12: When OpenShift Container Platform creates containers, it uses the container’s imagePullPolicy to determine if the image should be pulled prior to starting the container. There are three possible values for imagePullPolicy: Always, IfNotPresent, Never. If a container’s imagePullPolicy parameter is not specified, OpenShift Container Platform sets it based on the image’s tag. If the tag is latest, OpenShift Container Platform defaults imagePullPolicy to Always. Otherwise, OpenShift Container Platform defaults imagePullPolicy to IfNotPresent. -1.2.13: In OpenShift, RBAC roles can restrict access to pod subresources 'exec' and 'attach', while Security Context Constraints (SCCs) restrict access to run privileged containers. By default, OpenShift runs pods on worker nodes as unprivileged (with the restricted SCC). Unlike upstream Kubernetes, OpenShift does not enable the DenyEscalatingExec admission control plugin. OpenShift's Security Context Constraints (SCCs) provide the same level of restriction and have been contributed to Kubernetes as Pod Security Policies. PSPs are still beta in Kubernetes. -1.2.14: The ServiceAccount admission control plugin is enabled by default. Every service account has an associated user name that can be granted roles, just like a regular user. The user name for each service account is derived from its project and the name of the service account. Service accounts are required in each project to run builds, deployments, and other pods. The default service accounts that are automatically created for each project are isolated by the project namespace. -1.2.15: OpenShift enables both the upstream NamespaceLifecycle and OriginNamespaceLifecycle plugins. Openshift's own OriginNamespaceLifecycle admission plugin implements the CIS recommendation of preventing resources from being created while the namespace is being terminated. -1.2.16: OpenShift provides the same protection via the SecurityContextConstraints admission plugin, which is enabled by default. PodSecurityPolicy admission control plugin is disabled by default as it is still beta and not yet supported with OpenShift. - Security Context Constraints and Pod Security Policy cannot be used on the same cluster. -1.2.17: The NodeRestriction admission plugin is enabled by default in OCP 4. It cannot be disabled. -1.2.18: OpenShift API server is served over HTTPS with authentication and authorization; the secure API endpoint is bound to 0.0.0.0:8443 by default. -1.2.19: OpenShift API server is served over HTTPS with authentication and authorization; the secure API endpoint is bound to 0.0.0.0:8443 by default. -1.2.20: By default, traffic for the OpenShift API server is served over HTTPS with authentication and authorization; the secure API endpoint is bound to 0.0.0.0:8443. - - In OCP 4 the only supported way to access the API server pod is through the load balancer and then through the internal service. -1.2.21: Profiling is used to collect data to identify performance bottlenecks. To ensure the collected data is not exploited, profiling endpoints are exposed at each master port and secured via RBAC (see cluster-debugger role). By default, the profiling endpoints are accessible only by users bound to cluster-admin or cluster-debugger role. - - OpenShift exposes profiling in the web interface on localhost (a hostname that means this computer) if OPENSHIFT_PROFILE=web is set in master.env (?). This configuration is only meant to be used for OpenShift core development, and is never recommended for a live cluster. - - Although the profiling endpoint for API server can be completely disabled using the profiling flag under apiServerArguments, we do not recommend this as the endpoint is protected by RBAC and disabling profiling makes it more difficult to troubleshoot any problems. - Recommendation - Ensure OPENSHIFT_PROFILE is not set to web, which would expose the web interface on localhost. - - Verify status for OCP 4. -1.2.22: OpenShift audit works at the API server level, logging all requests coming to the server. API server audit is on by default. -1.2.23: OpenShift audit works at the API server level, logging all requests coming to the server. Configure via maximumFileRetentionDays. -1.2.24: OpenShift audit works at the API server level, logging all requests coming to the server. Configure via maximumRetainedFiles. -1.2.25: OpenShift audit works at the API server level, logging all requests coming to the server. Configure via maximumFileSizeMegabytes. -1.2.26: In OpenShift, the request-timeout flag defaults to 60 seconds. This can be increased if you wish. OpenShift configures the min-request-timeout flag via servingInfo.requestTimeoutSeconds via ???, which overrides request-timeout in certain scenarios and provides a more balanced timeout approach than a global request-timeout. OpenShift configures requestTimeoutSeconds with a default value of 3600 seconds (one hour). -1.2.27: OpenShift denies access for any OAuth Access token that does not exist in its etcd data store. OpenShift does not use the service-account-lookup flag. -1.2.28: OpenShift API server does not use the service-account-key-file argument. The ServiceAccount token authenticator is configured with serviceAccountConfig.publicKeyFiles. OpenShift does not reuse the apiserver TLS key. -1.2.29: OpenShift uses X.509 certificates to provide secure communication to etcd. OpenShift configures these automatically. OpenShift does not use the etcd-certfile or etcd-keyfile flags. - - /etc/kubernetes/static-pod-resources/secrets/etcd-client/tls.crt - - /etc/kubernetes/static-pod-resources/secrets/etcd-client/tls.key -1.2.30: OpenShift uses X.509 certificates to provide secure connections between API server and node/kubelet by default. OpenShift does not use values assigned to the tls-cert-file or tls-private-key-file flags. OpenShift generates these files and sets the arguments appropriately. - - /etc/kubernetes/static-pod-certs/secrets/service-network-serving-certkey/tls.crt - - /etc/kubernetes/static-pod-certs/secrets/service-network-serving-certkey/tls.key -1.2.31: OpenShift includes multiple certificate authorities (CAs) providing independent chains of trust, increasing the security posture of the cluster. The certificates generated by each CA are used to identify a particular OpenShift platform component to another OpenShift platform component. OpenShift configures the client-ca-file value and does not use value assigned to the client-ca-file flag. -1.2.32: OpenShift uses X.509 certificates to provide secure communication to etcd. OpenShift does not use values assigned to etcd-cafile. OpenShift generates this file and sets the arguments appropriately in the API server. OpenShift includes multiple certificate authorities (CAs) providing independent chains of trust, increasing the security posture of the cluster. The certificates generated by each CA are used to identify a particular OpenShift platform component to another OpenShift platform component. Communication with etcd is secured by the etcd serving CA. -1.2.33: OpenShift supports encryption of data at rest of etcd datastore, but it is up to the customer to configure. The ase-cbc cipher is used. Keys are stored on the filesystem of the master and automatically rotated. -1.2.34: OpenShift supports encryption of data at rest of etcd datastore, but it is up to the customer to configure. The ase-cbc cipher is used. Keys are stored on the filesystem of the master and automatically rotated. -1.2.35: The API server is only accessible through the load balancer. Ciphers for the ingress controller can be configured as of OpenShfit 4.3. The ability to configure cipher suites separately for the API server is on the roadmap. -1.3.3 : In OpenShift, every service account has an associated user name that can be granted roles, just like a regular user. The user name is derived from its project and name. As soon as a service account is created, two secrets are automatically added to it: an API token and credentials for the OpenShift Container Registry. The system ensures that service accounts always have an API token and registry credentials. -1.3.4 : By default, OpenShift starts kube-controller-manager with service-account-private-key-file=/etc/origin/master/servicaccounts.private.key. - - In OpenShift, every service account has an associated user name that can be granted roles, just like a regular user. The user name is derived from its project and name. As soon as a service account is created, two secrets are automatically added to it: an API token and credentials for the OpenShift Container Registry. The system ensures that service accounts always have an API token and registry credentials. - - In OpenShift 4, the kube-controller-manager is managed with the cluster Controller Manager Operator. -1.3.5 : OpenShift maps the master configuration serviceAccountConfig.masterCA to the kube-controller-manager root-ca-file flag, setting it to /etc/origin/master/ca-bundle.crt by default. -1.3.6 : Certificates for the kubelet are automatically created and rotated by the OpenShift Container Platform. The kubelet is installed automatically on every RHCOS node. The OpenShift kubelet-serving-CA manages certificates for the kubelet. Kubelet certificates are automatically issued and rotated. -1.3.7 : In OpenShift 4, the Controller Manager is managed by the Kubernetes Controller Manager Operator. - https://github.com/openshift/cluster-kube-controller-manager-operator - - In Openshift 4, the Controller Manager is deployed as a static pod. Static Pods are managed by the kubelet and are always bound to one Kubelet on a specific node. The kubelet automatically creates a mirror Pod on the API server for each static pod. This means that the pods running on a node are visible on the API server, but cannot be controlled from there. The bind-address argument is not used. -2.1 : OpenShift uses X.509 certificates to provide secure communication to etcd. OpenShift generates these files and sets the arguments appropriately. OpenShift does not use the etcd-certfile or etcd-keyfile flags. -2.2 : OpenShift uses X.509 certificates to provide secure communication to etcd. OpenShift installation generates these files and sets the arguments appropriately. -2.3 : OpenShift configures etcd with secure communication. Openshift installs etcd as static pods on control plane nodes, and mounts the configuration files from /etc/etcd/ on the host. The etcd.conf file includes peer-auto-tls configurations as referenced in /etc/etcd/etcd.conf. -2.4 : OpenShift configures etcd with secure communication. Openshift installs etcd as static pods on control plane nodes, and mounts the configuration files from /etc/etcd/ on the host. The etcd.conf file includes peer-cert-file and peer-key-file configurations as referenced in /etc/etcd/etcd.conf. -2.5 : OpenShift configures etcd with secure communication. Openshift installs etcd as static pods on control plane nodes, and mounts the configuration files from /etc/etcd/ on the host. The etcd.conf file includes peer-client-cert-auth configurations as referenced to the right. -2.6 : OpenShift configures etcd with secure communication. Openshift installs etcd as static pods on control plane nodes, and mounts the configuration files from /etc/etcd/ on the host. The etcd.conf file includes peer-auto-tls configurations as referenced in /etc/etcd/etcd.conf. -2.7 : OpenShift provides integrated management of certificates for internal cluster components. OpenShift 4 includes multiple CAs providing independent chains of trust, which ensure that a platform CA will never accidentally sign a certificate that can be used for the wrong purpose, increasing the security posture of the cluster. A unique CA is provided for etcd. -3.1.1 : For users to interact with OpenShift Container Platform, they must first authenticate to the cluster. The authentication layer identifies the user associated with requests to the OpenShift Container Platform API. The authorization layer then uses information about the requesting user to determine if the request is allowed. - https://docs.openshift.com/container-platform/4.3/authentication/understanding-authentication.html - - The OpenShift Container Platform master includes a built-in OAuth server for token-based authentication. Developers and administrators obtain OAuth access tokens to authenticate themselves to the API. It is recommended for an administrator to configure OAuth to specify an identity provider after the cluster is installed. User access to the cluster is managed through the identity provider. - https://docs.openshift.com/container-platform/4.3/authentication/understanding-identity-provider.html - - OpenShift includes built-in role based access control (RBAC) to determine whether a user is allowed to perform a given action within the cluster. Roles can have cluster scope or local (i.e. project) scope. - https://docs.openshift.com/container-platform/4.3/authentication/using-rbac.html - - In addition, OpenShift ships with a Service-CA which is intended intended to support service serving certificates for complex middleware applications that require encryption. These certificates are issued as TLS web server certificates. The service-ca controller uses the x509.SHA256WithRSA signature algorithm to generate service certificates. The service CA certificate, which issues the service certificates, is valid for 26 months and is automatically rotated when there is less than six months validity left. A Pod can access the service CA certificate by mounting a ConfigMap that is annotated with service.beta.openshift.io/inject-cabundle=true. Once annotated, the cluster automatically injects the service CA certificate into the service-ca.crt key on the ConfigMap. Access to this CA certificate allows TLS clients to verify connections to services using service serving certificates. You can manually rotate the service certificate by deleting the associated secret. Deleting the secret results in a new one being automatically created, resulting in a new certificate. - https://docs.openshift.com/container-platform/4.3/authentication/certificates/service-serving-certificate.html -3.2.1 : In OpenShift, auding of the API Server is on by default. Audit provides a security-relevant chronological set of records documenting the sequence of activities that have affected system by individual users, administrators, or other components of the system. Audit works at the API server level, logging all requests coming to the server. Each audit log contains two entries: - - The request line containing: - A Unique ID allowing to match the response line (see #2) - The source IP of the request - The HTTP method being invoked - The original user invoking the operation - The impersonated user for the operation (self meaning himself) - The impersonated group for the operation (lookup meaning user’s group) - The namespace of the request or - The URI as requested - - The response line containing: - The unique ID from #1 - The response code - - You can view logs for the master nodes for the OpenShift Container Platform API server or the Kubernetes API server. - https://docs.openshift.com/container-platform/4.3/nodes/nodes/nodes-nodes-audit-log.html -3.2.2 : You can configure the audit feature to set log level, retention policy, and the type of events to log. - You can set the log level settings for an overall component or the API server to one of the following. The setting can be different for each setting: - - Normal. Normal is the default. Normal working log information, including helpful notices for auditing or common operations. Similar to glog=2. - - Debug. Debug is for troubleshooting problems. A greater quanitity of notices than Normal, but contain less information than Trace. Common operations might be logged. Similar to glog=4. - - Trace. Trace is for troubleshooting problems when Debug is not verbose enough. Logs every function call as part of a common operation, including tracing execution of a query. Similar to glog=6. - - TraceAll. TraceAll is troubleshoting at the level of API content/decoding. Contains complete body content. In production clusters, this setting causes performance degradation and results in a significant number of logs. Similar to ` glog=8`. - - https://docs.openshift.com/container-platform/4.3/nodes/nodes/nodes-nodes-audit-log.html#nodes-nodes-audit-log-basic-config_nodes-nodes-audit-log -4.1.1 : Kubelet is run as atomic-openshift-node systemd unit and its configuration file is created with 644 permissions. -4.1.2 : Kubelet is run as atomic-openshift-node systemd unit and its configuration file is created with root:root ownership. -4.1.5 : The node's kubeconfig is created with 644 permissions. -4.1.6 : The node's kubeconfig is created with root:root. -4.1.7 : Client CA location defined in /etc/kubernetes/kubelet.conf: - - kind: KubeletConfiguration - apiVersion: kubelet.config.k8s.io/v1beta1 - authentication: - x509: - clientCAFile: /etc/kubernetes/kubelet-ca.crt - anonymous: - enabled: false - - /etc/kubernetes/kubelet-ca.crt has permissions 0644 -4.1.8 : Client CA location defined in /etc/kubernetes/kubelet.conf: - - kind: KubeletConfiguration - apiVersion: kubelet.config.k8s.io/v1beta1 - authentication: - x509: - clientCAFile: /etc/kubernetes/kubelet-ca.crt - anonymous: - enabled: false - - /etc/kubernetes/kubelet-ca.crt is owned by root:root -4.1.9 : /var/lib/kubelet/kubeconfig permissions set to 0600 -4.1.10 : /var/lib/kubelet/kubeconfig ownership set to root:root -4.2.1 : OpenShift uses a different approach to secure anonymous authorization. OpenShift explicitly sets anonymous-auth to true, as anonymous requests are used for discovery information, webhook integrations, etc. OpenShift allows anonymous requests (then authorizes them). - Access to OpenShift node is authenticated with certificate. kubelet apis are subresources of the node resource that can be restricted by RBAC roles. Anonymous access is denied for these subresources. OpenShift provides it's own fully integrated authentication and authorization mechanism. Unsecured endpoints reveal no sensitive data. Unauthenticated requests to secured endpoints are assigned to 'system:anonymous'. system:anonymous is not bound to any roles, and thus has no visibility by default. -4.2.2 : Unauthenticated/Unauthorized users have no access to OpenShift nodes. Kubelet flag authorization-mode is explicitly set to WebHook -4.2.3 : OpenShift provides integrated management of certificates for internal cluster components. OpenShift 4 includes multiple CAs providing independent chains of trust, which ensure that a platform CA will never accidentally sign a certificate that can be used for the wrong purpose, increasing the security posture of the cluster. Communication between the API server and the kubelet is secured by the kubelet serving CA. -4.2.4 : OpenShift disables the read-only port (10255) on all nodes by setting the read-only-port kubelet flag to 0 by defualt. -4.2.5 : OpenShift uses the kubernetes default of 4 hours for the streaming-connection-idle-timeout argument. Unless cluster administrator has added the value to the node configuration, the default will be used. The value is a timeout for HTTP streaming sessions going through a kubelet, like the port-forward, exec, or attach pod operations. The streaming-connection-idle-timeout should not be disabled by setting it to zero, but it can be lowered. Note that if the value is set too low, then users using those features may experience a service interruption due to the timeout. kubelet flags can be added to kubeletArguments of /etc/origin/node/node-config.yaml. -4.2.6 : Red Hat disagrees with the CIS recommendation for the protect-kernel-defauts. OpenShift node/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 what the kubelet desires and the OpenShift node to fail to start. -4.2.7 : OpenShift sets the make-iptables-util-changes argument to true by default. -4.2.8 : In OpenShift 4, nodeName will be set to the node hostname that is resolvable from all nodes in the cluster. -4.2.9 : OpenShift sets the event-qps argument to a default value of 5. This is the default set by Kubernetes. When this value is set to > 0, event creations per second are limited to the value set. If this value is set to 0, event creations per second are unlimited. -4.2.10 : OpenShift instead uses the cert-dir flag, for serving HTTPS traffic, which is used in the absence of the proposed flags. OpenShift sets cert-dir flag to /etc/origin/node/certificates, and generates the certificates in this directory for the kubelet to serve HTTPS traffic. -4.2.11 : OpenShift automatically rotates the Kubelet certificates. RotateKubeletClientCertificate to true by default. -4.2.12 : OpenShift automatically rotates the Kubelet certificates. RotateKubeletClientCertificate to true by default. -4.2.13 : All traffic to the API server is encrypted using TLS 1.3 -5.1.1 : OpenShift provides a set of default cluster roles that you can bind to users and groups cluster-wide or locally (per project namespace). Be mindful of the difference between local and cluster bindings. For example, if you bind the cluster-admin role to a user by using a local role binding, it might appear that this user has the privileges of a cluster administrator. This is not the case. Binding the cluster-admin to a user in a project grants super administrator privileges for only that project to the user. You can use the oc CLI to view cluster roles and bindings by using the oc describe command. For more information, see https://docs.openshift.com/container-platform/4.4/authentication/using-rbac.html#default-roles_using-rbac - Some of these roles such as cluster-admin provide wide-ranging privileges which should only be applied where absolutely necessary. Roles such as cluster-admin allow super-user access to perform any action on any resource. When used in a ClusterRoleBinding, it gives full control over every resource in the cluster and in all namespaces. When used in a RoleBinding, it gives full control over every resource in the rolebinding's namespace, including the namespace itself. - Review users and groups bound to cluster-admin and decide whether they require such access. Consider creating least-privilege roles for users and service accounts. -5.1.2 : Review the users who have get, list or watch access to secrets objects in the Kubernetes API. -5.1.3 : Retrieve the roles defined across each namespaces in the cluster and review for wildcards -5.1.4 : Review the users who have create access to pod objects in the Kubernetes API. -5.1.5 : Every OpenShift project has its own service accounts. Every service account has an associated user name that can be granted roles, just like a regular user. The user name for each service account is derived from its project and the name of the service account. Service accounts are required in each project to run builds, deployments, and other pods. The default service accounts that are automatically created for each project are isolated by the project namespace. -5.1.6 : Where possible, remove get, list and watch access to secret objects in the cluster. -5.2.1 : By default, privileged containers will not run on OpenShift worker nodes. -5.2.2 : By default, containers running on OpenShift worker nodes do not share the host process ID namespace. -5.2.3 : By default, containers running on OpenShift worker nodes do not share the host process IPC namespace. -5.2.4 : By default, containers running on OpenShift worker nodes do not share the host process network namespace. -5.2.5 : By default, privileged containers will not run on OpenShift worker nodes. The restricted SCC also prevents privilege escalation. -5.2.6 : By default, privileged containers will not run on OpenShift worker nodes. -5.2.7 : By default, containers running on OpenShift worker nodes are not granted the NET_RAW capability. -5.2.8 : By default, containers running on OpenShift worker nodes are granted no additional capabilities. -5.2.9 : By default, containers running on OpenShift worker nodes are granted no additional capabilities. -5.3.1 : OpenShift Container Platform uses a software-defined networking (SDN) approach to provide a unified cluster network that enables communication between Pods across the OpenShift Container Platform cluster. This Pod network is established and maintained by the OpenShift SDN, which configures an overlay network using Open vSwitch (OVS). The OpenShift SDN uses Network Policies. -5.3.2 : The OpenShift 4 CNI plugin uses network policies by default -- that is, it runs in ovs-networkpolicy mode. By default, all Pods in a project are accessible from other Pods and network endpoints. To isolate one or more Pods in a project, you can create NetworkPolicy objects in that project to indicate the allowed incoming connections. Project administrators can create and delete NetworkPolicy objects within their own project. -5.4.1 : Information about ways to provide sensitive data to pods is included in the documentation. - https://docs.openshift.com/container-platform/4.3/nodes/pods/nodes-pods-secrets.html -5.4.2 : OpenShift supports a broad ecosystem of security partners many of whom support integration with external vaults. -5.5.1 : You can control which images can be imported, tagged, and run in a cluster using either Allowed Registries for import or the ImagePolicy admission plug-in.The ImagePolicyWebhook admission plugin may be enabled and configured if desired. -5.6.1 : OpenShift Projects wrap Kubernetes namespaces are are used by default in OpenShift 4. -5.6.2 : In OpenShift 4, configuration of allowable seccomp profiles is managed through OpenShift Security Context Constraints. -5.6.3 : OpenShift's Security Context Constraint feature is on by default in OpenShift 4 and applied to all pods deployed on all worker nodes. -5.6.4 : In OpenShift Container Platform, projects (namespaces) are used to group and isolate related objects. When a request is made to create a new project using the web console or oc new-project command, an endpoint in OpenShift Container Platform is used to provision the project according to a template, which can be customized. The cluster administrator can allow and configure how developers and service accounts can create, or self-provision, their own projects. - - Projects starting with openshift- and kube- host cluster components that run as Pods and other infrastructure components. As such, OpenShift Container Platform does not allow you to create Projects starting with openshift- or kube- using the oc new-project command. diff --git a/scripts/kubeBench/kubecis_ocp_4_5.rem b/scripts/kubeBench/kubecis_ocp_4_5.rem deleted file mode 100644 index dad2309..0000000 --- a/scripts/kubeBench/kubecis_ocp_4_5.rem +++ /dev/null @@ -1,248 +0,0 @@ -1.1.1 : OpenShift 4 deploys both the openshift-apiserver and the kube-apiserver. The kube apiserver is deployed as a static pod. The openshift-apiserver is managed as a deployment and the yaml is stored in etcd. - The pod specification file for the kube apiserver is created on the control plane nodes at /etc/kubernetes/manifests/kube-apiserver-pod.yaml. The kube-apiserver is mounted via hostpath to the kube-apiserver pods via /etc/kubernetes/static-pod-resources/kube-apiserver-pod.yaml with permissions 0644. -1.1.2 : OpenShift 4 deploys both the openshift-apiserver and the kube-apiserver. The kube apiserver is deployed as a static pod. The openshift-apiserver is managed as a deployment and the yaml is stored in etcd. - The pod specification file for the kube apiserver is created on the control plane nodes at /etc/kubernetes/manifests/kube-apiserver-pod.yaml. The kube-apiserver is mounted via hostpath to the kube-apiserver pods via /etc/kubernetes/static-pod-resources/kube-apiserver-pod.yaml with ownership root:root. -1.1.3 : OpenShift 4 deploys two controller managers: the openshift-controller-manager and the openshift-kube-controller-manager. The kube-controller-manager is deployed as a static pod. The openshift-controller-manager is managed as a deployment and its yaml is stored in etcd. - The pod specification file for the openshift-kube-controller-manager is created on control plane nodes at /etc/kubernetes/manifests/kube-controller-manager-pod.yaml. It is mounted via hostpath to the controller-manager pods via /etc/kubernetes/static-pod-resources/kube-controller-manager-pod.yaml with permissions 0644. -1.1.4 : OpenShift 4 deploys two controller managers: the openshift-controller-manager and the openshift-kube-controller-manager. The kube-controller-manager is deployed as a static pod. The openshift-controller-manager is managed as a deployment and its yaml is stored in etcd. - The pod specification file for the openshift-kube-controller-manager is created on control plane nodes at /etc/kubernetes/manifests/kube-controller-manager-pod.yaml. It is mounted via hostpath to the kube-controller-manager pods via /etc/kubernetes/static-pod-resources/kube-controller-manager-pod.yaml with ownership root_root. -1.1.5 : In OpenShift 4 the kube-scheduler is deployed as a static pod and its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/kube-scheduler-pod.yaml. It is mounted via hostpath to the kube-controller-manager pods via /etc/kubernetes/static-pod-resources/kube-scheduler-pod.yaml with permissions 0644. -1.1.6 : In OpenShift 4 the kube-scheduler is deployed as a static pod and its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/kube-scheduler-pod.yaml. It is mounted via hostpath to the kube-controller-manager pods via /etc/kubernetes/static-pod-resources/kube-scheduler-pod.yaml with ownership root:root. -1.1.7 : In OpenShift 4 etcd is deployed by the cluster etcd operator. Its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/etcd-pod.yaml with permissions 0644. -1.1.8 : In OpenShift 4 etcd is deployed as a static pod and its pod specification file is created on control plane nodes at /etc/kubernetes/manifests/etcd-pod.yaml with ownership root:root. -1.1.9 : Ensure that the Container Network Interface file permissions, openshift-sdn and Open vSwitch file permissions are set to 644 or more restrictive. OpenShift deploys OVS as a network overlay by default. The SDN components are deployed as DaemonSets across the master/worker nodes with controllers limited to control plane nodes. Various configurations (ConfigMaps and other files managed by the operator via hostpath but stored on the container hosts) are stored in the following locations: - - CNI: - /host/etc/cni/net.d (all files <= 0644) - /host/opt/cni/bin (all files <= 0644, executables 0755) - /host/var/run/multus/cni/net.d - - SDN: - /var/lib/cni/networks/openshift-sdn (all files <= 0644) - /var/run/openshift-sdn (all files <= 0644) - - OVS: - /var/run/openvswitch (all files <= 0644) - /var/run/kubernetes (no files) - /etc/openvswitch (all files <= 0644) - /run/openvswitch (all files <= 0644) - /var/run/openvswitch (all files <= 0644) -1.1.10 : Ensure that the Container Network Interface file ownership is set to root:root. Ensure that the openshift-sdn file ownership is set to root:root and the Open vSwitch (OVS) file ownership is set to openvswitch:openvswitch. OpenShift deploys OVS as a network overlay by default. The SDN components are deployed as DaemonSets across the master/worker nodes with controllers limited to control plane nodes. Various configurations (ConfigMaps and other files managed by the operator via hostpath but stored on the container hosts) are stored in the following locations: - - CNI: - /host/etc/cni/net.d (ownership is 0:0) = CNI_CONF_DIR - /host/opt/cni/bin (ownership is 0:0) = CNI_BIN_DIR - /host/var/run/multus/cni/net.d = multus-cni-dir, confi dir - - SDN / OVS: - /var/run/openvswitch (ownership is 998:996 or openvswitch:openvswitch) - /etc/openvswitch (ownership is 998:996 or openvswitch:openvswitch) - /run/openvswitch (ownership is 998:996 or openvswitch:openvswitch) -1.1.11 : In OpenShift 4 etcd runs as a static pod on each control plane node. The etcd database is stored on the container host in /var/lib/etcd and mounted to the etcd-member container via the host path mount data-dir with the same filesystem path. The permissions for this directory on the container host is 0700. -1.1.12 : In OpenShift 4 etcd runs as a static pod on each control plane node. The etcd database is stored on the master nodes in /var/lib/etcd and mounted to the etcd-member container via the host path mount data-dir with the same filesystem path. The ownership for this directory (on the etcd-member container and on the container host) is root:root. In OCP 4, etcd cannot be deployed on separate nodes. For this reason, etcd ownership is managed in the same way as all other master components. This is not expected to change. - - Furthermore, OCP 4.4 includes a new etcd operator. The etcd operator will help to automate restoration of master nodes. There is also a new etcdctl container in the etcd static pod for quick debugging. cluster-admin rights are required to exec into etcd containers. -1.1.13 : In OpenShift 4 the kubeconfig file for system:admin (admin.conf) is stored in /etc/kubernetes/kubeconfig with permissions 0644. -1.1.14 : In OpenShift 4 the kubeconfig file for system:admin (admin.conf) is stored in /etc/kubernetes/kubeconfig with ownership root:root. -1.1.15 : The kubeconfig file for kube-scheduler is stored in the ConfigMap scheduler-kubeconfig in the namespace openshift-kube-scheduler. The file kubeconfig (scheduler.conf) is referenced in the pod via hostpath and is stored in /etc/kubernetes/static-pod-resources/configmaps/scheduler-kubeconfig/kubeconfig with permissions 0644. -1.1.16 : The kubeconfig file for kube-scheduler is stored in the ConfigMap scheduler-kubeconfig in the namespace openshift-kube-scheduler. The file kubeconfig (scheduler.conf) is referenced in the pod via hostpath and is stored in /etc/kubernetes/static-pod-resources/configmaps/scheduler-kubeconfig/kubeconfig with ownership root:root. -1.1.17 : The kubeconfig file for kube-controller-manager is stored in the ConfigMap controller-manager-kubeconfig in the namespace openshift-kube-controller-manager. The file kubeconfig (controller-manager.conf) is referenced in the pod via hostpath and is stored in /etc/kubernetes/static-pod-resources/configmaps/controller-manager-kubeconfig/kubeconfig with permissions 0644. -1.1.18 : The kubeconfig file for kube-controller-manager is stored in the ConfigMap controller-manager-kubeconfig in the namespace openshift-kube-controller-manager. The file kubeconfig (controller-manager.conf) is referenced in the pod via hostpath and is stored in /etc/kubernetes/static-pod-resources/configmaps/controller-manager-kubeconfig/kubeconfig with ownership root:root. -1.1.19 : Keys for control plane components deployed as static pods, kube-apiserver, kube-controller-manager, and openshift-kube-scheduler are stored in the directory /etc/kubernetes/static-pod-certs/secrets. The directory and file ownership are set to root:root. -1.1.20 : Keys for control plane components deployed as static pods, kube-apiserver, kube-controller-manager, and openshift-kube-scheduler are stored in the directory /etc/kubernetes/static-pod-certs/secrets. Certificate files all have permissions 0600. -1.1.21 : Keys for control plane components deployed as static pods, kube-apiserver, kube-controller-manager, and openshift-kube-scheduler are stored in the directory /etc/kubernetes/static-pod-certs/secrets. Key files all have permissions 0600. -1.2.1 : OpenShift provides it's own fully integrated authentication and authorization mechanism. OpenShift allows anonymous requests to the API server to support information discovery and webhook integrations. Anonymous requests are assigned the system:unauthenticated group, which is bound to cluster-scoped roles. Verify that the default behavior is maintained. If the default behavior is changed, platform components will not work properly, in particular Elasticsearch and Prometheus. The oauth-proxy deployed as part of these components makes anonymous use of /.well-known/oauth-authorization-server endpoint, granted by system:discovery role. -1.2.2 : OpenShift provides it's own fully integrated authentication and authorization mechanism. The apiserver is protected by either requiring an OAuth token issued by the platform's integrated OAuth server or signed certificates. By default the basic-auth-file method is not enabled in OpenShift. -1.2.3 : OpenShift does not use token-auth-file flag. OpenShift includes a built-in OAuth server rather than relying on a static token file. The OAuth server is integrated with the API server. -1.2.4 : OpenShift utilizes X.509 certificates for authentication of the control-plane components. OpenShift configures the API server to use an internal certificate authority (CA) to validate the user certificate sent during TLS negotiation. If the CA validation of the certificate is successful, the request is authenticated and user information is derived from the certificate subject fields. Certificates for control plane components like kube-apiserver, kube-controller-manager, kube-scheduler and etcd are stored with their respective static pod configurations in the directory /etc/kubernetes/static-pod-resources/*/secrets. -1.2.5 : OpenShift uses X.509 certificates to provide secure connections between API server and node/kubelet. OpenShift does not use kubelet-certificate-authority flag. The platform includes multiple certificate authorities (CAs) providing independent chains of trust, increasing the security posture of the cluster. The certificates generated by each CA are used to identify a particular OpenShift platform component to another OpenShift platform component. Communication between the API server and the kubelet is secured by the kubelet serving CA. -1.2.6 : OpenShift uses X.509 certificates to provide secure connections between API server and node/kubelet. OpenShift does not use kubelet-certificate-authority flag. The platform includes multiple certificate authorities (CAs) providing independent chains of trust, increasing the security posture of the cluster. The certificates generated by each CA are used to identify a particular OpenShift platform component to another OpenShift platform component. Communication between the API server and the kubelet is secured by the kubelet serving CA -1.2.7 : When the --authorization-mode argument is set to AlwaysAllow, the API Server allows all requests. It is not possible to configure an OpenShift cluster this way. The --authorization-mode flag is not used by OpenShift API Server. OpenShift is configured to use RBAC to authorize requests. See https://docs.openshift.com/container-platform/4.3/authentication/using-rbac.html - - Additional notes: - Requests to the API server are authenticated by X.509 certificates. External access to the API server is through the Ingress controller. A custom certificate can be added to the ingress controller. - - Role-based access control (RBAC) objects determine what actions a user is allowed to perform on what objects in an OpenShift cluster. Cluster administrators manage RBAC for the cluster. Project owners can manage RBAC for their individual OpenShift projects. -1.2.8 : In OpenShift, the Node authorizer is enabled by default. The authorization-mode argument is not configurable for the API server. The OpenShift API server does not use the values assigned to the flag authorization-mode. -1.2.9 : OpenShift supports RBAC. The --authorization-mode flag is not used by OpenShift API Server. -1.2.10: EventRateLimit admission plugin is alpha and cannot be enabled in Openshift. It was developed to alleviate the potential issue of flooding the API server with requests. However, the kubelet has since been fixed to send fewer events. In future Kubernetes releases, api priority and fairness will be used to limit the rate at which the API server accepts requests. -1.2.11: OpenShift does not enable the AlwaysAdmit admission control plugin. It cannot be enabled. -1.2.12: When OpenShift Container Platform creates containers, it uses the container’s imagePullPolicy to determine if the image should be pulled prior to starting the container. There are three possible values for imagePullPolicy: Always, IfNotPresent, Never. If a container’s imagePullPolicy parameter is not specified, OpenShift Container Platform sets it based on the image’s tag. If the tag is latest, OpenShift Container Platform defaults imagePullPolicy to Always. Otherwise, OpenShift Container Platform defaults imagePullPolicy to IfNotPresent. -1.2.13: In OpenShift, RBAC roles can restrict access to pod subresources 'exec' and 'attach', while Security Context Constraints (SCCs) restrict access to run privileged containers. By default, OpenShift runs pods on worker nodes as unprivileged (with the restricted SCC). Unlike upstream Kubernetes, OpenShift does not enable the DenyEscalatingExec admission control plugin. OpenShift's Security Context Constraints (SCCs) provide the same level of restriction and have been contributed to Kubernetes as Pod Security Policies. PSPs are still beta in Kubernetes. -1.2.14: The ServiceAccount admission control plugin is enabled by default. Every service account has an associated user name that can be granted roles, just like a regular user. The user name for each service account is derived from its project and the name of the service account. Service accounts are required in each project to run builds, deployments, and other pods. The default service accounts that are automatically created for each project are isolated by the project namespace. -1.2.15: OpenShift enables both the upstream NamespaceLifecycle and OriginNamespaceLifecycle plugins. Openshift's own OriginNamespaceLifecycle admission plugin implements the CIS recommendation of preventing resources from being created while the namespace is being terminated. -1.2.16: OpenShift provides the same protection via the SecurityContextConstraints admission plugin, which is enabled by default. PodSecurityPolicy admission control plugin is disabled by default as it is still beta and not yet supported with OpenShift. - Security Context Constraints and Pod Security Policy cannot be used on the same cluster. -1.2.17: The NodeRestriction admission plugin is enabled by default in OCP 4. It cannot be disabled. -1.2.18: OpenShift API server is served over HTTPS with authentication and authorization; the secure API endpoint is bound to 0.0.0.0:8443 by default. -1.2.19: OpenShift API server is served over HTTPS with authentication and authorization; the secure API endpoint is bound to 0.0.0.0:8443 by default. -1.2.20: By default, traffic for the OpenShift API server is served over HTTPS with authentication and authorization; the secure API endpoint is bound to 0.0.0.0:8443. - - In OCP 4 the only supported way to access the API server pod is through the load balancer and then through the internal service. -1.2.21: Profiling is used to collect data to identify performance bottlenecks. To ensure the collected data is not exploited, profiling endpoints are exposed at each master port and secured via RBAC (see cluster-debugger role). By default, the profiling endpoints are accessible only by users bound to cluster-admin or cluster-debugger role. - - OpenShift exposes profiling in the web interface on localhost (a hostname that means this computer) if OPENSHIFT_PROFILE=web is set in master.env (?). This configuration is only meant to be used for OpenShift core development, and is never recommended for a live cluster. - - Although the profiling endpoint for API server can be completely disabled using the profiling flag under apiServerArguments, we do not recommend this as the endpoint is protected by RBAC and disabling profiling makes it more difficult to troubleshoot any problems. - Recommendation - Ensure OPENSHIFT_PROFILE is not set to web, which would expose the web interface on localhost. - - Verify status for OCP 4. -1.2.22: OpenShift audit works at the API server level, logging all requests coming to the server. API server audit is on by default. -1.2.23: OpenShift audit works at the API server level, logging all requests coming to the server. Configure via maximumFileRetentionDays. -1.2.24: OpenShift audit works at the API server level, logging all requests coming to the server. Configure via maximumRetainedFiles. -1.2.25: OpenShift audit works at the API server level, logging all requests coming to the server. Configure via maximumFileSizeMegabytes. -1.2.26: In OpenShift, the request-timeout flag defaults to 60 seconds. This can be increased if you wish. OpenShift configures the min-request-timeout flag via servingInfo.requestTimeoutSeconds via ???, which overrides request-timeout in certain scenarios and provides a more balanced timeout approach than a global request-timeout. OpenShift configures requestTimeoutSeconds with a default value of 3600 seconds (one hour). -1.2.27: OpenShift denies access for any OAuth Access token that does not exist in its etcd data store. OpenShift does not use the service-account-lookup flag. -1.2.28: OpenShift API server does not use the service-account-key-file argument. The ServiceAccount token authenticator is configured with serviceAccountConfig.publicKeyFiles. OpenShift does not reuse the apiserver TLS key. -1.2.29: OpenShift uses X.509 certificates to provide secure communication to etcd. OpenShift configures these automatically. OpenShift does not use the etcd-certfile or etcd-keyfile flags. - - /etc/kubernetes/static-pod-resources/secrets/etcd-client/tls.crt - - /etc/kubernetes/static-pod-resources/secrets/etcd-client/tls.key -1.2.30: OpenShift uses X.509 certificates to provide secure connections between API server and node/kubelet by default. OpenShift does not use values assigned to the tls-cert-file or tls-private-key-file flags. OpenShift generates these files and sets the arguments appropriately. - - /etc/kubernetes/static-pod-certs/secrets/service-network-serving-certkey/tls.crt - - /etc/kubernetes/static-pod-certs/secrets/service-network-serving-certkey/tls.key -1.2.31: OpenShift includes multiple certificate authorities (CAs) providing independent chains of trust, increasing the security posture of the cluster. The certificates generated by each CA are used to identify a particular OpenShift platform component to another OpenShift platform component. OpenShift configures the client-ca-file value and does not use value assigned to the client-ca-file flag. -1.2.32: OpenShift uses X.509 certificates to provide secure communication to etcd. OpenShift does not use values assigned to etcd-cafile. OpenShift generates this file and sets the arguments appropriately in the API server. OpenShift includes multiple certificate authorities (CAs) providing independent chains of trust, increasing the security posture of the cluster. The certificates generated by each CA are used to identify a particular OpenShift platform component to another OpenShift platform component. Communication with etcd is secured by the etcd serving CA. -1.2.33: OpenShift supports encryption of data at rest of etcd datastore, but it is up to the customer to configure. The ase-cbc cipher is used. Keys are stored on the filesystem of the master and automatically rotated. -1.2.34: OpenShift supports encryption of data at rest of etcd datastore, but it is up to the customer to configure. The ase-cbc cipher is used. Keys are stored on the filesystem of the master and automatically rotated. -1.2.35: The API server is only accessible through the load balancer. Ciphers for the ingress controller can be configured as of OpenShfit 4.3. The ability to configure cipher suites separately for the API server is on the roadmap. -1.3.3 : In OpenShift, every service account has an associated user name that can be granted roles, just like a regular user. The user name is derived from its project and name. As soon as a service account is created, two secrets are automatically added to it: an API token and credentials for the OpenShift Container Registry. The system ensures that service accounts always have an API token and registry credentials. -1.3.4 : By default, OpenShift starts kube-controller-manager with service-account-private-key-file=/etc/origin/master/servicaccounts.private.key. - - In OpenShift, every service account has an associated user name that can be granted roles, just like a regular user. The user name is derived from its project and name. As soon as a service account is created, two secrets are automatically added to it: an API token and credentials for the OpenShift Container Registry. The system ensures that service accounts always have an API token and registry credentials. - - In OpenShift 4, the kube-controller-manager is managed with the cluster Controller Manager Operator. -1.3.5 : OpenShift maps the master configuration serviceAccountConfig.masterCA to the kube-controller-manager root-ca-file flag, setting it to /etc/origin/master/ca-bundle.crt by default. -1.3.6 : Certificates for the kubelet are automatically created and rotated by the OpenShift Container Platform. The kubelet is installed automatically on every RHCOS node. The OpenShift kubelet-serving-CA manages certificates for the kubelet. Kubelet certificates are automatically issued and rotated. -1.3.7 : In OpenShift 4, the Controller Manager is managed by the Kubernetes Controller Manager Operator. - https://github.com/openshift/cluster-kube-controller-manager-operator - - In Openshift 4, the Controller Manager is deployed as a static pod. Static Pods are managed by the kubelet and are always bound to one Kubelet on a specific node. The kubelet automatically creates a mirror Pod on the API server for each static pod. This means that the pods running on a node are visible on the API server, but cannot be controlled from there. The bind-address argument is not used. -1.4.1 : A fix to this issue: https://bugzilla.redhat.com/show_bug.cgi?id=1889488 None required. Profiling is protected by RBAC and cannot be disabled. -1.4.2 : By default, the --bind-address argument is not present, the readinessProbe and livenessProbe arguments are set to 10251 and the port argument is set to 0. Check the status of this issue: https://bugzilla.redhat.com/show_bug.cgi?id=1889488 -2.1 : OpenShift uses X.509 certificates to provide secure communication to etcd. OpenShift generates these files and sets the arguments appropriately. OpenShift does not use the etcd-certfile or etcd-keyfile flags. -2.2 : OpenShift uses X.509 certificates to provide secure communication to etcd. OpenShift installation generates these files and sets the arguments appropriately. -2.3 : OpenShift configures etcd with secure communication. Openshift installs etcd as static pods on control plane nodes, and mounts the configuration files from /etc/etcd/ on the host. The etcd.conf file includes peer-auto-tls configurations as referenced in /etc/etcd/etcd.conf. -2.4 : OpenShift configures etcd with secure communication. Openshift installs etcd as static pods on control plane nodes, and mounts the configuration files from /etc/etcd/ on the host. The etcd.conf file includes peer-cert-file and peer-key-file configurations as referenced in /etc/etcd/etcd.conf. -2.5 : OpenShift configures etcd with secure communication. Openshift installs etcd as static pods on control plane nodes, and mounts the configuration files from /etc/etcd/ on the host. The etcd.conf file includes peer-client-cert-auth configurations as referenced to the right. -2.6 : OpenShift configures etcd with secure communication. Openshift installs etcd as static pods on control plane nodes, and mounts the configuration files from /etc/etcd/ on the host. The etcd.conf file includes peer-auto-tls configurations as referenced in /etc/etcd/etcd.conf. -2.7 : OpenShift provides integrated management of certificates for internal cluster components. OpenShift 4 includes multiple CAs providing independent chains of trust, which ensure that a platform CA will never accidentally sign a certificate that can be used for the wrong purpose, increasing the security posture of the cluster. A unique CA is provided for etcd. -3.1.1 : For users to interact with OpenShift Container Platform, they must first authenticate to the cluster. The authentication layer identifies the user associated with requests to the OpenShift Container Platform API. The authorization layer then uses information about the requesting user to determine if the request is allowed. - https://docs.openshift.com/container-platform/4.3/authentication/understanding-authentication.html - - The OpenShift Container Platform master includes a built-in OAuth server for token-based authentication. Developers and administrators obtain OAuth access tokens to authenticate themselves to the API. It is recommended for an administrator to configure OAuth to specify an identity provider after the cluster is installed. User access to the cluster is managed through the identity provider. - https://docs.openshift.com/container-platform/4.3/authentication/understanding-identity-provider.html - - OpenShift includes built-in role based access control (RBAC) to determine whether a user is allowed to perform a given action within the cluster. Roles can have cluster scope or local (i.e. project) scope. - https://docs.openshift.com/container-platform/4.3/authentication/using-rbac.html - - In addition, OpenShift ships with a Service-CA which is intended intended to support service serving certificates for complex middleware applications that require encryption. These certificates are issued as TLS web server certificates. The service-ca controller uses the x509.SHA256WithRSA signature algorithm to generate service certificates. The service CA certificate, which issues the service certificates, is valid for 26 months and is automatically rotated when there is less than six months validity left. A Pod can access the service CA certificate by mounting a ConfigMap that is annotated with service.beta.openshift.io/inject-cabundle=true. Once annotated, the cluster automatically injects the service CA certificate into the service-ca.crt key on the ConfigMap. Access to this CA certificate allows TLS clients to verify connections to services using service serving certificates. You can manually rotate the service certificate by deleting the associated secret. Deleting the secret results in a new one being automatically created, resulting in a new certificate. - https://docs.openshift.com/container-platform/4.3/authentication/certificates/service-serving-certificate.html -3.2.1 : In OpenShift, auding of the API Server is on by default. Audit provides a security-relevant chronological set of records documenting the sequence of activities that have affected system by individual users, administrators, or other components of the system. Audit works at the API server level, logging all requests coming to the server. Each audit log contains two entries: - - The request line containing: - A Unique ID allowing to match the response line (see #2) - The source IP of the request - The HTTP method being invoked - The original user invoking the operation - The impersonated user for the operation (self meaning himself) - The impersonated group for the operation (lookup meaning user’s group) - The namespace of the request or - The URI as requested - - The response line containing: - The unique ID from #1 - The response code - - You can view logs for the master nodes for the OpenShift Container Platform API server or the Kubernetes API server. - https://docs.openshift.com/container-platform/4.3/nodes/nodes/nodes-nodes-audit-log.html -3.2.2 : You can configure the audit feature to set log level, retention policy, and the type of events to log. - You can set the log level settings for an overall component or the API server to one of the following. The setting can be different for each setting: - - Normal. Normal is the default. Normal working log information, including helpful notices for auditing or common operations. Similar to glog=2. - - Debug. Debug is for troubleshooting problems. A greater quanitity of notices than Normal, but contain less information than Trace. Common operations might be logged. Similar to glog=4. - - Trace. Trace is for troubleshooting problems when Debug is not verbose enough. Logs every function call as part of a common operation, including tracing execution of a query. Similar to glog=6. - - TraceAll. TraceAll is troubleshoting at the level of API content/decoding. Contains complete body content. In production clusters, this setting causes performance degradation and results in a significant number of logs. Similar to ` glog=8`. - - https://docs.openshift.com/container-platform/4.3/nodes/nodes/nodes-nodes-audit-log.html#nodes-nodes-audit-log-basic-config_nodes-nodes-audit-log -4.1.1 : Kubelet is run as atomic-openshift-node systemd unit and its configuration file is created with 644 permissions. -4.1.2 : Kubelet is run as atomic-openshift-node systemd unit and its configuration file is created with root:root ownership. -4.1.5 : The node's kubeconfig is created with 644 permissions. -4.1.6 : The node's kubeconfig is created with root:root. -4.1.7 : Client CA location defined in /etc/kubernetes/kubelet.conf: - - kind: KubeletConfiguration - apiVersion: kubelet.config.k8s.io/v1beta1 - authentication: - x509: - clientCAFile: /etc/kubernetes/kubelet-ca.crt - anonymous: - enabled: false - - /etc/kubernetes/kubelet-ca.crt has permissions 0644 -4.1.8 : Client CA location defined in /etc/kubernetes/kubelet.conf: - - kind: KubeletConfiguration - apiVersion: kubelet.config.k8s.io/v1beta1 - authentication: - x509: - clientCAFile: /etc/kubernetes/kubelet-ca.crt - anonymous: - enabled: false - - /etc/kubernetes/kubelet-ca.crt is owned by root:root -4.1.9 : /var/lib/kubelet/kubeconfig permissions set to 0600 -4.1.10 : /var/lib/kubelet/kubeconfig ownership set to root:root -4.2.1 : OpenShift uses a different approach to secure anonymous authorization. OpenShift explicitly sets anonymous-auth to true, as anonymous requests are used for discovery information, webhook integrations, etc. OpenShift allows anonymous requests (then authorizes them). - Access to OpenShift node is authenticated with certificate. kubelet apis are subresources of the node resource that can be restricted by RBAC roles. Anonymous access is denied for these subresources. OpenShift provides it's own fully integrated authentication and authorization mechanism. Unsecured endpoints reveal no sensitive data. Unauthenticated requests to secured endpoints are assigned to 'system:anonymous'. system:anonymous is not bound to any roles, and thus has no visibility by default. -4.2.2 : Unauthenticated/Unauthorized users have no access to OpenShift nodes. Kubelet flag authorization-mode is explicitly set to WebHook -4.2.3 : OpenShift provides integrated management of certificates for internal cluster components. OpenShift 4 includes multiple CAs providing independent chains of trust, which ensure that a platform CA will never accidentally sign a certificate that can be used for the wrong purpose, increasing the security posture of the cluster. Communication between the API server and the kubelet is secured by the kubelet serving CA. -4.2.4 : OpenShift disables the read-only port (10255) on all nodes by setting the read-only-port kubelet flag to 0 by defualt. -4.2.5 : OpenShift uses the kubernetes default of 4 hours for the streaming-connection-idle-timeout argument. Unless cluster administrator has added the value to the node configuration, the default will be used. The value is a timeout for HTTP streaming sessions going through a kubelet, like the port-forward, exec, or attach pod operations. The streaming-connection-idle-timeout should not be disabled by setting it to zero, but it can be lowered. Note that if the value is set too low, then users using those features may experience a service interruption due to the timeout. kubelet flags can be added to kubeletArguments of /etc/origin/node/node-config.yaml. -4.2.6 : Red Hat disagrees with the CIS recommendation for the protect-kernel-defauts. OpenShift node/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 what the kubelet desires and the OpenShift node to fail to start. -4.2.7 : OpenShift sets the make-iptables-util-changes argument to true by default. -4.2.8 : In OpenShift 4, nodeName will be set to the node hostname that is resolvable from all nodes in the cluster. -4.2.9 : OpenShift sets the event-qps argument to a default value of 5. This is the default set by Kubernetes. When this value is set to > 0, event creations per second are limited to the value set. If this value is set to 0, event creations per second are unlimited. -4.2.10 : OpenShift instead uses the cert-dir flag, for serving HTTPS traffic, which is used in the absence of the proposed flags. OpenShift sets cert-dir flag to /etc/origin/node/certificates, and generates the certificates in this directory for the kubelet to serve HTTPS traffic. -4.2.11 : OpenShift automatically rotates the Kubelet certificates. RotateKubeletClientCertificate to true by default. -4.2.12 : OpenShift automatically rotates the Kubelet certificates. RotateKubeletClientCertificate to true by default. -4.2.13 : All traffic to the API server is encrypted using TLS 1.3 -5.1.1 : OpenShift provides a set of default cluster roles that you can bind to users and groups cluster-wide or locally (per project namespace). Be mindful of the difference between local and cluster bindings. For example, if you bind the cluster-admin role to a user by using a local role binding, it might appear that this user has the privileges of a cluster administrator. This is not the case. Binding the cluster-admin to a user in a project grants super administrator privileges for only that project to the user. You can use the oc CLI to view cluster roles and bindings by using the oc describe command. For more information, see https://docs.openshift.com/container-platform/4.4/authentication/using-rbac.html#default-roles_using-rbac - Some of these roles such as cluster-admin provide wide-ranging privileges which should only be applied where absolutely necessary. Roles such as cluster-admin allow super-user access to perform any action on any resource. When used in a ClusterRoleBinding, it gives full control over every resource in the cluster and in all namespaces. When used in a RoleBinding, it gives full control over every resource in the rolebinding's namespace, including the namespace itself. - Review users and groups bound to cluster-admin and decide whether they require such access. Consider creating least-privilege roles for users and service accounts. -5.1.2 : Review the users who have get, list or watch access to secrets objects in the Kubernetes API. -5.1.3 : Where possible replace any use of wildcards in clusterroles and roles with specific objects or actions. -5.1.4 : Where possible, remove create access to pod objects in the cluster. -5.1.5 : None required. -5.1.6 : Where possible, remove get, list and watch access to secret objects in the cluster. -5.2.1 : By default, privileged containers will not run on OpenShift worker nodes. -5.2.2 : By default, containers running on OpenShift worker nodes do not share the host process ID namespace. -5.2.3 : By default, containers running on OpenShift worker nodes do not share the host process IPC namespace. -5.2.4 : By default, containers running on OpenShift worker nodes do not share the host process network namespace. -5.2.5 : By default, privileged containers will not run on OpenShift worker nodes. The restricted SCC also prevents privilege escalation. -5.2.6 : By default, privileged containers will not run on OpenShift worker nodes. -5.2.7 : By default, containers running on OpenShift worker nodes are not granted the NET_RAW capability. -5.2.8 : By default, containers running on OpenShift worker nodes are granted no additional capabilities. -5.2.9 : By default, containers running on OpenShift worker nodes are granted no additional capabilities. -5.3.1 : OpenShift Container Platform uses a software-defined networking (SDN) approach to provide a unified cluster network that enables communication between Pods across the OpenShift Container Platform cluster. This Pod network is established and maintained by the OpenShift SDN, which configures an overlay network using Open vSwitch (OVS). The OpenShift SDN uses Network Policies. -5.3.2 : The OpenShift 4 CNI plugin uses network policies by default -- that is, it runs in ovs-networkpolicy mode. By default, all Pods in a project are accessible from other Pods and network endpoints. To isolate one or more Pods in a project, you can create NetworkPolicy objects in that project to indicate the allowed incoming connections. Project administrators can create and delete NetworkPolicy objects within their own project. -5.4.1 : Information about ways to provide sensitive data to pods is included in the documentation. - https://docs.openshift.com/container-platform/4.3/nodes/pods/nodes-pods-secrets.html -5.4.2 : OpenShift supports a broad ecosystem of security partners many of whom support integration with external vaults. -5.5.1 : You can control which images can be imported, tagged, and run in a cluster using either Allowed Registries for import or the ImagePolicy admission plug-in.The ImagePolicyWebhook admission plugin may be enabled and configured if desired. -5.6.1 : Follow the documentation and create namespaces for objects in your deployment as you need them. - Default Value: - By default, Kubernetes starts with two initial namespaces: - 1. default - The default namespace for objects with no other namespace - 2. kube-system - The namespace for objects created by the Kubernetes system 3. openshift- - 4. openshift-* - The namespace for objects created by OpenShift -5.6.2 : 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. -5.6.3 : 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. -5.6.4 : Ensure that namespaces are created to allow for appropriate segregation of Kubernetes resources and that all new resources are created in a specific namespace. diff --git a/scripts/kubernetes-cis-benchmark/1.0.0/federation/check_federation.sh b/scripts/kubernetes-cis-benchmark/1.0.0/federation/check_federation.sh new file mode 100755 index 0000000..ace1978 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.0.0/federation/check_federation.sh @@ -0,0 +1,8 @@ + +if ps -ef | grep federation-apiserver 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then + info "Kubernetes Federated Deployments" +else + info "This node is not a Kubernetes Federated node" + exit 2 +fi + diff --git a/scripts/kubernetes-cis-benchmark/1.0.0/federation/federation_1_api_server.sh b/scripts/kubernetes-cis-benchmark/1.0.0/federation/federation_1_api_server.sh new file mode 100755 index 0000000..34bbd70 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.0.0/federation/federation_1_api_server.sh @@ -0,0 +1,189 @@ +info "3.1 - Federation API Server" + +check_3_1_1="3.1.1 Ensure that the --anonymous-auth argument is set to false" +if check_argument 'federation-apiserver' '--anonymous-auth=false' >/dev/null 2>&1; then + pass "$check_3_1_1" +else + warn "$check_3_1_1" +fi + +check_3_1_=2"3.1.2 Ensure that the --basic-auth-file argument is not set" +if check_argument 'federation-apiserver' '--basic-auth-file' >/dev/null 2>&1; then + warn "$check_3_1_2" +else + pass "$check_3_1_2" +fi + +check_3_1_3="3.1.3 Ensure that the --insecure-allow-any-token argument is not set" +if check_argument 'federation-apiserver' '--insecure-allow-any-token' >/dev/null 2>&1; then + warn "$check_3_1_3" +else + pass "$check_3_1_3" +fi + +check_3_1_4="3.1.4 Ensure that the --insecure-bind-address argument is not set" +if check_argument 'federation-apiserver' '--insecure-bind-address' >/dev/null 2>&1; then + warn "$check_3_1_4" +else + pass "$check_3_1_4" +fi + +check_3_1_5="3.1.5 Ensure that the --insecure-port argument is set to 0" +if check_argument 'federation-apiserver' '--insecure-port' >/dev/null 2>&1; then + port=$(get_argument_value 'federation-apiserver' '--insecure-port'|cut -d " " -f 1) + if [ "$port" = "0" ]; then + pass "$check_3_1_5" + else + warn "$check_3_1_5" + warn " * insecure-port: $port" + fi +else + warn "$check_3_1_5" +fi + +check_3_1_6="3.1.6 Ensure that the --secure-port argument is not set to 0" +if check_argument 'federation-apiserver' '--secure-port' >/dev/null 2>&1; then + port=$(get_argument_value 'federation-apiserver' '--secure-port'|cut -d " " -f 1) + if [ "$port" = "0" ]; then + warn "$check_3_1_6" + warn " * secure-port: $port" + else + pass "$check_3_1_6" + fi +else + pass "$check_3_1_6" +fi + +check_3_1_7="3.1.7 Ensure that the --profiling argument is set to false" +if check_argument 'federation-apiserver' '--profiling=false' >/dev/null 2>&1; then + pass "$check_3_1_7" +else + warn "$check_3_1_7" +fi + +check_3_1_8="3.1.8 Ensure that the admission control policy is not set to AlwaysAdmit" +if get_argument_value 'federation-apiserver' '--admission-control'| grep 'AlwaysAdmit' >/dev/null 2>&1; then + warn "$check_3_1_8" +else + pass "$check_3_1_8" +fi + +check_3_1_9="3.1.9 Ensure that the admission control policy is set to NamespaceLifecycle" +if get_argument_value 'federation-apiserver' '--admission-control'| grep 'NamespaceLifecycle' >/dev/null 2>&1; then + pass "$check_3_1_9" +else + warn "$check_3_1_9" +fi + +check_3_1_10="3.1.10 Ensure that the --audit-log-path argument is set as appropriate" +if check_argument 'federation-apiserver' '--audit-log-path' >/dev/null 2>&1; then + v=$(get_argument_value 'federation-apiserver' '--audit-log-path') + pass "$check_3_1_10" + pass " * audit-log-path: $v" +else + warn "$check_3_1_10" +fi + +check_3_1_11="3.1.11 Ensure that the --audit-log-maxage argument is set to 30 or as appropriate" +if check_argument 'federation-apiserver' '--audit-log-maxage' >/dev/null 2>&1; then + v=$(get_argument_value 'federation-apiserver' '--audit-log-maxage'|cut -d " " -f 1) + if [ "$v" = "30" ]; then + pass "$check_3_1_11" + pass " * audit-log-maxage: $v" + else + warn "$check_3_1_11" + warn " * audit-log-maxage: $v" + fi +else + warn "$check_3_1_11" +fi + +check_3_1_12="3.1.12 Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate" +if check_argument 'federation-apiserver' '--audit-log-maxbackup' >/dev/null 2>&1; then + v=$(get_argument_value 'federation-apiserver' '--audit-log-maxbackup' |cut -d " " -f 1) + if [ "$v" = "10" ]; then + pass "$check_3_1_12" + pass " * audit-log-maxbackup : $v" + else + warn "$check_3_1_12" + warn " * audit-log-maxbackup : $v" + fi +else + warn "$check_3_1_12" +fi + +check_3_1_13="3.1.13 Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate" +if check_argument 'federation-apiserver' '--audit-log-maxsize' >/dev/null 2>&1; then + v=$(get_argument_value 'federation-apiserver' '--audit-log-maxsize' |cut -d " " -f 1) + if [ "$v" = "100" ]; then + pass "$check_3_1_13" + pass " * audit-log-maxsize : $v" + else + warn "$check_3_1_13" + warn " * audit-log-maxsize : $v" + fi +else + warn "$check_3_1_13" +fi + +check_3_1_14="3.1.14 Ensure that the --authorization-mode argument is not set to AlwaysAllow" +if get_argument_value 'federation-apiserver' '--authorization-mode'| grep 'AlwaysAllow' >/dev/null 2>&1; then + warn "$check_3_1_14" +else + pass "$check_3_1_14" +fi + +check_3_1_15="3.1.15 Ensure that the --token-auth-file parameter is not set" +if check_argument 'federation-apiserver' '--token-auth-file' >/dev/null 2>&1; then + warn "$check_3_1_15" +else + pass "$check_3_1_15" +fi + +check_3_1_16="3.1.16 Ensure that the --service-account-lookup argument is set to true" +if check_argument 'federation-apiserver' '--service-account-lookup=true' >/dev/null 2>&1; then + pass "$check_3_1_16" +else + warn "$check_3_1_16" +fi + +check_3_1_17="3.1.17 Ensure that the --service-account-key-file argument is set as appropriate" +if check_argument 'federation-apiserver' '--service-account-key-file' >/dev/null 2>&1; then + v=$(get_argument_value 'federation-apiserver' '--service-account-key-file') + pass "$check_3_1_17" + pass " * service-account-key-file: $v" +else + warn "$check_3_1_17" +fi + +check_3_1_18="3.1.18 Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate" +if check_argument 'federation-apiserver' '--etcd-certfile' >/dev/null 2>&1; then + if check_argument 'federation-apiserver' '--etcd-keyfile' >/dev/null 2>&1; then + v1=$(get_argument_value 'federation-apiserver' '--etcd-certfile') + v2=$(get_argument_value 'federation-apiserver' '--etcd-keyfile') + pass "$check_3_1_18" + pass " * etcd-certfile: $v1" + pass " * etcd-keyfile: $v2" + else + warn "$check_3_1_18" + fi +else + warn "$check_3_1_18" +fi + +check_3_1_19="3.1.19 Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate" +if check_argument 'federation-apiserver' '--tls-cert-file' >/dev/null 2>&1; then + if check_argument 'federation-apiserver' '--tls-private-key-file' >/dev/null 2>&1; then + v1=$(get_argument_value 'federation-apiserver' '--tls-cert-file') + v2=$(get_argument_value 'federation-apiserver' '--tls-private-key-file') + pass "$check_3_1_19" + pass " * tls-cert-file: $v1" + pass " * tls-private-key-file: $v2" + else + warn "$check_3_1_19" + fi +else + warn "$check_3_1_19" +fi + + diff --git a/scripts/kubernetes-cis-benchmark/1.0.0/federation/federation_2_controller_manager.sh b/scripts/kubernetes-cis-benchmark/1.0.0/federation/federation_2_controller_manager.sh new file mode 100755 index 0000000..b9a5b7b --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.0.0/federation/federation_2_controller_manager.sh @@ -0,0 +1,9 @@ +info "3.2 - Federation Controller Manager" + +check_3_2_1="Ensure that the --profiling argument is set to false" +if check_argument 'federation-controller-manager' '--profiling=false' >/dev/null 2>&1; then + pass "$check_3_2_1" +else + warn "$check_3_2_1" +fi + diff --git a/scripts/kubernetes-cis-benchmark/1.0.0/master/master_1_api_server.sh b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_1_api_server.sh new file mode 100755 index 0000000..bc27337 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_1_api_server.sh @@ -0,0 +1,314 @@ +info "1.1 - API Server" + +check_1_1_1="1.1.1 - Ensure that the --allow-privileged argument is set to false" +if check_argument "$CIS_APISERVER_CMD" '--allow-privileged=false' >/dev/null 2>&1; then + pass "$check_1_1_1" +else + warn "$check_1_1_1" +fi + +check_1_1_2="1.1.2 - Ensure that the --anonymous-auth argument is set to false" +if check_argument "$CIS_APISERVER_CMD" '--anonymous-auth=false' >/dev/null 2>&1; then + pass "$check_1_1_2" +else + warn "$check_1_1_2" +fi + +check_1_1_3="1.1.3 - Ensure that the --basic-auth-file argument is not set" +if check_argument "$CIS_APISERVER_CMD" '--basic-auth-file' >/dev/null 2>&1; then + warn "$check_1_1_3" +else + pass "$check_1_1_3" +fi + +check_1_1_4="1.1.4 - Ensure that the --insecure-allow-any-token argument is not set" +if check_argument "$CIS_APISERVER_CMD" '--insecure-allow-any-token' >/dev/null 2>&1; then + warn "$check_1_1_4" +else + pass "$check_1_1_4" +fi + +check_1_1_5="1.1.5 - Ensure that the --kubelet-https argument is set to true" +if check_argument "$CIS_APISERVER_CMD" '--kubelet-https=false' >/dev/null 2>&1; then + warn "$check_1_1_5" +else + pass "$check_1_1_5" +fi + +check_1_1_6="1.1.6 - Ensure that the --insecure-bind-address argument is not set" +if check_argument "$CIS_APISERVER_CMD" '--insecure-bind-address' >/dev/null 2>&1; then + address=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-bind-address'|cut -d " " -f 1) + if [ "$address" = "127.0.0.1" ]; then + pass "$check_1_1_6" + pass " * insecure-bind-address: $address" + else + warn "$check_1_1_6" + warn " * insecure-bind-address: $address" + fi +else + pass "$check_1_1_6" +fi + +check_1_1_7="1.1.7 - Ensure that the --insecure-port argument is set to 0" +if check_argument "$CIS_APISERVER_CMD" '--insecure-port' >/dev/null 2>&1; then + port=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-port'|cut -d " " -f 1) + if [ "$port" = "0" ]; then + pass "$check_1_1_7" + else + warn "$check_1_1_7" + warn " * insecure-port: $port" + fi +else + warn "$check_1_1_7" +fi + +check_1_1_8="1.1.8 - Ensure that the --secure-port argument is not set to 0" +if check_argument "$CIS_APISERVER_CMD" '--secure-port' >/dev/null 2>&1; then + port=$(get_argument_value "$CIS_APISERVER_CMD" '--secure-port'|cut -d " " -f 1) + if [ "$port" = "0" ]; then + warn "$check_1_1_8" + warn " * secure-port: $port" + else + pass "$check_1_1_8" + fi +else + pass "$check_1_1_8" +fi + +check_1_1_9="1.1.9 - Ensure that the --profiling argument is set to false" +if check_argument "$CIS_APISERVER_CMD" '--profiling=false' >/dev/null 2>&1; then + pass "$check_1_1_9" +else + warn "$check_1_1_9" +fi + +check_1_1_10="1.1.10 - Ensure that the --repair-malformed-updates argument is set to false" +if check_argument "$CIS_APISERVER_CMD" '--repair-malformed-updates=false' >/dev/null 2>&1; then + pass "$check_1_1_10" +else + warn "$check_1_1_10" +fi + +check_1_1_11="1.1.11 - Ensure that the admission control policy is not set to AlwaysAdmit" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'AlwaysAdmit' >/dev/null 2>&1; then + warn "$check_1_1_11" +else + pass "$check_1_1_11" +fi + +check_1_1_12="1.1.12 - Ensure that the admission control policy is set to AlwaysPullImages" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'AlwaysPullImages' >/dev/null 2>&1; then + pass "$check_1_1_12" +else + warn "$check_1_1_12" +fi + +check_1_1_13="1.1.13 - Ensure that the admission control policy is set to DenyEscalatingExec" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'DenyEscalatingExec' >/dev/null 2>&1; then + pass "$check_1_1_13" +else + warn "$check_1_1_13" +fi + +check_1_1_14="1.1.14 - Ensure that the admission control policy is set to SecurityContextDeny" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'SecurityContextDeny' >/dev/null 2>&1; then + pass "$check_1_1_14" +else + warn "$check_1_1_14" +fi + +check_1_1_15="1.1.15 - Ensure that the admission control policy is set to NamespaceLifecycle" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'NamespaceLifecycle' >/dev/null 2>&1; then + pass "$check_1_1_15" +else + warn "$check_1_1_15" +fi + +check_1_1_16="1.1.16 - Ensure that the --audit-log-path argument is set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-path' >/dev/null 2>&1; then + pass "$check_1_1_16" +else + warn "$check_1_1_16" +fi + +check_1_1_17="1.1.17 - Ensure that the --audit-log-maxage argument is set to 30 or as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxage' >/dev/null 2>&1; then + maxage=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxage'|cut -d " " -f 1) + if [ "$maxage" = "30" ]; then + pass "$check_1_1_17" + pass " * audit-log-maxage: $maxage" + else + warn "$check_1_1_17" + warn " * audit-log-maxage: $maxage" + fi +else + warn "$check_1_1_17" +fi + +check_1_1_18="1.1.18 - Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxbackup' >/dev/null 2>&1; then + maxbackup=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxbackup'|cut -d " " -f 1) + if [ "$maxbackup" = "10" ]; then + pass "$check_1_1_18" + pass " * audit-log-maxbackup: $maxbackup" + else + warn "$check_1_1_18" + warn " * audit-log-maxbackup: $maxbackup" + fi +else + warn "$check_1_1_18" +fi + +check_1_1_19="1.1.19 - Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxsize' >/dev/null 2>&1; then + maxsize=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxsize'|cut -d " " -f 1) + if [ "$maxsize" = "100" ]; then + pass "$check_1_1_19" + pass " * audit-log-maxsize: $maxsize" + else + warn "$check_1_1_19" + warn " * audit-log-maxsize: $maxsize" + fi +else + warn "$check_1_1_19" +fi + +check_1_1_20="1.1.20 - Ensure that the --authorization-mode argument is not set to AlwaysAllow" +if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'AlwaysAllow' >/dev/null 2>&1; then + warn "$check_1_1_20" +else + pass "$check_1_1_20" +fi + +check_1_1_21="1.1.21 - Ensure that the --token-auth-file parameter is not set" +if check_argument "$CIS_APISERVER_CMD" '--token-auth-file' >/dev/null 2>&1; then + warn "$check_1_1_21" +else + pass "$check_1_1_21" +fi + +check_1_1_22="1.1.22 - Ensure that the --kubelet-certificate-authority argument is set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--kubelet-certificate-authority' >/dev/null 2>&1; then + pass "$check_1_1_22" +else + warn "$check_1_1_22" +fi + +check_1_1_23="1.1.23 - Ensure that the --kubelet-client-certificate and --kubelet-client-key arguments are set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-certificate' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-key' >/dev/null 2>&1; then + certificate=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-certificate') + key=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-key') + pass "$check_1_1_23" + pass " * kubelet-client-certificate: $certificate" + pass " * kubelet-client-key: $key" + else + warn "$check_1_1_23" + fi +else + warn "$check_1_1_23" +fi + +check_1_1_24="1.1.24 - Ensure that the --service-account-lookup argument is set to true" +if check_argument "$CIS_APISERVER_CMD" '--service-account-lookup' >/dev/null 2>&1; then + pass "$check_1_1_24" +else + warn "$check_1_1_24" +fi + +check_1_1_25="1.1.25 - Ensure that the admission control policy is set to PodSecurityPolicy" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'PodSecurityPolicy' >/dev/null 2>&1; then + pass "$check_1_1_25" +else + warn "$check_1_1_25" +fi + +check_1_1_26="1.1.26 - Ensure that the --service-account-key-file argument is set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--service-account-key-file' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_APISERVER_CMD" '--service-account-key-file') + pass "$check_1_1_26" + pass " * service-account-key-file: $file" +else + warn "$check_1_1_26" +fi + +check_1_1_27="1.1.27 - Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--etcd-certfile' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--etcd-keyfile' >/dev/null 2>&1; then + certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-certfile') + keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-keyfile') + pass "$check_1_1_27" + pass " * etcd-certfile: $certfile" + pass " * etcd-keyfile: $keyfile" + else + warn "$check_1_1_27" + fi +else + warn "$check_1_1_27" +fi + +check_1_1_28="1.1.28 - Ensure that the admission control policy is set to ServiceAccount" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'ServiceAccount' >/dev/null 2>&1; then + pass "$check_1_1_28" +else + warn "$check_1_1_28" +fi + +check_1_1_29="1.1.29 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--tls-cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--tls-private-key-file' >/dev/null 2>&1; then + certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-cert-file') + keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-private-key-file') + pass "$check_1_1_29" + pass " * tls-cert-file: $certfile" + pass " * tls-private-key-file: $keyfile" + else + warn "$check_1_1_29" + fi +else + warn "$check_1_1_29" +fi + +check_1_1_30="1.1.30 - Ensure that the --client-ca-file argument is set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then + cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') + pass "$check_1_1_30" + pass " * client-ca-file: $cafile" +else + warn "$check_1_1_30" +fi + +check_1_1_31="1.1.31 - Ensure that the --etcd-cafile argument is set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--etcd-cafile' >/dev/null 2>&1; then + cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-cafile') + pass "$check_1_1_31" + pass " * etcd-cafile: $cafile" +else + warn "$check_1_1_31" +fi + +check_1_1_32="1.1.32 - Ensure that the admission control policy is set to NodeRestriction" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'NodeRestriction' >/dev/null 2>&1; then + pass "$check_1_1_32" +else + warn "$check_1_1_32" +fi + +check_1_1_33="1.1.33 - Ensure that the --experimental-encryption-provider-config argument is set as appropriate" +if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then + pass "$check_1_1_33" +else + warn "$check_1_1_33" +fi + +check_1_1_34="1.1.34 - Ensure that the encryption provider is set to aescbc" +if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then + encryptionConfig=$(get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config') + if sed ':a;N;$!ba;s/\n/ /g' $encryptionConfig |grep "providers:\s* - aescbc" >/dev/null 2>&1; then + pass "$check_1_1_34" + else + warn "$check_1_1_34" + fi +else + warn "$check_1_1_34" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.0.0/master/master_2_scheduler.sh b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_2_scheduler.sh new file mode 100755 index 0000000..0d18066 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_2_scheduler.sh @@ -0,0 +1,9 @@ +info "1.2 - Scheduler" + +check_1_2_1="1.2.1 - Ensure that the --profiling argument is set to false" +if check_argument "$CIS_SCHEDULER_CMD" '--profiling=false' >/dev/null 2>&1; then + pass "$check_1_2_1" +else + warn "$check_1_2_1" +fi + diff --git a/scripts/kubernetes-cis-benchmark/1.0.0/master/master_3_contoller_manager.sh b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_3_contoller_manager.sh new file mode 100755 index 0000000..7300653 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_3_contoller_manager.sh @@ -0,0 +1,49 @@ +info "1.3 - Controller Manager" + +check_1_3_1="1.3.1 - Ensure that the --terminated-pod-gc-threshold argument is set as appropriate" +if check_argument "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold' >/dev/null 2>&1; then + threshold=$(get_argument_value "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold') + pass "$check_1_3_1" + pass " * terminated-pod-gc-threshold: $threshold" +else + warn "$check_1_3_1" +fi + +check_1_3_2="1.3.2 - Ensure that the --profiling argument is set to false" +if check_argument "$CIS_MANAGER_CMD" '--profiling=false' >/dev/null 2>&1; then + pass "$check_1_3_2" +else + warn "$check_1_3_2" +fi + +check_1_3_3="1.3.3 - Ensure that the --insecure-experimental-approve-all-kubelet-csrs-for-group argument is not set" +if check_argument "$CIS_MANAGER_CMD" '--insecure-experimental-approve-all-kubelet-csrs-for-group' >/dev/null 2>&1; then + warn "$check_1_3_3" +else + pass "$check_1_3_3" +fi + +check_1_3_4="1.3.4 - Ensure that the --use-service-account-credentials argument is set to true" +if check_argument "$CIS_MANAGER_CMD" '--use-service-account-credentials' >/dev/null 2>&1; then + pass "$check_1_3_4" +else + warn "$check_1_3_4" +fi + +check_1_3_5="1.3.5 - Ensure that the --service-account-private-key-file argument is set as appropriate" +if check_argument "$CIS_MANAGER_CMD" '--service-account-private-key-file' >/dev/null 2>&1; then + keyfile=$(get_argument_value "$CIS_MANAGER_CMD" '--service-account-private-key-file') + pass "$check_1_3_5" + pass " * service-account-private-key-file: $keyfile" +else + warn "$check_1_3_5" +fi + +check_1_3_6="1.3.6 - Ensure that the --root-ca-file argument is set as appropriate" +if check_argument "$CIS_MANAGER_CMD" '--root-ca-file' >/dev/null 2>&1; then + cafile=$(get_argument_value "$CIS_MANAGER_CMD" '--root-ca-file') + pass "$check_1_3_6" + pass " * root-ca-file: $cafile" +else + warn "$check_1_3_6" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.0.0/master/master_4_configuration_files.sh b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_4_configuration_files.sh new file mode 100755 index 0000000..d04d2dd --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_4_configuration_files.sh @@ -0,0 +1,168 @@ +info "1.4 - Configuration Files" + +check_1_4_1="1.4.1 - Ensure that the apiserver file permissions are set to 644 or more restrictive" +if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then + file="/etc/kubernetes/manifests/kube-apiserver.json" +else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_1" + else + warn "$check_1_4_1" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_1" + info " * File not found" +fi + +check_1_4_2="1.4.2 - Ensure that the apiserver file ownership is set to root:root" +if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then + file="/etc/kubernetes/manifests/kube-apiserver.json" +else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_2" + else + warn "$check_1_4_2" + warn " * Wrong ownership for $file" + fi +else + info "$check_1_4_2" +fi + +check_1_4_3="1.4.3 - Ensure that the config file permissions are set to 644 or more restrictive" +file="/etc/kubernetes/admin.conf" +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_3" + else + warn "$check_1_4_3" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_3" + info " * File not found" +fi + +check_1_4_4="1.4.4 - Ensure that the config file ownership is set to root:root" +file="/etc/kubernetes/admin.conf" +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_4" + else + warn "$check_1_4_4" + warn " * Wrong ownership for $file" + fi +else + info "$check_1_4_4" + info " * File not found" +fi + +check_1_4_5="1.4.5 - Ensure that the scheduler file permissions are set to 644 or more restrictive" +if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then + file="/etc/kubernetes/manifests/kube-scheduler.json" +else + file="/etc/kubernetes/manifests/kube-scheduler.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_5" + else + warn "$check_1_4_5" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_5" + info " * File not found" +fi + +check_1_4_6="1.4.6 - Ensure that the scheduler file ownership is set to root:root" +if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then + file="/etc/kubernetes/manifests/kube-scheduler.json" +else + file="/etc/kubernetes/manifests/kube-scheduler.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_6" + else + warn "$check_1_4_6" + warn " * Wrong ownership for $file" + fi +else + info "$check_1_4_6" + info " * File not found" +fi + +check_1_4_7="1.4.7 - Ensure that the etcd.conf file permissions are set to 644 or more restrictive" +if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then + file="/etc/kubernetes/manifests/etcd.json" +else + file="/etc/kubernetes/manifests/etcd.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_7" + else + warn "$check_1_4_7" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_7" + info " * File not found" +fi + +check_1_4_8="1.4.8 - Ensure that the etcd.conf file ownership is set to root:root" +if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then + file="/etc/kubernetes/manifests/etcd.json" +else + file="/etc/kubernetes/manifests/etcd.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_8" + else + warn "$check_1_4_8" + warn " * Wrong ownership for $file" + fi +else + info "$check_1_4_8" +fi + +#TODO +check_1_4_9="1.4.9 - Ensure that the flanneld file permissions are set to 644 or more restrictive" +check_1_4_10="1.4.10 - Ensure that the flanneld file ownership is set to root:root" +check_1_4_11="1.4.11 - Ensure that the etcd data directory permissions are set to 700 or more restrictive" +directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') +if [ -d $directory ]; then + if [ "$(stat -c %a $directory)" -eq 700 ]; then + pass "$check_1_4_11" + else + warn "$check_1_4_11" + perm=$(stat -c %a $directory) + warn " * Wrong permissions for $directory:$perm" + fi +else + warn "$check_1_4_11" + warn " * Directory not found:$directory" +fi + +check_1_4_12="1.4.12 - Ensure that the etcd data directory ownership is set to etcd:etcd" +directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') +if [ -d $directory ]; then + if [ "$(stat -c %U:%G $directory)" = "etcd:etcd" ]; then + pass "$check_1_4_12" + else + warn "$check_1_4_12" + owner=$(stat -c %U:%G $directory) + warn " * Wrong ownership for $directory:$owner" + fi +else + warn "$check_1_4_12" + warn " * Directory not found:$directory" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.0.0/master/master_5_etcd.sh b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_5_etcd.sh new file mode 100755 index 0000000..8d3c988 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_5_etcd.sh @@ -0,0 +1,78 @@ +info "1.5 - etcd" + +check_1_5_1="1.5.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)" +if check_argument "$CIS_ETCD_CMD" '--cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_ETCD_CMD" '--key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_ETCD_CMD" '--cert-file') + kfile=$(get_argument_value "$CIS_ETCD_CMD" '--key-file') + pass "$check_1_5_1" + pass " * cert-file: $cfile" + pass " * key-file: $kfile" + else + warn "$check_1_5_1" + fi +else + warn "$check_1_5_1" +fi + +check_1_5_2="1.5.2 - Ensure that the --client-cert-auth argument is set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--client-cert-auth' >/dev/null 2>&1; then + pass "$check_1_5_2" +else + warn "$check_1_5_2" +fi + +check_1_5_3="1.5.3 - Ensure that the --auto-tls argument is not set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--auto-tls=tru' >/dev/null 2>&1; then + warn "$check_1_5_3" +else + pass "$check_1_5_3" +fi + +check_1_5_4="1.5.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_ETCD_CMD" '--peer-key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-cert-file') + kfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-key-file') + pass "$check_1_5_4" + pass " * peer-cert-file: $cfile" + pass " * peer-key-file: $kfile" + else + warn "$check_1_5_4" + fi +else + warn "$check_1_5_4" +fi + +check_1_5_5="1.5.5 - Ensure that the --peer-client-cert-auth argument is set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-client-cert-auth' >/dev/null 2>&1; then + pass "$check_1_5_5" +else + warn "$check_1_5_5" +fi + +check_1_5_6="1.5.6 - Ensure that the --peer-auto-tls argument is not set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-auto-tls=true' >/dev/null 2>&1; then + warn "$check_1_5_6" +else + pass "$check_1_5_6" +fi + +check_1_5_7="1.5.7 - Ensure that the --wal-dir argument is set as appropriate (Scored)" +if check_argument "$CIS_ETCD_CMD" '--wal-dir' >/dev/null 2>&1; then + wdir=$(get_argument_value "$CIS_ETCD_CMD" '--wal-dir') + pass "$check_1_5_7" + pass " * wal-dir: $wdir" +else + warn "$check_1_5_7" +fi + +check_1_5_8="1.5.8 - Ensure that the --max-wals argument is set to 0 (Scored)" +if check_argument "$CIS_ETCD_CMD" '--max-wals=0' >/dev/null 2>&1; then + pass "$check_1_5_8" +else + warn "$check_1_5_8" +fi + +#TODO +check_1_5_9="1.5.9 - Ensure that a unique Certificate Authority is used for etcd (Not Scored)" diff --git a/scripts/kubernetes-cis-benchmark/1.0.0/master/master_6_general_security_primitives.sh b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_6_general_security_primitives.sh new file mode 100755 index 0000000..de9bf56 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.0.0/master/master_6_general_security_primitives.sh @@ -0,0 +1,48 @@ +info "1.6 - General Security Primitives" + +# Make the loop separator be a new-line in POSIX compliant fashion +set -f; IFS=$' +' + +check_1_6_1="1.6.1 - Ensure that the cluster-admin role is only used where required(Not Scored)" +cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) +info $check_1_6_1 +for admin in $cluster_admins; do + info " * $admin" +done + +check_1_6_2="1.6.2 - Create Pod Security Policies for your cluster (Not Scored)" +policies=$(kubectl get psp) +info $check_1_6_2 +for policy in $policies; do + info " * $policy" +done + +check_1_6_3="1.6.3 - Create administrative boundaries between resources using namespaces (Not Scored)" +namespaces=$(kubectl get namespaces) +info $check_1_6_3 +for namespace in $namespaces; do + info " * $namespace" +done + +check_1_6_4="1.6.4 - Create network segmentation using Network Policies (Not Scored)" +policies=$(kubectl get pods --namespace=kube-system) +info $check_1_6_4 +for policy in $policies; do + info " * $policy" +done + +check_1_6_5="1.6.5 - Avoid using Kubernetes Secrets (Not Scored)" +secrets=$(kubectl get secrets) +info $check_1_6_5 +for secret in $secrets; do + info " * $secret" +done + +#TODO +check_1_6_6="1.6.6 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)" +info $check_1_6_6 +check_1_6_7="1.6.7 - Apply Security Context to Your Pods and Containers (Not Scored)" +info $check_1_6_7 +check_1_6_8="1.6.8 - Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)" +info $check_1_6_8 diff --git a/scripts/kubeBench/kube_worker_1_0_0.tmpl b/scripts/kubernetes-cis-benchmark/1.0.0/worker/worker_1_kubelet.sh old mode 100644 new mode 100755 similarity index 50% rename from scripts/kubeBench/kube_worker_1_0_0.tmpl rename to scripts/kubernetes-cis-benchmark/1.0.0/worker/worker_1_kubelet.sh index 4bc4e21..63a1d6c --- a/scripts/kubeBench/kube_worker_1_0_0.tmpl +++ b/scripts/kubernetes-cis-benchmark/1.0.0/worker/worker_1_kubelet.sh @@ -1,94 +1,3 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - txtrst='\033[0m' -fi - -info () { - printf "%b\n" "${bldblu}[INFO]${txtrst} $1" -} - -pass () { - printf "%b\n" "${bldgrn}[PASS]${txtrst} $1" -} - -warn () { - printf "%b\n" "${bldred}[WARN]${txtrst} $1" -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2016- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_KUBELET_CMD="<<<.Replace_kubelet_cmd>>>" - -if ps -ef | grep "$CIS_KUBELET_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Worker Node Security Configuration" -else - info "This node is not a Kubernetes worker node" - exit 2 -fi - info "2.1 - Kubelet" check_2_1_1="2.1.1 - Ensure that the --allow-privileged argument is set to false" @@ -212,96 +121,3 @@ else warn "$check_2_1_13" fi -info "2.2 - Configuration Files" - -check_2_2_1="2.2.1 - Ensure that the config file permissions are set to 644 or more restrictive" -if [ -f "/etc/kubernetes/config" ]; then - file="/etc/kubernetes/config" -else - file="/etc/kubernetes/kubelet.conf" -fi - -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_2_2_1" - else - warn "$check_2_2_1" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_1" - info " * File not found" -fi - -check_2_2_2="2.2.2 - Ensure that the config file ownership is set to root:root" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_2" - else - warn "$check_2_2_2" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_2" -fi - -check_2_2_3="2.2.3 - Ensure that the kubelet file permissions are set to 644 or more restrictive" -if [ -f "/etc/kubernetes/kubelet" ]; then - file="/etc/kubernetes/kubelet" -else - file="/etc/kubernetes/kubelet.conf" -fi - -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_2_2_3" - else - warn "$check_2_2_3" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_3" - info " * File not found" -fi - -check_2_2_4="2.2.4 - Ensure that the kubelet file ownership is set to root:root" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_4" - else - warn "$check_2_2_4" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_4" -fi - -check_2_2_5="2.2.5 - Ensure that the proxy file permissions are set to 644 or more restrictive" -file="/etc/kubernetes/proxy" - -if [ -f "$file" ]; then - if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 ]; then - pass "$check_2_2_5" - else - warn "$check_2_2_5" - warn " * Wrong permissions for $file" - fi -else - info "$check_2_2_5" - info " * File not found" -fi - -check_2_2_6="2.2.6 - Ensure that the proxy file ownership is set to root:root" -if [ -f "$file" ]; then - if [ "$(stat -c %u%g $file)" -eq 00 ]; then - pass "$check_2_2_6" - else - warn "$check_2_2_6" - warn " * Wrong ownership for $file" - fi -else - info "$check_2_2_6" -fi - - -exit 0; diff --git a/scripts/kubernetes-cis-benchmark/1.0.0/worker/worker_2_configure_files.sh b/scripts/kubernetes-cis-benchmark/1.0.0/worker/worker_2_configure_files.sh new file mode 100755 index 0000000..08191bb --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.0.0/worker/worker_2_configure_files.sh @@ -0,0 +1,92 @@ +info "2.2 - Configuration Files" + +check_2_2_1="2.2.1 - Ensure that the config file permissions are set to 644 or more restrictive" +if [ -f "/etc/kubernetes/config" ]; then + file="/etc/kubernetes/config" +else + file="/etc/kubernetes/kubelet.conf" +fi + +if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_2_2_1" + else + warn "$check_2_2_1" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_1" + info " * File not found" +fi + +check_2_2_2="2.2.2 - Ensure that the config file ownership is set to root:root" +if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_2" + else + warn "$check_2_2_2" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_2" +fi + +check_2_2_3="2.2.3 - Ensure that the kubelet file permissions are set to 644 or more restrictive" +if [ -f "/etc/kubernetes/kubelet" ]; then + file="/etc/kubernetes/kubelet" +else + file="/etc/kubernetes/kubelet.conf" +fi + +if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_2_2_3" + else + warn "$check_2_2_3" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_3" + info " * File not found" +fi + +check_2_2_4="2.2.4 - Ensure that the kubelet file ownership is set to root:root" +if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_4" + else + warn "$check_2_2_4" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_4" +fi + +check_2_2_5="2.2.5 - Ensure that the proxy file permissions are set to 644 or more restrictive" +file="/etc/kubernetes/proxy" + +if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_2_2_5" + else + warn "$check_2_2_5" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_5" + info " * File not found" +fi + +check_2_2_6="2.2.6 - Ensure that the proxy file ownership is set to root:root" +if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_6" + else + warn "$check_2_2_6" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_6" +fi + + diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/federation.sh b/scripts/kubernetes-cis-benchmark/1.2.0/federation.sh new file mode 100755 index 0000000..9e4bd31 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/federation.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# ------------------------------------------------------------------------------ +# Kubenetes CIS benchmark 1.6 +# +# Neuvector, Inc. (c) 2016- +# +# NeuVector delivers an application and network intelligent container security +# solution that automatically adapts to protect running containers. Don’t let +# security concerns slow down your CI/CD processes. +# ------------------------------------------------------------------------------ +# Load dependencies +. ./helper.sh + +# Check for required program(s) +req_progs='grep' +for p in $req_progs; do + command -v "$p" >/dev/null 2>&1 || { printf "%s command not found.\n" "$p"; exit 1; } +done + +# Load all the tests from tests/ and run them +main () { + info "3 - Federated Deployments" + + for test in federation/federation_*.sh + do + . ./"$test" + done +} + +main "$@" + diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/federation/check_federation.sh b/scripts/kubernetes-cis-benchmark/1.2.0/federation/check_federation.sh new file mode 100755 index 0000000..ace1978 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/federation/check_federation.sh @@ -0,0 +1,8 @@ + +if ps -ef | grep federation-apiserver 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then + info "Kubernetes Federated Deployments" +else + info "This node is not a Kubernetes Federated node" + exit 2 +fi + diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/federation/federation_1_api_server.sh b/scripts/kubernetes-cis-benchmark/1.2.0/federation/federation_1_api_server.sh new file mode 100755 index 0000000..34bbd70 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/federation/federation_1_api_server.sh @@ -0,0 +1,189 @@ +info "3.1 - Federation API Server" + +check_3_1_1="3.1.1 Ensure that the --anonymous-auth argument is set to false" +if check_argument 'federation-apiserver' '--anonymous-auth=false' >/dev/null 2>&1; then + pass "$check_3_1_1" +else + warn "$check_3_1_1" +fi + +check_3_1_=2"3.1.2 Ensure that the --basic-auth-file argument is not set" +if check_argument 'federation-apiserver' '--basic-auth-file' >/dev/null 2>&1; then + warn "$check_3_1_2" +else + pass "$check_3_1_2" +fi + +check_3_1_3="3.1.3 Ensure that the --insecure-allow-any-token argument is not set" +if check_argument 'federation-apiserver' '--insecure-allow-any-token' >/dev/null 2>&1; then + warn "$check_3_1_3" +else + pass "$check_3_1_3" +fi + +check_3_1_4="3.1.4 Ensure that the --insecure-bind-address argument is not set" +if check_argument 'federation-apiserver' '--insecure-bind-address' >/dev/null 2>&1; then + warn "$check_3_1_4" +else + pass "$check_3_1_4" +fi + +check_3_1_5="3.1.5 Ensure that the --insecure-port argument is set to 0" +if check_argument 'federation-apiserver' '--insecure-port' >/dev/null 2>&1; then + port=$(get_argument_value 'federation-apiserver' '--insecure-port'|cut -d " " -f 1) + if [ "$port" = "0" ]; then + pass "$check_3_1_5" + else + warn "$check_3_1_5" + warn " * insecure-port: $port" + fi +else + warn "$check_3_1_5" +fi + +check_3_1_6="3.1.6 Ensure that the --secure-port argument is not set to 0" +if check_argument 'federation-apiserver' '--secure-port' >/dev/null 2>&1; then + port=$(get_argument_value 'federation-apiserver' '--secure-port'|cut -d " " -f 1) + if [ "$port" = "0" ]; then + warn "$check_3_1_6" + warn " * secure-port: $port" + else + pass "$check_3_1_6" + fi +else + pass "$check_3_1_6" +fi + +check_3_1_7="3.1.7 Ensure that the --profiling argument is set to false" +if check_argument 'federation-apiserver' '--profiling=false' >/dev/null 2>&1; then + pass "$check_3_1_7" +else + warn "$check_3_1_7" +fi + +check_3_1_8="3.1.8 Ensure that the admission control policy is not set to AlwaysAdmit" +if get_argument_value 'federation-apiserver' '--admission-control'| grep 'AlwaysAdmit' >/dev/null 2>&1; then + warn "$check_3_1_8" +else + pass "$check_3_1_8" +fi + +check_3_1_9="3.1.9 Ensure that the admission control policy is set to NamespaceLifecycle" +if get_argument_value 'federation-apiserver' '--admission-control'| grep 'NamespaceLifecycle' >/dev/null 2>&1; then + pass "$check_3_1_9" +else + warn "$check_3_1_9" +fi + +check_3_1_10="3.1.10 Ensure that the --audit-log-path argument is set as appropriate" +if check_argument 'federation-apiserver' '--audit-log-path' >/dev/null 2>&1; then + v=$(get_argument_value 'federation-apiserver' '--audit-log-path') + pass "$check_3_1_10" + pass " * audit-log-path: $v" +else + warn "$check_3_1_10" +fi + +check_3_1_11="3.1.11 Ensure that the --audit-log-maxage argument is set to 30 or as appropriate" +if check_argument 'federation-apiserver' '--audit-log-maxage' >/dev/null 2>&1; then + v=$(get_argument_value 'federation-apiserver' '--audit-log-maxage'|cut -d " " -f 1) + if [ "$v" = "30" ]; then + pass "$check_3_1_11" + pass " * audit-log-maxage: $v" + else + warn "$check_3_1_11" + warn " * audit-log-maxage: $v" + fi +else + warn "$check_3_1_11" +fi + +check_3_1_12="3.1.12 Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate" +if check_argument 'federation-apiserver' '--audit-log-maxbackup' >/dev/null 2>&1; then + v=$(get_argument_value 'federation-apiserver' '--audit-log-maxbackup' |cut -d " " -f 1) + if [ "$v" = "10" ]; then + pass "$check_3_1_12" + pass " * audit-log-maxbackup : $v" + else + warn "$check_3_1_12" + warn " * audit-log-maxbackup : $v" + fi +else + warn "$check_3_1_12" +fi + +check_3_1_13="3.1.13 Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate" +if check_argument 'federation-apiserver' '--audit-log-maxsize' >/dev/null 2>&1; then + v=$(get_argument_value 'federation-apiserver' '--audit-log-maxsize' |cut -d " " -f 1) + if [ "$v" = "100" ]; then + pass "$check_3_1_13" + pass " * audit-log-maxsize : $v" + else + warn "$check_3_1_13" + warn " * audit-log-maxsize : $v" + fi +else + warn "$check_3_1_13" +fi + +check_3_1_14="3.1.14 Ensure that the --authorization-mode argument is not set to AlwaysAllow" +if get_argument_value 'federation-apiserver' '--authorization-mode'| grep 'AlwaysAllow' >/dev/null 2>&1; then + warn "$check_3_1_14" +else + pass "$check_3_1_14" +fi + +check_3_1_15="3.1.15 Ensure that the --token-auth-file parameter is not set" +if check_argument 'federation-apiserver' '--token-auth-file' >/dev/null 2>&1; then + warn "$check_3_1_15" +else + pass "$check_3_1_15" +fi + +check_3_1_16="3.1.16 Ensure that the --service-account-lookup argument is set to true" +if check_argument 'federation-apiserver' '--service-account-lookup=true' >/dev/null 2>&1; then + pass "$check_3_1_16" +else + warn "$check_3_1_16" +fi + +check_3_1_17="3.1.17 Ensure that the --service-account-key-file argument is set as appropriate" +if check_argument 'federation-apiserver' '--service-account-key-file' >/dev/null 2>&1; then + v=$(get_argument_value 'federation-apiserver' '--service-account-key-file') + pass "$check_3_1_17" + pass " * service-account-key-file: $v" +else + warn "$check_3_1_17" +fi + +check_3_1_18="3.1.18 Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate" +if check_argument 'federation-apiserver' '--etcd-certfile' >/dev/null 2>&1; then + if check_argument 'federation-apiserver' '--etcd-keyfile' >/dev/null 2>&1; then + v1=$(get_argument_value 'federation-apiserver' '--etcd-certfile') + v2=$(get_argument_value 'federation-apiserver' '--etcd-keyfile') + pass "$check_3_1_18" + pass " * etcd-certfile: $v1" + pass " * etcd-keyfile: $v2" + else + warn "$check_3_1_18" + fi +else + warn "$check_3_1_18" +fi + +check_3_1_19="3.1.19 Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate" +if check_argument 'federation-apiserver' '--tls-cert-file' >/dev/null 2>&1; then + if check_argument 'federation-apiserver' '--tls-private-key-file' >/dev/null 2>&1; then + v1=$(get_argument_value 'federation-apiserver' '--tls-cert-file') + v2=$(get_argument_value 'federation-apiserver' '--tls-private-key-file') + pass "$check_3_1_19" + pass " * tls-cert-file: $v1" + pass " * tls-private-key-file: $v2" + else + warn "$check_3_1_19" + fi +else + warn "$check_3_1_19" +fi + + diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/federation/federation_2_controller_manager.sh b/scripts/kubernetes-cis-benchmark/1.2.0/federation/federation_2_controller_manager.sh new file mode 100755 index 0000000..b9a5b7b --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/federation/federation_2_controller_manager.sh @@ -0,0 +1,9 @@ +info "3.2 - Federation Controller Manager" + +check_3_2_1="Ensure that the --profiling argument is set to false" +if check_argument 'federation-controller-manager' '--profiling=false' >/dev/null 2>&1; then + pass "$check_3_2_1" +else + warn "$check_3_2_1" +fi + diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/master.sh b/scripts/kubernetes-cis-benchmark/1.2.0/master.sh new file mode 100755 index 0000000..0233f07 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/master.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# ------------------------------------------------------------------------------ +# Kubenetes CIS benchmark 1.6 +# +# Neuvector, Inc. (c) 2016- +# ------------------------------------------------------------------------------ + +# Load dependencies +. ./helper.sh + +# Check for required program(s) +req_progs='grep' +for p in $req_progs; do + command -v "$p" >/dev/null 2>&1 || { printf "%s command not found.\n" "$p"; exit 1; } +done + +# Load all the tests from master/ and run them +main () { + for test in master/master_*.sh + do + . ./"$test" + done +} + +main "$@" diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/master/master_1_api_server.sh b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_1_api_server.sh new file mode 100755 index 0000000..e65913a --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_1_api_server.sh @@ -0,0 +1,340 @@ +info "1.1 - API Server" + +check_1_1_1="1.1.1 - Ensure that the --anonymous-auth argument is set to false" +if check_argument "$CIS_APISERVER_CMD" '--anonymous-auth=false' >/dev/null 2>&1; then + pass "$check_1_1_1" +else + warn "$check_1_1_1" +fi + +check_1_1_2="1.1.2 - Ensure that the --basic-auth-file argument is not set" +if check_argument "$CIS_APISERVER_CMD" '--basic-auth-file' >/dev/null 2>&1; then + warn "$check_1_1_2" +else + pass "$check_1_1_2" +fi + +check_1_1_3="1.1.3 - Ensure that the --insecure-allow-any-token argument is not set" +if check_argument "$CIS_APISERVER_CMD" '--insecure-allow-any-token' >/dev/null 2>&1; then + warn "$check_1_1_3" +else + pass "$check_1_1_3" +fi + +check_1_1_4="1.1.4 - Ensure that the --kubelet-https argument is set to true" +if check_argument "$CIS_APISERVER_CMD" '--kubelet-https=false' >/dev/null 2>&1; then + warn "$check_1_1_4" +else + pass "$check_1_1_4" +fi + +check_1_1_5="1.1.5 - Ensure that the --insecure-bind-address argument is not set" +if check_argument "$CIS_APISERVER_CMD" '--insecure-bind-address' >/dev/null 2>&1; then + address=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-bind-address'|cut -d " " -f 1) + if [ "$address" = "127.0.0.1" ]; then + pass "$check_1_1_5" + pass " * insecure-bind-address: $address" + else + warn "$check_1_1_5" + warn " * insecure-bind-address: $address" + fi +else + pass "$check_1_1_5" +fi + +check_1_1_6="1.1.6 - Ensure that the --insecure-port argument is set to 0" +if check_argument "$CIS_APISERVER_CMD" '--insecure-port' >/dev/null 2>&1; then + port=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-port'|cut -d " " -f 1) + if [ "$port" = "0" ]; then + pass "$check_1_1_6" + else + warn "$check_1_1_6" + warn " * insecure-port: $port" + fi +else + warn "$check_1_1_6" +fi + +check_1_1_7="1.1.7 - Ensure that the --secure-port argument is not set to 0" +if check_argument "$CIS_APISERVER_CMD" '--secure-port' >/dev/null 2>&1; then + port=$(get_argument_value "$CIS_APISERVER_CMD" '--secure-port'|cut -d " " -f 1) + if [ "$port" = "0" ]; then + warn "$check_1_1_7" + warn " * secure-port: $port" + else + pass "$check_1_1_7" + fi +else + pass "$check_1_1_7" +fi + +check_1_1_8="1.1.8 - Ensure that the --profiling argument is set to false" +if check_argument "$CIS_APISERVER_CMD" '--profiling=false' >/dev/null 2>&1; then + pass "$check_1_1_8" +else + warn "$check_1_1_8" +fi + +check_1_1_9="1.1.9 - Ensure that the --repair-malformed-updates argument is set to false" +if check_argument "$CIS_APISERVER_CMD" '--repair-malformed-updates=false' >/dev/null 2>&1; then + pass "$check_1_1_9" +else + warn "$check_1_1_9" +fi + +check_1_1_10="1.1.10 - Ensure that the admission control policy is not set to AlwaysAdmit" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'AlwaysAdmit' >/dev/null 2>&1; then + warn "$check_1_1_10" +else + pass "$check_1_1_10" +fi + +check_1_1_11="1.1.11 - Ensure that the admission control policy is set to AlwaysPullImages" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'AlwaysPullImages' >/dev/null 2>&1; then + pass "$check_1_1_11" +else + warn "$check_1_1_11" +fi + +check_1_1_12="1.1.12 - Ensure that the admission control policy is set to DenyEscalatingExec" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'DenyEscalatingExec' >/dev/null 2>&1; then + pass "$check_1_1_12" +else + warn "$check_1_1_12" +fi + +check_1_1_13="1.1.13 - Ensure that the admission control policy is set to SecurityContextDeny" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'SecurityContextDeny' >/dev/null 2>&1; then + pass "$check_1_1_13" +else + warn "$check_1_1_13" +fi + +check_1_1_14="1.1.14 - Ensure that the admission control policy is set to NamespaceLifecycle" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'NamespaceLifecycle' >/dev/null 2>&1; then + pass "$check_1_1_14" +else + warn "$check_1_1_14" +fi + +check_1_1_15="1.1.15 - Ensure that the --audit-log-path argument is set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-path' >/dev/null 2>&1; then + pass "$check_1_1_15" +else + warn "$check_1_1_15" +fi + +check_1_1_16="1.1.16 - Ensure that the --audit-log-maxage argument is set to 30 or as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxage' >/dev/null 2>&1; then + maxage=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxage'|cut -d " " -f 1) + if [ "$maxage" = "30" ]; then + pass "$check_1_1_16" + pass " * audit-log-maxage: $maxage" + else + warn "$check_1_1_16" + warn " * audit-log-maxage: $maxage" + fi +else + warn "$check_1_1_16" +fi + +check_1_1_17="1.1.17 - Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxbackup' >/dev/null 2>&1; then + maxbackup=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxbackup'|cut -d " " -f 1) + if [ "$maxbackup" = "10" ]; then + pass "$check_1_1_17" + pass " * audit-log-maxbackup: $maxbackup" + else + warn "$check_1_1_17" + warn " * audit-log-maxbackup: $maxbackup" + fi +else + warn "$check_1_1_17" +fi + +check_1_1_18="1.1.18 - Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxsize' >/dev/null 2>&1; then + maxsize=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxsize'|cut -d " " -f 1) + if [ "$maxsize" = "100" ]; then + pass "$check_1_1_18" + pass " * audit-log-maxsize: $maxsize" + else + warn "$check_1_1_18" + warn " * audit-log-maxsize: $maxsize" + fi +else + warn "$check_1_1_18" +fi + +check_1_1_19="1.1.19 - Ensure that the --authorization-mode argument is not set to AlwaysAllow" +if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'AlwaysAllow' >/dev/null 2>&1; then + warn "$check_1_1_19" +else + pass "$check_1_1_19" +fi + +check_1_1_20="1.1.20 - Ensure that the --token-auth-file parameter is not set" +if check_argument "$CIS_APISERVER_CMD" '--token-auth-file' >/dev/null 2>&1; then + warn "$check_1_1_20" +else + pass "$check_1_1_20" +fi + +check_1_1_21="1.1.21 - Ensure that the --kubelet-certificate-authority argument is set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--kubelet-certificate-authority' >/dev/null 2>&1; then + pass "$check_1_1_21" +else + warn "$check_1_1_21" +fi + +check_1_1_22="1.1.22 - Ensure that the --kubelet-client-certificate and --kubelet-client-key arguments are set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-certificate' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-key' >/dev/null 2>&1; then + certificate=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-certificate') + key=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-key') + pass "$check_1_1_22" + pass " * kubelet-client-certificate: $certificate" + pass " * kubelet-client-key: $key" + else + warn "$check_1_1_22" + fi +else + warn "$check_1_1_22" +fi + +check_1_1_23="1.1.23 - Ensure that the --service-account-lookup argument is set to true" +if check_argument "$CIS_APISERVER_CMD" '--service-account-lookup' >/dev/null 2>&1; then + pass "$check_1_1_23" +else + warn "$check_1_1_23" +fi + +check_1_1_24="1.1.24 - Ensure that the admission control policy is set to PodSecurityPolicy" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'PodSecurityPolicy' >/dev/null 2>&1; then + pass "$check_1_1_24" +else + warn "$check_1_1_24" +fi + +check_1_1_25="1.1.25 - Ensure that the --service-account-key-file argument is set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--service-account-key-file' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_APISERVER_CMD" '--service-account-key-file') + pass "$check_1_1_25" + pass " * service-account-key-file: $file" +else + warn "$check_1_1_25" +fi + +check_1_1_26="1.1.26 - Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--etcd-certfile' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--etcd-keyfile' >/dev/null 2>&1; then + certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-certfile') + keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-keyfile') + pass "$check_1_1_26" + pass " * etcd-certfile: $certfile" + pass " * etcd-keyfile: $keyfile" + else + warn "$check_1_1_26" + fi +else + warn "$check_1_1_26" +fi + +check_1_1_27="1.1.27 - Ensure that the admission control policy is set to ServiceAccount" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'ServiceAccount' >/dev/null 2>&1; then + pass "$check_1_1_27" +else + warn "$check_1_1_27" +fi + +check_1_1_28="1.1.28 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--tls-cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--tls-private-key-file' >/dev/null 2>&1; then + certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-cert-file') + keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-private-key-file') + pass "$check_1_1_28" + pass " * tls-cert-file: $certfile" + pass " * tls-private-key-file: $keyfile" + else + warn "$check_1_1_28" + fi +else + warn "$check_1_1_28" +fi + +check_1_1_29="1.1.29 - Ensure that the --client-ca-file argument is set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then + cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') + pass "$check_1_1_29" + pass " * client-ca-file: $cafile" +else + warn "$check_1_1_29" +fi + +check_1_1_30="1.1.30 - Ensure that the --etcd-cafile argument is set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--etcd-cafile' >/dev/null 2>&1; then + cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-cafile') + pass "$check_1_1_30" + pass " * etcd-cafile: $cafile" +else + warn "$check_1_1_30" +fi + +check_1_1_31="1.1.31 - Ensure that the --authorization-mode argument is set to Node" +if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'Node' >/dev/null 2>&1; then + pass "$check_1_1_31" +else + warn "$check_1_1_31" +fi + +check_1_1_32="1.1.32 - Ensure that the admission control policy is set to NodeRestriction" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'NodeRestriction' >/dev/null 2>&1; then + pass "$check_1_1_32" +else + warn "$check_1_1_32" +fi + +check_1_1_33="1.1.33 - Ensure that the --experimental-encryption-provider-config argument is set as appropriate" +if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then + pass "$check_1_1_33" +else + warn "$check_1_1_33" +fi + +check_1_1_34="1.1.34 - Ensure that the encryption provider is set to aescbc" +if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then + encryptionConfig=$(get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config') + if sed ':a;N;$!ba;s/\n/ /g' $encryptionConfig |grep "providers:\s* - aescbc" >/dev/null 2>&1; then + pass "$check_1_1_34" + else + warn "$check_1_1_34" + fi +else + warn "$check_1_1_34" +fi + +check_1_1_35="1.1.35 - Ensure that the admission control policy is set to EventRateLimit" +if get_argument_value "$CIS_APISERVER_CMD" '--admission-control'| grep 'EventRateLimit' >/dev/null 2>&1; then + pass "$check_1_1_35" + admissionctrl=$(get_argument_value "$CIS_APISERVER_CMD" '--admission-control') + pass " * : $admissionctrl" +else + warn "$check_1_1_35" +fi + +check_1_1_36="1.1.36 - Ensure that the AdvancedAuditing argument is not set to false" +if get_argument_value "$CIS_APISERVER_CMD" '--feature-gates'| grep 'AdvancedAuditing=false' >/dev/null 2>&1; then + warn "$check_1_1_36" +else + pass "$check_1_1_36" +fi + +check_1_1_37="1.1.37 - Ensure that the --request-timeout argument is set as appropriate" +if check_argument "$CIS_APISERVER_CMD" '--request-timeout' >/dev/null 2>&1; then + requestTimeout=$(get_argument_value "$CIS_APISERVER_CMD" '--request-timeout') + warn "$check_1_1_37" + warn " * request-timeout: $requestTimeout" +else + pass "$check_1_1_37" +fi + diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/master/master_2_scheduler.sh b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_2_scheduler.sh new file mode 100755 index 0000000..0d18066 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_2_scheduler.sh @@ -0,0 +1,9 @@ +info "1.2 - Scheduler" + +check_1_2_1="1.2.1 - Ensure that the --profiling argument is set to false" +if check_argument "$CIS_SCHEDULER_CMD" '--profiling=false' >/dev/null 2>&1; then + pass "$check_1_2_1" +else + warn "$check_1_2_1" +fi + diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/master/master_3_contoller_manager.sh b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_3_contoller_manager.sh new file mode 100755 index 0000000..24cd6be --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_3_contoller_manager.sh @@ -0,0 +1,45 @@ +info "1.3 - Controller Manager" + +check_1_3_1="1.3.1 - Ensure that the --terminated-pod-gc-threshold argument is set as appropriate" +# Filter out processes like "/bin/tee -a /var/log/kube-controller-manager.log" +# which exist on kops-managed clusters. +if check_argument "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold' >/dev/null 2>&1; then + threshold=$(get_argument_value "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold') + pass "$check_1_3_1" + pass " * terminated-pod-gc-threshold: $threshold" +else + echo "done" + warn "$check_1_3_1" +fi + +check_1_3_2="1.3.2 - Ensure that the --profiling argument is set to false" +if check_argument "$CIS_MANAGER_CMD" '--profiling=false' >/dev/null 2>&1; then + pass "$check_1_3_2" +else + warn "$check_1_3_2" +fi + +check_1_3_3="1.3.3 - Ensure that the --use-service-account-credentials argument is set to true" +if check_argument "$CIS_MANAGER_CMD" '--use-service-account-credentials' >/dev/null 2>&1; then + pass "$check_1_3_3" +else + warn "$check_1_3_3" +fi + +check_1_3_4="1.3.4 - Ensure that the --service-account-private-key-file argument is set as appropriate" +if check_argument "$CIS_MANAGER_CMD" '--service-account-private-key-file' >/dev/null 2>&1; then + keyfile=$(get_argument_value "$CIS_MANAGER_CMD" '--service-account-private-key-file') + pass "$check_1_3_4" + pass " * service-account-private-key-file: $keyfile" +else + warn "$check_1_3_4" +fi + +check_1_3_5="1.3.5 - Ensure that the --root-ca-file argument is set as appropriate" +if check_argument "$CIS_MANAGER_CMD" '--root-ca-file' >/dev/null 2>&1; then + cafile=$(get_argument_value "$CIS_MANAGER_CMD" '--root-ca-file') + pass "$check_1_3_5" + pass " * root-ca-file: $cafile" +else + warn "$check_1_3_5" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/master/master_4_configuration_files.sh b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_4_configuration_files.sh new file mode 100755 index 0000000..9fe1a73 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_4_configuration_files.sh @@ -0,0 +1,293 @@ +info "1.4 - Configuration Files" + +check_1_4_1="1.4.1 - Ensure that the API server pod specification file permissions are set to 644 or more restrictive" +if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then + file="/etc/kubernetes/manifests/kube-apiserver.json" +elif [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" +else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_1" + else + warn "$check_1_4_1" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_1" + info " * File not found" +fi + +check_1_4_2="1.4.2 - Ensure that the API server pod specification file ownership is set to root:root" +if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then + file="/etc/kubernetes/manifests/kube-apiserver.json" +elif [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" +else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_2" + else + warn "$check_1_4_2" + warn " * Wrong ownership for $file" + fi +else + info "$check_1_4_2" +fi + +check_1_4_3="1.4.3 - Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive" +if [ -f "/etc/kubernetes/manifests/kube-controller-manager.json" ]; then + file="/etc/kubernetes/manifests/kube-controller-manager.json" +elif [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-controller-manager.manifest" +else + file="/etc/kubernetes/manifests/kube-controller-manager.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_3" + else + warn "$check_1_4_3" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_3" + info " * File not found" +fi + +check_1_4_4="1.4.4 - Ensure that the controller manager pod specification file ownership is set to root:root" +if [ -f "/etc/kubernetes/manifests/kube-controller-manager.json" ]; then + file="/etc/kubernetes/manifests/kube-controller-manager.json" +elif [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-controller-manager.manifest" +else + file="/etc/kubernetes/manifests/kube-controller-manager.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_4" + else + warn "$check_1_4_4" + warn " * Wrong ownership for $file" + fi +else + info "$check_1_4_4" + info " * File not found" +fi + +check_1_4_5="1.4.5 - Ensure that the scheduler pod specification file permissions are set to 644 or more restrictive" +if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then + file="/etc/kubernetes/manifests/kube-scheduler.json" +elif [ -f "/etc/kubernetes/manifests/kube-scheduler.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-scheduler.manifest" +else + file="/etc/kubernetes/manifests/kube-scheduler.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_5" + else + warn "$check_1_4_5" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_5" + info " * File not found" +fi + +check_1_4_6="1.4.6 - Ensure that the scheduler pod specification file ownership is set to root:root" +if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then + file="/etc/kubernetes/manifests/kube-scheduler.json" +elif [ -f "/etc/kubernetes/manifests/kube-scheduler.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-scheduler.manifest" +else + file="/etc/kubernetes/manifests/kube-scheduler.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %U:%G $file)" = "root:root" ]; then + pass "$check_1_4_6" + else + warn "$check_1_4_6" + owner=$(stat -c %U:%G $file) + warn " * Wrong ownership for $file:$owner" + fi +else + info "$check_1_4_6" + info " * File not found" +fi + +check_1_4_7="1.4.7 - Ensure that the etcd pod specification file permissions are set to 644 or more restrictive" +if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then + file="/etc/kubernetes/manifests/etcd.json" +elif [ -f "/etc/kubernetes/manifests/etcd.manifest" ]; then + # kops + # Also this file is a symlink, hence 'stat -L' below. + file="/etc/kubernetes/manifests/etcd.manifest" +else + file="/etc/kubernetes/manifests/etcd.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -L -c %a $file)" -eq 644 -o "$(stat -L -c %a $file)" -eq 640 -o "$(stat -L -c %a $file)" -eq 600 ]; then + pass "$check_1_4_7" + else + warn "$check_1_4_7" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_7" + info " * File not found" +fi + +check_1_4_8="1.4.8 - Ensure that the etcd pod specification file ownership is set to root:root" +if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then + file="/etc/kubernetes/manifests/etcd.json" +elif [ -f "/etc/kubernetes/manifests/etcd.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/etcd.manifest" +else + file="/etc/kubernetes/manifests/etcd.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %U:%G $file)" = "root:root" ]; then + pass "$check_1_4_8" + else + warn "$check_1_4_8" + owner=$(stat -c %U:%G $directory) + warn " * Wrong ownership for $file:$owner" + fi +else + info "$check_1_4_8" +fi + +#TODO +check_1_4_9="1.4.9 - Ensure that the Container Network Interface file permissions are set to 644 or more restrictive" +check_1_4_10="1.4.10 - Ensure that the Container Network Interface file ownership is set to root:root" +check_1_4_11="1.4.11 - Ensure that the etcd data directory permissions are set to 700 or more restrictive" +directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') +if [ -d "$directory" ]; then + if [ "$(stat -c %a $directory)" -eq 700 ]; then + pass "$check_1_4_11" + else + warn "$check_1_4_11" + perm=$(stat -c %a $directory) + warn " * Wrong permissions for $directory:$perm" + fi +else + warn "$check_1_4_11" + warn " * Directory not found:$directory" +fi + +check_1_4_12="1.4.12 - Ensure that the etcd data directory ownership is set to etcd:etcd" +directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') +if [ -d "$directory" ]; then + if [ "$(stat -c %U:%G $directory)" = "etcd:etcd" ]; then + pass "$check_1_4_12" + else + warn "$check_1_4_12" + owner=$(stat -c %U:%G $directory) + warn " * Wrong ownership for $directory:$owner" + fi +else + warn "$check_1_4_12" + warn " * Directory not found:$directory" +fi + +check_1_4_13="1.4.13 - Ensure that the admin.conf file permissions are set to 644 or more restrictive" +file="/etc/kubernetes/admin.conf" +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_13" + else + warn "$check_1_4_13" + perm=$(stat -c %a $file) + warn " * Wrong permissions for $file:$perm" + fi +else + warn "$check_1_4_13" + warn " * File not found:$file" +fi + +check_1_4_14="1.4.14 - Ensure that the admin.conf file ownership is set to root:root" +file="/etc/kubernetes/admin.conf" +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_14" + else + warn "$check_1_4_14" + owner=$(stat -c %U:%G $file) + warn " * Wrong ownership for $file:$owner" + fi +else + warn "$check_1_4_14" + warn " * File not found:$file" +fi + +check_1_4_15="1.4.15 - Ensure that the scheduler.conf file permissions are set to 644 or more restrictive" +file="/etc/kubernetes/scheduler.conf" +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_15" + else + warn "$check_1_4_15" + perm=$(stat -c %a $file) + warn " * Wrong permissions for $file:$perm" + fi +else + warn "$check_1_4_15" + warn " * File not found:$file" +fi + +check_1_4_16="1.4.16 - Ensure that the scheduler.conf file ownership is set to root:root" +file="/etc/kubernetes/scheduler.conf" +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_16" + else + warn "$check_1_4_16" + owner=$(stat -c %U:%G $file) + warn " * Wrong ownership for $file:$owner" + fi +else + warn "$check_1_4_16" + warn " * File not found:$file" +fi + +check_1_4_17="1.4.17 - Ensure that the controller-manager.conf file permissions are set to 644 or more restrictive" +file="/etc/kubernetes/controller-manager.conf" +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_17" + else + warn "$check_1_4_17" + perm=$(stat -c %a $file) + warn " * Wrong permissions for $file:$perm" + fi +else + warn "$check_1_4_17" + warn " * File not found:$file" +fi + +check_1_4_18="1.4.18 - Ensure that the controller-manager.conf file ownership is set to root:root" +file="/etc/kubernetes/controller-manager.conf" +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_18" + else + warn "$check_1_4_18" + owner=$(stat -c %U:%G $file) + warn " * Wrong ownership for $file:$owner" + fi +else + warn "$check_1_4_18" + warn " * File not found:$file" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/master/master_5_etcd.sh b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_5_etcd.sh new file mode 100755 index 0000000..8d3c988 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_5_etcd.sh @@ -0,0 +1,78 @@ +info "1.5 - etcd" + +check_1_5_1="1.5.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)" +if check_argument "$CIS_ETCD_CMD" '--cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_ETCD_CMD" '--key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_ETCD_CMD" '--cert-file') + kfile=$(get_argument_value "$CIS_ETCD_CMD" '--key-file') + pass "$check_1_5_1" + pass " * cert-file: $cfile" + pass " * key-file: $kfile" + else + warn "$check_1_5_1" + fi +else + warn "$check_1_5_1" +fi + +check_1_5_2="1.5.2 - Ensure that the --client-cert-auth argument is set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--client-cert-auth' >/dev/null 2>&1; then + pass "$check_1_5_2" +else + warn "$check_1_5_2" +fi + +check_1_5_3="1.5.3 - Ensure that the --auto-tls argument is not set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--auto-tls=tru' >/dev/null 2>&1; then + warn "$check_1_5_3" +else + pass "$check_1_5_3" +fi + +check_1_5_4="1.5.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_ETCD_CMD" '--peer-key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-cert-file') + kfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-key-file') + pass "$check_1_5_4" + pass " * peer-cert-file: $cfile" + pass " * peer-key-file: $kfile" + else + warn "$check_1_5_4" + fi +else + warn "$check_1_5_4" +fi + +check_1_5_5="1.5.5 - Ensure that the --peer-client-cert-auth argument is set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-client-cert-auth' >/dev/null 2>&1; then + pass "$check_1_5_5" +else + warn "$check_1_5_5" +fi + +check_1_5_6="1.5.6 - Ensure that the --peer-auto-tls argument is not set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-auto-tls=true' >/dev/null 2>&1; then + warn "$check_1_5_6" +else + pass "$check_1_5_6" +fi + +check_1_5_7="1.5.7 - Ensure that the --wal-dir argument is set as appropriate (Scored)" +if check_argument "$CIS_ETCD_CMD" '--wal-dir' >/dev/null 2>&1; then + wdir=$(get_argument_value "$CIS_ETCD_CMD" '--wal-dir') + pass "$check_1_5_7" + pass " * wal-dir: $wdir" +else + warn "$check_1_5_7" +fi + +check_1_5_8="1.5.8 - Ensure that the --max-wals argument is set to 0 (Scored)" +if check_argument "$CIS_ETCD_CMD" '--max-wals=0' >/dev/null 2>&1; then + pass "$check_1_5_8" +else + warn "$check_1_5_8" +fi + +#TODO +check_1_5_9="1.5.9 - Ensure that a unique Certificate Authority is used for etcd (Not Scored)" diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/master/master_6_general_security_primitives.sh b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_6_general_security_primitives.sh new file mode 100755 index 0000000..1eec522 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/master/master_6_general_security_primitives.sh @@ -0,0 +1,50 @@ +info "1.6 - General Security Primitives" + +# Make the loop separator be a new-line in POSIX compliant fashion +set -f; IFS=$' +' + +check_1_6_1="1.6.1 - Ensure that the cluster-admin role is only used where required(Not Scored)" +cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) +info $check_1_6_1 +for admin in $cluster_admins; do + info " * $admin" +done + +check_1_6_2="1.6.2 - Create Pod Security Policies for your cluster (Not Scored)" +policies=$(kubectl get psp) +info $check_1_6_2 +for policy in $policies; do + info " * $policy" +done + +check_1_6_3="1.6.3 - Create administrative boundaries between resources using namespaces (Not Scored)" +namespaces=$(kubectl get namespaces) +info $check_1_6_3 +for namespace in $namespaces; do + info " * $namespace" +done + +check_1_6_4="1.6.4 - Create network segmentation using Network Policies (Not Scored)" +policies=$(kubectl get pods --namespace=kube-system) +info $check_1_6_4 +for policy in $policies; do + info " * $policy" +done + +check_1_6_5="1.6.5 - Avoid using Kubernetes Secrets (Not Scored)" +secrets=$(kubectl get secrets) +info $check_1_6_5 +for secret in $secrets; do + info " * $secret" +done + +#TODO +check_1_6_6="1.6.6 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)" +info $check_1_6_6 +check_1_6_7="1.6.7 - Apply Security Context to Your Pods and Containers (Not Scored)" +info $check_1_6_7 +check_1_6_8="1.6.8 - Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)" +info $check_1_6_8 +check_1_6_9="1.6.9 - Place compensating controls in the form of PSP and RBAC for privileged containers usage" +info $check_1_6_9 diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/worker.sh b/scripts/kubernetes-cis-benchmark/1.2.0/worker.sh new file mode 100755 index 0000000..2901ba7 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/worker.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# ------------------------------------------------------------------------------ +# Kubenetes CIS benchmark 1.6 +# +# Neuvector, Inc. (c) 2016- +# +# ------------------------------------------------------------------------------ + +# Load dependencies +. ./helper.sh + +# Check for required program(s) +req_progs='grep' +for p in $req_progs; do + command -v "$p" >/dev/null 2>&1 || { printf "%s command not found.\n" "$p"; exit 1; } +done + +# Load all the tests from worker/ and run them +main () { + for test in worker/worker_*.sh + do + . ./"$test" + done +} + +main "$@" diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/worker/worker_1_kubelet.sh b/scripts/kubernetes-cis-benchmark/1.2.0/worker/worker_1_kubelet.sh new file mode 100755 index 0000000..63a1d6c --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/worker/worker_1_kubelet.sh @@ -0,0 +1,123 @@ +info "2.1 - Kubelet" + +check_2_1_1="2.1.1 - Ensure that the --allow-privileged argument is set to false" +if check_argument "$CIS_KUBELET_CMD" '--allow-privileged=false' >/dev/null 2>&1; then + pass "$check_2_1_1" +else + warn "$check_2_1_1" +fi + +check_2_1_2="2.1.2 - Ensure that the --anonymous-auth argument is set to false" +if check_argument "$CIS_KUBELET_CMD" '--anonymous-auth=false' >/dev/null 2>&1; then + pass "$check_2_1_2" +else + warn "$check_2_1_2" +fi + +check_2_1_3="2.1.3 - Ensure that the --authorization-mode argument is not set to AlwaysAllow" +if check_argument "$CIS_KUBELET_CMD" '--authorization-mode=AlwaysAllow' >/dev/null 2>&1; then + warn "$check_2_1_3" +else + pass "$check_2_1_3" +fi + +check_2_1_4="2.1.4 - Ensure that the --client-ca-file argument is set as appropriate" +if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then + cafile=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') + pass "$check_2_1_4" + pass " * client-ca-file: $cafile" +else + warn "$check_2_1_4" +fi + +check_2_1_5="2.1.5 - Ensure that the --read-only-port argument is set to 0" +if check_argument "$CIS_KUBELET_CMD" '--read-only-port' >/dev/null 2>&1; then + port=$(get_argument_value "$CIS_KUBELET_CMD" '--read-only-port' | cut -d " " -f 1) + if [ $port = "0" ]; then + pass "$check_2_1_5" + else + warn "$check_2_1_5" + warn " * read-only-port: $port" + fi +else + warn "$check_2_1_5" +fi + +check_2_1_6="2.1.6 - Ensure that the --streaming-connection-idle-timeout argument is not set to 0" +if check_argument "$CIS_KUBELET_CMD" '--streaming-connection-idle-timeout=0' >/dev/null 2>&1; then + timeout=$(get_argument_value "$CIS_KUBELET_CMD" '--streaming-connection-idle-timeout') + warn "$check_2_1_6" + warn " * streaming-connection-idle-timeout: $timeout" +else + pass "$check_2_1_6" +fi + +check_2_1_7="2.1.7 - Ensure that the --protect-kernel-defaults argument is set to true" +if check_argument "$CIS_KUBELET_CMD" '--protect-kernel-defaults=true' >/dev/null 2>&1; then + pass "$check_2_1_7" +else + warn "$check_2_1_7" +fi + +check_2_1_8="2.1.8 - Ensure that the --make-iptables-util-chains argument is set to true" +if check_argument "$CIS_KUBELET_CMD" '--make-iptables-util-chains=true' >/dev/null 2>&1; then + pass "$check_2_1_8" +else + warn "$check_2_1_8" +fi + +check_2_1_9="2.1.9 - Ensure that the --keep-terminated-pod-volumes argument is set to false" +if check_argument "$CIS_KUBELET_CMD" '--keep-terminated-pod-volumes=false' >/dev/null 2>&1; then + pass "$check_2_1_9" +else + warn "$check_2_1_9" +fi + +check_2_1_10="2.1.10 - Ensure that the --hostname-override argument is not set" +if check_argument "$CIS_KUBELET_CMD" '--hostname-override' >/dev/null 2>&1; then + warn "$check_2_1_10" +else + pass "$check_2_1_10" +fi + +check_2_1_11="2.1.11 - Ensure that the --event-qps argument is set to 0" +if check_argument "$CIS_KUBELET_CMD" '--event-qps' >/dev/null 2>&1; then + event=$(get_argument_value "$CIS_KUBELET_CMD" '--event-qps' | cut -d " " -f 1) + if [ $event = "0" ]; then + pass "$check_2_1_11" + else + warn "$check_2_1_11" + warn " * event-qps: $event" + fi +else + warn "$check_2_1_11" +fi + +check_2_1_12="2.1.12 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate" +if check_argument "$CIS_KUBELET_CMD" '--tls-cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_KUBELET_CMD" '--tls-private-key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-cert-file') + kfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-private-key-file') + pass "$check_2_1_12" + pass " * tls-cert-file: $cfile" + pass " * tls-private-key-file: $kfile" + else + warn "$check_2_1_12" + fi +else + warn "$check_2_1_12" +fi + +check_2_1_13="2.1.13 - Ensure that the --cadvisor-port argument is set to 0" +if check_argument "$CIS_KUBELET_CMD" '--cadvisor-port' >/dev/null 2>&1; then + port=$(get_argument_value "$CIS_KUBELET_CMD" '--cadvisor-port' | cut -d " " -f 1) + if [ $port = "0" ]; then + pass "$check_2_1_13" + else + warn "$check_2_1_13" + warn " * cadvisor-port: $port" + fi +else + warn "$check_2_1_13" +fi + diff --git a/scripts/kubernetes-cis-benchmark/1.2.0/worker/worker_2_configure_files.sh b/scripts/kubernetes-cis-benchmark/1.2.0/worker/worker_2_configure_files.sh new file mode 100755 index 0000000..227fc39 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.2.0/worker/worker_2_configure_files.sh @@ -0,0 +1,131 @@ +info "2.2 - Configuration Files" + +check_2_2_1="2.2.1 - Ensure that the config file permissions are set to 644 or more restrictive" +if [ -f "/etc/kubernetes/config" ]; then + file="/etc/kubernetes/config" +elif [ -f "/var/lib/kubelet/kubeconfig" ]; then + # kops + file="/var/lib/kubelet/kubeconfig" +else + file="/etc/kubernetes/kubelet.conf" +fi + +if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + pass "$check_2_2_1" + else + warn "$check_2_2_1" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_1" + info " * File not found" +fi + +check_2_2_2="2.2.2 - Ensure that the config file ownership is set to root:root" +if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_2" + else + warn "$check_2_2_2" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_2" +fi + +check_2_2_3="2.2.3 - Ensure that the kubelet file permissions are set to 644 or more restrictive" +if [ -f "/etc/kubernetes/kubelet" ]; then + file="/etc/kubernetes/kubelet" +elif [ -f "/etc/sysconfig/kubelet" ]; then + # kops + file="/etc/sysconfig/kubelet" +else + file="/etc/kubernetes/kubelet.conf" +fi + +if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + pass "$check_2_2_3" + else + warn "$check_2_2_3" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_3" + info " * File not found" +fi + +check_2_2_4="2.2.4 - Ensure that the kubelet file ownership is set to root:root" +if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_4" + else + warn "$check_2_2_4" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_4" +fi + +check_2_2_5="2.2.5 - Ensure that the proxy file permissions are set to 644 or more restrictive" +if [ -f "/var/lib/kube-proxy/kubeconfig" ]; then + # kops + file="/var/lib/kube-proxy/kubeconfig" +else + file="/etc/kubernetes/proxy" +fi + +if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + pass "$check_2_2_5" + else + warn "$check_2_2_5" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_5" + info " * File not found" +fi + +check_2_2_6="2.2.6 - Ensure that the proxy file ownership is set to root:root" +if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_6" + else + warn "$check_2_2_6" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_6" +fi + +check_2_2_7="2.2.7 - Ensure that the certificate authorities file permissions are set to 644 or more restrictive" +if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + pass "$check_2_2_7" + pass " * client-ca-file: $file" + else + warn "$check_2_2_7" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_7" + info " * --client-ca-file not set" +fi + +check_2_2_8="2.2.8 - Ensure that the client certificate authorities file ownership is set to root:root" +if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_8" + pass " * client-ca-file: $file" + else + warn "$check_2_2_8" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_8" + info " * --client-ca-file not set" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.4.1/master/master_1_api_server.sh b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_1_api_server.sh new file mode 100755 index 0000000..a7f6d0b --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_1_api_server.sh @@ -0,0 +1,356 @@ +info "1.1 - API Server" + +check_1_1_1="1.1.1 - Ensure that the --anonymous-auth argument is set to false (Not Scored)" +if check_argument "$CIS_APISERVER_CMD" '--anonymous-auth=false' >/dev/null 2>&1; then + pass "$check_1_1_1" +else + warn "$check_1_1_1" +fi + +check_1_1_2="1.1.2 - Ensure that the --basic-auth-file argument is not set (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--basic-auth-file' >/dev/null 2>&1; then + warn "$check_1_1_2" +else + pass "$check_1_1_2" +fi + +check_1_1_3="1.1.3 - Ensure that the --insecure-allow-any-token argument is not set (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--insecure-allow-any-token' >/dev/null 2>&1; then + warn "$check_1_1_3" +else + pass "$check_1_1_3" +fi + +check_1_1_4="1.1.4 - Ensure that the --kubelet-https argument is set to true (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--kubelet-https=false' >/dev/null 2>&1; then + warn "$check_1_1_4" +else + pass "$check_1_1_4" +fi + +check_1_1_5="1.1.5 - Ensure that the --insecure-bind-address argument is not set (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--insecure-bind-address' >/dev/null 2>&1; then + address=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-bind-address'|cut -d " " -f 1) + if [ "$address" = "127.0.0.1" ]; then + pass "$check_1_1_5" + pass " * insecure-bind-address: $address" + else + warn "$check_1_1_5" + warn " * insecure-bind-address: $address" + fi +else + pass "$check_1_1_5" +fi + +check_1_1_6="1.1.6 - Ensure that the --insecure-port argument is set to 0 (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--insecure-port' >/dev/null 2>&1; then + port=$(get_argument_value "$CIS_APISERVER_CMD" '--insecure-port'|cut -d " " -f 1) + if [ "$port" = "0" ]; then + pass "$check_1_1_6" + else + warn "$check_1_1_6" + warn " * insecure-port: $port" + fi +else + warn "$check_1_1_6" +fi + +check_1_1_7="1.1.7 - Ensure that the --secure-port argument is not set to 0 (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--secure-port' >/dev/null 2>&1; then + port=$(get_argument_value "$CIS_APISERVER_CMD" '--secure-port'|cut -d " " -f 1) + if [ "$port" = "0" ]; then + warn "$check_1_1_7" + warn " * secure-port: $port" + else + pass "$check_1_1_7" + fi +else + pass "$check_1_1_7" +fi + +check_1_1_8="1.1.8 - Ensure that the --profiling argument is set to false (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--profiling=false' >/dev/null 2>&1; then + pass "$check_1_1_8" +else + warn "$check_1_1_8" +fi + +check_1_1_9="1.1.9 - Ensure that the --repair-malformed-updates argument is set to false (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--repair-malformed-updates=false' >/dev/null 2>&1; then + pass "$check_1_1_9" +else + warn "$check_1_1_9" +fi + +check_1_1_10="1.1.10 - Ensure that the admission control plugin AlwaysAdmit is not set (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'AlwaysAdmit' >/dev/null 2>&1; then + warn "$check_1_1_10" +else + pass "$check_1_1_10" +fi + +check_1_1_11="1.1.11 - Ensure that the admission control plugin AlwaysPullImages is set (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'AlwaysPullImages' >/dev/null 2>&1; then + pass "$check_1_1_11" +else + warn "$check_1_1_11" +fi + +check_1_1_12="1.1.12 - [DEPRECATED] Ensure that the admission control plugin DenyEscalatingExec is set (Not Scored)" +pass "$check_1_1_12" + +check_1_1_13="1.1.13 - Ensure that the admission control plugin SecurityContextDeny is set (Not Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'SecurityContextDeny' >/dev/null 2>&1; then + pass "$check_1_1_13" +else + warn "$check_1_1_13" +fi + +check_1_1_14="1.1.14 - Ensure that the admission control plugin NamespaceLifecycle is set (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--disable-admission-plugins'| grep 'NamespaceLifecycle' >/dev/null 2>&1; then + warn "$check_1_1_14" +else + pass "$check_1_1_14" +fi + +check_1_1_15="1.1.15 - Ensure that the --audit-log-path argument is set as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-path' >/dev/null 2>&1; then + pass "$check_1_1_15" +else + warn "$check_1_1_15" +fi + +check_1_1_16="1.1.16 - Ensure that the --audit-log-maxage argument is set to 30 or as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxage' >/dev/null 2>&1; then + maxage=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxage'|cut -d " " -f 1) + if [ "$maxage" = "30" ]; then + pass "$check_1_1_16" + pass " * audit-log-maxage: $maxage" + else + warn "$check_1_1_16" + warn " * audit-log-maxage: $maxage" + fi +else + warn "$check_1_1_16" +fi + +check_1_1_17="1.1.17 - Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxbackup' >/dev/null 2>&1; then + maxbackup=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxbackup'|cut -d " " -f 1) + if [ "$maxbackup" = "10" ]; then + pass "$check_1_1_17" + pass " * audit-log-maxbackup: $maxbackup" + else + warn "$check_1_1_17" + warn " * audit-log-maxbackup: $maxbackup" + fi +else + warn "$check_1_1_17" +fi + +check_1_1_18="1.1.18 - Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--audit-log-maxsize' >/dev/null 2>&1; then + maxsize=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-log-maxsize'|cut -d " " -f 1) + if [ "$maxsize" = "100" ]; then + pass "$check_1_1_18" + pass " * audit-log-maxsize: $maxsize" + else + warn "$check_1_1_18" + warn " * audit-log-maxsize: $maxsize" + fi +else + warn "$check_1_1_18" +fi + +check_1_1_19="1.1.19 - Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'AlwaysAllow' >/dev/null 2>&1; then + warn "$check_1_1_19" +else + pass "$check_1_1_19" +fi + +check_1_1_20="1.1.20 - Ensure that the --token-auth-file parameter is not set (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--token-auth-file' >/dev/null 2>&1; then + warn "$check_1_1_20" +else + pass "$check_1_1_20" +fi + +check_1_1_21="1.1.21 - Ensure that the --kubelet-certificate-authority argument is set as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--kubelet-certificate-authority' >/dev/null 2>&1; then + pass "$check_1_1_21" +else + warn "$check_1_1_21" +fi + +check_1_1_22="1.1.22 - Ensure that the --kubelet-client-certificate and --kubelet-client- key arguments are set as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-certificate' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--kubelet-client-key' >/dev/null 2>&1; then + certificate=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-certificate') + key=$(get_argument_value "$CIS_APISERVER_CMD" '--kubelet-client-key') + pass "$check_1_1_22" + pass " * kubelet-client-certificate: $certificate" + pass " * kubelet-client-key: $key" + else + warn "$check_1_1_22" + fi +else + warn "$check_1_1_22" +fi + +check_1_1_23="1.1.23 - Ensure that the --service-account-lookup argument is set to true (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--service-account-lookup' >/dev/null 2>&1; then + pass "$check_1_1_23" +else + warn "$check_1_1_23" +fi + +check_1_1_24="1.1.24 - Ensure that the admission control plugin PodSecurityPolicy is set (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'PodSecurityPolicy' >/dev/null 2>&1; then + pass "$check_1_1_24" +else + warn "$check_1_1_24" +fi + +check_1_1_25="1.1.25 - Ensure that the --service-account-key-file argument is set as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--service-account-key-file' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_APISERVER_CMD" '--service-account-key-file') + pass "$check_1_1_25" + pass " * service-account-key-file: $file" +else + warn "$check_1_1_25" +fi + +check_1_1_26="1.1.26 - Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--etcd-certfile' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--etcd-keyfile' >/dev/null 2>&1; then + certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-certfile') + keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-keyfile') + pass "$check_1_1_26" + pass " * etcd-certfile: $certfile" + pass " * etcd-keyfile: $keyfile" + else + warn "$check_1_1_26" + fi +else + warn "$check_1_1_26" +fi + +check_1_1_27="1.1.27 - Ensure that the admission control plugin ServiceAccount is set (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--disable-admission-plugins'| grep 'ServiceAccount' >/dev/null 2>&1; then + warn "$check_1_1_27" +else + pass "$check_1_1_27" +fi + +check_1_1_28="1.1.28 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--tls-cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--tls-private-key-file' >/dev/null 2>&1; then + certfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-cert-file') + keyfile=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-private-key-file') + pass "$check_1_1_28" + pass " * tls-cert-file: $certfile" + pass " * tls-private-key-file: $keyfile" + else + warn "$check_1_1_28" + fi +else + warn "$check_1_1_28" +fi + +check_1_1_29="1.1.29 - Ensure that the --client-ca-file argument is set as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then + cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') + pass "$check_1_1_29" + pass " * client-ca-file: $cafile" +else + warn "$check_1_1_29" +fi + +check_1_1_30="1.1.30 - Ensure that the --etcd-cafile argument is set as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--etcd-cafile' >/dev/null 2>&1; then + cafile=$(get_argument_value "$CIS_APISERVER_CMD" '--etcd-cafile') + pass "$check_1_1_30" + pass " * etcd-cafile: $cafile" +else + warn "$check_1_1_30" +fi + +check_1_1_31="1.1.31 - Ensure that the API Server only makes use of Strong Cryptographic Ciphers (Not Scored)" +if check_argument "$CIS_APISERVER_CMD" '--tls-cipher-suites' >/dev/null 2>&1; then + ciphers=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-cipher-suites'|cut -d " " -f 1) + found=$(echo $ciphers| sed -rn '/(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)/p') + if [ ! -z "$found" ]; then + pass "$check_1_1_31" + else + warn "$check_1_1_31" + fi +else + warn "$check_1_1_31" +fi + +check_1_1_32="1.1.32 - Ensure that the --authorization-mode argument includes Node (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'Node' >/dev/null 2>&1; then + pass "$check_1_1_32" +else + warn "$check_1_1_32" +fi + +check_1_1_33="1.1.33 - Ensure that the admission control plugin NodeRestriction is set (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'NodeRestriction' >/dev/null 2>&1; then + pass "$check_1_1_33" +else + warn "$check_1_1_33" +fi + +check_1_1_34="1.1.34 - Ensure that the --encryption-provider-config argument is set as appropriate (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then + pass "$check_1_1_34" +else + warn "$check_1_1_34" +fi + +check_1_1_35="1.1.35 - Ensure that the encryption provider is set to aescbc (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config'| grep 'EncryptionConfig' >/dev/null 2>&1; then + encryptionConfig=$(get_argument_value "$CIS_APISERVER_CMD" '--experimental-encryption-provider-config') + if sed ':a;N;$!ba;s/\n/ /g' $encryptionConfig |grep "providers:\s* - aescbc" >/dev/null 2>&1; then + pass "$check_1_1_35" + else + warn "$check_1_1_35" + fi +else + warn "$check_1_1_35" +fi + +check_1_1_36="1.1.36 - Ensure that the admission control plugin EventRateLimit is set (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins'| grep 'EventRateLimit' >/dev/null 2>&1; then + pass "$check_1_1_36" + admissionctrl=$(get_argument_value "$CIS_APISERVER_CMD" '--enable-admission-plugins') + pass " * : $admissionctrl" +else + warn "$check_1_1_36" +fi + +check_1_1_37="1.1.37 - Ensure that the AdvancedAuditing argument is not set to false (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--feature-gates'| grep 'AdvancedAuditing=false' >/dev/null 2>&1; then + warn "$check_1_1_37" +else + pass "$check_1_1_37" +fi + +check_1_1_38="1.1.38 - Ensure that the --request-timeout argument is set as appropriate (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--request-timeout' >/dev/null 2>&1; then + requestTimeout=$(get_argument_value "$CIS_APISERVER_CMD" '--request-timeout') + warn "$check_1_1_38" + warn " * request-timeout: $requestTimeout" +else + pass "$check_1_1_38" +fi + +check_1_1_39="1.1.39 - Ensure that the --authorization-mode argument includes RBAC (Scored)" +if get_argument_value "$CIS_APISERVER_CMD" '--authorization-mode'| grep 'RBAC' >/dev/null 2>&1; then + pass "$check_1_1_39" +else + warn "$check_1_1_39" +fi + diff --git a/scripts/kubernetes-cis-benchmark/1.4.1/master/master_2_scheduler.sh b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_2_scheduler.sh new file mode 100755 index 0000000..99e9300 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_2_scheduler.sh @@ -0,0 +1,15 @@ +info "1.2 - Scheduler" + +check_1_2_1="1.2.1 - Ensure that the --profiling argument is set to false (Scored)" +if check_argument "$CIS_SCHEDULER_CMD" '--profiling=false' >/dev/null 2>&1; then + pass "$check_1_2_1" +else + warn "$check_1_2_1" +fi + +check_1_2_2="1.2.2 - Ensure that the --address argument is set to 127.0.0.1 (Scored)" +if get_argument_value "$CIS_SCHEDULER_CMD" '--address'| grep '127.0.0.1' >/dev/null 2>&1; then + pass "$check_1_2_2" +else + warn "$check_1_2_2" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.4.1/master/master_3_contoller_manager.sh b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_3_contoller_manager.sh new file mode 100755 index 0000000..74df74d --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_3_contoller_manager.sh @@ -0,0 +1,64 @@ +info "1.3 - Controller Manager" + +check_1_3_1="1.3.1 - Ensure that the --terminated-pod-gc-threshold argument is set as appropriate (Scored)" +# Filter out processes like "/bin/tee -a /var/log/kube-controller-manager.log" +# which exist on kops-managed clusters. +if check_argument "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold' >/dev/null 2>&1; then + threshold=$(get_argument_value "$CIS_MANAGER_CMD" '--terminated-pod-gc-threshold') + pass "$check_1_3_1" + pass " * terminated-pod-gc-threshold: $threshold" +else + warn "$check_1_3_1" +fi + +check_1_3_2="1.3.2 - Ensure that the --profiling argument is set to false (Scored)" +if check_argument "$CIS_MANAGER_CMD" '--profiling=false' >/dev/null 2>&1; then + pass "$check_1_3_2" +else + warn "$check_1_3_2" +fi + +check_1_3_3="1.3.3 - Ensure that the --use-service-account-credentials argument is set to true (Scored)" +if check_argument "$CIS_MANAGER_CMD" '--use-service-account-credentials' >/dev/null 2>&1; then + pass "$check_1_3_3" +else + warn "$check_1_3_3" +fi + +check_1_3_4="1.3.4 - Ensure that the --service-account-private-key-file argument is set as appropriate (Scored)" +if check_argument "$CIS_MANAGER_CMD" '--service-account-private-key-file' >/dev/null 2>&1; then + keyfile=$(get_argument_value "$CIS_MANAGER_CMD" '--service-account-private-key-file') + pass "$check_1_3_4" + pass " * service-account-private-key-file: $keyfile" +else + warn "$check_1_3_4" +fi + +check_1_3_5="1.3.5 - Ensure that the --root-ca-file argument is set as appropriate (Scored)" +if check_argument "$CIS_MANAGER_CMD" '--root-ca-file' >/dev/null 2>&1; then + cafile=$(get_argument_value "$CIS_MANAGER_CMD" '--root-ca-file') + pass "$check_1_3_5" + pass " * root-ca-file: $cafile" +else + warn "$check_1_3_5" +fi + +check_1_3_6="1.3.6 - Ensure that the RotateKubeletServerCertificate argument is set to true (Scored)" +if check_argument "$CIS_MANAGER_CMD" '--feature-gates' >/dev/null 2>&1; then + serverCert=$(get_argument_value "$CIS_MANAGER_CMD" '--feature-gates') + found=$(echo $serverCert| grep 'RotateKubeletServerCertificate=true') + if [ ! -z $found ]; then + pass "$check_1_3_6" + else + warn "$check_1_3_6" + fi +else + warn "$check_1_3_6" +fi + +check_1_3_7="1.3.7 - Ensure that the --address argument is set to 127.0.0.1 (Scored)" +if get_argument_value "$CIS_MANAGER_CMD" '--address'| grep '127.0.0.1' >/dev/null 2>&1; then + pass "$check_1_3_7" +else + warn "$check_1_3_7" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.4.1/master/master_4_configuration_files.sh b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_4_configuration_files.sh new file mode 100755 index 0000000..2fbedde --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_4_configuration_files.sh @@ -0,0 +1,346 @@ +info "1.4 - Configuration Files" + +check_1_4_1="1.4.1 - Ensure that the API server pod specification file permissions are set to 644 or more restrictive (Scored)" +if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then + file="/etc/kubernetes/manifests/kube-apiserver.json" +elif [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" +else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_1" + else + warn "$check_1_4_1" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_1" + info " * File not found" +fi + +check_1_4_2="1.4.2 - Ensure that the API server pod specification file ownership is set to root:root (Scored)" +if [ -f "/etc/kubernetes/manifests/kube-apiserver.json" ]; then + file="/etc/kubernetes/manifests/kube-apiserver.json" +elif [ -f "/etc/kubernetes/manifests/kube-apiserver.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-apiserver.manifest" +else + file="/etc/kubernetes/manifests/kube-apiserver.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_2" + else + warn "$check_1_4_2" + warn " * Wrong ownership for $file" + fi +else + info "$check_1_4_2" +fi + +check_1_4_3="1.4.3 - Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive (Scored)" +if [ -f "/etc/kubernetes/manifests/kube-controller-manager.json" ]; then + file="/etc/kubernetes/manifests/kube-controller-manager.json" +elif [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-controller-manager.manifest" +else + file="/etc/kubernetes/manifests/kube-controller-manager.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_3" + else + warn "$check_1_4_3" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_3" + info " * File not found" +fi + +check_1_4_4="1.4.4 - Ensure that the controller manager pod specification file ownership is set to root:root (Scored)" +if [ -f "/etc/kubernetes/manifests/kube-controller-manager.json" ]; then + file="/etc/kubernetes/manifests/kube-controller-manager.json" +elif [ -f "/etc/kubernetes/manifests/kube-controller-manager.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-controller-manager.manifest" +else + file="/etc/kubernetes/manifests/kube-controller-manager.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_4" + else + warn "$check_1_4_4" + warn " * Wrong ownership for $file" + fi +else + info "$check_1_4_4" + info " * File not found" +fi + +check_1_4_5="1.4.5 - Ensure that the scheduler pod specification file permissions are set to 644 or more restrictive (Scored)" +if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then + file="/etc/kubernetes/manifests/kube-scheduler.json" +elif [ -f "/etc/kubernetes/manifests/kube-scheduler.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-scheduler.manifest" +else + file="/etc/kubernetes/manifests/kube-scheduler.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_5" + else + warn "$check_1_4_5" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_5" + info " * File not found" +fi + +check_1_4_6="1.4.6 - Ensure that the scheduler pod specification file ownership is set to root:root (Scored)" +if [ -f "/etc/kubernetes/manifests/kube-scheduler.json" ]; then + file="/etc/kubernetes/manifests/kube-scheduler.json" +elif [ -f "/etc/kubernetes/manifests/kube-scheduler.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/kube-scheduler.manifest" +else + file="/etc/kubernetes/manifests/kube-scheduler.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %U:%G $file)" = "root:root" ]; then + pass "$check_1_4_6" + else + warn "$check_1_4_6" + owner=$(stat -c %U:%G $file) + warn " * Wrong ownership for $file:$owner" + fi +else + info "$check_1_4_6" + info " * File not found" +fi + +check_1_4_7="1.4.7 - Ensure that the etcd pod specification file permissions are set to 644 or more restrictive (Scored)" +if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then + file="/etc/kubernetes/manifests/etcd.json" +elif [ -f "/etc/kubernetes/manifests/etcd.manifest" ]; then + # kops + # Also this file is a symlink, hence 'stat -L' below. + file="/etc/kubernetes/manifests/etcd.manifest" +else + file="/etc/kubernetes/manifests/etcd.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -L -c %a $file)" -eq 644 -o "$(stat -L -c %a $file)" -eq 640 -o "$(stat -L -c %a $file)" -eq 600 ]; then + pass "$check_1_4_7" + else + warn "$check_1_4_7" + warn " * Wrong permissions for $file" + fi +else + info "$check_1_4_7" + info " * File not found" +fi + +check_1_4_8="1.4.8 - Ensure that the etcd pod specification file ownership is set to root:root (Scored)" +if [ -f "/etc/kubernetes/manifests/etcd.json" ]; then + file="/etc/kubernetes/manifests/etcd.json" +elif [ -f "/etc/kubernetes/manifests/etcd.manifest" ]; then + # kops + file="/etc/kubernetes/manifests/etcd.manifest" +else + file="/etc/kubernetes/manifests/etcd.yaml" +fi +if [ -f $file ]; then + if [ "$(stat -c %U:%G $file)" = "root:root" ]; then + pass "$check_1_4_8" + else + warn "$check_1_4_8" + owner=$(stat -c %U:%G $directory) + warn " * Wrong ownership for $file:$owner" + fi +else + info "$check_1_4_8" +fi + +#TODO +check_1_4_9="1.4.9 - Ensure that the Container Network Interface file permissions are set to 644 or more restrictive (Not Scored)" +info "$check_1_4_9" + +check_1_4_10="1.4.10 - Ensure that the Container Network Interface file ownership is set to root:root (Not Scored)" +info "$check_1_4_10" + +check_1_4_11="1.4.11 - Ensure that the etcd data directory permissions are set to 700 or more restrictive (Scored)" +directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') +if [ -d "$directory" ]; then + if [ "$(stat -c %a $directory)" -eq 700 ]; then + pass "$check_1_4_11" + else + warn "$check_1_4_11" + perm=$(stat -c %a $directory) + warn " * Wrong permissions for $directory:$perm" + fi +else + warn "$check_1_4_11" + warn " * Directory not found:$directory" +fi + +check_1_4_12="1.4.12 - Ensure that the etcd data directory ownership is set to etcd:etcd (Scored)" +directory=$(get_argument_value "$CIS_ETCD_CMD" '--data-dir') +if [ -d "$directory" ]; then + if [ "$(stat -c %U:%G $directory)" = "etcd:etcd" ]; then + pass "$check_1_4_12" + else + warn "$check_1_4_12" + owner=$(stat -c %U:%G $directory) + warn " * Wrong ownership for $directory:$owner" + fi +else + warn "$check_1_4_12" + warn " * Directory not found:$directory" +fi + +check_1_4_13="1.4.13 - Ensure that the admin.conf file permissions are set to 644 or more restrictive (Scored)" +file="/etc/kubernetes/admin.conf" +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_13" + else + warn "$check_1_4_13" + perm=$(stat -c %a $file) + warn " * Wrong permissions for $file:$perm" + fi +else + warn "$check_1_4_13" + warn " * File not found:$file" +fi + +check_1_4_14="1.4.14 - Ensure that the admin.conf file ownership is set to root:root (Scored)" +file="/etc/kubernetes/admin.conf" +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_14" + else + warn "$check_1_4_14" + owner=$(stat -c %U:%G $file) + warn " * Wrong ownership for $file:$owner" + fi +else + warn "$check_1_4_14" + warn " * File not found:$file" +fi + +check_1_4_15="1.4.15 - Ensure that the scheduler.conf file permissions are set to 644 or more restrictive (Scored)" +file="/etc/kubernetes/scheduler.conf" +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_15" + else + warn "$check_1_4_15" + perm=$(stat -c %a $file) + warn " * Wrong permissions for $file:$perm" + fi +else + warn "$check_1_4_15" + warn " * File not found:$file" +fi + +check_1_4_16="1.4.16 - Ensure that the scheduler.conf file ownership is set to root:root (Scored)" +file="/etc/kubernetes/scheduler.conf" +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_16" + else + warn "$check_1_4_16" + owner=$(stat -c %U:%G $file) + warn " * Wrong ownership for $file:$owner" + fi +else + warn "$check_1_4_16" + warn " * File not found:$file" +fi + +check_1_4_17="1.4.17 - Ensure that the controller-manager.conf file permissions are set to 644 or more restrictive (Scored)" +file="/etc/kubernetes/controller-manager.conf" +if [ -f $file ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 ]; then + pass "$check_1_4_17" + else + warn "$check_1_4_17" + perm=$(stat -c %a $file) + warn " * Wrong permissions for $file:$perm" + fi +else + warn "$check_1_4_17" + warn " * File not found:$file" +fi + +check_1_4_18="1.4.18 - Ensure that the controller-manager.conf file ownership is set to root:root (Scored)" +file="/etc/kubernetes/controller-manager.conf" +if [ -f $file ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_1_4_18" + else + warn "$check_1_4_18" + owner=$(stat -c %U:%G $file) + warn " * Wrong ownership for $file:$owner" + fi +else + warn "$check_1_4_18" + warn " * File not found:$file" +fi + +check_1_4_19="1.4.19 - Ensure that the Kubernetes PKI directory and file ownership is set to root:root (Scored)" +file="/etc/kubernetes/pki/" +files=$(find $file) +pass=true +for f in ${files}; do + if [ "$(stat -c %u%g $f)" != 00 ]; then + pass=false; + break; + fi +done + +if [ "$pass" = "true" ]; then + pass "$check_1_4_19" +else + warn "$check_1_4_19" +fi + +check_1_4_20="1.4.20 - Ensure that the Kubernetes PKI certificate file permissions are set to 644 or more restrictive (Scored)" +files=$(find $file -name "*.crt") +pass=true +for f in ${files}; do + if ! [ "$(stat -c %a $f)" -eq 644 -o "$(stat -c %a $f)" -eq 600 -o "$(stat -c %a $f)" -eq 400 ]; then + pass=false; + break; + fi +done + +if [ "$pass" = "true" ]; then + pass "$check_1_4_20" +else + warn "$check_1_4_20" +fi + +check_1_4_21="1.4.21 - Ensure that the Kubernetes PKI key file permissions are set to 600 (Scored)" +files=$(find $file -name "*.key") +pass=true +for f in ${files}; do + if ! [ "$(stat -c %a $f)" -eq 600 ]; then + pass=false; + break; + fi +done + +if [ "$pass" = "true" ]; then + pass "$check_1_4_21" +else + warn "$check_1_4_21" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.4.1/master/master_5_etcd.sh b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_5_etcd.sh new file mode 100755 index 0000000..9ee4f45 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_5_etcd.sh @@ -0,0 +1,80 @@ +info "1.5 - etcd" + +check_1_5_1="1.5.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)" +if check_argument "$CIS_ETCD_CMD" '--cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_ETCD_CMD" '--key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_ETCD_CMD" '--cert-file') + kfile=$(get_argument_value "$CIS_ETCD_CMD" '--key-file') + pass "$check_1_5_1" + pass " * cert-file: $cfile" + pass " * key-file: $kfile" + else + warn "$check_1_5_1" + fi +else + warn "$check_1_5_1" +fi + +check_1_5_2="1.5.2 - Ensure that the --client-cert-auth argument is set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--client-cert-auth' >/dev/null 2>&1; then + pass "$check_1_5_2" +else + warn "$check_1_5_2" +fi + +check_1_5_3="1.5.3 - Ensure that the --auto-tls argument is not set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--auto-tls=true' >/dev/null 2>&1; then + warn "$check_1_5_3" +else + pass "$check_1_5_3" +fi + +check_1_5_4="1.5.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_ETCD_CMD" '--peer-key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-cert-file') + kfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-key-file') + pass "$check_1_5_4" + pass " * peer-cert-file: $cfile" + pass " * peer-key-file: $kfile" + else + warn "$check_1_5_4" + fi +else + warn "$check_1_5_4" +fi + +check_1_5_5="1.5.5 - Ensure that the --peer-client-cert-auth argument is set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-client-cert-auth' >/dev/null 2>&1; then + pass "$check_1_5_5" +else + warn "$check_1_5_5" +fi + +check_1_5_6="1.5.6 - Ensure that the --peer-auto-tls argument is not set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-auto-tls=true' >/dev/null 2>&1; then + warn "$check_1_5_6" +else + pass "$check_1_5_6" +fi + +check_1_5_7="1.5.7 - Ensure that a unique Certificate Authority is used for etcd (Not Scored)" +if check_argument "$CIS_ETCD_CMD" '--trusted-ca-file' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then + tfile=$(get_argument_value "$CIS_ETCD_CMD" '--trusted-ca-file') + cfile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') + if [ "$tfile" = "$cfile" ]; then + pass "$check_1_5_7" + pass " * trusted-ca-file: $tfile" + pass " * client-ca-file: $cfile" + else + warn "$check_1_5_7" + fi + else + warn "$check_1_5_7" + warn " * client-ca-file doesn't exist" + fi +else + warn "$check_1_5_7" + warn " * trusted-ca-file doesn't exist" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.4.1/master/master_6_general_security_primitives.sh b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_6_general_security_primitives.sh new file mode 100755 index 0000000..bee87ea --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_6_general_security_primitives.sh @@ -0,0 +1,39 @@ +info "1.6 - General Security Primitives" + +# Make the loop separator be a new-line in POSIX compliant fashion +set -f; IFS=$' +' +check_1_6_1="1.6.1 - Place compensating controls in the form of PSP and RBAC for privileged containers usage (Not Scored)" +info "$check_1_6_1" + +check_1_6_2="1.6.2 - Ensure that the cluster-admin role is only used where required(Not Scored)" +cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) +info $check_1_6_2 +for admin in $cluster_admins; do + info " * $admin" +done + +check_1_6_3="1.6.3 - Create administrative boundaries between resources using namespaces (Not Scored)" +namespaces=$(kubectl get namespaces) +info $check_1_6_3 +for namespace in $namespaces; do + info " * $namespace" +done + +check_1_6_4="1.6.4 - Create network segmentation using Network Policies (Not Scored)" +policies=$(kubectl get pods --namespace=kube-system) +info $check_1_6_4 +for policy in $policies; do + info " * $policy" +done + +check_1_6_5="1.6.5 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)" +info "$check_1_6_5" + +check_1_6_6="1.6.6 - Apply Security Context to Your Pods and Containers (Not Scored)" +info $check_1_6_6 +check_1_6_7="1.6.7 - Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)" +info $check_1_6_7 +check_1_6_8="1.6.8 - Configure Network policies as appropriate (Not Scored)" +info $check_1_6_8 + diff --git a/scripts/kubernetes-cis-benchmark/1.4.1/master/master_7_podSecurityPolicies.sh b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_7_podSecurityPolicies.sh new file mode 100644 index 0000000..91497d1 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.4.1/master/master_7_podSecurityPolicies.sh @@ -0,0 +1,99 @@ +check_1_7_1="1.7.1 - Do not admit privileged containers (Not Scored)" +names=$(kubectl get psp 2>/dev/null | sed 1,1d | cut -d " " -f 1) +result="" +for name in $names; do + result=$(kubectl get psp $name -o=jsonpath='{.spec.privileged}'|grep true) + if [ -z "$result" ]; then + break; + fi +done +if [ -z "$result" ]; then + pass "$check_1_7_1" +else + warn "$check_1_7_1" +fi + +check_1_7_2="1.7.2 - Do not admit containers wishing to share the host process ID namespace (Scored)" +result="" +for name in $names; do + result=$(kubectl get psp $name -o=jsonpath='{.spec.hostPID}'|grep true) + if [ -z "$result" ]; then + break; + fi +done +if [ -z "$result" ]; then + pass "$check_1_7_2" +else + warn "$check_1_7_2" +fi + +check_1_7_3="1.7.3 - Do not admit containers wishing to share the host IPC namespace (Scored)" +result="" +for name in $names; do + result=$(kubectl get psp $name -o=jsonpath='{.spec.hostIPC}'|grep true) + if [ -z "$result" ]; then + break; + fi +done +if [ -z "$result" ]; then + pass "$check_1_7_3" +else + warn "$check_1_7_3" +fi + +check_1_7_4="1.7.4 - Do not admit containers wishing to share the host network namespace (Scored)" +result="" +for name in $names; do + result=$(kubectl get psp $name -o=jsonpath='{.spec.hostNetwork}'|grep true) + if [ -z "$result" ]; then + break; + fi +done +if [ -z "$result" ]; then + pass "$check_1_7_4" +else + warn "$check_1_7_4" +fi + +check_1_7_5="1.7.5 - Do not admit containers with allowPrivilegeEscalation (Scored)" +result="" +for name in $names; do + result=$(kubectl get psp $name -o=jsonpath='{.spec.allowPrivilegeEscalation}'|grep true) + if [ -z "$result" ]; then + break; + fi +done +if [ -z "$result" ]; then + pass "$check_1_7_5" +else + warn "$check_1_7_5" +fi + +check_1_7_6="1.7.6 - Do not admit root containers (Not Scored)" +result="" +for name in $names; do + result=$(kubectl get psp $name -o=jsonpath='{.spec.runAsUser.rule}' | grep -v -E '(\<0\>)|(MustRunAsNonRoot)') + if [ -z "$result" ]; then + break; + fi +done +if [ -z "$result" ]; then + pass "$check_1_7_6" +else + warn "$check_1_7_6" +fi + +check_1_7_7="1.7.7 - Do not admit containers with dangerous capabilities (Not Scored)" +result="" +for name in $names; do + result=$(kubectl get psp $name -o=jsonpath='{.spec.allowPrivilegeEscalation}'|grep true) + if [ -z "$result" ]; then + break; + fi +done +if [ -z "$result" ]; then + pass "$check_1_7_7" +else + warn "$check_1_7_7" +fi + diff --git a/scripts/kubernetes-cis-benchmark/1.4.1/worker/worker_1_kubelet.sh b/scripts/kubernetes-cis-benchmark/1.4.1/worker/worker_1_kubelet.sh new file mode 100755 index 0000000..804a986 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.4.1/worker/worker_1_kubelet.sh @@ -0,0 +1,127 @@ +info "2.1 - Kubelet" + +check_2_1_1="2.1.1 - Ensure that the --anonymous-auth argument is set to false (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--anonymous-auth=false' >/dev/null 2>&1; then + pass "$check_2_1_1" +else + warn "$check_2_1_1" +fi + +check_2_1_2="2.1.2 - Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--authorization-mode=AlwaysAllow' >/dev/null 2>&1; then + warn "$check_2_1_2" +else + pass "$check_2_1_2" +fi + +check_2_1_3="2.1.3 - Ensure that the --client-ca-file argument is set as appropriate (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then + cafile=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') + pass "$check_2_1_3" + pass " * client-ca-file: $cafile" +else + warn "$check_2_1_3" +fi + +check_2_1_4="2.1.4 - Ensure that the --read-only-port argument is set to 0 (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--read-only-port' >/dev/null 2>&1; then + port=$(get_argument_value "$CIS_KUBELET_CMD" '--read-only-port' | cut -d " " -f 1) + if [ $port = "0" ]; then + pass "$check_2_1_4" + else + warn "$check_2_1_4" + warn " * read-only-port: $port" + fi +else + warn "$check_2_1_4" +fi + +check_2_1_5="2.1.5 - Ensure that the --streaming-connection-idle-timeout argument is not set to 0 (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--streaming-connection-idle-timeout=0' >/dev/null 2>&1; then + timeout=$(get_argument_value "$CIS_KUBELET_CMD" '--streaming-connection-idle-timeout') + warn "$check_2_1_5" + warn " * streaming-connection-idle-timeout: $timeout" +else + pass "$check_2_1_5" +fi + +check_2_1_6="2.1.6 - Ensure that the --protect-kernel-defaults argument is set to true (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--protect-kernel-defaults=true' >/dev/null 2>&1; then + pass "$check_2_1_6" +else + warn "$check_2_1_6" +fi + +check_2_1_7="2.1.7 - Ensure that the --make-iptables-util-chains argument is set to true (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--make-iptables-util-chains=true' >/dev/null 2>&1; then + pass "$check_2_1_7" +else + warn "$check_2_1_7" +fi + +check_2_1_8="2.1.8 - Ensure that the --hostname-override argument is not set (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--hostname-override' >/dev/null 2>&1; then + warn "$check_2_1_8" +else + pass "$check_2_1_8" +fi + +check_2_1_9="2.1.9 - Ensure that the --event-qps argument is set to 0 (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--event-qps' >/dev/null 2>&1; then + event=$(get_argument_value "$CIS_KUBELET_CMD" '--event-qps' | cut -d " " -f 1) + if [ $event = "0" ]; then + pass "$check_2_1_9" + else + warn "$check_2_1_9" + warn " * event-qps: $event" + fi +else + warn "$check_2_1_9" +fi + +check_2_1_10="2.1.10 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--tls-cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_KUBELET_CMD" '--tls-private-key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-cert-file') + kfile=$(get_argument_value "$CIS_KUBELET_CMD" '--tls-private-key-file') + pass "$check_2_1_10" + pass " * tls-cert-file: $cfile" + pass " * tls-private-key-file: $kfile" + else + warn "$check_2_1_10" + fi +else + warn "$check_2_1_10" +fi + +check_2_1_11="2.1.11 - [DEPRECATED] Ensure that the --cadvisor-port argument is set to 0 (Not Scored)" +pass "$check_2_1_11" + +check_2_1_12="2.1.12 - Ensure that the --rotate-certificates argument is not set to false (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--rotate-certificates=true' >/dev/null 2>&1; then + pass "$check_2_1_12" +else + warn "$check_2_1_12" +fi + +check_2_1_13="2.1.13 - Ensure that the RotateKubeletServerCertificate argument is set to true (Scored)" +file="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" +found=$(sed -rn '/--feature-gates=RotateKubeletServerCertificate=true/p' $file) +if [ -z "$found" ]; then + warn "$check_2_1_13" +else + pass "$check_2_1_13" +fi + +check_2_1_14="2.1.14 - Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers (Not Scored)" +if check_argument "$CIS_KUBELET_CMD" '--tls-cipher-suites' >/dev/null 2>&1; then + ciphers=$(get_argument_value "$CIS_APISERVER_CMD" '--tls-cipher-suites'|cut -d " " -f 1) + found=$(echo $ciphers| sed -rn '/(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)/p') + if [ ! -z "$found" ]; then + pass "$check_2_1_14" + else + warn "$check_2_1_14" + fi +else + warn "$check_2_1_14" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.4.1/worker/worker_2_configure_files.sh b/scripts/kubernetes-cis-benchmark/1.4.1/worker/worker_2_configure_files.sh new file mode 100755 index 0000000..54123dd --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.4.1/worker/worker_2_configure_files.sh @@ -0,0 +1,152 @@ +info "2.2 - Configuration Files" + +check_2_2_1="2.2.1 - Ensure that the kubelet service file permissions are set to 644 or more restrictive (Scored)" +file="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" + +if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + pass "$check_2_2_1" + else + warn "$check_2_2_1" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_1" + info " * File not found" +fi + +check_2_2_2="2.2.2 - Ensure that the kubelet.conf file permissions are set to 644 or more restrictive (Scored)" +file="/etc/kubernetes/kubelet.conf" +if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + pass "$check_2_2_2" + else + warn "$check_2_2_2" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_2" + info " * File not found" +fi + + +check_2_2_3="2.2.3 - Ensure that the kubelet.conf file ownership is set to root:root (Scored)" +file="/etc/kubernetes/kubelet.conf" +if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_3" + else + warn "$check_2_2_3" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_3" +fi + +check_2_2_4="2.2.4 - Ensure that the kubelet service file ownership is set to root:root (Scored)" +file="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf" +if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_4" + else + warn "$check_2_2_4" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_4" +fi + +check_2_2_5="2.2.5 - Ensure that the proxy kubeconfig file permissions are set to 644 or more restrictive (Scored)" +file="" +if check_argument "$CIS_PROXY_CMD" '--kubeconfig' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_PROXY_CMD" '--kubeconfig'|cut -d " " -f 1) +fi + +if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + pass "$check_2_2_5" + else + warn "$check_2_2_5" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_5" + info " * --kubeconfig not set" +fi + +check_2_2_6="2.2.6 - Ensure that the proxy kubeconfig file ownership is set to root:root (Scored)" +file="" +if check_argument "$CIS_PROXY_CMD" '--kubeconfig' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_PROXY_CMD" '--kubeconfig'|cut -d " " -f 1) +fi +if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_6" + else + warn "$check_2_2_6" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_6" + info " * --kubeconfig not set" +fi + +check_2_2_7="2.2.7 - Ensure that the certificate authorities file permissions are set to 644 or more restrictive (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + pass "$check_2_2_7" + pass " * client-ca-file: $file" + else + warn "$check_2_2_7" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_7" + info " * --client-ca-file not set" +fi + +check_2_2_8="2.2.8 - Ensure that the client certificate authorities file ownership is set to root:root (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--client-ca-file' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_KUBELET_CMD" '--client-ca-file') + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_8" + pass " * client-ca-file: $file" + else + warn "$check_2_2_8" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_8" + info " * --client-ca-file not set" +fi + +check_2_2_9="2.2.9 - Ensure that the kubelet configuration file has permissions set to 644 or more restrictive (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--config' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_KUBELET_CMD" '--config') + if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 640 -o "$(stat -c %a $file)" -eq 600 -o "$(stat -c %a $file)" -eq 400 ]; then + pass "$check_2_2_9" + pass " * config: $file" + else + warn "$check_2_2_9" + warn " * Wrong permissions for $file" + fi +else + info "$check_2_2_9" + info " * --config not set" +fi + +check_2_2_10="2.2.10 - Ensure that the kubelet configuration file ownership is set to root:root (Scored)" +if check_argument "$CIS_KUBELET_CMD" '--config' >/dev/null 2>&1; then + file=$(get_argument_value "$CIS_KUBELET_CMD" '--config') + if [ "$(stat -c %u%g $file)" -eq 00 ]; then + pass "$check_2_2_10" + pass " * client: $file" + else + warn "$check_2_2_10" + warn " * Wrong ownership for $file" + fi +else + info "$check_2_2_10" + info " * --config not set" +fi diff --git a/scripts/kubeBench/kube_master_1_5_1.tmpl b/scripts/kubernetes-cis-benchmark/1.5.1/master/1_control_plane_components.sh similarity index 76% rename from scripts/kubeBench/kube_master_1_5_1.tmpl rename to scripts/kubernetes-cis-benchmark/1.5.1/master/1_control_plane_components.sh index d482e01..5e6812d 100644 --- a/scripts/kubeBench/kube_master_1_5_1.tmpl +++ b/scripts/kubernetes-cis-benchmark/1.5.1/master/1_control_plane_components.sh @@ -1,159 +1,3 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.9, 5.3.2, 5.4.2, 5.5.1, 5.7.2, 5.7.3, 5.7.4" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_APISERVER_CMD="<<<.Replace_apiserver_cmd>>>" -CIS_MANAGER_CMD="<<<.Replace_manager_cmd>>>" -CIS_SCHEDULER_CMD="<<<.Replace_scheduler_cmd>>>" -CIS_ETCD_CMD="<<<.Replace_etcd_cmd>>>" -CIS_PROXY_CMD="<<<.Replace_proxy_cmd>>>" - -if ps -ef | grep "$CIS_APISERVER_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Master Node Security Configuration" -else - info "This node is not a Kubernetes master node" - exit 2 -fi - info "1 - Control Plane Components" info "1.1 - Master Node Configuration Files" @@ -878,109 +722,3 @@ if get_argument_value "$CIS_SCHEDULER_CMD" '--bind-address'| grep '127.0.0.1' >/ else warn "$check_1_4_2" fi -info "2 - etcd" - -check_2_1="2.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)" -if check_argument "$CIS_ETCD_CMD" '--cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_ETCD_CMD" '--key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_ETCD_CMD" '--cert-file') - kfile=$(get_argument_value "$CIS_ETCD_CMD" '--key-file') - pass "$check_2_1" - pass " * cert-file: $cfile" - pass " * key-file: $kfile" - else - warn "$check_2_1" - fi -else - warn "$check_2_1" -fi - -check_2_2="2.2 - Ensure that the --client-cert-auth argument is set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--client-cert-auth' >/dev/null 2>&1; then - pass "$check_2_2" -else - warn "$check_2_2" -fi - -check_2_3="2.3 - Ensure that the --auto-tls argument is not set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--auto-tls=true' >/dev/null 2>&1; then - warn "$check_2_3" -else - pass "$check_2_3" -fi - -check_2_4="2.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_ETCD_CMD" '--peer-key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-cert-file') - kfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-key-file') - pass "$check_2_4" - pass " * peer-cert-file: $cfile" - pass " * peer-key-file: $kfile" - else - warn "$check_2_4" - fi -else - warn "$check_2_4" -fi - -check_2_5="2.5 - Ensure that the --peer-client-cert-auth argument is set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-client-cert-auth=true' >/dev/null 2>&1; then - pass "$check_2_5" -else - warn "$check_2_5" -fi - -check_2_6="2.6 - Ensure that the --peer-auto-tls argument is not set to true (Scored)" -if check_argument "$CIS_ETCD_CMD" '--peer-auto-tls=true' >/dev/null 2>&1; then - warn "$check_2_6" -else - pass "$check_2_6" -fi - -#todo apiserver vs kube-apiserver -check_2_7="2.7 - Ensure that a unique Certificate Authority is used for etcd (Not Scored)" -if check_argument "$CIS_ETCD_CMD" '--trusted-ca-file' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then - tfile=$(get_argument_value "$CIS_ETCD_CMD" '--trusted-ca-file') - cfile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') - if [ "$tfile" = "$cfile" ]; then - pass "$check_2_7" - pass " * trusted-ca-file: $tfile" - pass " * client-ca-file: $cfile" - else - warn "$check_2_7" - fi - else - warn "$check_2_7" - warn " * client-ca-file doesn't exist" - fi -else - warn "$check_2_7" - warn " * trusted-ca-file doesn't exist" -fi -info "3 - Control Plane Configuration" - -info "3.1 - Authentication and Authorization" - -check_3_1_1="3.1.1 - Client certificate authentication should not be used for users (Not Scored)" -info "$check_3_1_1" -info " * Review user access to the cluster and ensure that users are not making use of Kubernetes client certificate authentication." - -info "3.2 - Logging" - -check_3_2_1="3.2.1 - Ensure that a minimal audit policy is created (Scored)" -if check_argument "$CIS_APISERVER_CMD" '--audit-policy-file' >/dev/null 2>&1; then - auditPolicyFile=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-policy-file') - pass "$check_3_2_1" - pass " * audit-policy-file: $auditPolicyFile" -else - warn "$check_3_2_1" -fi - -check_3_2_2="3.2.2 - Ensure that the audit policy covers key security concerns (Not Scored)" -info "$check_3_2_2" -info " * Access to Secrets managed by the cluster. Care should be taken to only log Metadata for requests to Secrets, ConfigMaps, and TokenReviews, in order to avoid the risk of logging sensitive data." -info " * Modification of pod and deployment objects." -info " * Use of pods/exec, pods/portforward, pods/proxy and services/proxy." -exit 0; diff --git a/scripts/kubernetes-cis-benchmark/1.5.1/master/2_etcd.sh b/scripts/kubernetes-cis-benchmark/1.5.1/master/2_etcd.sh new file mode 100644 index 0000000..1c59bed --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.5.1/master/2_etcd.sh @@ -0,0 +1,81 @@ +info "2 - etcd" + +check_2_1="2.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Scored)" +if check_argument "$CIS_ETCD_CMD" '--cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_ETCD_CMD" '--key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_ETCD_CMD" '--cert-file') + kfile=$(get_argument_value "$CIS_ETCD_CMD" '--key-file') + pass "$check_2_1" + pass " * cert-file: $cfile" + pass " * key-file: $kfile" + else + warn "$check_2_1" + fi +else + warn "$check_2_1" +fi + +check_2_2="2.2 - Ensure that the --client-cert-auth argument is set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--client-cert-auth' >/dev/null 2>&1; then + pass "$check_2_2" +else + warn "$check_2_2" +fi + +check_2_3="2.3 - Ensure that the --auto-tls argument is not set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--auto-tls=true' >/dev/null 2>&1; then + warn "$check_2_3" +else + pass "$check_2_3" +fi + +check_2_4="2.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_ETCD_CMD" '--peer-key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-cert-file') + kfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-key-file') + pass "$check_2_4" + pass " * peer-cert-file: $cfile" + pass " * peer-key-file: $kfile" + else + warn "$check_2_4" + fi +else + warn "$check_2_4" +fi + +check_2_5="2.5 - Ensure that the --peer-client-cert-auth argument is set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-client-cert-auth=true' >/dev/null 2>&1; then + pass "$check_2_5" +else + warn "$check_2_5" +fi + +check_2_6="2.6 - Ensure that the --peer-auto-tls argument is not set to true (Scored)" +if check_argument "$CIS_ETCD_CMD" '--peer-auto-tls=true' >/dev/null 2>&1; then + warn "$check_2_6" +else + pass "$check_2_6" +fi + +#todo apiserver vs kube-apiserver +check_2_7="2.7 - Ensure that a unique Certificate Authority is used for etcd (Not Scored)" +if check_argument "$CIS_ETCD_CMD" '--trusted-ca-file' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then + tfile=$(get_argument_value "$CIS_ETCD_CMD" '--trusted-ca-file') + cfile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') + if [ "$tfile" = "$cfile" ]; then + pass "$check_2_7" + pass " * trusted-ca-file: $tfile" + pass " * client-ca-file: $cfile" + else + warn "$check_2_7" + fi + else + warn "$check_2_7" + warn " * client-ca-file doesn't exist" + fi +else + warn "$check_2_7" + warn " * trusted-ca-file doesn't exist" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.5.1/master/3_control_plane_configuration.sh b/scripts/kubernetes-cis-benchmark/1.5.1/master/3_control_plane_configuration.sh new file mode 100644 index 0000000..cb22b0f --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.5.1/master/3_control_plane_configuration.sh @@ -0,0 +1,24 @@ +info "3 - Control Plane Configuration" + +info "3.1 - Authentication and Authorization" + +check_3_1_1="3.1.1 - Client certificate authentication should not be used for users (Not Scored)" +info "$check_3_1_1" +info " * Review user access to the cluster and ensure that users are not making use of Kubernetes client certificate authentication." + +info "3.2 - Logging" + +check_3_2_1="3.2.1 - Ensure that a minimal audit policy is created (Scored)" +if check_argument "$CIS_APISERVER_CMD" '--audit-policy-file' >/dev/null 2>&1; then + auditPolicyFile=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-policy-file') + pass "$check_3_2_1" + pass " * audit-policy-file: $auditPolicyFile" +else + warn "$check_3_2_1" +fi + +check_3_2_2="3.2.2 - Ensure that the audit policy covers key security concerns (Not Scored)" +info "$check_3_2_2" +info " * Access to Secrets managed by the cluster. Care should be taken to only log Metadata for requests to Secrets, ConfigMaps, and TokenReviews, in order to avoid the risk of logging sensitive data." +info " * Modification of pod and deployment objects." +info " * Use of pods/exec, pods/portforward, pods/proxy and services/proxy." diff --git a/scripts/kubernetes-cis-benchmark/1.5.1/master/5_policies.sh b/scripts/kubernetes-cis-benchmark/1.5.1/master/5_policies.sh new file mode 100644 index 0000000..318f0b5 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.5.1/master/5_policies.sh @@ -0,0 +1,99 @@ +info "5 - Policies" +info "5.1 - RBAC and Service Accounts" + +# Make the loop separator be a new-line in POSIX compliant fashion +set -f; IFS=$' +' + +check_5_1_1="5.1.1 - Ensure that the cluster-admin role is only used where required (Not Scored)" +cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) +info "$check_5_1_1" +for admin in $cluster_admins; do + info " * $admin" +done + +check_5_1_2="5.1.2 - Minimize access to secrets (Not Scored)" +policies=$(kubectl get psp) +info "$check_5_1_2" +for policy in $policies; do + info " * $policy" +done + +check_5_1_3="5.1.3 - Create administrative boundaries between resources using namespaces (Not Scored)" +namespaces=$(kubectl get namespaces) +info "$check_5_1_3" +for namespace in $namespaces; do + info " * $namespace" +done + +check_5_1_4="5.1.4 - Create network segmentation using Network Policies (Not Scored)" +policies=$(kubectl get pods --namespace=kube-system) +info "$check_5_1_4" +for policy in $policies; do + info " * $policy" +done + +check_5_1_5="5.1.5 - Avoid using Kubernetes Secrets (Not Scored)" +secrets=$(kubectl get secrets) +info "$check_5_1_5" +for secret in $secrets; do + info " * $secret" +done + +#TODO +check_5_1_6="5.1.6 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)" +info "$check_5_1_6" +check_5_1_7="5.1.7 - Apply Security Context to Your Pods and Containers (Not Scored)" +info "$check_5_1_7" +check_5_1_8="5.1.8 - Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)" +info "$check_5_1_8" +check_5_1_9="5.1.9 - Place compensating controls in the form of PSP and RBAC for privileged containers usage (Not Scored)" +info "$check_5_1_9" + +info "5.2 - Pod Security Policies" + +check_5_2_1="5.2.1 - Minimize the admission of privileged containers (Not Scored)" +info "$check_5_2_1" +check_5_2_2="5.2.2 - Minimize the admission of containers wishing to share the host process ID namespace (Scored)" +info "$check_5_2_2" +check_5_2_3="5.2.3 - Minimize the admission of containers wishing to share the host IPC namespace (Scored)" +info "$check_5_2_3" +check_5_2_4="5.2.4 - Minimize the admission of containers wishing to share the host network namespace (Scored)" +info "$check_5_2_4" +check_5_2_5="5.2.5 - Minimize the admission of containers with allowPrivilegeEscalation (Scored)" +info "$check_5_2_5" +check_5_2_6="5.2.6 - Minimize the admission of root containers (Not Scored)" +info "$check_5_2_6" +check_5_2_7="5.2.7 - Minimize the admission of containers with the NET_RAW capability (Not Scored)" +info "$check_5_2_7" +check_5_2_8="5.2.8 - Minimize the admission of containers with added capabilities (Not Scored)" +info "$check_5_2_8" +check_5_2_9="5.2.9 - Minimize the admission of containers with capabilities assigned (Not Scored)" +info "$check_5_2_9" + +info "5.3 - Network Policies and CNI" +check_5_3_1="5.3.1 - Ensure that the CNI in use supports Network Policies (Not Scored)" +info "$check_5_3_1" +check_5_3_2="5.3.2 - Ensure that all Namespaces have Network Policies defined (Scored)" +info "$check_5_3_2" + +info "5.4 - Secrets Management" +check_5_4_1="5.4.1 - Prefer using secrets as files over secrets as environment variables (Not Scored)" +info "$check_5_4_1" +check_5_4_2="5.4.2 - Consider external secret storage (Not Scored)" +info "$check_5_4_2" + +info "5.5 - Extensible Admission Control" +check_5_5_1="5.5.1 - Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)" +info "$check_5_5_1" + +info "5.6 - General Policies" +check_5_6_1="5.6.1 - Create administrative boundaries between resources using namespaces (Not Scored)" +info "$check_5_6_1" +#todo remedition +check_5_6_2="5.6.2 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)" +info "$check_5_6_2" +check_5_6_3="5.6.3 - Apply Security Context to Your Pods and Containers (Not Scored)" +info "$check_5_6_3" +check_5_6_4="5.6.4 - The default namespace should not be used (Scored)" +info "$check_5_6_4" diff --git a/scripts/kubeBench/kube_worker_1_5_1.tmpl b/scripts/kubernetes-cis-benchmark/1.5.1/worker/4_worker_nodes.sh similarity index 72% rename from scripts/kubeBench/kube_worker_1_5_1.tmpl rename to scripts/kubernetes-cis-benchmark/1.5.1/worker/4_worker_nodes.sh index f45bf4c..4ed293d 100644 --- a/scripts/kubeBench/kube_worker_1_5_1.tmpl +++ b/scripts/kubernetes-cis-benchmark/1.5.1/worker/4_worker_nodes.sh @@ -1,156 +1,3 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.9, 5.3.2, 5.4.2, 5.5.1, 5.7.2, 5.7.3, 5.7.4" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_KUBELET_CMD="<<<.Replace_kubelet_cmd>>>" -CIS_PROXY_CMD="<<<.Replace_proxy_cmd>>>" - -if ps -ef | grep "$CIS_KUBELET_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Worker Node Security Configuration" -else - info "This node is not a Kubernetes worker node" - exit 2 -fi - info "4.1 - Worker Node Configuration Files" check_4_1_1="4.1.1 - Ensure that the kubelet service file permissions are set to 644 or more restrictive (Scored)" @@ -428,4 +275,3 @@ else warn "$check_4_2_13" fi -exit 0; diff --git a/scripts/kubeBench/kube_master_1_6_0.tmpl b/scripts/kubernetes-cis-benchmark/1.6.0/master/1_control_plane_components.sh similarity index 66% rename from scripts/kubeBench/kube_master_1_6_0.tmpl rename to scripts/kubernetes-cis-benchmark/1.6.0/master/1_control_plane_components.sh index f5b6b9f..7598914 100644 --- a/scripts/kubeBench/kube_master_1_6_0.tmpl +++ b/scripts/kubernetes-cis-benchmark/1.6.0/master/1_control_plane_components.sh @@ -1,179 +1,3 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.9, 5.3.2, 5.4.2, 5.5.1, 5.7.2, 5.7.3, 5.7.4" -not_scored="1.1.9, 1.1.10, 1.1.20, 1.1.21, 1.2.1, 1.2.10, 1.2.12, 1.2.13, 1.2.33, 1.2.34, 1.2.35, 1.3.1, 2.7, 3.1.1, 3.2.2, 4,2.8, 4.2.9, 4.2.13, 5.1.1, 5.1.2, 5.1.3, 5.1.4, 5.1.6, 5.2.1, 5.2.6, 5.2.7, 5.2.8, 5.2.9, 5.3.1, 5.4.1, 5.4.2, 5.5.1, 5.7.1, 5.7.2, 5.7.3" -assessment_manual="1.1.9, 1.1.10, 1.1.20, 1.1.21, 1.2.1, 1.2.10, 1.2.12, 1.2.13, 1.2.33, 1.2.34, 1.2.35, 1.3.1, 2.7, 3.1.1, 3.2.1, 3.2.2, 4.1.3, 4.1.4, 4.1.6, 4.1.7, 4.1.8, 4.2.4, 4.2.5, 4.2.8, 4.2.9, 4.2.10, 4.2.11, 4.2.12, 4.2.13, 5.1.1, 5.1.2, 5.1.3, 5.1.4, 5.1.5, 5.1.6, 5.2.1, 5.2.2, 5.2.3, 5.2.4, 5.2.5, 5.2.6, 5.2.7, 5.2.8, 5.2.9, 5.3.1, 5.3.2, 5.4.1, 5.4.2, 5.5.1, 5.7.1, 5.7.2, 5.7.3, 5.7.4" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - fi - - level_info="" - scoring_info="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_info="${bldgry}[Level 2]${txtrst}" - else - level_info="${bldgry}[Level 1]${txtrst}" - fi - if echo "$not_scored" | grep -q "\<${idx}\>"; then - scoring_info="${bldgry}[Not Scored]${txtrst}" - else - scoring_info="${bldgry}[Scored]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_info}${s_txt}${scoring_info} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - fi - - level_info="" - scoring_info="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_info="${bldgry}[Level 2]${txtrst}" - else - level_info="${bldgry}[Level 1]${txtrst}" - fi - if echo "$not_scored" | grep -q "\<${idx}\>"; then - scoring_info="${bldgry}[Not Scored]${txtrst}" - else - scoring_info="${bldgry}[Scored]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_info}${s_txt}${scoring_info} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - fi - - level_info="" - scoring_info="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_info="${bldgry}[Level 2]${txtrst}" - else - level_info="${bldgry}[Level 1]${txtrst}" - fi - if echo "$not_scored" | grep -q "\<${idx}\>"; then - scoring_info="${bldgry}[Not Scored]${txtrst}" - else - scoring_info="${bldgry}[Scored]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_info}${s_txt}${scoring_info} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_APISERVER_CMD="<<<.Replace_apiserver_cmd>>>" -CIS_MANAGER_CMD="<<<.Replace_manager_cmd>>>" -CIS_SCHEDULER_CMD="<<<.Replace_scheduler_cmd>>>" -CIS_ETCD_CMD="<<<.Replace_etcd_cmd>>>" -CIS_PROXY_CMD="<<<.Replace_proxy_cmd>>>" - -if ps -ef | grep "$CIS_APISERVER_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Master Node Security Configuration" -else - info "This node is not a Kubernetes master node" - exit 2 -fi - info "1 - Control Plane Components" info "1.1 - Master Node Configuration Files" @@ -898,208 +722,3 @@ if get_argument_value "$CIS_SCHEDULER_CMD" '--bind-address'| grep '127.0.0.1' >/ else warn "$check_1_4_2" fi -info "2 - etcd" - -check_2_1="2.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Automated)" -if check_argument "$CIS_ETCD_CMD" '--cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_ETCD_CMD" '--key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_ETCD_CMD" '--cert-file') - kfile=$(get_argument_value "$CIS_ETCD_CMD" '--key-file') - pass "$check_2_1" - pass " * cert-file: $cfile" - pass " * key-file: $kfile" - else - warn "$check_2_1" - fi -else - warn "$check_2_1" -fi - -check_2_2="2.2 - Ensure that the --client-cert-auth argument is set to true (Automated)" -if check_argument "$CIS_ETCD_CMD" '--client-cert-auth' >/dev/null 2>&1; then - pass "$check_2_2" -else - warn "$check_2_2" -fi - -check_2_3="2.3 - Ensure that the --auto-tls argument is not set to true (Automated)" -if check_argument "$CIS_ETCD_CMD" '--auto-tls=true' >/dev/null 2>&1; then - warn "$check_2_3" -else - pass "$check_2_3" -fi - -check_2_4="2.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Automated)" -if check_argument "$CIS_ETCD_CMD" '--peer-cert-file' >/dev/null 2>&1; then - if check_argument "$CIS_ETCD_CMD" '--peer-key-file' >/dev/null 2>&1; then - cfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-cert-file') - kfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-key-file') - pass "$check_2_4" - pass " * peer-cert-file: $cfile" - pass " * peer-key-file: $kfile" - else - warn "$check_2_4" - fi -else - warn "$check_2_4" -fi - -check_2_5="2.5 - Ensure that the --peer-client-cert-auth argument is set to true (Automated)" -if check_argument "$CIS_ETCD_CMD" '--peer-client-cert-auth=true' >/dev/null 2>&1; then - pass "$check_2_5" -else - warn "$check_2_5" -fi - -check_2_6="2.6 - Ensure that the --peer-auto-tls argument is not set to true (Automated)" -if check_argument "$CIS_ETCD_CMD" '--peer-auto-tls=true' >/dev/null 2>&1; then - warn "$check_2_6" -else - pass "$check_2_6" -fi - -#todo apiserver vs kube-apiserver -check_2_7="2.7 - Ensure that a unique Certificate Authority is used for etcd (Manual)" -if check_argument "$CIS_ETCD_CMD" '--trusted-ca-file' >/dev/null 2>&1; then - if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then - tfile=$(get_argument_value "$CIS_ETCD_CMD" '--trusted-ca-file') - cfile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') - if [ "$tfile" = "$cfile" ]; then - pass "$check_2_7" - pass " * trusted-ca-file: $tfile" - pass " * client-ca-file: $cfile" - else - warn "$check_2_7" - fi - else - warn "$check_2_7" - warn " * client-ca-file doesn't exist" - fi -else - warn "$check_2_7" - warn " * trusted-ca-file doesn't exist" -fi -info "3 - Control Plane Configuration" - -info "3.1 - Authentication and Authorization" - -check_3_1_1="3.1.1 - Client certificate authentication should not be used for users (Manual)" -info "$check_3_1_1" -info " * Review user access to the cluster and ensure that users are not making use of Kubernetes client certificate authentication." - -info "3.2 - Logging" - -check_3_2_1="3.2.1 - Ensure that a minimal audit policy is created (Manual)" -if check_argument "$CIS_APISERVER_CMD" '--audit-policy-file' >/dev/null 2>&1; then - auditPolicyFile=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-policy-file') - pass "$check_3_2_1" - pass " * audit-policy-file: $auditPolicyFile" -else - warn "$check_3_2_1" -fi - -check_3_2_2="3.2.2 - Ensure that the audit policy covers key security concerns (Manual)" -info "$check_3_2_2" -info " * Access to Secrets managed by the cluster. Care should be taken to only log Metadata for requests to Secrets, ConfigMaps, and TokenReviews, in order to avoid the risk of logging sensitive data." -info " * Modification of pod and deployment objects." -info " * Use of pods/exec, pods/portforward, pods/proxy and services/proxy." -info "5 - Policies" -info "5.1 - RBAC and Service Accounts" - -# Make the loop separator be a new-line in POSIX compliant fashion -set -f; IFS=$' -' - -check_5_1_1="5.1.1 - Ensure that the cluster-admin role is only used where required (Manual)" -cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) -info "$check_5_1_1" -for admin in $cluster_admins; do - info " * $admin" -done - -check_5_1_2="5.1.2 - Minimize access to secrets (Manual)" -policies=$(kubectl get psp) -info "$check_5_1_2" -for policy in $policies; do - info " * $policy" -done - -check_5_1_3="5.1.3 - Create administrative boundaries between resources using namespaces (Manual)" -namespaces=$(kubectl get namespaces) -info "$check_5_1_3" -for namespace in $namespaces; do - info " * $namespace" -done - -check_5_1_4="5.1.4 - Create network segmentation using Network Policies (Manual)" -policies=$(kubectl get pods --namespace=kube-system) -info "$check_5_1_4" -for policy in $policies; do - info " * $policy" -done - -check_5_1_5="5.1.5 - Avoid using Kubernetes Secrets (Manual)" -secrets=$(kubectl get secrets) -info "$check_5_1_5" -for secret in $secrets; do - info " * $secret" -done - -#TODO -check_5_1_6="5.1.6 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Manual)" -info "$check_5_1_6" -check_5_1_7="5.1.7 - Apply Security Context to Your Pods and Containers (Manual)" -info "$check_5_1_7" -check_5_1_8="5.1.8 - Configure Image Provenance using ImagePolicyWebhook admission controller (Manual)" -info "$check_5_1_8" -check_5_1_9="5.1.9 - Place compensating controls in the form of PSP and RBAC for privileged containers usage (Manual)" -info "$check_5_1_9" - -info "5.2 - Pod Security Policies" - -check_5_2_1="5.2.1 - Minimize the admission of privileged containers (Manual)" -info "$check_5_2_1" -check_5_2_2="5.2.2 - Minimize the admission of containers wishing to share the host process ID namespace (Manual)" -info "$check_5_2_2" -check_5_2_3="5.2.3 - Minimize the admission of containers wishing to share the host IPC namespace (Manual)" -info "$check_5_2_3" -check_5_2_4="5.2.4 - Minimize the admission of containers wishing to share the host network namespace (Manual)" -info "$check_5_2_4" -check_5_2_5="5.2.5 - Minimize the admission of containers with allowPrivilegeEscalation (Manual)" -info "$check_5_2_5" -check_5_2_6="5.2.6 - Minimize the admission of root containers (Manual)" -info "$check_5_2_6" -check_5_2_7="5.2.7 - Minimize the admission of containers with the NET_RAW capability (Manual)" -info "$check_5_2_7" -check_5_2_8="5.2.8 - Minimize the admission of containers with added capabilities (Manual)" -info "$check_5_2_8" -check_5_2_9="5.2.9 - Minimize the admission of containers with capabilities assigned (Manual)" -info "$check_5_2_9" - -info "5.3 - Network Policies and CNI" -check_5_3_1="5.3.1 - Ensure that the CNI in use supports Network Policies (Manual)" -info "$check_5_3_1" -check_5_3_2="5.3.2 - Ensure that all Namespaces have Network Policies defined (Manual)" -info "$check_5_3_2" - -info "5.4 - Secrets Management" -check_5_4_1="5.4.1 - Prefer using secrets as files over secrets as environment variables (Manual)" -info "$check_5_4_1" -check_5_4_2="5.4.2 - Consider external secret storage (Manual)" -info "$check_5_4_2" - -info "5.5 - Extensible Admission Control" -check_5_5_1="5.5.1 - Configure Image Provenance using ImagePolicyWebhook admission controller (Manual)" -info "$check_5_5_1" - -info "5.7 - General Policies" -check_5_7_1="5.7.1 - Create administrative boundaries between resources using namespaces (Manual)" -info "$check_5_7_1" -#todo remedition -check_5_7_2="5.7.2 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Manual)" -info "$check_5_7_2" -check_5_7_3="5.7.3 - Apply Security Context to Your Pods and Containers (Manual)" -info "$check_5_6_3" -check_5_7_4="5.7.4 - The default namespace should not be used (Manual)" -info "$check_5_7_4" -exit 0; diff --git a/scripts/kubernetes-cis-benchmark/1.6.0/master/2_etcd.sh b/scripts/kubernetes-cis-benchmark/1.6.0/master/2_etcd.sh new file mode 100644 index 0000000..5bd6c30 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.6.0/master/2_etcd.sh @@ -0,0 +1,81 @@ +info "2 - etcd" + +check_2_1="2.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Automated)" +if check_argument "$CIS_ETCD_CMD" '--cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_ETCD_CMD" '--key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_ETCD_CMD" '--cert-file') + kfile=$(get_argument_value "$CIS_ETCD_CMD" '--key-file') + pass "$check_2_1" + pass " * cert-file: $cfile" + pass " * key-file: $kfile" + else + warn "$check_2_1" + fi +else + warn "$check_2_1" +fi + +check_2_2="2.2 - Ensure that the --client-cert-auth argument is set to true (Automated)" +if check_argument "$CIS_ETCD_CMD" '--client-cert-auth' >/dev/null 2>&1; then + pass "$check_2_2" +else + warn "$check_2_2" +fi + +check_2_3="2.3 - Ensure that the --auto-tls argument is not set to true (Automated)" +if check_argument "$CIS_ETCD_CMD" '--auto-tls=true' >/dev/null 2>&1; then + warn "$check_2_3" +else + pass "$check_2_3" +fi + +check_2_4="2.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Automated)" +if check_argument "$CIS_ETCD_CMD" '--peer-cert-file' >/dev/null 2>&1; then + if check_argument "$CIS_ETCD_CMD" '--peer-key-file' >/dev/null 2>&1; then + cfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-cert-file') + kfile=$(get_argument_value "$CIS_ETCD_CMD" '--peer-key-file') + pass "$check_2_4" + pass " * peer-cert-file: $cfile" + pass " * peer-key-file: $kfile" + else + warn "$check_2_4" + fi +else + warn "$check_2_4" +fi + +check_2_5="2.5 - Ensure that the --peer-client-cert-auth argument is set to true (Automated)" +if check_argument "$CIS_ETCD_CMD" '--peer-client-cert-auth=true' >/dev/null 2>&1; then + pass "$check_2_5" +else + warn "$check_2_5" +fi + +check_2_6="2.6 - Ensure that the --peer-auto-tls argument is not set to true (Automated)" +if check_argument "$CIS_ETCD_CMD" '--peer-auto-tls=true' >/dev/null 2>&1; then + warn "$check_2_6" +else + pass "$check_2_6" +fi + +#todo apiserver vs kube-apiserver +check_2_7="2.7 - Ensure that a unique Certificate Authority is used for etcd (Manual)" +if check_argument "$CIS_ETCD_CMD" '--trusted-ca-file' >/dev/null 2>&1; then + if check_argument "$CIS_APISERVER_CMD" '--client-ca-file' >/dev/null 2>&1; then + tfile=$(get_argument_value "$CIS_ETCD_CMD" '--trusted-ca-file') + cfile=$(get_argument_value "$CIS_APISERVER_CMD" '--client-ca-file') + if [ "$tfile" = "$cfile" ]; then + pass "$check_2_7" + pass " * trusted-ca-file: $tfile" + pass " * client-ca-file: $cfile" + else + warn "$check_2_7" + fi + else + warn "$check_2_7" + warn " * client-ca-file doesn't exist" + fi +else + warn "$check_2_7" + warn " * trusted-ca-file doesn't exist" +fi diff --git a/scripts/kubernetes-cis-benchmark/1.6.0/master/3_control_plane_configuration.sh b/scripts/kubernetes-cis-benchmark/1.6.0/master/3_control_plane_configuration.sh new file mode 100644 index 0000000..9e15658 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.6.0/master/3_control_plane_configuration.sh @@ -0,0 +1,24 @@ +info "3 - Control Plane Configuration" + +info "3.1 - Authentication and Authorization" + +check_3_1_1="3.1.1 - Client certificate authentication should not be used for users (Manual)" +info "$check_3_1_1" +info " * Review user access to the cluster and ensure that users are not making use of Kubernetes client certificate authentication." + +info "3.2 - Logging" + +check_3_2_1="3.2.1 - Ensure that a minimal audit policy is created (Manual)" +if check_argument "$CIS_APISERVER_CMD" '--audit-policy-file' >/dev/null 2>&1; then + auditPolicyFile=$(get_argument_value "$CIS_APISERVER_CMD" '--audit-policy-file') + pass "$check_3_2_1" + pass " * audit-policy-file: $auditPolicyFile" +else + warn "$check_3_2_1" +fi + +check_3_2_2="3.2.2 - Ensure that the audit policy covers key security concerns (Manual)" +info "$check_3_2_2" +info " * Access to Secrets managed by the cluster. Care should be taken to only log Metadata for requests to Secrets, ConfigMaps, and TokenReviews, in order to avoid the risk of logging sensitive data." +info " * Modification of pod and deployment objects." +info " * Use of pods/exec, pods/portforward, pods/proxy and services/proxy." diff --git a/scripts/kubernetes-cis-benchmark/1.6.0/master/5_policies.sh b/scripts/kubernetes-cis-benchmark/1.6.0/master/5_policies.sh new file mode 100644 index 0000000..9b2afba --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/1.6.0/master/5_policies.sh @@ -0,0 +1,99 @@ +info "5 - Policies" +info "5.1 - RBAC and Service Accounts" + +# Make the loop separator be a new-line in POSIX compliant fashion +set -f; IFS=$' +' + +check_5_1_1="5.1.1 - Ensure that the cluster-admin role is only used where required (Manual)" +cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) +info "$check_5_1_1" +for admin in $cluster_admins; do + info " * $admin" +done + +check_5_1_2="5.1.2 - Minimize access to secrets (Manual)" +policies=$(kubectl get psp) +info "$check_5_1_2" +for policy in $policies; do + info " * $policy" +done + +check_5_1_3="5.1.3 - Create administrative boundaries between resources using namespaces (Manual)" +namespaces=$(kubectl get namespaces) +info "$check_5_1_3" +for namespace in $namespaces; do + info " * $namespace" +done + +check_5_1_4="5.1.4 - Create network segmentation using Network Policies (Manual)" +policies=$(kubectl get pods --namespace=kube-system) +info "$check_5_1_4" +for policy in $policies; do + info " * $policy" +done + +check_5_1_5="5.1.5 - Avoid using Kubernetes Secrets (Manual)" +secrets=$(kubectl get secrets) +info "$check_5_1_5" +for secret in $secrets; do + info " * $secret" +done + +#TODO +check_5_1_6="5.1.6 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Manual)" +info "$check_5_1_6" +check_5_1_7="5.1.7 - Apply Security Context to Your Pods and Containers (Manual)" +info "$check_5_1_7" +check_5_1_8="5.1.8 - Configure Image Provenance using ImagePolicyWebhook admission controller (Manual)" +info "$check_5_1_8" +check_5_1_9="5.1.9 - Place compensating controls in the form of PSP and RBAC for privileged containers usage (Manual)" +info "$check_5_1_9" + +info "5.2 - Pod Security Policies" + +check_5_2_1="5.2.1 - Minimize the admission of privileged containers (Manual)" +info "$check_5_2_1" +check_5_2_2="5.2.2 - Minimize the admission of containers wishing to share the host process ID namespace (Manual)" +info "$check_5_2_2" +check_5_2_3="5.2.3 - Minimize the admission of containers wishing to share the host IPC namespace (Manual)" +info "$check_5_2_3" +check_5_2_4="5.2.4 - Minimize the admission of containers wishing to share the host network namespace (Manual)" +info "$check_5_2_4" +check_5_2_5="5.2.5 - Minimize the admission of containers with allowPrivilegeEscalation (Manual)" +info "$check_5_2_5" +check_5_2_6="5.2.6 - Minimize the admission of root containers (Manual)" +info "$check_5_2_6" +check_5_2_7="5.2.7 - Minimize the admission of containers with the NET_RAW capability (Manual)" +info "$check_5_2_7" +check_5_2_8="5.2.8 - Minimize the admission of containers with added capabilities (Manual)" +info "$check_5_2_8" +check_5_2_9="5.2.9 - Minimize the admission of containers with capabilities assigned (Manual)" +info "$check_5_2_9" + +info "5.3 - Network Policies and CNI" +check_5_3_1="5.3.1 - Ensure that the CNI in use supports Network Policies (Manual)" +info "$check_5_3_1" +check_5_3_2="5.3.2 - Ensure that all Namespaces have Network Policies defined (Manual)" +info "$check_5_3_2" + +info "5.4 - Secrets Management" +check_5_4_1="5.4.1 - Prefer using secrets as files over secrets as environment variables (Manual)" +info "$check_5_4_1" +check_5_4_2="5.4.2 - Consider external secret storage (Manual)" +info "$check_5_4_2" + +info "5.5 - Extensible Admission Control" +check_5_5_1="5.5.1 - Configure Image Provenance using ImagePolicyWebhook admission controller (Manual)" +info "$check_5_5_1" + +info "5.7 - General Policies" +check_5_7_1="5.7.1 - Create administrative boundaries between resources using namespaces (Manual)" +info "$check_5_7_1" +#todo remedition +check_5_7_2="5.7.2 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Manual)" +info "$check_5_7_2" +check_5_7_3="5.7.3 - Apply Security Context to Your Pods and Containers (Manual)" +info "$check_5_6_3" +check_5_7_4="5.7.4 - The default namespace should not be used (Manual)" +info "$check_5_7_4" diff --git a/scripts/kubeBench/kube_worker_1_6_0.tmpl b/scripts/kubernetes-cis-benchmark/1.6.0/worker/4_worker_nodes.sh similarity index 66% rename from scripts/kubeBench/kube_worker_1_6_0.tmpl rename to scripts/kubernetes-cis-benchmark/1.6.0/worker/4_worker_nodes.sh index 8c5ff24..0d3df54 100644 --- a/scripts/kubeBench/kube_worker_1_6_0.tmpl +++ b/scripts/kubernetes-cis-benchmark/1.6.0/worker/4_worker_nodes.sh @@ -1,176 +1,3 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.9, 5.3.2, 5.4.2, 5.5.1, 5.7.2, 5.7.3, 5.7.4" -not_scored="1.1.9, 1.1.10, 1.1.20, 1.1.21, 1.2.1, 1.2.10, 1.2.12, 1.2.13, 1.2.33, 1.2.34, 1.2.35, 1.3.1, 2.7, 3.1.1, 3.2.2, 4,2.8, 4.2.9, 4.2.13, 5.1.1, 5.1.2, 5.1.3, 5.1.4, 5.1.6, 5.2.1, 5.2.6, 5.2.7, 5.2.8, 5.2.9, 5.3.1, 5.4.1, 5.4.2, 5.5.1, 5.7.1, 5.7.2, 5.7.3" -assessment_manual="1.1.9, 1.1.10, 1.1.20, 1.1.21, 1.2.1, 1.2.10, 1.2.12, 1.2.13, 1.2.33, 1.2.34, 1.2.35, 1.3.1, 2.7, 3.1.1, 3.2.1, 3.2.2, 4.1.3, 4.1.4, 4.1.6, 4.1.7, 4.1.8, 4.2.4, 4.2.5, 4.2.8, 4.2.9, 4.2.10, 4.2.11, 4.2.12, 4.2.13, 5.1.1, 5.1.2, 5.1.3, 5.1.4, 5.1.5, 5.1.6, 5.2.1, 5.2.2, 5.2.3, 5.2.4, 5.2.5, 5.2.6, 5.2.7, 5.2.8, 5.2.9, 5.3.1, 5.3.2, 5.4.1, 5.4.2, 5.5.1, 5.7.1, 5.7.2, 5.7.3, 5.7.4" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - fi - - level_info="" - scoring_info="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_info="${bldgry}[Level 2]${txtrst}" - else - level_info="${bldgry}[Level 1]${txtrst}" - fi - if echo "$not_scored" | grep -q "\<${idx}\>"; then - scoring_info="${bldgry}[Not Scored]${txtrst}" - else - scoring_info="${bldgry}[Scored]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_info}${s_txt}${scoring_info} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - fi - - level_info="" - scoring_info="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_info="${bldgry}[Level 2]${txtrst}" - else - level_info="${bldgry}[Level 1]${txtrst}" - fi - if echo "$not_scored" | grep -q "\<${idx}\>"; then - scoring_info="${bldgry}[Not Scored]${txtrst}" - else - scoring_info="${bldgry}[Scored]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_info}${s_txt}${scoring_info} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Automated)"; then - s_txt="${bldcyn}[Automated]${txtrst}" - elif echo "$1" | grep -q "(Manual)"; then - s_txt="${bldcyn}[Manual]${txtrst}" - fi - - level_info="" - scoring_info="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_info="${bldgry}[Level 2]${txtrst}" - else - level_info="${bldgry}[Level 1]${txtrst}" - fi - if echo "$not_scored" | grep -q "\<${idx}\>"; then - scoring_info="${bldgry}[Not Scored]${txtrst}" - else - scoring_info="${bldgry}[Scored]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_info}${s_txt}${scoring_info} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}=//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_KUBELET_CMD="<<<.Replace_kubelet_cmd>>>" -CIS_PROXY_CMD="<<<.Replace_proxy_cmd>>>" - -if ps -ef | grep "$CIS_KUBELET_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Worker Node Security Configuration" -else - info "This node is not a Kubernetes worker node" - exit 2 -fi - info "4.1 - Worker Node Configuration Files" check_4_1_1="4.1.1 - Ensure that the kubelet service file permissions are set to 644 or more restrictive (Automated)" @@ -448,4 +275,3 @@ else warn "$check_4_2_13" fi -exit 0; diff --git a/scripts/kubernetes-cis-benchmark/LICENSE b/scripts/kubernetes-cis-benchmark/LICENSE new file mode 100644 index 0000000..3ce7cc5 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 NeuVector Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/scripts/kubernetes-cis-benchmark/NeuVector-Logo.png b/scripts/kubernetes-cis-benchmark/NeuVector-Logo.png new file mode 100644 index 0000000..e94d0fe Binary files /dev/null and b/scripts/kubernetes-cis-benchmark/NeuVector-Logo.png differ diff --git a/scripts/kubernetes-cis-benchmark/README.md b/scripts/kubernetes-cis-benchmark/README.md new file mode 100644 index 0000000..3825c38 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/README.md @@ -0,0 +1,31 @@ +# CIS Kubernetes Benchmark + +![CIS Kubernetes Benchmark output](https://raw.githubusercontent.com/neuvector/kubernetes-cis-benchmark/master/bench.png "CIS Kubernetes Benchmark output") + +This set of scripts can be used to check the Kubernetes installation against the best-practices. + +### Supported CIS Kubernetes versions + +| CIS Kubernetes Benchmark Version | Kubernetes versions | +|---|---| +| 1.0.0 | 1.6 | +| 1.2.0 | 1.8 | +| 1.5.1 | 1.15 | +| 1.6.0 | 1.16 - 1.18 | + +### Running the benchmark checks + +On the Kubernetes master nodes, +``` +$ ./master.sh +``` + +On the Kubernetes worker nodes, +``` +$ ./worker.sh +``` + +On the Kubernetes federation nodes, +``` +$ ./federation.sh + diff --git a/scripts/kubernetes-cis-benchmark/bench.png b/scripts/kubernetes-cis-benchmark/bench.png new file mode 100644 index 0000000..1759d1b Binary files /dev/null and b/scripts/kubernetes-cis-benchmark/bench.png differ diff --git a/scripts/kubernetes-cis-benchmark/federation.sh b/scripts/kubernetes-cis-benchmark/federation.sh new file mode 100755 index 0000000..ecf56e3 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/federation.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# ------------------------------------------------------------------------------ +# Kubenetes CIS benchmark +# +# Neuvector, Inc. (c) 2016- +# +# ------------------------------------------------------------------------------ + +# Load dependencies +. ./helper.sh + +ver=$1 +if [ -z "$1" ]; then + warn "usage: ./federation.sh version" + exit +fi +# Check for required program(s) +req_progs='grep pgrep sed' +for p in $req_progs; do + command -v "$p" >/dev/null 2>&1 || { printf "%s command not found.\n" "$p"; exit 1; } +done + +# Load all the tests from tests/ and run them +main () { + info "3 - Federated Deployments" + + for test in $ver/federation/federation_*.sh + do + . ./"$test" + done +} + +main "$@" + diff --git a/scripts/kubeBench/kube_master_gke_1_0_0.tmpl b/scripts/kubernetes-cis-benchmark/gke/master/1_control_plane_components.sh similarity index 61% rename from scripts/kubeBench/kube_master_gke_1_0_0.tmpl rename to scripts/kubernetes-cis-benchmark/gke/master/1_control_plane_components.sh index b0c8304..466a237 100644 --- a/scripts/kubeBench/kube_master_gke_1_0_0.tmpl +++ b/scripts/kubernetes-cis-benchmark/gke/master/1_control_plane_components.sh @@ -1,160 +1,3 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.6, 5.2.9, 5.3.2, 5.4.2, 5.6.2, 5.6.3, 5.6.4, -6.1.4, 6.2.1, 6.4.2, 6.5.1, 6.5.7, 6.6.1, 6.6.4, 6.6.8, 6.7.2, 6.8.3, 6.10.4, 6.10.5" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}[= ]//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_APISERVER_CMD="<<<.Replace_apiserver_cmd>>>" -CIS_MANAGER_CMD="<<<.Replace_manager_cmd>>>" -CIS_SCHEDULER_CMD="<<<.Replace_scheduler_cmd>>>" -CIS_ETCD_CMD="<<<.Replace_etcd_cmd>>>" -CIS_PROXY_CMD="<<<.Replace_proxy_cmd>>>" - -if ps -ef | grep "$CIS_APISERVER_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Master Node Security Configuration" -else - info "This node is not a Kubernetes master node" - exit 2 -fi - info "1 - Control Plane Components" info "1.1 - Master Node Configuration Files" @@ -359,44 +202,3 @@ info "$check_1_4_1" check_1_4_2="1.4.2 - Ensure that the --bind-address argument is set to 127.0.0.1 (Not Scored)" info "$check_1_4_2" -info "2 - etcd" - -check_2_1="2.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Not Scored)" -info "$check_2_1" - -check_2_2="2.2 - Ensure that the --client-cert-auth argument is set to true (Not Scored)" -info "$check_2_2" - -check_2_3="2.3 - Ensure that the --auto-tls argument is not set to true (Not Scored)" -info "$check_2_3" - -check_2_4="2.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Not Scored)" -info "$check_2_4" - -check_2_5="2.5 - Ensure that the --peer-client-cert-auth argument is set to true (Not Scored)" -info "$check_2_5" - -check_2_6="2.6 - Ensure that the --peer-auto-tls argument is not set to true (Not Scored)" -info "$check_2_6" - -check_2_7="2.7 - Ensure that a unique Certificate Authority is used for etcd (Not Scored)" -info "$check_2_7" -info "3 - Control Plane Configuration" - -info "3.1 - Authentication and Authorization" - -check_3_1_1="3.1.1 - Client certificate authentication should not be used for users (Not Scored)" -info "$check_3_1_1" -info " * Review user access to the cluster and ensure that users are not making use of Kubernetes client certificate authentication." - -info "3.2 - Logging" -#todo review -check_3_2_1="3.2.1 - Ensure that a minimal audit policy is created (Not Scored)" -info "$check_3_2_1" - -check_3_2_2="3.2.2 - Ensure that the audit policy covers key security concerns (Not Scored)" -info "$check_3_2_2" -info " * Access to Secrets managed by the cluster. Care should be taken to only log Metadata for requests to Secrets, ConfigMaps, and TokenReviews, in order to avoid the risk of logging sensitive data." -info " * Modification of pod and deployment objects." -info " * Use of pods/exec, pods/portforward, pods/proxy and services/proxy." -exit 0; diff --git a/scripts/kubernetes-cis-benchmark/gke/master/2_etcd.sh b/scripts/kubernetes-cis-benchmark/gke/master/2_etcd.sh new file mode 100644 index 0000000..318312d --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/gke/master/2_etcd.sh @@ -0,0 +1,22 @@ +info "2 - etcd" + +check_2_1="2.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate (Not Scored)" +info "$check_2_1" + +check_2_2="2.2 - Ensure that the --client-cert-auth argument is set to true (Not Scored)" +info "$check_2_2" + +check_2_3="2.3 - Ensure that the --auto-tls argument is not set to true (Not Scored)" +info "$check_2_3" + +check_2_4="2.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate (Not Scored)" +info "$check_2_4" + +check_2_5="2.5 - Ensure that the --peer-client-cert-auth argument is set to true (Not Scored)" +info "$check_2_5" + +check_2_6="2.6 - Ensure that the --peer-auto-tls argument is not set to true (Not Scored)" +info "$check_2_6" + +check_2_7="2.7 - Ensure that a unique Certificate Authority is used for etcd (Not Scored)" +info "$check_2_7" diff --git a/scripts/kubernetes-cis-benchmark/gke/master/3_control_plane_configuration.sh b/scripts/kubernetes-cis-benchmark/gke/master/3_control_plane_configuration.sh new file mode 100644 index 0000000..feabadc --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/gke/master/3_control_plane_configuration.sh @@ -0,0 +1,18 @@ +info "3 - Control Plane Configuration" + +info "3.1 - Authentication and Authorization" + +check_3_1_1="3.1.1 - Client certificate authentication should not be used for users (Not Scored)" +info "$check_3_1_1" +info " * Review user access to the cluster and ensure that users are not making use of Kubernetes client certificate authentication." + +info "3.2 - Logging" +#todo review +check_3_2_1="3.2.1 - Ensure that a minimal audit policy is created (Not Scored)" +info "$check_3_2_1" + +check_3_2_2="3.2.2 - Ensure that the audit policy covers key security concerns (Not Scored)" +info "$check_3_2_2" +info " * Access to Secrets managed by the cluster. Care should be taken to only log Metadata for requests to Secrets, ConfigMaps, and TokenReviews, in order to avoid the risk of logging sensitive data." +info " * Modification of pod and deployment objects." +info " * Use of pods/exec, pods/portforward, pods/proxy and services/proxy." diff --git a/scripts/kubernetes-cis-benchmark/gke/master/5_policies.sh b/scripts/kubernetes-cis-benchmark/gke/master/5_policies.sh new file mode 100644 index 0000000..7d68f4b --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/gke/master/5_policies.sh @@ -0,0 +1,105 @@ +info "5 - Policies" +info "5.1 - RBAC and Service Accounts" + +# Make the loop separator be a new-line in POSIX compliant fashion +set -f; IFS=$' +' + +check_5_1_1="5.1.1 - Ensure that the cluster-admin role is only used where required (Not Scored)" +cluster_admins=$(kubectl get clusterrolebindings -o=custom-columns=NAME:.metadata.name,ROLE:.roleRef.name,SUBJECT:.subjects[*].name) +info "$check_5_1_1" +for admin in $cluster_admins; do + info " * $admin" +done + +check_5_1_2="5.1.2 - Minimize access to secrets (Not Scored)" +policies=$(kubectl get psp) +info "$check_5_1_2" +for policy in $policies; do + info " * $policy" +done + +check_5_1_3="5.1.3 - Minimize wildcard use in Roles and ClusterRoles (Not Scored)" +namespaces=$(kubectl get namespaces) +info "$check_5_1_3" +for namespace in $namespaces; do + info " * $namespace" +done + +check_5_1_4="5.1.4 - Minimize access to create pods (Not Scored)" +policies=$(kubectl get pods --namespace=kube-system) +info "$check_5_1_4" +for policy in $policies; do + info " * $policy" +done + +check_5_1_5="5.1.5 - Ensure that default service accounts are not actively used. (Scored)" +secrets=$(kubectl get secrets) +info "$check_5_1_5" +for secret in $secrets; do + info " * $secret" +done + +#TODO +check_5_1_6="5.1.6 - Ensure that Service Account Tokens are only mounted where necessary (Not Scored)" +info "$check_5_1_6" + +info "5.2 - Pod Security Policies" + +check_5_2_1="5.2.1 - Minimize the admission of privileged containers (Scored)" +info "$check_5_2_1" + +check_5_2_2="5.2.2 - Minimize the admission of containers wishing to share the host process ID namespace (Scored)" +info "$check_5_2_2" + +check_5_2_3="5.2.3 - Minimize the admission of containers wishing to share the host IPC namespace (Scored)" +info "$check_5_2_3" + +check_5_2_4="5.2.4 - Minimize the admission of containers wishing to share the host network namespace (Scored)" +info "$check_5_2_4" + +check_5_2_5="5.2.5 - Minimize the admission of containers with allowPrivilegeEscalation (Scored)" +info "$check_5_2_5" + +check_5_2_6="5.2.6 - Minimize the admission of root containers (Scored)" +info "$check_5_2_6" + +check_5_2_7="5.2.7 - Minimize the admission of containers with the NET_RAW capability (Scored)" +info "$check_5_2_7" + +check_5_2_8="5.2.8 - Minimize the admission of containers with added capabilities (Scored)" +info "$check_5_2_8" + +check_5_2_9="5.2.9 - Minimize the admission of containers with capabilities assigned (Scored)" +info "$check_5_2_9" + +info "5.3 - Network Policies and CNI" +check_5_3_1="5.3.1 - Ensure that the CNI in use supports Network Policies (Not Scored)" +info "$check_5_3_1" + +check_5_3_2="5.3.2 - Ensure that all Namespaces have Network Policies defined (Scored)" +info "$check_5_3_2" + +info "5.4 - Secrets Management" +check_5_4_1="5.4.1 - Prefer using secrets as files over secrets as environment variables (Not Scored)" +info "$check_5_4_1" + +check_5_4_2="5.4.2 - Consider external secret storage (Not Scored)" +info "$check_5_4_2" + +info "5.5 - Extensible Admission Control" +check_5_5_1="5.5.1 - Configure Image Provenance using ImagePolicyWebhook admission controller (Not Scored)" +info "$check_5_5_1" + +info "5.6 - General Policies" +check_5_6_1="5.6.1 - Create administrative boundaries between resources using namespaces (Not Scored)" +info "$check_5_6_1" + +check_5_6_2="5.6.2 - Ensure that the seccomp profile is set to docker/default in your pod definitions (Not Scored)" +info "$check_5_6_2" + +check_5_6_3="5.6.3 - Apply Security Context to Your Pods and Containers (Not Scored)" +info "$check_5_6_3" + +check_5_6_4="5.6.4 - The default namespace should not be used (Scored)" +info "$check_5_6_4" diff --git a/scripts/kubernetes-cis-benchmark/gke/master/6_managed_services.sh b/scripts/kubernetes-cis-benchmark/gke/master/6_managed_services.sh new file mode 100644 index 0000000..bee6437 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/gke/master/6_managed_services.sh @@ -0,0 +1,124 @@ +info "6 - Managed services" +info "6.1 - Image Registry and Image Scanning" + +check_6_1_1="6.1.1 - Ensure Image Vulnerability Scanning using GCR Container Analysis or a third-party provider (Scored)" +info "$check_6_1_1" + +check_6_1_2="6.1.2 - Minimize user access to GCR (Scored)" +info "$check_6_1_2" + +check_6_1_3="6.1.3 - Minimize cluster access to read-only for GCR (Scored)" +info "$check_6_1_3" + +check_6_1_4="6.1.4 - Minimize Container Registries to only those approved (Not Scored)" +info "$check_6_1_4" + +info "6.2 - Identity and Access Management (IAM)" +check_6_2_1="6.2.1 - Ensure GKE clusters are not running using the Compute Engine default service account (Scored)" +info "$check_6_2_1" + +check_6_2_2="6.2.2 - Prefer using dedicated GCP Service Accounts and Workload Identity (Not Scored)" +info "$check_6_2_2" + +info "6.3 - Cloud Key Management Service (Cloud KMS)" +check_6_3_1="6.3.1 - Ensure Kubernetes Secrets are encrypted using keys managed in Cloud KMS (Scored)" +info "$check_6_3_1" + +info "6.4 - Node Metadata" +check_6_4_1="6.4.1 - Ensure legacy Compute Engine instance metadata APIs are Disabled (Scored)" +info "$check_6_4_1" + +check_6_4_2="6.4.2 - Ensure the GKE Metadata Server is Enabled (Not Scored)" +info "$check_6_4_2" + +info "6.5 - Node Configuration and Maintenance" +check_6_5_1="6.5.1 - Ensure legacy Compute Engine instance metadata APIs are Disabled (Scored)" +info "$check_6_5_1" + +check_6_5_2="6.5.2 - Ensure Node Auto-Repair is enabled for GKE nodes (Scored)" +info "$check_6_5_2" + +check_6_5_3="6.5.3 - Ensure Node Auto-Upgrade is enabled for GKE nodes (Scored)" +info "$check_6_5_3" + +check_6_5_4="6.5.4 - Automate GKE version management using Release Channels (Not Scored)" +info "$check_6_5_4" + +check_6_5_5="6.5.5 - Ensure Shielded GKE Nodes are Enabled (Not Scored)" +info "$check_6_5_5" + +check_6_5_6="6.5.6 - Ensure Integrity Monitoring for Shielded GKE Nodes is Enabled (Not Scored)" +info "$check_6_5_6" + +check_6_5_7="6.5.7 - Ensure Secure Boot for Shielded GKE Nodes is Enabled (Not Scored)" +info "$check_6_5_7" + +info "6.6 - Cluster Networking" +check_6_6_1="6.6.1 - Enable VPC Flow Logs and Intranode Visibility (Not Scored)" +info "$check_6_6_1" + +check_6_6_2="6.6.2 - Ensure use of VPC-native clusters (Scored)" +info "$check_6_6_2" + +check_6_6_3="6.6.3 - Ensure Master Authorized Networks is Enabled (Scored)" +info "$check_6_6_3" + +check_6_6_4="6.6.4 - Ensure clusters are created with Private Endpoint Enabled and Public Access Disabled (Scored)" +info "$check_6_6_4" + +check_6_6_5="6.6.5 - Ensure clusters are created with Private Nodes (Scored)" +info "$check_6_6_5" + +check_6_6_6="6.6.6 - Consider firewalling GKE worker nodes (Not Scored)" +info "$check_6_6_6" + +check_6_6_7="6.6.7 - Ensure Network Policy is Enabled and set as appropriate (Not Scored)" +info "$check_6_6_7" + +check_6_6_8="6.6.8 - Ensure use of Google-managed SSL Certificates (Not Scored)" +info "$check_6_6_8" + +info "6.7 - Cluster Networking" +check_6_7_1="6.7.1 - Ensure Stackdriver Kubernetes Logging and Monitoring is Enabled (Scored)" +info "$check_6_7_1" + +check_6_7_2="6.7.2 - Enable Linux auditd logging (Not Scored)" +info "$check_6_7_2" + +info "6.8 - Authentication and Authorization" + +check_6_8_1="6.8.1 - Ensure Basic Authentication using static passwords is Disabled (Scored)" +info "$check_6_8_1" + +check_6_8_2="6.8.2 - Ensure authentication using Client Certificates is Disabled (Scored)" +info "$check_6_8_2" + +check_6_8_3="6.8.3 - Manage Kubernetes RBAC users with Google Groups for GKE (Not Scored)" +info "$check_6_8_3" + +check_6_8_4="6.8.4 - Ensure Legacy Authorization (ABAC) is Disabled (Scored)" +info "$check_6_8_4" + +info "6.9 - Storage" +check_6_9_1="6.9.1 - Enable Customer-Managed Encryption Keys (CMEK) for GKE Persistent Disks (PD) (Not Scored)" +info "$check_6_9_1" + +info "6.10 - Other Cluster Configurations" + +check_6_10_1="6.10.1 - Ensure Kubernetes Web UI is Disabled (Scored)" +info "$check_6_10_1" + +check_6_10_2="6.10.2 - Ensure that Alpha clusters are not used for production workloads (Scored)" +info "$check_6_10_2" + +check_6_10_3="6.10.3 - Ensure Pod Security Policy is Enabled and set as appropriate (Not Scored)" +info "$check_6_10_3" + +check_6_10_4="6.10.4 - Consider GKE Sandbox for running untrusted workloads (Not Scored)" +info "$check_6_10_4" + +check_6_10_5="6.10.5 - Ensure use of Binary Authorization (Scored)" +info "$check_6_10_5" + +check_6_10_6="6.10.6 - Enable Cloud Security Command Center (Cloud SCC) (Not Scored)" +info "$check_6_10_6" diff --git a/scripts/kubeBench/kube_worker_gke_1_0_0.tmpl b/scripts/kubernetes-cis-benchmark/gke/worker/4_worker_nodes.sh similarity index 66% rename from scripts/kubeBench/kube_worker_gke_1_0_0.tmpl rename to scripts/kubernetes-cis-benchmark/gke/worker/4_worker_nodes.sh index facc9cc..32733ab 100644 --- a/scripts/kubeBench/kube_worker_gke_1_0_0.tmpl +++ b/scripts/kubernetes-cis-benchmark/gke/worker/4_worker_nodes.sh @@ -1,157 +1,3 @@ -#!/bin/sh - -if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then - bldred='' - bldgrn='' - bldblu='' - bldylw='' - bldcyn='' - bldgry='' - txtrst='' -else - bldred='\033[1;31m' - bldgrn='\033[1;32m' - bldblu='\033[1;34m' - bldylw='\033[1;33m' - bldcyn='\033[1;36m' - bldgry='\033[1;37m' - txtrst='\033[0m' -fi - -level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.6, 5.2.9, 5.3.2, 5.4.2, 5.6.2, 5.6.3, 5.6.4, -6.1.4, 6.2.1, 6.4.2, 6.5.1, 6.5.7, 6.6.1, 6.6.4, 6.6.8, 6.7.2, 6.8.3, 6.10.4, 6.10.5" - -info () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" -} - -pass () { - - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" - -} - -warn () { - s_txt="" - if echo "$1" | grep -q "(Scored)"; then - s_txt="${bldcyn}[Scored]${txtrst}" - elif echo "$1" | grep -q "(Not Scored)"; then - s_txt="${bldcyn}[Not Scored]${txtrst}" - fi - - level_txt="" - if [ ${#s_txt} -ne 0 ]; then - idx=$(echo "$1" | cut -d " " -f 1) - if echo "$level2" | grep -q "\<${idx}\>"; then - level_txt="${bldgry}[Level 2]${txtrst}" - else - level_txt="${bldgry}[Level 1]${txtrst}" - fi - fi - - printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" - -} - -yell () { - printf "%b\n" "${bldylw}$1${txtrst}\n" -} - -yell "# ------------------------------------------------------------------------------ -# Kubernetes CIS benchmark -# -# NeuVector, Inc. (c) 2020- -# -# NeuVector delivers an application and network intelligent container security -# solution that automatically adapts to protect running containers. Don’t let -# security concerns slow down your CI/CD processes. -# ------------------------------------------------------------------------------" - -#get a process command line from /proc -get_command_line_args() { - PROC="$1" - len=${#PROC} - if [ $len -gt 15 ]; then - ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" - else - for PID in $(pgrep -n "$PROC") - do - tr "\0" " " < /proc/"$PID"/cmdline - done - fi -} - -#get an argument value from command line -get_argument_value() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" | - sed \ - -e "s/^${OPTION}[= ]//g" -} - -#check whether an argument exist in command line -check_argument() { - CMD="$1" - OPTION="$2" - - get_command_line_args "$CMD" | - sed \ - -e 's/\-\-/\n--/g' \ - | - grep "^${OPTION}" -} - -CIS_KUBELET_CMD="<<<.Replace_kubelet_cmd>>>" -CIS_PROXY_CMD="<<<.Replace_proxy_cmd>>>" - -if ps -ef | grep "$CIS_KUBELET_CMD" 2>/dev/null | grep -v "grep" >/dev/null 2>&1; then - info "Kubernetes Worker Node Security Configuration" -else - info "This node is not a Kubernetes worker node" - exit 2 -fi - info "4.1 - Worker Node Configuration Files" check_4_1_1="4.1.1 - Ensure that the kubelet service file permissions are set to 644 or more restrictive (Not Scored)" diff --git a/scripts/kubernetes-cis-benchmark/helper.sh b/scripts/kubernetes-cis-benchmark/helper.sh new file mode 100755 index 0000000..1518ebf --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/helper.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then + bldred='' + bldgrn='' + bldblu='' + bldylw='' + txtrst='' +else + bldred='\033[1;31m' + bldgrn='\033[1;32m' + bldblu='\033[1;34m' + bldylw='\033[1;33m' + txtrst='\033[0m' +fi + +info () { + printf "%b\n" "${bldblu}[INFO]${txtrst} $1" +} + +pass () { + printf "%b\n" "${bldgrn}[PASS]${txtrst} $1" +} + +warn () { + printf "%b\n" "${bldred}[WARN]${txtrst} $1" +} + +yell () { + printf "%b\n" "${bldylw}$1${txtrst}\n" +} + +yell "# ------------------------------------------------------------------------------ +# Kubernetes CIS benchmark +# +# NeuVector, Inc. (c) 2016- +# +# NeuVector delivers an application and network intelligent container security +# solution that automatically adapts to protect running containers. Don’t let +# security concerns slow down your CI/CD processes. +# ------------------------------------------------------------------------------" + +#get a process command line from /proc +get_command_line_args() { + PROC="$1" + len=${#PROC} + if [ $len -gt 15 ]; then + ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" + else + for PID in $(pgrep -n "$PROC") + do + tr "\0" " " < /proc/"$PID"/cmdline + done + fi +} + +#get an argument value from command line +get_argument_value() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" | + sed \ + -e "s/^${OPTION}=//g" +} + +#check whether an argument exist in command line +check_argument() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" +} + diff --git a/scripts/kubernetes-cis-benchmark/helper1_4_1.sh b/scripts/kubernetes-cis-benchmark/helper1_4_1.sh new file mode 100644 index 0000000..35da676 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/helper1_4_1.sh @@ -0,0 +1,146 @@ +#!/bin/sh + +if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then + bldred='' + bldgrn='' + bldblu='' + bldylw='' + bldcyn='' + bldgry='' + txtrst='' +else + bldred='\033[1;31m' + bldgrn='\033[1;32m' + bldblu='\033[1;34m' + bldylw='\033[1;33m' + bldcyn='\033[1;36m' + bldgry='\033[1;37m' + txtrst='\033[0m' +fi + +notScored="1.1.1, 1.1.12, 1.1.13, 1.1.31, 1.4.9, 1.4.10, 1.5.7, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.6.5, 1.6.6, 1.6.7, 1.6.8, +1.7.1, 1.7.6, 1.7.7, 2.1.11, 2.1.14" +level2="1.3.6, 1.5.7, 1.6.1, 1.6.4, 1.6.5, 1.6.6, 1.6.7, 1.6.8, + 1.7.6, 1.7.7" + +info () { + + s_txt="" + if echo "$1" | grep -q "(Scored)"; then + s_txt="${bldcyn}[Scored]${txtrst}" + elif echo "$1" | grep -q "(Not Scored)"; then + s_txt="${bldcyn}[Not Scored]${txtrst}" + fi + + level_txt="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_txt="${bldgry}[Level 2]${txtrst}" + else + level_txt="${bldgry}[Level 1]${txtrst}" + fi + fi + + printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" +} + +pass () { + + s_txt="" + if echo "$1" | grep -q "(Scored)"; then + s_txt="${bldcyn}[Scored]${txtrst}" + elif echo "$1" | grep -q "(Not Scored)"; then + s_txt="${bldcyn}[Not Scored]${txtrst}" + fi + + level_txt="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_txt="${bldgry}[Level 2]${txtrst}" + else + level_txt="${bldgry}[Level 1]${txtrst}" + fi + fi + + printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" + +} + +warn () { + s_txt="" + if echo "$1" | grep -q "(Scored)"; then + s_txt="${bldcyn}[Scored]${txtrst}" + elif echo "$1" | grep -q "(Not Scored)"; then + s_txt="${bldcyn}[Not Scored]${txtrst}" + fi + + level_txt="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_txt="${bldgry}[Level 2]${txtrst}" + else + level_txt="${bldgry}[Level 1]${txtrst}" + fi + fi + + printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" + +} + +yell () { + printf "%b\n" "${bldylw}$1${txtrst}\n" +} + +yell "# ------------------------------------------------------------------------------ +# Kubernetes CIS benchmark +# +# NeuVector, Inc. (c) 2020- +# +# NeuVector delivers an application and network intelligent container security +# solution that automatically adapts to protect running containers. Don’t let +# security concerns slow down your CI/CD processes. +# ------------------------------------------------------------------------------" + +#get a process command line from /proc +get_command_line_args() { + PROC="$1" + len=${#PROC} + if [ $len -gt 15 ]; then + ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" + else + for PID in $(pgrep -n "$PROC") + do + tr "\0" " " < /proc/"$PID"/cmdline + done + fi +} + +#get an argument value from command line +get_argument_value() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" | + sed \ + -e "s/^${OPTION}=//g" +} + +#check whether an argument exist in command line +check_argument() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" +} + diff --git a/scripts/kubernetes-cis-benchmark/helper1_5_1.sh b/scripts/kubernetes-cis-benchmark/helper1_5_1.sh new file mode 100644 index 0000000..9130880 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/helper1_5_1.sh @@ -0,0 +1,143 @@ +#!/bin/sh + +if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then + bldred='' + bldgrn='' + bldblu='' + bldylw='' + bldcyn='' + bldgry='' + txtrst='' +else + bldred='\033[1;31m' + bldgrn='\033[1;32m' + bldblu='\033[1;34m' + bldylw='\033[1;33m' + bldcyn='\033[1;36m' + bldgry='\033[1;37m' + txtrst='\033[0m' +fi + +level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.9, 5.3.2, 5.4.2, 5.5.1, 5.7.2, 5.7.3, 5.7.4" + +info () { + + s_txt="" + if echo "$1" | grep -q "(Scored)"; then + s_txt="${bldcyn}[Scored]${txtrst}" + elif echo "$1" | grep -q "(Not Scored)"; then + s_txt="${bldcyn}[Not Scored]${txtrst}" + fi + + level_txt="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_txt="${bldgry}[Level 2]${txtrst}" + else + level_txt="${bldgry}[Level 1]${txtrst}" + fi + fi + + printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" +} + +pass () { + + s_txt="" + if echo "$1" | grep -q "(Scored)"; then + s_txt="${bldcyn}[Scored]${txtrst}" + elif echo "$1" | grep -q "(Not Scored)"; then + s_txt="${bldcyn}[Not Scored]${txtrst}" + fi + + level_txt="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_txt="${bldgry}[Level 2]${txtrst}" + else + level_txt="${bldgry}[Level 1]${txtrst}" + fi + fi + + printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" + +} + +warn () { + s_txt="" + if echo "$1" | grep -q "(Scored)"; then + s_txt="${bldcyn}[Scored]${txtrst}" + elif echo "$1" | grep -q "(Not Scored)"; then + s_txt="${bldcyn}[Not Scored]${txtrst}" + fi + + level_txt="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_txt="${bldgry}[Level 2]${txtrst}" + else + level_txt="${bldgry}[Level 1]${txtrst}" + fi + fi + + printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" + +} + +yell () { + printf "%b\n" "${bldylw}$1${txtrst}\n" +} + +yell "# ------------------------------------------------------------------------------ +# Kubernetes CIS benchmark +# +# NeuVector, Inc. (c) 2020- +# +# NeuVector delivers an application and network intelligent container security +# solution that automatically adapts to protect running containers. Don’t let +# security concerns slow down your CI/CD processes. +# ------------------------------------------------------------------------------" + +#get a process command line from /proc +get_command_line_args() { + PROC="$1" + len=${#PROC} + if [ $len -gt 15 ]; then + ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" + else + for PID in $(pgrep -n "$PROC") + do + tr "\0" " " < /proc/"$PID"/cmdline + done + fi +} + +#get an argument value from command line +get_argument_value() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" | + sed \ + -e "s/^${OPTION}=//g" +} + +#check whether an argument exist in command line +check_argument() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" +} + diff --git a/scripts/kubernetes-cis-benchmark/helper1_6_0.sh b/scripts/kubernetes-cis-benchmark/helper1_6_0.sh new file mode 100644 index 0000000..864160e --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/helper1_6_0.sh @@ -0,0 +1,163 @@ +#!/bin/sh + +if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then + bldred='' + bldgrn='' + bldblu='' + bldylw='' + bldcyn='' + bldgry='' + txtrst='' +else + bldred='\033[1;31m' + bldgrn='\033[1;32m' + bldblu='\033[1;34m' + bldylw='\033[1;33m' + bldcyn='\033[1;36m' + bldgry='\033[1;37m' + txtrst='\033[0m' +fi + +level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.9, 5.3.2, 5.4.2, 5.5.1, 5.7.2, 5.7.3, 5.7.4" +not_scored="1.1.9, 1.1.10, 1.1.20, 1.1.21, 1.2.1, 1.2.10, 1.2.12, 1.2.13, 1.2.33, 1.2.34, 1.2.35, 1.3.1, 2.7, 3.1.1, 3.2.2, 4,2.8, 4.2.9, 4.2.13, 5.1.1, 5.1.2, 5.1.3, 5.1.4, 5.1.6, 5.2.1, 5.2.6, 5.2.7, 5.2.8, 5.2.9, 5.3.1, 5.4.1, 5.4.2, 5.5.1, 5.7.1, 5.7.2, 5.7.3" +assessment_manual="1.1.9, 1.1.10, 1.1.20, 1.1.21, 1.2.1, 1.2.10, 1.2.12, 1.2.13, 1.2.33, 1.2.34, 1.2.35, 1.3.1, 2.7, 3.1.1, 3.2.1, 3.2.2, 4.1.3, 4.1.4, 4.1.6, 4.1.7, 4.1.8, 4.2.4, 4.2.5, 4.2.8, 4.2.9, 4.2.10, 4.2.11, 4.2.12, 4.2.13, 5.1.1, 5.1.2, 5.1.3, 5.1.4, 5.1.5, 5.1.6, 5.2.1, 5.2.2, 5.2.3, 5.2.4, 5.2.5, 5.2.6, 5.2.7, 5.2.8, 5.2.9, 5.3.1, 5.3.2, 5.4.1, 5.4.2, 5.5.1, 5.7.1, 5.7.2, 5.7.3, 5.7.4" + +info () { + + s_txt="" + if echo "$1" | grep -q "(Automated)"; then + s_txt="${bldcyn}[Automated]${txtrst}" + elif echo "$1" | grep -q "(Manual)"; then + s_txt="${bldcyn}[Manual]${txtrst}" + fi + + level_info="" + scoring_info="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_info="${bldgry}[Level 2]${txtrst}" + else + level_info="${bldgry}[Level 1]${txtrst}" + fi + if echo "$not_scored" | grep -q "\<${idx}\>"; then + scoring_info="${bldgry}[Not Scored]${txtrst}" + else + scoring_info="${bldgry}[Scored]${txtrst}" + fi + fi + + printf "%b\n" "${bldblu}[INFO]${txtrst}${level_info}${s_txt}${scoring_info} $1" +} + +pass () { + + s_txt="" + if echo "$1" | grep -q "(Automated)"; then + s_txt="${bldcyn}[Automated]${txtrst}" + elif echo "$1" | grep -q "(Manual)"; then + s_txt="${bldcyn}[Manual]${txtrst}" + fi + + level_info="" + scoring_info="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_info="${bldgry}[Level 2]${txtrst}" + else + level_info="${bldgry}[Level 1]${txtrst}" + fi + if echo "$not_scored" | grep -q "\<${idx}\>"; then + scoring_info="${bldgry}[Not Scored]${txtrst}" + else + scoring_info="${bldgry}[Scored]${txtrst}" + fi + fi + + printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_info}${s_txt}${scoring_info} $1" + +} + +warn () { + s_txt="" + if echo "$1" | grep -q "(Automated)"; then + s_txt="${bldcyn}[Automated]${txtrst}" + elif echo "$1" | grep -q "(Manual)"; then + s_txt="${bldcyn}[Manual]${txtrst}" + fi + + level_info="" + scoring_info="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_info="${bldgry}[Level 2]${txtrst}" + else + level_info="${bldgry}[Level 1]${txtrst}" + fi + if echo "$not_scored" | grep -q "\<${idx}\>"; then + scoring_info="${bldgry}[Not Scored]${txtrst}" + else + scoring_info="${bldgry}[Scored]${txtrst}" + fi + fi + + printf "%b\n" "${bldred}[WARN]${txtrst}${level_info}${s_txt}${scoring_info} $1" + +} + +yell () { + printf "%b\n" "${bldylw}$1${txtrst}\n" +} + +yell "# ------------------------------------------------------------------------------ +# Kubernetes CIS benchmark +# +# NeuVector, Inc. (c) 2020- +# +# NeuVector delivers an application and network intelligent container security +# solution that automatically adapts to protect running containers. Don’t let +# security concerns slow down your CI/CD processes. +# ------------------------------------------------------------------------------" + +#get a process command line from /proc +get_command_line_args() { + PROC="$1" + len=${#PROC} + if [ $len -gt 15 ]; then + ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" + else + for PID in $(pgrep -n "$PROC") + do + tr "\0" " " < /proc/"$PID"/cmdline + done + fi +} + +#get an argument value from command line +get_argument_value() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" | + sed \ + -e "s/^${OPTION}=//g" +} + +#check whether an argument exist in command line +check_argument() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" +} + diff --git a/scripts/kubernetes-cis-benchmark/helper_gke.sh b/scripts/kubernetes-cis-benchmark/helper_gke.sh new file mode 100644 index 0000000..a7057ef --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/helper_gke.sh @@ -0,0 +1,144 @@ +#!/bin/sh + +if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then + bldred='' + bldgrn='' + bldblu='' + bldylw='' + bldcyn='' + bldgry='' + txtrst='' +else + bldred='\033[1;31m' + bldgrn='\033[1;32m' + bldblu='\033[1;34m' + bldylw='\033[1;33m' + bldcyn='\033[1;36m' + bldgry='\033[1;37m' + txtrst='\033[0m' +fi + +level2="1.3.6, 2.7, 3.1.1, 3.2.2, 4.2.9, 5.2.6, 5.2.9, 5.3.2, 5.4.2, 5.6.2, 5.6.3, 5.6.4, +6.1.4, 6.2.1, 6.4.2, 6.5.1, 6.5.7, 6.6.1, 6.6.4, 6.6.8, 6.7.2, 6.8.3, 6.10.4, 6.10.5" + +info () { + + s_txt="" + if echo "$1" | grep -q "(Scored)"; then + s_txt="${bldcyn}[Scored]${txtrst}" + elif echo "$1" | grep -q "(Not Scored)"; then + s_txt="${bldcyn}[Not Scored]${txtrst}" + fi + + level_txt="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_txt="${bldgry}[Level 2]${txtrst}" + else + level_txt="${bldgry}[Level 1]${txtrst}" + fi + fi + + printf "%b\n" "${bldblu}[INFO]${txtrst}${level_txt}${s_txt} $1" +} + +pass () { + + s_txt="" + if echo "$1" | grep -q "(Scored)"; then + s_txt="${bldcyn}[Scored]${txtrst}" + elif echo "$1" | grep -q "(Not Scored)"; then + s_txt="${bldcyn}[Not Scored]${txtrst}" + fi + + level_txt="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_txt="${bldgry}[Level 2]${txtrst}" + else + level_txt="${bldgry}[Level 1]${txtrst}" + fi + fi + + printf "%b\n" "${bldgrn}[PASS]${txtrst}${level_txt}${s_txt} $1" + +} + +warn () { + s_txt="" + if echo "$1" | grep -q "(Scored)"; then + s_txt="${bldcyn}[Scored]${txtrst}" + elif echo "$1" | grep -q "(Not Scored)"; then + s_txt="${bldcyn}[Not Scored]${txtrst}" + fi + + level_txt="" + if [ ${#s_txt} -ne 0 ]; then + idx=$(echo "$1" | cut -d " " -f 1) + if echo "$level2" | grep -q "\<${idx}\>"; then + level_txt="${bldgry}[Level 2]${txtrst}" + else + level_txt="${bldgry}[Level 1]${txtrst}" + fi + fi + + printf "%b\n" "${bldred}[WARN]${txtrst}${level_txt}${s_txt} $1" + +} + +yell () { + printf "%b\n" "${bldylw}$1${txtrst}\n" +} + +yell "# ------------------------------------------------------------------------------ +# Kubernetes CIS benchmark +# +# NeuVector, Inc. (c) 2020- +# +# NeuVector delivers an application and network intelligent container security +# solution that automatically adapts to protect running containers. Don’t let +# security concerns slow down your CI/CD processes. +# ------------------------------------------------------------------------------" + +#get a process command line from /proc +get_command_line_args() { + PROC="$1" + len=${#PROC} + if [ $len -gt 15 ]; then + ps aux|grep "$CMD "|grep -v "grep" |sed "s/.*$CMD \(.*\)/\1/g" + else + for PID in $(pgrep -n "$PROC") + do + tr "\0" " " < /proc/"$PID"/cmdline + done + fi +} + +#get an argument value from command line +get_argument_value() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" | + sed \ + -e "s/^${OPTION}[= ]//g" +} + +#check whether an argument exist in command line +check_argument() { + CMD="$1" + OPTION="$2" + + get_command_line_args "$CMD" | + sed \ + -e 's/\-\-/\n--/g' \ + | + grep "^${OPTION}" +} + diff --git a/scripts/kubernetes-cis-benchmark/master.sh b/scripts/kubernetes-cis-benchmark/master.sh new file mode 100755 index 0000000..5525ff7 --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/master.sh @@ -0,0 +1,63 @@ +#!/bin/sh +# ------------------------------------------------------------------------------ +# Kubenetes CIS benchmark +# +# Neuvector, Inc. (c) 2016- +# +# ------------------------------------------------------------------------------ + +usage () { + cat </dev/null 2>&1 || { printf "%s command not found.\n" "$p"; exit 1; } +done + +# Load all the audits from master/ and run them +main () { + + for audit in $ver/master/*.sh + do + . ./"$audit" + done +} + +main "$@" diff --git a/scripts/kubernetes-cis-benchmark/worker.sh b/scripts/kubernetes-cis-benchmark/worker.sh new file mode 100755 index 0000000..358fedd --- /dev/null +++ b/scripts/kubernetes-cis-benchmark/worker.sh @@ -0,0 +1,60 @@ +#!/bin/sh +# ------------------------------------------------------------------------------ +# Kubenetes CIS benchmark +# +# Neuvector, Inc. (c) 2016- +# +# ------------------------------------------------------------------------------ + +usage () { + cat </dev/null 2>&1 || { printf "%s command not found.\n" "$p"; exit 1; } +done + +# Load all the tests from worker/ and run them +main () { + + for audit in $ver/worker/*.sh + do + . ./"$audit" + done +} + +main "$@" diff --git a/scripts/nist.sh b/scripts/nist.sh new file mode 100644 index 0000000..41343d7 --- /dev/null +++ b/scripts/nist.sh @@ -0,0 +1,57 @@ +source /usr/local/bin/compliance_check/scripts/common.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/functions/helper_lib.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/1_host_configuration.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/2_docker_daemon_configuration.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/3_docker_daemon_configuration_files.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/4_container_images.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/5_container_runtime.sh + +check_1_2_2 +check_1_1_18 +check_1_1_5 +check_1_1_6 +check_1_1_7 +check_1_1_9 +check_1_1_10 +check_1_1_13 +check_1_1_14 + +check_2_5 +check_2_7 +check_2_14 + + +check_3_2 +check_3_3 +check_3_4 +check_3_5 +check_3_6 +check_3_7 +check_3_8 +check_3_9 +check_3_10 +check_3_11 +check_3_12 +check_3_13 +check_3_14 +check_3_15 +check_3_16 +check_3_17 +check_3_18 +check_3_19 +check_3_20 +check_3_21 +check_3_22 + +check_4_8 + + +#check_5_4 +#check_5_5 +#check_5_6 +#check_5_7 +#check_5_17 +#check_5_25 +#check_5_31 +#check_5_12 +#check_5_30 \ No newline at end of file diff --git a/scripts/nistkube.sh b/scripts/nistkube.sh new file mode 100644 index 0000000..6a41539 --- /dev/null +++ b/scripts/nistkube.sh @@ -0,0 +1,30 @@ +source /usr/local/bin/compliance_check/scripts/common.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/functions/helper_lib.sh +source /usr/local/bin/compliance_check/scripts/kube-bench/helper1_6_0.sh +if [ -z "${NODE_TYPE}" ] +then + NODE_TYPE="master" +fi +if [ -z "$CIS_VERSION" ] +then + CIS_VERSION="1.6.0" +fi +source "/usr/local/bin/compliance_check/scripts/kube-bench/${CIS_VERSION}/${NODE_TYPE}.sh" + +if [[ $NODE_TYPE == "master" ]] +then + df_k8_1_1_1 + df_k8_1_1_2 + df_k8_1_1_3 +else + df_k8_4_1_1 + df_k8_4_1_2 + df_k8_4_1_3 + df_k8_4_1_4 + df_k8_4_1_5 + df_k8_4_1_6 + df_k8_4_1_7 + df_k8_4_1_8 + df_k8_4_1_9 + df_k8_4_1_10 +fi diff --git a/scripts/pci.sh b/scripts/pci.sh new file mode 100644 index 0000000..3c92b51 --- /dev/null +++ b/scripts/pci.sh @@ -0,0 +1,55 @@ +source /usr/local/bin/compliance_check/scripts/common.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/functions/helper_lib.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/1_host_configuration.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/2_docker_daemon_configuration.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/3_docker_daemon_configuration_files.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/4_container_images.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/tests/5_container_runtime.sh + +check_1_2_2 +check_1_1_18 +check_1_1_5 +check_1_1_6 +check_1_1_7 +check_1_1_9 +check_1_1_10 +check_1_1_13 +check_1_1_14 + +check_2_5 +check_2_7 +check_2_14 + + +check_3_2 +check_3_3 +check_3_4 +check_3_5 +check_3_6 +check_3_7 +check_3_8 +check_3_9 +check_3_10 +check_3_11 +check_3_12 +check_3_13 +check_3_14 +check_3_15 +check_3_16 +check_3_17 +check_3_18 +check_3_19 +check_3_20 +check_3_21 +check_3_22 + + +#check_5_4 +#check_5_5 +#check_5_6 +#check_5_7 +#check_5_17 +#check_5_25 +#check_5_31 +#check_5_12 +#check_5_30 \ No newline at end of file diff --git a/scripts/pcikube.sh b/scripts/pcikube.sh new file mode 100644 index 0000000..6a41539 --- /dev/null +++ b/scripts/pcikube.sh @@ -0,0 +1,30 @@ +source /usr/local/bin/compliance_check/scripts/common.sh +source /usr/local/bin/compliance_check/scripts/docker-bench-security/functions/helper_lib.sh +source /usr/local/bin/compliance_check/scripts/kube-bench/helper1_6_0.sh +if [ -z "${NODE_TYPE}" ] +then + NODE_TYPE="master" +fi +if [ -z "$CIS_VERSION" ] +then + CIS_VERSION="1.6.0" +fi +source "/usr/local/bin/compliance_check/scripts/kube-bench/${CIS_VERSION}/${NODE_TYPE}.sh" + +if [[ $NODE_TYPE == "master" ]] +then + df_k8_1_1_1 + df_k8_1_1_2 + df_k8_1_1_3 +else + df_k8_4_1_1 + df_k8_4_1_2 + df_k8_4_1_3 + df_k8_4_1_4 + df_k8_4_1_5 + df_k8_4_1_6 + df_k8_4_1_7 + df_k8_4_1_8 + df_k8_4_1_9 + df_k8_4_1_10 +fi diff --git a/share/clus_apis.go b/share/clus_apis.go new file mode 100644 index 0000000..c35c19a --- /dev/null +++ b/share/clus_apis.go @@ -0,0 +1,2567 @@ +package share + +import ( + "fmt" + admissionv1beta1 "k8s.io/api/admission/v1beta1" + "net" + "strconv" + "strings" + "time" +) + +const CLUSObjectStore string = "object/" +const CLUSLockStore string = "lock/" +const CLUSNetworkStore string = "network/" +const CLUSWorkloadProfileStore string = "profiles/" +const CLUSStateStore string = "state/" +const CLUSScanStore string = "scan/" +const CLUSBenchStore string = "bench/" +const CLUSRecalculateStore string = "recalculate/" //not to be watched by consul +const CLUSFqdnStore string = "fqdn/" //not to be watched by consul +const CLUSNodeStore string = "node/" + +// lock +const CLUSLockConfigKey string = CLUSLockStore + "all" +const CLUSLockUserKey string = CLUSLockStore + "user" +const CLUSLockPolicyKey string = CLUSLockStore + "policy" +const CLUSLockServerKey string = CLUSLockStore + "server" +const CLUSLockUpgradeKey string = CLUSLockStore + "upgrade" +const CLUSLockAdmCtrlKey string = CLUSLockStore + "adm_ctrl" +const CLUSLockFedKey string = CLUSLockStore + "federation" +const CLUSLockScannerKey string = CLUSLockStore + "scanner" +const CLUSLockCrdQueueKey string = CLUSLockStore + "crd_queue" +const CLUSLockCloudKey string = CLUSLockStore + "cloud" + +//const CLUSLockResponseRuleKey string = CLUSLockStore + "response_rule" + +// config +// TODO: Should we move config/ out of object/, currently handling object/ and config/ is +// synchronized in one watcher thread +// !!! NOTE: When adding new config items, update the import/export list as well !!! + +const ( + CFGEndpointSystem = "system" + CFGEndpointEULA = "eula_oss" + CFGEndpointScan = "scan" + CFGEndpointUser = "user" + CFGEndpointServer = "server" + CFGEndpointGroup = "group" + CFGEndpointPolicy = "policy" + CFGEndpointLicense = "license" + CFGEndpointResponseRule = "response_rule" + CFGEndpointProcessProfile = "process_profile" + CFGEndpointRegistry = "registry" + CFGEndpointDomain = "domain" + CFGEndpointFileMonitor = "file_monitor" + CFGEndpointFileAccessRule = "file_rule" + CFGEndpointAdmissionControl = "admission_control" + CFGEndpointCrd = "crd" + CFGEndpointFederation = "federation" + CFGEndpointDlpRule = "dlp_rule" + CFGEndpointDlpGroup = "dlp_group" + CFGEndpointWafRule = "waf_rule" + CFGEndpointWafGroup = "waf_group" + CFGEndpointScript = "script" + CFGEndpointCloud = "cloud" + CFGEndpointCompliance = "compliance" + CFGEndpointVulnerability = "vulnerability" + CFGEndpointUserRole = "user_role" + CFGEndpointPwdProfile = "pwd_profile" +) +const CLUSConfigStore string = CLUSObjectStore + "config/" +const CLUSConfigSystemKey string = CLUSConfigStore + CFGEndpointSystem +const CLUSConfigEULAKey string = CLUSConfigStore + CFGEndpointEULA +const CLUSConfigScanKey string = CLUSConfigStore + CFGEndpointScan +const CLUSConfigUserStore string = CLUSConfigStore + CFGEndpointUser + "/" +const CLUSConfigServerStore string = CLUSConfigStore + CFGEndpointServer + "/" +const CLUSConfigGroupStore string = CLUSConfigStore + CFGEndpointGroup + "/" +const CLUSConfigPolicyStore string = CLUSConfigStore + CFGEndpointPolicy + "/" +const CLUSConfigLicenseKey string = CLUSConfigStore + CFGEndpointLicense +const CLUSConfigResponseRuleStore string = CLUSConfigStore + CFGEndpointResponseRule + "/" +const CLUSConfigProcessProfileStore string = CLUSConfigStore + CFGEndpointProcessProfile + "/" +const CLUSConfigRegistryStore string = CLUSConfigStore + CFGEndpointRegistry + "/" +const CLUSConfigFileMonitorStore string = CLUSConfigStore + CFGEndpointFileMonitor + "/" +const CLUSConfigFileAccessRuleStore string = CLUSConfigStore + CFGEndpointFileAccessRule + "/" +const CLUSConfigAdmissionControlStore string = CLUSConfigStore + CFGEndpointAdmissionControl + "/" +const CLUSConfigCrdStore string = CLUSConfigStore + CFGEndpointCrd + "/" +const CLUSConfigFederationStore string = CLUSConfigStore + CFGEndpointFederation + "/" +const CLUSConfigDlpRuleStore string = CLUSConfigStore + CFGEndpointDlpRule + "/" +const CLUSConfigDlpGroupStore string = CLUSConfigStore + CFGEndpointDlpGroup + "/" +const CLUSConfigWafRuleStore string = CLUSConfigStore + CFGEndpointWafRule + "/" +const CLUSConfigWafGroupStore string = CLUSConfigStore + CFGEndpointWafGroup + "/" +const CLUSConfigScriptStore string = CLUSConfigStore + CFGEndpointScript + "/" +const CLUSConfigCloudStore string = CLUSConfigStore + CFGEndpointCloud + "/" +const CLUSConfigComplianceStore string = CLUSConfigStore + CFGEndpointCompliance + "/" +const CLUSConfigVulnerabilityStore string = CLUSConfigStore + CFGEndpointVulnerability + "/" +const CLUSConfigDomainStore string = CLUSConfigStore + CFGEndpointDomain + "/" +const CLUSConfigUserRoleStore string = CLUSConfigStore + CFGEndpointUserRole + "/" +const CLUSConfigPwdProfileStore string = CLUSConfigStore + CFGEndpointPwdProfile + "/" + +// !!! NOTE: When adding new config items, update the import/export list as well !!! + +const CLUSUniconfStore string = CLUSObjectStore + "uniconf/" // Target both controller and specific enforcer + +// object +const CLUSHostStore string = CLUSObjectStore + "host/" +const CLUSAgentStore string = CLUSObjectStore + "agent/" +const CLUSControllerStore string = CLUSObjectStore + "controller/" +const CLUSWorkloadStore string = CLUSObjectStore + "workload/" +const CLUSNetworkEPStore string = CLUSObjectStore + "networkep/" +const CLUSThreatLogStore string = CLUSObjectStore + "threatlog/" +const CLUSEventLogStore string = CLUSObjectStore + "eventlog/" +const CLUSIncidentLogStore string = CLUSObjectStore + "incidentlog/" +const CLUSAuditLogStore string = CLUSObjectStore + "auditlog/" +const CLUSCloudStore string = CLUSObjectStore + "cloud/" +const CLUSCrdProcStore string = "crdcontent/" +const CLUSCertStore string = CLUSObjectStore + "cert/" +const CLUSLicenseStore string = CLUSObjectStore + "license/" + +// network +const PolicyIPRulesDefaultName string = "GroupIPRules" +const PolicyIPRulesVersionID string = "NeuVectorPolicyVersion" // used for indicate policy version changed +const DlpRulesDefaultName string = "DlpWorkloadRules" +const DlpRuleName string = "dlprule" +const DlpRuleStore string = CLUSNetworkStore + DlpRuleName + "/" +const WafRuleName string = "wafrule" +const WafRuleStore string = CLUSNetworkStore + WafRuleName + "/" +const NetworkSystemKey string = CLUSNetworkStore + CFGEndpointSystem + +// profiles +const ProfileCommonGroup string = "common" // nodes +const ProfileGroup string = "group" +const ProfileProcess string = "process" +const ProfileFileMonitor string = "file" +const ProfileFileAccess string = "fileAccess" +const ProfileScript string = "script" +const ProfileGroupStore string = CLUSWorkloadProfileStore + ProfileGroup + "/" +const ProfileProcessStore string = CLUSWorkloadProfileStore + ProfileProcess + "/" +const ProfileFileMonitorStore string = CLUSWorkloadProfileStore + ProfileFileMonitor + "/" +const ProfileFileAccessStore string = CLUSWorkloadProfileStore + ProfileFileAccess + "/" +const ProfileFileScriptStore string = CLUSWorkloadProfileStore + ProfileScript + "/" +const CLUSNodeCommonStoreKey string = CLUSNodeStore + ProfileCommonGroup + "/" +const CLUSNodeCommonProfileStore string = CLUSNodeCommonStoreKey + CLUSWorkloadProfileStore + +// state +const CLUSCtrlEnabledValue string = "ok" + +// cluster key represent one installation, which will remain unchanged when controllers +// come and go, and rolling upgrade. It is not part of system configuration. +const CLUSCtrlInstallationKey string = CLUSStateStore + "installation" +const CLUSCtrlNodeAdmissionKey string = CLUSStateStore + "ctrl_ready" // node admission +const CLUSCtrlConfigLoadedKey string = CLUSStateStore + "ctrl_cfg_load" +const CLUSCtrlDistLockStore string = CLUSStateStore + "dist_lock/" +const CLUSCtrlUsageReportStore string = CLUSStateStore + "usage_report/" +const CLUSCtrlVerKey string = CLUSStateStore + "ctrl_ver" +const CLUSExpiredTokenStore string = CLUSStateStore + "expired_token/" +const CLUSImportStore string = CLUSStateStore + "import/" + +func CLUSExpiredTokenKey(token string) string { + return fmt.Sprintf("%s%s", CLUSExpiredTokenStore, token) +} + +func CLUSCtrlDistLockKey(lock string) string { + return strings.Replace(lock, CLUSLockStore, CLUSCtrlDistLockStore, 1) +} + +func CLUSCtrlUsageReportKey(ts int64) string { + return fmt.Sprintf("%s%d", CLUSCtrlUsageReportStore, ts) +} + +func CLUSCtrlUsageReportKey2TS(key string) int64 { + v := keyLastToken(key) + if s, err := strconv.ParseInt(v, 10, 64); err == nil { + return s + } + return 0 +} + +// multi-clusters +const CLUSConfigFedResponseRuleKey string = CLUSConfigResponseRuleStore + "fed/" +const CLUSConfigFedAdmCtrlKey string = CLUSConfigAdmissionControlStore + "fed/" + +const ( + GroupKindContainer string = "container" + GroupKindAddress string = "address" + GroupKindIPService string = "ip_service" + GroupKindExternal string = "external" + GroupKindNode string = "node" +) + +// scan +const CLUSScanStateStore string = CLUSScanStore + "state/" +const CLUSScanDataStore string = CLUSScanStore + "data/" +const CLUSScannerStore string = CLUSScanStore + "scanner/" +const CLUSScannerStatsStore string = CLUSScanStore + "scanner_stats/" +const CLUSScannerDBVersionID string = "NeuVectorCVEDBVersion" // used for indicate db version changed +const CLUSScannerDBStore string = CLUSScanStore + "database/" + +//recalculate +const CLUSRecalPolicyStore string = CLUSRecalculateStore + "policy/" //not to be watched by consul + +func CLUSPolicyIPRulesKey(name string) string { + return fmt.Sprintf("%s%s", CLUSNetworkStore, name) +} + +func CLUSRecalPolicyIPRulesKey(name string) string { + return fmt.Sprintf("%s%s", CLUSRecalPolicyStore, name) +} + +//fqdn +const CLUSFqdnIpStore string = CLUSFqdnStore + "ip/" //not to be watched by consul + +func CLUSFqdnIpKey(hostID string, fqdname string) string { + return fmt.Sprintf("%s%s/%s", CLUSFqdnIpStore, hostID, fqdname) +} + +const InternalIPNetDefaultName string = "InternalIPNet" +const SpecialIPNetDefaultName string = "SpecialIPNet" + +func CLUSInternalIPNetsKey(name string) string { + return fmt.Sprintf("%s%s", CLUSNetworkStore, name) +} + +// uniconf +func CLUSUniconfTargetStore(target string) string { + return fmt.Sprintf("%s%s", CLUSUniconfStore, target) +} + +func CLUSUniconfControllerKey(target, id string) string { + return fmt.Sprintf("%s/controller/%s", CLUSUniconfTargetStore(target), id) +} + +func CLUSUniconfAgentKey(target, id string) string { + return fmt.Sprintf("%s/agent/%s", CLUSUniconfTargetStore(target), id) +} + +func CLUSUniconfWorkloadKey(target, id string) string { + return fmt.Sprintf("%s/workload/%s", CLUSUniconfTargetStore(target), id) +} + +func CLUSUniconfKey2Subject(key string) string { + return CLUSKeyNthToken(key, 3) +} + +func CLUSUniconfKey2ID(key string) string { + return CLUSKeyNthToken(key, 4) +} + +func CLUSUserKey(username string) string { + return fmt.Sprintf("%s%s", CLUSConfigUserStore, username) +} + +func CLUSPwdProfileKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigPwdProfileStore, name) +} + +func CLUSDomainKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigDomainStore, name) +} + +func CLUSServerKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigServerStore, name) +} + +func CLUSHostKey(hostID string, by string) string { + return fmt.Sprintf("%s%s/%s", CLUSHostStore, by, hostID) +} + +func CLUSAgentKey(hostID string, devID string) string { + return fmt.Sprintf("%s%s/%s", CLUSAgentStore, hostID, devID) +} + +func CLUSControllerKey(hostID string, devID string) string { + return fmt.Sprintf("%s%s/%s", CLUSControllerStore, hostID, devID) +} + +func CLUSWorkloadKey(hostID string, wlID string) string { + return fmt.Sprintf("%s%s/%s", CLUSWorkloadStore, hostID, wlID) +} + +func CLUSNetworkEPKey(hostID string, epID string) string { + return fmt.Sprintf("%s%s/%s", CLUSNetworkEPStore, hostID, epID) +} + +func eventLogStore(hostID string, devID string) string { + return fmt.Sprintf("%s%s/%s", CLUSEventLogStore, hostID, devID) +} + +func CLUSThreatLogKey(hostID string, devID string) string { + return fmt.Sprintf("%s%s/%s", CLUSThreatLogStore, hostID, devID) +} + +func CLUSIncidentLogKey(hostID string, devID string) string { + return fmt.Sprintf("%s%s/%s", CLUSIncidentLogStore, hostID, devID) +} + +func CLUSAuditLogKey(hostID string, devID string) string { + return fmt.Sprintf("%s%s/%s", CLUSAuditLogStore, hostID, devID) +} + +func CLUSAgentEventLogKey(hostID string, devID string) string { + return fmt.Sprintf("%s/agent", eventLogStore(hostID, devID)) +} + +func CLUSControllerEventLogKey(hostID string, devID string) string { + return fmt.Sprintf("%s/controller", eventLogStore(hostID, devID)) +} + +func CLUSGroupKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigGroupStore, name) +} + +func CLUSGroupNetworkKey(name string) string { + return fmt.Sprintf("%s%s", ProfileGroupStore, name) +} + +func CLUSPolicyRuleKey(name string, id uint32) string { + return fmt.Sprintf("%s%s/rule/%v", CLUSConfigPolicyStore, name, id) +} + +func CLUSPolicyRuleListKey(name string) string { + return fmt.Sprintf("%s%s/rules", CLUSConfigPolicyStore, name) +} + +func CLUSPolicyZipRuleListKey(name string) string { + return fmt.Sprintf("%s%s/ziprules", CLUSConfigPolicyStore, name) +} + +func CLUSScanDataHostKey(id string) string { + return fmt.Sprintf("%sreport/host/%s", CLUSScanDataStore, id) +} + +func CLUSScanDataWorkloadKey(id string) string { + return fmt.Sprintf("%sreport/workload/%s", CLUSScanDataStore, id) +} + +func CLUSScanDataPlatformKey(id string) string { + return fmt.Sprintf("%sreport/platform/%s", CLUSScanDataStore, id) +} + +func CLUSScanStateHostKey(id string) string { + return fmt.Sprintf("%sreport/host/%s", CLUSScanStateStore, id) +} + +func CLUSScanStateWorkloadKey(id string) string { + return fmt.Sprintf("%sreport/workload/%s", CLUSScanStateStore, id) +} + +func CLUSScanStatePlatformKey(id string) string { + return fmt.Sprintf("%sreport/platform/%s", CLUSScanStateStore, id) +} + +func CLUSBenchKey(hostID string) string { + return fmt.Sprintf("%s%s", CLUSBenchStore, hostID) +} + +func CLUSBenchReportKey(hostID string, bench BenchType) string { + return fmt.Sprintf("%s/report/%s", CLUSBenchKey(hostID), bench) +} + +func CLUSCustomCheckConfigKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigScriptStore, name) +} + +func CLUSCustomCheckNetworkKey(name string) string { + return fmt.Sprintf("%s%s", ProfileFileScriptStore, name) +} + +const CLUSConfigComplianceProfileStore string = CLUSConfigComplianceStore + "profile/" +const CLUSConfigVulnerabilityProfileStore string = CLUSConfigVulnerabilityStore + "profile/" + +func CLUSComplianceProfileKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigComplianceProfileStore, name) +} + +func CLUSVulnerabilityProfileKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigVulnerabilityProfileStore, name) +} + +func CLUSDomainConfigKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigDomainStore, name) +} + +func CLUSRegistryConfigKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigRegistryStore, name) +} + +func CLUSRegistryStateKey(name string) string { + return fmt.Sprintf("%sregistry/%s", CLUSScanStateStore, name) +} + +func CLUSRegistryImageStateKey(name, id string) string { + return fmt.Sprintf("%simage/%s/%s", CLUSScanStateStore, name, id) +} + +func CLUSRegistryImageDataKey(name, id string) string { + return fmt.Sprintf("%simage/%s/%s", CLUSScanDataStore, name, id) +} + +func CLUSRegistryImageStateStore(name string) string { + return fmt.Sprintf("%simage/%s", CLUSScanStateStore, name) +} + +func CLUSRegistryImageDataStore(name string) string { + return fmt.Sprintf("%simage/%s", CLUSScanDataStore, name) +} + +func CLUSScannerKey(id string) string { + return fmt.Sprintf("%s%s", CLUSScannerStore, id) +} + +func CLUSScannerStatsKey(id string) string { + return fmt.Sprintf("%s%s", CLUSScannerStatsStore, id) +} + +func CLUSFileMonitorKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigFileMonitorStore, name) +} + +func CLUSFileMonitorNetworkKey(name string) string { + return fmt.Sprintf("%s%s", ProfileFileMonitorStore, name) +} + +func CLUSFileAccessRuleKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigFileAccessRuleStore, name) +} + +func CLUSFileAccessRuleNetworkKey(name string) string { + return fmt.Sprintf("%s%s", ProfileFileAccessStore, name) +} + +// Host ID is included in the workload key to helps us retrieve all workloads on a host +// quickly. Without it, we have to loop through all workload keys; using agent ID is +// also problematic, as a new agent has no idea of the agent ID when the workload +// was created. +func CLUSWorkloadHostStore(hostID string) string { + return fmt.Sprintf("%sworkload/%s/", CLUSObjectStore, hostID) +} + +func CLUSNetworkEPHostStore(hostID string) string { + return fmt.Sprintf("%snetworkep/%s/", CLUSObjectStore, hostID) +} + +func CLUSKeyLength(key string) int { + tokens := strings.Split(key, "/") + return len(tokens) +} + +func CLUSKeyNthToken(key string, nth int) string { + tokens := strings.Split(key, "/") + if len(tokens) > nth { + return tokens[nth] + } + return "" +} + +func keyLastToken(key string) string { + if n := strings.LastIndexByte(key, '/'); n != -1 { + return key[n+1:] + } + return key +} + +func CLUSKey2Target(key string) string { + return CLUSKeyNthToken(key, 0) +} + +func CLUSObjectKey2Object(key string) string { + return CLUSKeyNthToken(key, 1) +} + +func CLUSConfigKey2Config(key string) string { + return CLUSKeyNthToken(key, 2) +} + +func CLUSCloudKey2Type(key string) string { + return CLUSKeyNthToken(key, 2) +} + +func CLUSHostKey2ID(key string) string { + return keyLastToken(key) +} + +func CLUSDeviceKey2ID(key string) string { + return keyLastToken(key) +} + +func CLUSWorkloadKey2ID(key string) string { + return keyLastToken(key) +} + +func CLUSNetworkEPKey2ID(key string) string { + return keyLastToken(key) +} + +func CLUSGroupKey2Name(key string) string { + return keyLastToken(key) +} + +func CLUSProfileKey2Name(key string) string { + return keyLastToken(key) +} + +func CLUSDlpRuleKey2Name(key string) string { + return keyLastToken(key) +} + +func CLUSDlpGroupKey2Name(key string) string { + return keyLastToken(key) +} + +func CLUSWafRuleKey2Name(key string) string { + return keyLastToken(key) +} + +func CLUSWafGroupKey2Name(key string) string { + return keyLastToken(key) +} + +func CLUSPolicyRuleKey2ID(key string) uint32 { + s := keyLastToken(key) + id, _ := strconv.Atoi(s) + return uint32(id) +} + +func CLUSKeyLastToken(key string) string { + return keyLastToken(key) +} + +const ( + CLUSResCfgRule = "rule" + CLUSResCfgRuleList = "rules" +) + +func CLUSPolicyKey2ResPolicySubkey(key string) (string, string) { // returns policy name(like "default"/"fed") & "rule"/"rules" + return CLUSKeyNthToken(key, 3), CLUSKeyNthToken(key, 4) +} + +func CLUSIsPolicyRuleKey(key string) bool { + return CLUSKeyNthToken(key, 4) == "rule" +} + +func CLUSIsPolicyRuleListKey(key string) bool { + return CLUSKeyNthToken(key, 4) == "rules" +} + +func CLUSIsPolicyZipRuleListKey(key string) bool { + return CLUSKeyNthToken(key, 4) == "ziprules" +} + +func CLUSNetworkKey2Subject(key string) string { + return CLUSKeyNthToken(key, 1) +} + +func CLUSScannerKey2ID(key string) string { + return CLUSKeyNthToken(key, 2) +} + +func CLUSScanKey2Subject(key string) string { + return CLUSKeyNthToken(key, 2) +} + +func CLUSScanStateKey2Type(key string) string { + return CLUSKeyNthToken(key, 3) +} + +func CLUSScanStateKey2ID(key string) string { + return CLUSKeyNthToken(key, 4) +} + +func CLUSComplianceKey2Type(key string) string { + return CLUSKeyNthToken(key, 3) +} + +func CLUSComplianceProfileKey2Name(key string) string { + return keyLastToken(key) +} + +func CLUSVulnerabilityKey2Type(key string) string { + return CLUSKeyNthToken(key, 3) +} + +func CLUSVulnerabilityProfileKey2Name(key string) string { + return keyLastToken(key) +} + +func CLUSDomainKey2Name(key string) string { + return keyLastToken(key) +} + +func CLUSFileMonitorKey2Group(key string) string { + return CLUSKeyNthToken(key, 3) +} + +func CLUSGroupKey2GroupName(key string) string { + return CLUSKeyNthToken(key, 3) +} + +type CLUSDistLocker struct { + LockedBy string `json:"locked_by"` + LockedAt time.Time `json:"locked_at"` + Caller string `json:"caller"` +} + +// ScanResult is used for local RPC so the structure can be stored in the cluster +type CLUSScanReport struct { + ScannedAt time.Time `json:"scanned_at"` + ScanResult +} + +type CLUSScanState struct { + ScannedAt time.Time `json:"scanned_at"` + Status string `json:"status"` +} + +type CLUSScanConfig struct { + AutoScan bool `json:"auto_scan"` +} + +type CLUSCtrlVersion struct { + CtrlVersion string `json:"version"` + KVVersion string `json:"kv_version"` +} + +type CLUSSyslogConfig struct { + SyslogIP net.IP `json:"syslog_ip"` + SyslogServer string `json:"syslog_server"` + SyslogIPProto uint8 `json:"syslog_ip_proto"` + SyslogPort uint16 `json:"syslog_port"` + SyslogLevel string `json:"syslog_level"` + SyslogEnable bool `json:"syslog_enable"` + SyslogCategories []string `json:"syslog_categories"` + SyslogInJSON bool `json:"syslog_in_json"` +} + +type CLUSSystemUsageReport struct { + Signature string `json:"signature"` + ReportedAt time.Time `json:"reported"` + Platform string `json:"platform"` + Hosts int `json:"hosts"` + CPUCores int `json:"cores"` + Controllers int `json:"controllers"` + Agents int `json:"enforcers"` + Scanners int `json:"scanners"` + CVEDBVersion string `json:"cvedb_version"` + Registries int `json:"registries"` + Domains int `json:"domains"` + RunningPods int `json:"running_pods"` + Groups int `json:"groups"` + MonitorGroups int `json:"moinitor_groups"` + ProtectGroups int `json:"protect_groups"` + PolicyRules int `json:"policy_rules"` + AdmCtrlRules int `json:"adm_ctrl_rules"` + RespRules int `json:"response_rules"` + CRDRules int `json:"crd_rules"` + Clusters int `json:"clusters"` + SLessProjs int `json:"sl_projs"` + InstallationID string `json:"installation_id"` +} + +type CLUSProxy struct { + Enable bool `json:"enable"` + URL string `json:"url"` + Username string `json:"username"` + Password string `json:"password,cloak"` +} + +type CLUSIBMSAConfigNV struct { + EpEnabled bool `json:"ep_enabled"` + EpStart uint32 `json:"ep_start"` // set to 1 after /v1/partner/ibm_sa/setup/test return 200 + EpDashboardURL string `json:"ep_dashboard_url"` + EpConnectedAt time.Time `json:"ep_connected_at"` +} + +type CLUSIBMSAConfig struct { + AccountID string `json:"accountID,cloak"` + APIKey string `json:"apikey,cloak"` + ProviderID string `json:"providerId,cloak"` // service-id + FindingsURL string `json:"findingsURL"` + TokenURL string `json:"tokenURL"` +} + +type CLUSIBMSAOnboardData struct { + NoteName string `json:"note_name"` + ID string `json:"id,cloak"` // service-id ? + ProviderID string `json:"provider_id"` +} + +type CLUSWebhook struct { + Name string `json:"name"` + Url string `json:"url"` + Enable bool `json:"enable"` + Type string `json:"type"` + CfgType TCfgType `json:"cfg_type"` +} + +type CLUSSystemConfig struct { + NewServicePolicyMode string `json:"new_service_policy_mode"` + NewServiceProfileBaseline string `json:"new_service_profile_baseline"` + UnusedGroupAging uint8 `json:"unused_group_aging"` + CLUSSyslogConfig + SingleCVEPerSyslog bool `json:"single_cve_per_syslog"` + AuthOrder []string `json:"auth_order"` + AuthByPlatform bool `json:"auth_by_platform"` + RancherEP string `json:"rancher_ep"` + InternalSubnets []string `json:"configured_internal_subnets,omitempty"` + WebhookEnable_UNUSED bool `json:"webhook_enable"` + WebhookUrl_UNUSED string `json:"webhook_url"` + Webhooks []CLUSWebhook `json:"webhooks"` + ClusterName string `json:"cluster_name"` + ControllerDebug []string `json:"controller_debug"` + TapProxymesh bool `json:"tap_proxymesh"` + RegistryHttpProxy CLUSProxy `json:"registry_http_proxy"` + RegistryHttpsProxy CLUSProxy `json:"registry_https_proxy"` + IBMSAConfigNV CLUSIBMSAConfigNV `json:"ibmsa_config_nv"` + IBMSAConfig CLUSIBMSAConfig `json:"ibmsa_config"` + IBMSAOnboardData CLUSIBMSAOnboardData `json:"ibmsa_onboard_data"` + XffEnabled bool `json:"xff_enabled"` + CfgType TCfgType `json:"cfg_type"` + NetServiceStatus bool `json:"net_service_status"` + NetServicePolicyMode string `json:"net_service_policy_mode"` + ModeAutoD2M bool `json:"mode_auto_d2m"` + ModeAutoD2MDuration int64 `json:"mode_auto_d2m_duration"` + ModeAutoM2P bool `json:"mode_auto_m2p"` + ModeAutoM2PDuration int64 `json:"mode_auto_m2p_duration"` +} + +type CLUSEULA struct { + Accepted bool `json:"accepted"` +} + +type CLUSUser struct { + Fullname string `json:"fullname"` + Username string `json:"username"` + PasswordHash string `json:"password_hash"` + PwdResetTime time.Time `json:"pwd_reset_time"` + PwdHashHistory []string `json:"pwd_hash_history"` // not including the current password's hash + Domain string `json:"domain"` // This is not used. Other 'domain' maps to namespace, this is not. + Server string `json:"server"` + EMail string `json:"email"` + Role string `json:"role"` + RoleOverride bool `json:"role_oride"` // Used for shadow user + Timeout uint32 `json:"timeout"` + Locale string `json:"locale"` + RoleDomains map[string][]string `json:"role_domains"` + LastLoginAt time.Time `json:"last_login_at"` + LoginCount uint32 `json:"login_count"` + FailedLoginCount uint32 `json:"failed_login_count"` // failed consecutive login failure. reset to 0 after a successful login + BlockLoginSince time.Time `json:"block_login_since"` // reset to 0 after a successful login +} + +type GroupRoleMapping struct { + Group string `json:"group"` // mapped group + GlobalRole string `json:"global_role"` // group's mapped role on global domain + RoleDomains map[string][]string `json:"role_domains,omitempty"` // group's mapped role -> domains +} + +type CLUSServerAuth struct { + DefaultRole string `json:"default_role"` + RoleGroups map[string][]string `json:"groups"` // role -> groups. obsolete since 4.2 + GroupMappedRoles []*GroupRoleMapping `json:"group_mapped_roles"` // group -> (role -> domains). supported since 4.2 +} + +type CLUSServerLDAP struct { + CLUSServerAuth + Type string `json:"type"` + Hostname string `json:"hostname"` + Port uint16 `json:"port"` + SSL bool `json:"ssl"` + BaseDN string `json:"base_dn"` + BindDN string `json:"bind_dn"` // Must handle upgrade if it is cloaked + BindPasswd string `json:"bind_password,cloak"` + GroupMemberAttr string `json:"group_member_attr"` + UserNameAttr string `json:"username_attr"` +} + +type CLUSServerSAML struct { + CLUSServerAuth + SSOURL string `json:"sso_url"` + Issuer string `json:"issuer"` + X509Cert string `json:"x509_cert,cloak"` + GroupClaim string `json:"group_claim"` +} + +type CLUSServerOIDC struct { + CLUSServerAuth + Issuer string `json:"issuer"` + AuthURL string `json:"authorization_endpoint"` + TokenURL string `json:"token_endpoint"` + UserInfoURL string `json:"user_info_endpoint"` + JWKSURL string `json:"jwks_endpoint"` + ClientID string `json:"client_id"` // Must handle upgrade if it is cloaked + ClientSecret string `json:"client_secret,cloak"` + Scopes []string `json:"scopes"` + GroupClaim string `json:"group_claim"` +} + +type CLUSServer struct { + Name string `json:"name"` + Enable bool `json:"enable"` + LDAP *CLUSServerLDAP `json:"ldap,omitempty"` + SAML *CLUSServerSAML `json:"saml,omitempty"` + OIDC *CLUSServerOIDC `json:"oidc,omitempty"` +} + +const ( + // host: address is meaningful only on local host. Native container IP has this scope. + CLUSIPAddrScopeLocalhost = "host" + // global: address is global + CLUSIPAddrScopeGlobal = "global" + // nat: address for NAT access. Typically, this the address of the host. + CLUSIPAddrScopeNAT = "nat" +) + +type CLUSIPAddr struct { + IPNet net.IPNet `json:"ipnet"` + Gateway string `json:"gateway"` + Scope string `json:"scope"` + NetworkID string `json:"net_id"` + NetworkName string `json:"net_name"` +} + +type CLUSHost struct { + ID string `json:"id"` + Name string `json:"name"` + Runtime string `json:"runtime"` + Platform string `json:"platform"` + Flavor string `json:"flavor"` // platform flavor + Network string `json:"network"` + RuntimeVer string `json:"runtime_version"` + RuntimeAPIVer string `json:"runtime_api_version"` + OS string `json:"os"` + Kernel string `json:"kernel"` + CPUs int64 `json:"cpus"` + Memory int64 `json:"memory"` + Ifaces map[string][]CLUSIPAddr `json:"interfaces"` + TunnelIP []net.IPNet `json:"tunnel_ips"` + CapDockerBench bool `json:"cap_docker_bench"` + CapKubeBench bool `json:"cap_kube_bench"` + StorageDriver string `json:"storage_driver"` + CgroupVersion int `json:"cgroup_version"` +} + +type CLUSDevice struct { + ID string `json:"id"` + Name string `json:"name"` + SelfHostname string `json:"self_hostname"` + HostName string `json:"host_name"` + HostID string `json:"host_id"` + Domain string `json:"domain"` + NetworkMode string `json:"network_mode"` + PidMode string `json:"pid_mode"` + Ver string `json:"version"` + Labels map[string]string `json:"labels"` + CreatedAt time.Time `json:"created_at"` + StartedAt time.Time `json:"started_at"` + JoinedAt time.Time `json:"joined_at"` + MemoryLimit int64 `json:"memory_limit"` + CPUs string `json:"cpus"` + ClusterIP string `json:"cluster_ip"` + RPCServerPort uint16 `json:"rpc_server_port"` + Pid int `json:"pid"` + Ifaces map[string][]CLUSIPAddr `json:"interfaces"` +} + +type CLUSAgent struct { + CLUSDevice +} + +type CLUSController struct { + CLUSDevice + Leader bool `json:"leader"` + OrchConnStatus string `json:"orch_conn_status"` + OrchConnLastError string `json:"orch_conn_last_error"` +} + +type CLUSProtoPort struct { + IPProto uint8 `json:"ip_proto"` + Port uint16 `json:"port"` +} + +type CLUSIPPort struct { + IPNet net.IPNet `json:"ipnet"` + Port uint16 `json:"port"` +} + +type CLUSMappedPort struct { + CLUSProtoPort + HostIP net.IP `json:"host_ip"` + HostPort uint16 `json:"host_port"` +} + +type CLUSApp struct { + CLUSProtoPort + Proto uint32 `json:"protocol"` + Server uint32 `json:"server"` + Application uint32 `json:"application"` +} + +const ( + NEPTypeLB = "netlb" +) + +type CLUSNetworkEP struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + NetworkID string `json:"net_id"` + IP []net.IP `json:"ip"` +} + +type CLUSWorkload struct { + ID string `json:"id"` + Name string `json:"name"` + AgentID string `json:"agent_id"` + SelfHostname string `json:"self_hostname"` + HostName string `json:"host_name"` + HostID string `json:"host_id"` + Image string `json:"image"` + ImageID string `json:"image_id"` + Privileged bool `json:"privileged"` + RunAsRoot bool `json:"run_as_root"` + NetworkMode string `json:"network_mode"` + ShareNetNS string `json:"share_netns"` + Service string `json:"service"` + Domain string `json:"domain"` + Author string `json:"author"` + PlatformRole string `json:"platform_role"` + CreatedAt time.Time `json:"created_at"` + StartedAt time.Time `json:"started_at"` + FinishedAt time.Time `json:"finished_at"` + Running bool `json:"running"` + CapIntcp bool `json:"cap_intcp"` + CapSniff bool `json:"cap_sniff"` + Inline bool `json:"inline"` + Quarantine bool `json:"quarantine"` + SecuredAt time.Time `json:"secured_at"` + ExitCode int `json:"exit_code"` + Pid int `json:"pid"` + Ifaces map[string][]CLUSIPAddr `json:"interfaces"` + Ports map[string]CLUSMappedPort `json:"ports"` + Labels map[string]string `json:"labels"` + Apps map[string]CLUSApp `json:"apps"` + MemoryLimit int64 `json:"memory_limit"` + CPUs string `json:"cpus"` + ProxyMesh bool `json:"proxymesh"` + Sidecar bool `json:"sidecar"` +} + +type CLUSDomain struct { + Name string `json:"name"` + Dummy bool `json:"dummy"` + Disable bool `json:"disable"` + Tags []string `json:"tags"` +} + +type CLUSCriteriaEntry struct { + Key string `json:"key"` + Value string `json:"value"` + Op string `json:"op"` +} + +type CLUSFqdnIp struct { + FqdnName string `json:"fqdn_name"` + FqdnIP []net.IP `json:"fqdn_ip"` +} + +type TCfgType int + +const ( + Learned = iota + 1 + UserCreated + GroundCfg + FederalCfg + SystemDefined +) + +type CLUSGroup struct { + Name string `json:"name"` + Comment string `json:"comment"` + Learned_UNUSED bool `json:"learned"` + Reserved bool `json:"reserved"` + Criteria []CLUSCriteriaEntry `json:"criteria"` + Domain string `json:"domain"` + CreaterDomains []string `json:"creater_domains"` + PolicyMode string `json:"policy_mode,omitempty"` + ProfileMode string `json:"profile_mode,omitempty"` + NotScored bool `json:"not_scored,omitempty"` + Kind string `json:"kind,omitempty"` + PlatformRole string `json:"platform_role"` + CapIntcp bool `json:"cap_intcp"` + CfgType TCfgType `json:"cfg_type"` + BaselineProfile string `json:"baseline_profile"` +} + +type CLUSPolicyRule struct { + ID uint32 `json:"id"` + Comment string `json:"comment"` + From string `json:"from"` // group name + To string `json:"to"` // group name + FromHost string `json:"from_host"` + ToHost string `json:"to_host"` + Ports string `json:"ports"` // free-style port list + Applications []uint32 `json:"applications"` + Action string `json:"action"` + Learned_UNUSED bool `json:"learned"` + Disable bool `json:"Disable"` + CreatedAt time.Time `json:"created_at"` + LastModAt time.Time `json:"last_modified_at"` + CfgType TCfgType `json:"cfg_type"` + Priority uint32 `json:"priority"` +} + +type CLUSRuleHead struct { + ID uint32 `json:"id"` + Priority uint32 `json:"priority"` + Learned_UNUSED bool `json:"learned"` + CfgType TCfgType `json:"cfg_type"` +} + +const ( + WireInline string = "inline" + WireDefault string = "default" +) + +// QuarantineReason: +const QuarantineReasonUser string = "user-configured" + +func QuarantineReasonEvent(event string, id uint32) string { + return fmt.Sprintf("%s (rule %d)", event, id) +} + +type CLUSWorkloadConfig struct { + Wire string `json:"wire,omitempty"` + Quarantine bool `json:"quarantine,omitempty"` + QuarReason string `json:"quarantine_reason,omitempty"` +} + +type CLUSAgentConfig struct { + Debug []string `json:"debug,omitempty"` + DisableNvProtectMode bool `json:"disable_nvprotect"` + DisableKvCongestCtl bool `json:"disable_kvcctl"` +} + +type CLUSControllerConfig struct { + Debug []string `json:"debug,omitempty"` +} + +type CLUSVolume struct { + Bytes uint64 `json:"bytes"` + Sessions uint32 `json:"sessions"` +} + +var CLUSIPExternal net.IP = net.IPv4zero +var CLUSWLExternal string = "nv.external" +var CLUSWLAddress string = "nv.address" +var CLUSWLService string = "nv.service" +var CLUSWLModeGroup string = "nv.mode_group" +var CLUSWLAddressGroup string = "nv.address_group" +var CLUSHostAddrGroup string = "nv.hostaddr_group" //used as wlid for "nodes" in policy calculation +var CLUSWLFqdnPrefix string = "fqdn:" +var CLUSLearnedHostPrefix string = "Host:" +var CLUSLearnedWorkloadPrefix string = "Workload:" +var CLUSEndpointIngress string = "ingress" + +const DefaultGroupRuleID uint32 = 0 +const PolicyLearnedIDBase = 10000 +const PolicyFedRuleIDBase = 100000 +const PolicyFedRuleIDMax = 110000 // exclusive +const PolicyGroundRuleIDBase = 110000 +const PolicyGroundRuleIDMax = 120000 + +// Special internal subnet IP +const ( + SpecInternalTunnelIP = "tunnelip" + SpecInternalSvcIP = "svcip" + SpecInternalHostIP = "hostip" + SpecInternalDevIP = "devip" + SpecInternalUwlIP = "uwlip" + SpecInternalExtIP = "extip" +) + +type CLUSPortApp struct { + Ports string `json:"port"` + Application uint32 `json:"application"` + CheckApp bool `json:"check_app"` +} + +type CLUSWorkloadAddr struct { + WlID string `json:"workload_id"` + PolicyMode string `json:"mode,omitempty"` + LocalIP []net.IP `json:"local_ip,omitempty"` + GlobalIP []net.IP `json:"global_ip,omitempty"` + NatIP []net.IP `json:"nat_ip,omitempty"` + LocalPortApp []CLUSPortApp `json:"local_port_app,omitempty"` + NatPortApp []CLUSPortApp `json:"nat_port_app,omitempty"` +} + +type CLUSGroupIPPolicy struct { + ID uint32 `json:"policy_id"` + From []*CLUSWorkloadAddr `json:"from_addr"` + To []*CLUSWorkloadAddr `json:"to_addr,omitempty"` + Action uint8 `json:"action"` +} + +type CLUSGroupIPPolicyVer struct { + Key string `json:"key"` + PolicyIPRulesVersion string `json:"pol_version"` + SlotNo int `json:"slot_no"` + RulesLen int `json:"rules_len"` + WorkloadSlot int `json:"workload_slot,omitempty"` + WorkloadLen int `json:"workload_len,omitempty"` +} + +type CLUSSubnet struct { + Subnet net.IPNet `json:"subnet"` + Scope string `json:"scope"` +} + +type CLUSSpecSubnet struct { + Subnet net.IPNet `json:"subnet"` + Scope string `json:"scope"` + IpType string `json:"iptype"` +} + +type CLUSLogFilter struct { + Tail int `json:"tail"` +} + +// This value is stored in the cluster, so should not change the order +type TLogEvent uint +type TLogIncident uint +type TLogAudit uint + +const ( + CLUSEvWorkloadStart TLogEvent = iota + CLUSEvWorkloadStop + CLUSEvWorkloadRemove + CLUSEvWorkloadSecured + CLUSEvWorkloadUnsecured_UNUSED + CLUSEvAgentStart + CLUSEvAgentStop + CLUSEvAgentJoin + CLUSEvAgentDisconnect + CLUSEvAgentConnect + CLUSEvAgentKicked + CLUSEvControllerStart + CLUSEvControllerStop + CLUSEvControllerJoin + CLUSEvControllerDisconnect + CLUSEvControllerConnect + CLUSEvAuthLogin + CLUSEvAuthLogout + CLUSEvAuthTimeout + CLUSEvAuthLoginFailed + CLUSEvRESTWrite + CLUSEvRESTRead + CLUSEvScannerJoin + CLUSEvScannerUpdate + CLUSEvScannerLeave + CLUSEvScanFail + CLUSEvScanSucceed + CLUSEvBenchDockerFail + CLUSEvBenchKubeFail + CLUSEvLicenseUpdate + CLUSEvLicenseExpire + CLUSEvLicenseRemove + CLUSEvLicenseEnforcerLimitReached + CLUSEvHostPrivilEscalate_UNUSED + CLUSEvHostSuspiciousProcess_UNUSED + CLUSEvContainerPrivilEscalate_UNUSED + CLUSEvContainerSuspiciousProcess_UNUSED + CLUSEvWorkloadQuarantined + CLUSEvWorkloadUnquarantined + CLUSEvAuthAccessDenied + CLUSEvAdmCtrlK8sConfigured // for admission control + CLUSEvAdmCtrlK8sConfigFailed // for admission control + CLUSEvInitCfgMapDone // for initial Config + CLUSEvInitCfgMapError // for initial Config + CLUSEvCrdImported // for crd Config import + CLUSEvCrdRemoved // for crd Config remove due to k8s miss + CLUSEvCrdErrDetected // for remove error crd + CLUSEvFedPromote // for multi-clusters + CLUSEvFedDemote // for multi-clusters + CLUSEvFedJoin // for multi-clusters + CLUSEvFedLeave // for multi-clusters + CLUSEvFedKick // for multi-clusters + CLUSEvFedPolicySync // for multi-clusters + CLUSEvImport + CLUSEvImportFail + CLUSEvExport + CLUSEvExportFail + CLUSEvControllerLeadLost + CLUSEvControllerLeadElect + CLUSEvCloudScanRet + CLUSEvCloudScanAlert + CLUSEvCloudScanFail + CLUSEvGroupAutoRemove + CLUSEvLicenseStatusInvalid + CLUSEvLicenseStatusRevoked + CLUSEvLicenseValidationError + CLUSEvLicenseUsageReportError + CLUSEvLicenseUsageServerError + CLUSEvAuthLoginBlocked // temporarily block user login (too many consecutive login failures) + CLUSEvAuthLoginUnblocked // unblock user login + CLUSEvAuthUserPwdResetByAdmin // user password reset not by the owner user + CLUSEvMemoryPressureAgent + CLUSEvMemoryPressureController + CLUSEvK8sNvRBAC +) + +const ( + CLUSIncidHostPrivilEscalate TLogIncident = iota + CLUSIncidHostSuspiciousProcess + CLUSIncidContainerPrivilEscalate + CLUSIncidContainerSuspiciousProcess + CLUSIncidHostFileAccessViolation + CLUSIncidHostPackageUpdated + CLUSIncidContainerFileAccessViolation + CLUSIncidContainerPackageUpdated + CLUSIncidHostTunnel + CLUSIncidContainerTunnel + CLUSIncidHostProcessViolation + CLUSIncidContainerProcessViolation +) + +const ( + CLUSAuditComplianceContainerBenchViolation TLogAudit = iota + CLUSAuditComplianceHostBenchViolation + CLUSAuditAdmCtrlK8sReqAllowed // for admission control + CLUSAuditAdmCtrlK8sReqViolation // for admission control + CLUSAuditAdmCtrlK8sReqDenied // for admission control + CLUSAuditComplianceHostCustomCheckViolation + CLUSAuditComplianceContainerCustomCheckViolation + CLUSAuditAwsLambdaScanWarning + CLUSAuditAwsLambdaScanNormal + CLUSAuditComplianceImageBenchViolation + CLUSAuditComplianceContainerFileBenchViolation +) + +type CLUSEventLog struct { + Event TLogEvent `json:"event"` + HostID string `json:"host_id"` + HostName string `json:"host_name"` + ControllerID string `json:"controller_id"` + ControllerName string `json:"controller_name"` + AgentID string `json:"agent_id"` + AgentName string `json:"agent_name"` + WorkloadID string `json:"workload_id"` + WorkloadName string `json:"workload_name"` + ReportedAt time.Time `json:"reported_at"` + User string `json:"user"` + UserRoles map[string]string `json:"user_roles"` + UserAddr string `json:"user_addr"` + UserSession string `json:"user_session"` + RESTMethod string `json:"rest_method,omitempty"` + RESTRequest string `json:"rest_request,omitempty"` + RESTBody string `json:"rest_body,omitempty"` + EnforcerLimit int `json:"enforcer_limit,omitempty"` + LicenseExpire time.Time `json:"license_expire,omitempty"` + Msg string `json:"message"` +} + +type CLUSThreatLog struct { + ID string `json:"id"` + ThreatID uint32 `json:"threat_id"` + Severity uint8 `json:"severity"` + Action uint8 `json:"action"` + CapLen uint16 `json:"cap_len"` + Count uint32 `json:"count"` + HostID string `json:"host_id"` + HostName string `json:"host_name"` + AgentID string `json:"agent_id"` + AgentName string `json:"agent_name"` + WorkloadID string `json:"workload_id"` + WorkloadName string `json:"workload_name"` + ReportedAt time.Time `json:"reported_at"` + SrcIP net.IP `json:"src_ip"` + DstIP net.IP `json:"dst_ip"` + EtherType uint16 `json:"ether_type"` + SrcPort uint16 `json:"src_port"` + DstPort uint16 `json:"dst_port"` + IPProto uint8 `json:"ip_proto"` + ICMPCode uint8 `json:"icmp_code"` + ICMPType uint8 `json:"icmp_type"` + LocalPeer bool `json:"local_peer"` // Local host connection + PktIngress bool `json:"pkt_ingress"` + SessIngress bool `json:"sess_ingress"` + Tap bool `json:"tap"` + Application uint32 `json:"application"` + Msg string `json:"message"` + Packet string `json:"packet"` +} + +type CLUSIncidentLog struct { + LogUID string `json:"log_uid"` + ID TLogIncident `json:"id"` + HostID string `json:"host_id"` + HostName string `json:"host_name"` + AgentID string `json:"agent_id"` + AgentName string `json:"agent_name"` + WorkloadID string `json:"workload_id"` + WorkloadName string `json:"workload_name"` + ReportedAt time.Time `json:"reported_at"` + ProcName string `json:"process_name,omitempty"` + ProcPath string `json:"process_path,omitempty"` + ProcCmds []string `json:"process_cmd,omitempty"` + ProcRealUID int `json:"proc_real_uid,omitempty"` + ProcEffUID int `json:"proc_eff_uid,omitempty"` + ProcRealUser string `json:"proc_real_user,omitempty"` + ProcEffUser string `json:"proc_eff_user,omitempty"` + FilePath string `json:"file_path,omitempty"` + Files []string `json:"file_name,omitempty"` + LocalIP net.IP `json:"local_ip,omitempty"` + RemoteIP net.IP `json:"remote_ip,omitempty"` + EtherType uint16 `json:"ether_type"` + LocalPort uint16 `json:"local_port,omitempty"` + RemotePort uint16 `json:"remote_port,omitempty"` + IPProto uint8 `json:"ip_proto,omitempty"` + ConnIngress bool `json:"conn_ingress"` + LocalPeer bool `json:"local_peer"` + ProcPName string `json:"process_parent_name,omitempty"` + ProcPPath string `json:"process_parent_path,omitempty"` + Count int `json:"count,omitempty"` + StartAt time.Time `json:"start_at,omitempty"` + Action string `json:"action"` + RuleID string `json:"rule_id"` + Group string `json:"group"` + Msg string `json:"message"` +} + +type CLUSAuditBenchItem struct { + Level string `json:"level"` + TestNum string `json:"test_num"` + Msg string `json:"message"` + Group string `json:"group"` + Profile string `json:"profile"` + Scored bool `json:"scored"` + Automated bool `json:"automated"` +} + +type CLUSAuditLog struct { + ID TLogAudit `json:"id"` + HostID string `json:"host_id"` + HostName string `json:"host_name"` + AgentID string `json:"agent_id"` + AgentName string `json:"agent_name"` + WorkloadID string `json:"workload_id"` + WorkloadName string `json:"workload_name"` + Count uint32 `json:"count"` + ReportedAt time.Time `json:"reported_at"` + Items []CLUSAuditBenchItem `json:"items"` + Props map[string]string `json:"props"` + Region string `json:"region,omitempty"` + ProjectName string `json:"project_name,omitempty"` +} + +const SnifferIdAgentField = 8 + +type CLUSComplianceProfileEntry struct { + TestNum string `json:"test_num"` + Tags []string `json:"tags"` +} + +type CLUSComplianceProfile struct { + Name string `json:"name"` + DisableSystem bool `json:"disable_system"` + Entries map[string]CLUSComplianceProfileEntry `json:"entries"` +} + +type CLUSVulnerabilityProfileEntry struct { + ID uint32 `json:"id"` + Name string `json:"name"` + NameFilter string `json:"name_f"` + Comment string `json:"comment"` + Days uint `json:"days"` // Only used for 'recent' vuln entries + Domains []string `json:"domains"` + Images []string `json:"images"` +} + +type CLUSVulnerabilityProfile struct { + Name string `json:"name"` + Entries []*CLUSVulnerabilityProfileEntry `json:"entries"` +} + +type CLUSBenchItem struct { + Level string `json:"level"` + TestNum string `json:"test_number"` + Header string `json:"header"` + Message []string `json:"message"` + Remediation string `json:"remediation"` + Scored bool `json:"scored"` + Automated bool `json:"automated"` + Profile string `json:"profile"` + Group string `json:"group"` +} + +type CLUSBenchReport struct { + Status BenchStatus `json:"status"` + RunAt time.Time `json:"run_at"` + Version string `json:"version"` + Items []*CLUSBenchItem `json:"items"` +} + +type BenchType string +type BenchStatus int + +const ( + BenchDockerHost BenchType = "docker_host" + BenchDockerContainer BenchType = "docker_container" // all containers report + BenchKubeMaster BenchType = "kube_master" + BenchKubeWorker BenchType = "kube_worker" + BenchContainer BenchType = "container" // per-container report + BenchCustomHost BenchType = "custom_host" + BenchCustomContainer BenchType = "custom_container" + BenchContainerSecret BenchType = "container_secret" + BenchContainerSetID BenchType = "container_setid" +) + +const ( + BenchStatusIdle BenchStatus = iota + BenchStatusScheduled + BenchStatusRunning + BenchStatusFinished + BenchStatusNotSupport + BenchStatusDockerHostFail + BenchStatusDockerContainerFail + BenchStatusKubeMasterFail + BenchStatusKubeWorkerFail + BenchStatusMax +) + +const ( + BenchLevelPass = "PASS" + BenchLevelInfo = "INFO" + BenchLevelWarn = "WARN" + BenchLevelHigh = "HIGH" + BenchLevelNote = "NOTE" + BenchLevelError = "ERROR" + BenchProfileL1 = "Level 1" + BenchProfileL2 = "Level 2" +) + +type CLUSCustomCheck struct { + Name string `json:"name"` + Script string `json:"script"` +} + +type CLUSCustomCheckGroup struct { + Scripts []*CLUSCustomCheck `json:"scripts"` +} + +type CLUSEventCondition struct { + CondType string `json:"type,omitempty"` + CondValue string `json:"value,omitempty"` +} + +type CLUSResponseRule struct { + ID uint32 `json:"id"` + Event string `json:"event"` + Comment string `json:"comment,omitempty"` + Group string `json:"group,omitempty"` + Conditions []CLUSEventCondition `json:"conditions,omitempty"` + Actions []string `json:"actions"` + Webhooks []string `json:"webhooks"` + Disable bool `json:"disable,omitempty"` + CfgType TCfgType `json:"cfg_type"` +} + +func CLUSResponseRuleKey(policyName string, id uint32) string { + return fmt.Sprintf("%s%s/rule/%v", CLUSConfigResponseRuleStore, policyName, id) +} + +func CLUSResponseRuleListKey(name string) string { + return fmt.Sprintf("%s%s/rules", CLUSConfigResponseRuleStore, name) +} + +func CLUSProfileKey(group string) string { + return fmt.Sprintf("%s%s", ProfileProcessStore, group) +} + +func CLUSProfileConfigKey(group string) string { + return fmt.Sprintf("%s%s", CLUSConfigProcessProfileStore, group) +} + +type CLUSProcessProfileEntry struct { + Name string `json:"name"` + Path string `json:"path"` + User string `json:"user"` + Uid int32 `json:"uid"` + Hash []byte `json:"hash"` + Action string `json:"action"` + CfgType TCfgType `json:"cfg_type"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Uuid string `json:"uuid"` + DerivedGroup string `json:"dgroup"` + AllowFileUpdate bool `json:"allow_update"` + ProbeCmd string `json:"probe_cmd"` +} + +type CLUSProcessProfile struct { + Group string `json:"group"` + AlertDisable bool `json:"alert_disabled"` + HashEnable bool `json:"hash_enabled"` + Mode string `json:"mode"` + Baseline string `json:"baseline"` + Process []*CLUSProcessProfileEntry `json:"process"` + CfgType TCfgType `json:"cfg_type"` +} + +type CLUSRegistryFilter struct { + Org string `json:"organization"` + Repo string `json:"repository"` + Tag string `json:"tag"` +} + +type CLUSRegistryState struct { + Status string `json:"status"` + ErrMsg string `json:"error_message"` + ErrDetail string `json:"error_detail"` + StartedAt int64 `json:"started_at"` +} + +type CLUSAWSAccountKey struct { + ID string `json:"id"` + AccessKeyID string `json:"access_key_id,cloak"` + SecretAccessKey string `json:"secret_access_key,cloak"` + Region string `json:"region"` +} + +type CLUSGCRKey struct { + JsonKey string `json:"json_key,cloak"` +} + +type CLUSRegistryConfig struct { + Registry string `json:"registry"` + Name string `json:"name"` + Type string `json:"type"` + Username string `json:"username"` + Password string `json:"password,cloak"` + AuthToken string `json:"auth_token,cloak"` + AuthWithToken bool `json:"auth_with_token"` + Domains []string `json:"domains"` + CreaterDomains []string `json:"creater_domains"` + Filters []string `json:"filters"` + ParsedFilters []*CLUSRegistryFilter `json:"parsed_filters"` + RescanImage bool `json:"rescan_image"` + ScanLayers bool `json:"scan_layers"` + DisableFiles bool `json:"disable_files"` + RepoLimit int `json:"repo_limit"` + TagLimit int `json:"tag_limit"` + Schedule string `json:"schedule"` + PollPeriod int `json:"poll_period"` + AwsKey *CLUSAWSAccountKey `json:"aws_key"` + GcrKey *CLUSGCRKey `json:"gcr_key"` + JfrogMode string `json:"jfrog_mode"` + JfrogAQL bool `json:"jfrog_aql"` + GitlabApiUrl string `json:"gitlab_api_url"` + GitlabPrivateToken string `json:"gitlab_private_token,cloak"` + IBMCloudAccount string `json:"ibmcloud_account"` + IBMCloudTokenURL string `json:"ibmcloud_token_url"` +} + +type CLUSImage struct { + Domain string `json:"domain"` + Repo string `json:"repo"` + Tag string `json:"tag"` + RegMod string `json:"reg_mod"` +} + +// This flag can be used to force rescan with the new controller +const ( + ScanFlagCVE = 0x01 + ScanFlagLayers = 0x02 + ScanFlagFiles = 0x04 +) + +type CLUSRegistryImageSummary struct { + ImageID string `json:"image_id"` + Registry string `json:"registry"` + RegName string `json:"reg_name"` + Images []CLUSImage `json:"repo_tag"` + Digest string `json:"digest"` + ScannedAt time.Time `json:"scanned_at"` + BaseOS string `json:"base_os"` + Version string `json:"version"` + Result ScanErrorCode `json:"result"` + Status string `json:"status"` + Author string `json:"author"` + RunAsRoot bool `json:"run_as_root"` + Signed bool `json:"signed"` // [2019.Apr] comment out until we can accurately tell it + ScanFlags uint32 `json:"scan_flags"` + Provider ScanProvider `json:"provider"` + Size int64 `json:"size"` +} + +type CLUSScanner struct { + ID string `json:"id"` + CVEDBVersion string `json:"db_version"` + CVEDBCreateTime string `json:"db_create_time"` + JoinedAt time.Time `json:"joined_at"` + RPCServer string `json:"rpc_server"` + RPCServerPort uint16 `json:"rpc_port"` + BuiltIn bool `json:"builtin"` + CVEDBEntries int `json:"db_entries"` +} + +type CLUSScannerStats struct { + ID string `json:"id"` + TotalContainers int `json:"total_containers"` + TotalHosts int `json:"total_hosts"` + TotalImages int `json:"total_images"` + TotalServerless int `json:"total_serverless"` + ScannedContainers int `json:"scanned_containers"` + ScannedHosts int `json:"scanned_hosts"` + ScannedImages int `json:"scanned_images"` + ScannedServerless int `json:"scanned_serverless"` +} + +type CLUSScannerDB struct { + CVEDBVersion string `json:"db_version"` + CVEDBCreateTime string `json:"db_create_time"` + CVEDB map[string]*ScanVulnerability `json:"db"` +} + +type CLUSScannedVulInfo struct { + PublishDate int64 `json:"publish_date"` + WithFix bool `json:"with_fix"` + Score float32 `json:"score"` +} + +type CLUSScannedVulInfoSimple struct { + Score float32 `json:"score"` +} + +// Admission control +const ( + AdmCtrlModeMonitor = "monitor" + AdmCtrlModeProtect = "protect" + + AdmClientModeSvc = "service" + AdmClientModeUrl = "url" + + AdmCtrlActionAllow = PolicyActionAllow + AdmCtrlActionDeny = PolicyActionDeny +) + +type CLUSAdmissionCert struct { + CN string `json:"cn"` + CaKeyPath string `json:"ca_key_path"` + CaKey []byte `json:"ca_key"` + CaCertPath string `json:"ca_cert_path"` + CaCert []byte `json:"ca_cert"` + KeyPath string `json:"key_path"` + Key []byte `json:"key"` + CertPath string `json:"cert_path"` + Cert []byte `json:"cert"` +} + +type CLUSAdmissionCertCloaked struct { // a superset of CLUSAdmissionCert + CN string `json:"cn"` + CaKeyPath string `json:"ca_key_path"` // obsolete, use const AdmCAKeyPath + CaKey []byte `json:"ca_key"` // not written to kv + CaCertPath string `json:"ca_cert_path"` // obsolete, use const AdmCACertPath + CaCert []byte `json:"ca_cert"` // not written to kv + KeyPath string `json:"key_path"` // obsolete, calc at runtime like "neuvector-svc-admission-webhook.{ns}.svc.key.pem" + Key []byte `json:"key"` // not written to kv + CertPath string `json:"cert_path"` // obsolete, calc at runtime like "neuvector-svc-admission-webhook.{ns}.svc.cert.pem" + Cert []byte `json:"cert"` // not written to kv + CaKeyNew string `json:"ca_key_new,cloak"` // for v.3.0 + CaCertNew string `json:"ca_cert_new,cloak"` // for v.3.0 + KeyNew string `json:"key_new,cloak"` // for v.3.0 + CertNew string `json:"cert_new,cloak"` // for v.3.0, cert for webhook server + Cloaked bool `json:"cloaked"` +} + +type CLUSX509Cert struct { + CN string `json:"cn"` + Key string `json:"key,cloak"` + Cert string `json:"cert,cloak"` +} + +func (c *CLUSX509Cert) IsEmpty() bool { + if c == nil || len(c.Key) == 0 || len(c.Cert) == 0 { + return true + } + return false +} + +type CLUSAdmCtrlState struct { + Enable bool `json:"enable"` + Uri string `json:"uri"` // for neuvector-validating-admission-webhook.neuvector.svc webhook + NvStatusUri string `json:"nv_status_uri"` // for neuvector-validating-status-webhook.neuvector.svc webhook +} + +// NvDeployStatus field is only for object/config/admission_control/default/state only +type CLUSAdmissionState struct { + Enable bool `json:"enable"` + Mode string `json:"mode"` + DefaultAction string `json:"default_action"` + AdmClientMode string `json:"adm_client_mode"` + FailurePolicy string `json:"failure_policy"` // empty means "Ignore". it's only for neuvector-svc-admission-webhook + TimeoutSeconds int32 `json:"timeout_seconds"` // 0 means 30 + NvDeployStatus map[string]bool `json:"nvDeployStatus"` // key is NvDeploymentName/NvAdmSvcName/NvCrdSvcName. value being true means the k8s resource exists + CtrlStates map[string]*CLUSAdmCtrlState `json:"ctrl_states"` // key is NvAdmValidateType + CfgType TCfgType `json:"cfg_type"` +} + +type CLUSAdmissionStats struct { // see type RESTAdmissionStats + K8sAllowedRequests uint64 `json:"k8s_allowed_requests"` + K8sDeniedRequests uint64 `json:"k8s_denied_requests"` + K8sErroneousRequests uint64 `json:"k8s_erroneous_requests"` + K8sIgnoredRequests uint64 `json:"k8s_ignored_requests"` + K8sProcessingRequests int64 `json:"k8s_processing_requests"` + JenkinsAllowedRequests uint64 `json:"jenkins_allowed_requests"` // obsolete + JenkinsDeniedRequests uint64 `json:"jenkins_denied_requests"` // obsolete + JenkinsErroneousRequests uint64 `json:"jenkins_erroneous_requests"` // obsolete +} + +type CLUSAdmRuleCriterion struct { // see type RESTAdmRuleCriterion + Name string `json:"name"` + Op string `json:"op"` + Value string `json:"value"` + ValueSlice []string `json:"value_slice"` + SubCriteria []*CLUSAdmRuleCriterion `json:"sub_criteria,omitempty"` +} + +type CLUSAdmissionRule struct { // see type RESTAdmissionRule + ID uint32 `json:"id"` + Category string `json:"category"` + Comment string `json:"comment"` + Criteria []*CLUSAdmRuleCriterion `json:"criteria"` + Disable bool `json:"disable"` + Critical bool `json:"critical"` + CfgType TCfgType `json:"cfg_type"` + RuleType string `json:"rule_type"` // "exception", "deny" +} + +type CLUSAdmissionRules struct { + RuleMap map[uint32]*CLUSAdmissionRule `json:"rule_map"` // key is rule ID + RuleHeads []*CLUSRuleHead `json:"rule_heads"` +} + +const ( + CLUSAdmissionCfgCert = "cert" + CLUSAdmissionCfgState = "state" + CLUSAdmissionCfgRule = "rule" + CLUSAdmissionCfgRuleList = "rules" + CLUSAdmissionStatistics = "statistics" +) + +const ( + CLUSRootCAKey = "rootCA" +) + +func CLUSObjectCertKey(cn string) string { + // ex: r object/cert/rootCA or object/cert/neuvector-svc-admission-webhook.neuvector.svc + return fmt.Sprintf("%s%s", CLUSCertStore, cn) +} + +func CLUSAdmissionCertKey(store, policyName string) string { // obsolete + // ex: object/config/admission_control/cert + return fmt.Sprintf("%s%s/%s", store, policyName, CLUSAdmissionCfgCert) +} + +func CLUSAdmissionStateKey(store, policyName string) string { + // ex: object/config/admission_control/default/state + return fmt.Sprintf("%s%s/%s", store, policyName, CLUSAdmissionCfgState) +} + +func CLUSAdmissionRuleKey(policyName, admType, ruleType string, id uint32) string { + // ex: object/config/admission_control/default/rule/{admType}/{ruleType}/{id} - admType: [mutate|validate], ruleType: deny + return fmt.Sprintf("%s%s/%s/%s/%s/%v", CLUSConfigAdmissionControlStore, policyName, CLUSAdmissionCfgRule, admType, ruleType, id) +} + +func CLUSAdmissionRuleListKey(policyName, admType, ruleType string) string { + // ex: object/config/admission_control/default/rules/{admType}/{ruleType} - admType: [mutate|validate], ruleType: deny + return fmt.Sprintf("%s%s/%s/%s/%s", CLUSConfigAdmissionControlStore, policyName, CLUSAdmissionCfgRuleList, admType, ruleType) +} + +func CLUSAdmissionStatsKey(policyName string) string { + // ex: object/config/admission_control/default/statistics + return fmt.Sprintf("%s%s/%s", CLUSConfigAdmissionControlStore, policyName, CLUSAdmissionStatistics) +} + +func CLUSPolicyKey2AdmCfgPolicySubkey(key string, last bool) string { + if last { + tokens := strings.Split(key, "/") + if len(tokens) != 4 { + return "" + } + return tokens[3] + } else { + return CLUSKeyNthToken(key, 3) + } +} + +func CLUSPolicyKey2AdmCfgSubkey(key string) string { + return CLUSKeyNthToken(key, 4) +} + +func CLUSCrdKey(crdType, name string) string { + + return fmt.Sprintf("%s%s/%s", CLUSConfigCrdStore, crdType, name) +} + +func CLUSPolicyRuleKey2AdmRuleType(key, cfgType string) (string, string) { + cfgSubKey := CLUSPolicyKey2AdmCfgSubkey(key) + if cfgSubKey == cfgType { + return CLUSKeyNthToken(key, 5), CLUSKeyNthToken(key, 6) + } else { + return "", "" + } +} + +type CLUSFileAccessFilterRule struct { + Apps []string `json:"apps"` + Behavior string `json:"behavior"` + CustomerAdd bool `json:"customer_add"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +type CLUSFileAccessRule struct { + Group string + Filters map[string]*CLUSFileAccessFilterRule `json:"filters"` + FiltersCRD map[string]*CLUSFileAccessFilterRule `json:"filters_crd"` +} + +type CLUSFileMonitorFilter struct { + Filter string `json:"filter"` + Path string `json:"path"` + Regex string `json:"regex"` + Recursive bool `json:"recursive"` + CustomerAdd bool `json:"customer_add"` + Behavior string `json:"behavior"` + DerivedGroup string `json:"dgroup,omitempty"` +} + +type CLUSFileMonitorProfile struct { + Group string + Mode string + CfgType TCfgType `json:"cfg_type"` + Filters []CLUSFileMonitorFilter `json:"filters"` + FiltersCRD []CLUSFileMonitorFilter `json:"filters_crd"` +} + +type CLUSCrdProcessRule struct { + Name string `json:"name"` + Path string `json:"path"` + Action string `json:"action"` + AllowFileUpdate bool `json:"allow_update"` +} + +type CLUSCrdFileRule struct { + Filter string `json:"filter"` + Recursive bool `json:"recursive"` + Behavior string `json:"behavior"` + App []string `json:"app"` +} + +type CLUSCrdProcessProfile struct { + Baseline string `json:"baseline"` // "default" or "shield", for process profile +} + +type CLUSCrdSecurityRule struct { + Name string `json:"name"` + Groups []string `json:"groups"` + Rules map[string]uint32 `json:"rules"` + ProfileName string `json:"profile_name"` + ProfileMode string `json:"profile_mode"` + ProcessProfile CLUSCrdProcessProfile `json:"process_profile"` + ProcessRules []CLUSCrdProcessRule `json:"process_rules"` + FileRules []CLUSCrdFileRule `json:"file_rules"` + DlpGroupSensors []string `json:"dlp_group_sensors"` // dlp sensors associated with the target group + WafGroupSensors []string `json:"waf_group_sensors"` // waf sensors associated with the target group + AdmCtrlRules map[string]uint32 `json:"admctrl_rules"` // map key is the generated name of admission control rule, valud is assigned rule id + DlpSensor string `json:"dlp_sensor"` // dlp sensor defined in this crd security rule + WafSensor string `json:"waf_sensor"` // waf sensor defined in this crd security rule +} + +// Multi-Clusters (Federation) +const ( + FedAdmCtrlExceptRulesType = "fed_admctrl_exception" + FedAdmCtrlDenyRulesType = "fed_admctrl_deny" + FedNetworkRulesType = "fed_netwwork_rule" + FedResponseRulesType = "fed_response_rule" + FedGroupType = "fed_group" + FedFileMonitorProfilesType = "fed_file_profile" + FedProcessProfilesType = "fed_process_profile" + FedSystemConfigType = "fed_system_config" +) + +const ( + CriticalAdmCtrlExceptRulesType = "critical_allow" + CrdAdmCtrlExceptRulesType = "crd_allow" + CrdAdmCtrlDenyRulesType = "crd_deny" +) + +const ( + DefaultComplianceProfileName = "default" + DefaultVulnerabilityProfileName = "default" + DefaultPolicyName = "default" // mapping of ScopeLocal + FedPolicyName = "fed" // mapping of ScopeFed +) + +const ( + ScopeLocal = "local" + ScopeFed = "fed" + ScopeAll = "" + ScopeError = "error" +) + +const ( + StartPingFedJoints = iota + 1 + StopPingFedJoints + StartPollFedMaster + StopPollFedMaster + InstantPollFedMaster + InstantPingFedJoints + JointLoadOwnKeys + MasterLoadJointKeys + PurgeJointKeys + MasterUnloadJointKeys + StartPostToIBMSA + StopPostToIBMSA + PostToIBMSA + RestartWebhookServer +) + +const ( + CLUSFedMembershipSubKey = "membership" + CLUSFedClustersListSubKey = "clusters_list" + CLUSFedClustersStatusSubKey = "clusters_status" + CLUSFedClustersSubKey = "clusters" + CLUSFedRulesRevisionSubKey = "rules_revision" + CLUSFedToPingPollSubKey = "ping_poll" +) + +const ( + CLUSFedMembershipKey = CLUSConfigFederationStore + CLUSFedMembershipSubKey // stores CLUSFedMembership + CLUSFedClustersListKey = CLUSConfigFederationStore + CLUSFedClustersListSubKey // stores CLUSFedJoinedClusterList + CLUSFedClustersStatusKey = CLUSConfigFederationStore + CLUSFedClustersStatusSubKey // each subkey stores CLUSFedClusterStatus + CLUSFedClustersKey = CLUSConfigFederationStore + CLUSFedClustersSubKey // each subkey stores CLUSFedJointClusterInfo + CLUSFedRulesRevisionKey = CLUSConfigFederationStore + CLUSFedRulesRevisionSubKey // stores CLUSFedRulesRevision + CLUSFedToPingPollKey = CLUSConfigFederationStore + CLUSFedToPingPollSubKey // stores CLUSFedDoPingPoll + CLUSFedSystemKey = CLUSConfigFederationStore + CFGEndpointSystem // stores CLUSFedSystemConfig +) + +func CLUSEmptyFedRulesRevision() *CLUSFedRulesRevision { + fedRev := &CLUSFedRulesRevision{ + Revisions: map[string]uint64{ + FedAdmCtrlExceptRulesType: 0, + FedAdmCtrlDenyRulesType: 0, + FedNetworkRulesType: 0, + FedResponseRulesType: 0, + FedGroupType: 0, + FedFileMonitorProfilesType: 0, + FedProcessProfilesType: 0, + FedSystemConfigType: 0, + }, + } + + return fedRev +} + +func CLUSFedJointClusterKey(id string) string { + // ex: object/config/federation/clusters/{000-111-222} + return fmt.Sprintf("%s/%s", CLUSFedClustersKey, id) +} + +func CLUSFedJointClusterStatusKey(id string) string { + // ex: object/config/federation/clusters_status/{000-111-222} + return fmt.Sprintf("%s/%s", CLUSFedClustersStatusKey, id) +} + +func CLUSFedKey2CfgKey(key string) string { + return CLUSKeyNthToken(key, 3) +} + +func CLUSFedKey2ClusterIdKey(key string) string { + return CLUSKeyNthToken(key, 4) +} + +type CLUSRestServerInfo struct { // provided by admin + Server string `json:"server"` + Port uint `json:"port"` +} + +type CLUSFedMasterClusterInfo struct { + Disabled bool `json:"disabled"` + Name string `json:"name"` + ID string `json:"id"` + Secret string `json:"secret,cloak"` // used for encryoting/decrypting join_ticket issued by the master cluster + CACert string `json:"ca_cert,cloak"` // base64 encoded + User string `json:"user,omitempty"` // the user who promotes this cluster to master cluster in federation + RestInfo CLUSRestServerInfo `json:"rest_info"` +} + +type CLUSFedJointClusterInfo struct { + Disabled bool `json:"disabled"` + Name string `json:"name"` + ID string `json:"id"` + Secret string `json:"secret,cloak"` // generated by joint cluster befor joining federation + ClientKey string `json:"client_key,cloak"` // base64 encoded + ClientCert string `json:"client_cert,cloak"` // base64 encoded + User string `json:"user,omitempty"` // the user who joins this cluster to federation + RestInfo CLUSRestServerInfo `json:"rest_info"` + ProxyRequired bool `json:"proxy_required"` // a joint cluster may be reachable without proxy even master cluster is configured to use proxy. decided when it joins fed +} + +type CLUSFedMembership struct { // stored on each cluster (master & joint cluster) + FedRole string `json:"fed_role"` // "", "master" or "joint" + PingInterval uint32 `json:"ping_interval,omitempty"` // in minute, for master cluster to ping joing clusters + PollInterval uint32 `json:"poll_interval,omitempty"` // in minute, for joint clusters to poll master cluster + LocalRestInfo CLUSRestServerInfo `json:"local_rest_info"` // meaningful when the role is "" + MasterCluster CLUSFedMasterClusterInfo `json:"master_cluster,omitempty"` // meaningful when the role is "master" or "joint" + JointCluster CLUSFedJointClusterInfo `json:"joint_cluster,omitempty"` // meaningful when the role is "joint" + PendingDismiss bool `json:"pending_dismiss"` // set to true when the cluster is demoted/kicked & leaves fed. set to false when the fed rules cleanup is done + PendingDismissAt time.Time `json:"pending_dismiss_at"` + UseProxy string `json:"use_proxy"` // http / https +} + +type CLUSFedClusterStatus struct { + Status int `json:"status"` // status of a joint cluster +} + +type CLUSFedJoinedClusterList struct { // only available on master cluster + IDs []string `json:"ids,omitempty"` // all non-master clusters' id in the federation +} + +// fed ruleTypes' revision data. stored under object/config/federation/rules_revision +type CLUSFedRulesRevision struct { + Revisions map[string]uint64 `json:"revisions"` // key is fed rules type, value is revision +} + +type CLUSFedDoPingPoll struct { + Cmd uint32 `json:"cmd"` + FullPolling uint32 `json:"full_polling"` + Now int64 `json:"now"` +} + +type CLUSFedAdmCtrlRulesData struct { + Revision uint64 `json:"revision"` + Rules map[string]*CLUSAdmissionRules `json:"rules"` // key is fed rules type +} + +type CLUSFedGroupsData struct { + Revision uint64 `json:"revision"` + Groups []*CLUSGroup `json:"groups"` +} + +type CLUSFedNetworkRulesData struct { + Revision uint64 `json:"revision"` + Rules []*CLUSPolicyRule `json:"rules"` + RuleHeads []*CLUSRuleHead `json:"rule_heads"` +} + +type CLUSFedResponseRulesData struct { + Revision uint64 `json:"revision"` + Rules map[uint32]*CLUSResponseRule `json:"rules"` + RuleHeads []*CLUSRuleHead `json:"rule_heads"` +} + +type CLUSFedFileMonitorData struct { + Revision uint64 `json:"revision"` + Profiles []*CLUSFileMonitorProfile `json:"profiles"` + AccessRules []*CLUSFileAccessRule `json:"access_rules"` +} + +type CLUSFedProcessProfileData struct { + Revision uint64 `json:"revision"` + Profiles []*CLUSProcessProfile `json:"profiles"` +} + +type CLUSFedSystemConfigData struct { + Revision uint64 `json:"revision"` + SystemConfig *CLUSSystemConfig `json:"system_config"` +} + +//dlp rule +const ( + DlpRuleKeyPattern string = "pattern" +) + +const ( + DlpPatternContextURI string = "url" + DlpPatternContextHEAD string = "header" + DlpPatternContextBODY string = "body" + DlpPatternContextPACKET string = "packet" + DlpPatternContextDefault string = "body" +) + +const ( + CLUSDlpDefaultSensor = "sensor.dlpdfltnv" + CLUSDlpSsnSensor = "sensor.ssn" + CLUSDlpCcSensor = "sensor.creditcard" + CLUSWafDefaultSensor = "sensor.wafdfltnv" +) + +const ( + DlpRuleNameCreditCard string = "rule.creditcard" + DlpRuleNameCcAxp string = "rule.americanexpress" + DlpRuleNameCcDiscover string = "rule.discover" + DlpRuleNameCcMaster string = "rule.master" + DlpRuleNameCcVisa string = "rule.visa" + DlpRuleNameCcDinerV1 string = "rule.diner1" + DlpRuleNameCcDinerV2 string = "rule.diner2" + DlpRuleNameCcJcb string = "rule.jcb" + DlpRuleNameSsn string = "rule.ssn" +) + +const ( + DlpWlRuleIn = "inside" + DlpWlRuleOut = "outside" + WafWlRuleIn = "wafinside" + WafWlRuleOut = "wafoutside" +) + +func CLUSDlpRuleKey(sensor string) string { + return fmt.Sprintf("%s%s", DlpRuleStore, sensor) +} + +func CLUSDlpWorkloadRulesKey(name string) string { + return fmt.Sprintf("%s%s", CLUSNetworkStore, name) +} + +func CLUSDlpRuleConfigKey(sensor string) string { + return fmt.Sprintf("%s%s", CLUSConfigDlpRuleStore, sensor) +} + +func CLUSDlpGroupConfigKey(group string) string { + return fmt.Sprintf("%s%s", CLUSConfigDlpGroupStore, group) +} + +func CLUSWafRuleKey(sensor string) string { + return fmt.Sprintf("%s%s", WafRuleStore, sensor) +} + +func CLUSWafRuleConfigKey(sensor string) string { + return fmt.Sprintf("%s%s", CLUSConfigWafRuleStore, sensor) +} + +func CLUSWafGroupConfigKey(group string) string { + return fmt.Sprintf("%s%s", CLUSConfigWafGroupStore, group) +} + +func CLUSCrdQueueKey(name string) string { + return fmt.Sprintf("%s%s", CLUSCrdProcStore, name) +} + +type CLUSDlpCriteriaEntry struct { + Key string `json:"key"` + Value string `json:"value"` + Op string `json:"op"` + Context string `json:"context,omitempty"` +} + +type CLUSDlpRule struct { + Name string `json:"name"` + ID uint32 `json:"id"` + Patterns []CLUSDlpCriteriaEntry `json:"patterns"` + CfgType TCfgType `json:"cfg_type"` +} + +type CLUSDlpSensor struct { + Name string `json:"name"` + Groups map[string]string `json:"groups,omitempty"` //group to action mapping, + RuleListNames map[string]string `json:"rule_list_names,omitempty"` + RuleList map[string]*CLUSDlpRule `json:"rule_list,omitempty"` + PreRuleList map[string][]*CLUSDlpRule `json:"pre_rule_list,omitempty"` + Comment string `json:"comment,omitempty"` + Predefine bool `json:"predefine,omitempty"` + CfgType TCfgType `json:"cfg_type"` +} + +type CLUSDlpSetting struct { + Name string `json:"name"` + Action string `json:"action"` +} + +type CLUSDlpWorkloadRule struct { + WorkloadId string `json:"workload_id"` + PolicyMode string `json:"mode,omitempty"` + RuleListNames []*CLUSDlpSetting `json:"rule_list_names"` + RuleIds []uint32 `json:"rule_ids"` + RuleType string `json:"ruletype"` +} + +type CLUSWorkloadDlpRules struct { + DlpRuleList []*CLUSDlpRule `json:"dlp_rule_list"` + DlpWlRules []*CLUSDlpWorkloadRule `json:"dlp_wl_rules"` +} + +type CLUSDlpGroup struct { + Name string `json:"name"` + Status bool `json:"status"` + Sensors []*CLUSDlpSetting `json:"sensors"` + CfgType TCfgType `json:"cfg_type"` +} + +//waf +type CLUSWafCriteriaEntry struct { + Key string `json:"key"` + Value string `json:"value"` + Op string `json:"op"` + Context string `json:"context,omitempty"` +} + +type CLUSWafRule struct { + Name string `json:"name"` // internal waf rule name + ID uint32 `json:"id"` + Patterns []CLUSWafCriteriaEntry `json:"patterns"` + CfgType TCfgType `json:"cfg_type"` +} + +type CLUSWafSensor struct { + Name string `json:"name"` + Groups map[string]string `json:"groups,omitempty"` // group to action mapping, only for memory cache. it's always empty in kv + RuleListNames map[string]string `json:"rule_list_names,omitempty"` // key, value: internal waf rule name; for non-default sensors + RuleList map[string]*CLUSWafRule `json:"rule_list,omitempty"` // key: internal waf rule name; for default sensor only + PreRuleList map[string][]*CLUSWafRule `json:"pre_rule_list,omitempty"` + Comment string `json:"comment,omitempty"` + Predefine bool `json:"predefine,omitempty"` + CfgType TCfgType `json:"cfg_type"` +} + +type CLUSWafSetting struct { + Name string `json:"name"` // unique sensor name + Action string `json:"action"` +} + +type CLUSWafWorkloadRule struct { + WorkloadId string `json:"workload_id"` + PolicyMode string `json:"mode,omitempty"` + RuleListNames []*CLUSWafSetting `json:"rule_list_names"` + RuleIds []uint32 `json:"rule_ids"` + RuleType string `json:"ruletype"` +} + +type CLUSWorkloadWafRules struct { + WafRuleList []*CLUSWafRule `json:"waf_rule_list"` + WafWlRules []*CLUSWafWorkloadRule `json:"waf_wl_rules"` +} + +type CLUSWafGroup struct { + Name string `json:"name"` + Status bool `json:"status"` + Sensors []*CLUSWafSetting `json:"sensors"` + CfgType TCfgType `json:"cfg_type"` +} + +type CLUSCrdRecord struct { + CrdRecord *admissionv1beta1.AdmissionReview +} + +type CLUSCrdEventRecord struct { + CrdEventRecord []string +} + +////// Process UUID Rules +// Reserved(256 entries): 00000000-0000-0000-0000-0000000000XX +// Default rules: 00000000-0000-0000-0000-00000000000X +// Linux-specific: 00000000-0000-0000-0000-00000000001X ans 2X +// Windows-specific: 00000000-0000-0000-0000-00000000003X ans 4X +const CLUSReservedUuidPrefix string = "00000000-0000-0000-0000-0000000000" // reserved the last 2 digits + +////// +const CLUSReservedUuidNotAlllowed string = "00000000-0000-0000-0000-000000000000" // processes beyond white list +const CLUSReservedUuidRiskyApp string = "00000000-0000-0000-0000-000000000001" // riskApp +const CLUSReservedUuidTunnelProc string = "00000000-0000-0000-0000-000000000002" // tunnel +const CLUSReservedUuidRootEscalation string = "00000000-0000-0000-0000-000000000003" // root privilege escallation +const CLUSReservedUuidDockerCp string = "00000000-0000-0000-0000-000000000004" // docker cp +const CLUSReservedUuidAnchorMode string = "00000000-0000-0000-0000-000000000005" // rejected by anchor mode +const CLUSReservedUuidShieldMode string = "00000000-0000-0000-0000-000000000006" // rejected by non-family process + +type ProcRule struct { + Active int `json:"active"` + Group string `json:"group"` + Rule CLUSProcessProfileEntry `json:"rule"` +} + +type ProcRuleMap struct { + RuleMap map[string]*ProcRule `json:"rulemap"` +} + +type CLUSAwsFuncPermission struct { + AttachedPolicy bool `json:"aws_attached_policy"` + AllowedDetail []string `json:"allowed_detail"` +} + +type CLUSAwsFuncScanOutput struct { + AllowedRes map[string]CLUSAwsFuncPermission `json:"allowd_res"` // key: policyName value: list of resource + ReqRes map[string][]string `json:"req_res"` // key: policyName value: list of resource + ScanState string `json:"scan_state"` + ScanError string `json:"scan_error"` + ScanResult CLUSScanReport `json:"scan_result"` + Arn string `json:"arn"` + NvSecID string `json:"nvsecid"` + Version string `json:"version"` +} + +const MaxLambdaHistory = 3 + +type CLUSAwsFuncScanOutputList struct { + AwsLambdaRecord [MaxLambdaHistory]*CLUSAwsFuncScanOutput `json:"aws_lambda_record"` + SlsUploadOutput *CLUSAwsFuncScanOutput `json:"sls_upload_output"` +} + +type CLUSAwsFuncScanInput struct { + FuncName string `json:"func_name"` + RoleName string `json:"role_name"` + Region string `json:"region"` + FuncLink string `json:"func_link"` + Arn string `json:"arn"` + NvSecID string `json:"nv_sec_id"` + Version string `json:"version"` +} + +type CLUSAwsScanInput struct { + AccID string `json:"accid,cloak"` + AccKey string `json:"acckey,cloak"` + ProjectName string `json:"projectname"` + ScanFunctionList []*CLUSAwsFuncScanInput `json:"scanFunctionList"` + DelFunctionList []*CLUSAwsFuncScanInput `json:"DelFunctionList"` +} + +type CLUSAwsLambdaFunc struct { + Name string `json:"func_name"` + CodeSha256 string `json:"code_sha256"` + Status string `json:"status"` + ScanResult string `json:"scan_result"` + PermitLevel string `json:"PermitLevel"` + Role string `json:"role"` + Arn string `json:"arn"` + NvSecID string `json:"nv_sec_id"` + Version string `json:"version"` + HighVuls int `json:"high"` + MedVuls int `json:"medium"` +} + +type CLUSAwsLambdaRegionRes struct { + Region string `json:"region"` + Status string `json:"status"` + LambdaFunc map[string]*CLUSAwsLambdaFunc `json:"lambda_func"` +} + +type CLUSAwsLambdaRes struct { + Status string `json:"status"` + ResourceMap map[string]*CLUSAwsLambdaRegionRes `json:"aws_region_resource"` +} + +type CLUSAwsResource struct { + AccID string `json:"accid,cloak"` + AccKey string `json:"acckey,cloak"` + ProjectName string `json:"projectname"` + RegionList []string `json:"region_list"` + ResLambda *CLUSAwsLambdaRes `json:"aws_lambda_resource"` +} + +type CLUSAwsProjectCfg struct { + AccID string `json:"accid,cloak"` + AccKey string `json:"acckey,cloak"` + ProjectName string `json:"projectname"` + RegionList []string `json:"region_list"` +} + +func CLUSCloudCfgKey(cloudType, projectName string) string { + return fmt.Sprintf("%s%s/%s", CLUSConfigCloudStore, cloudType, projectName) +} + +func CLUSCloudKey(cloudType, projectName string) string { + return fmt.Sprintf("%s%s/%s", CLUSCloudStore, cloudType, projectName) +} + +func CLUSCloudFuncKey(cloudType, project, region, funcName string) string { + return fmt.Sprintf("%s%s/%s/%s/%s", CLUSCloudStore, cloudType, project, region, funcName) +} + +// SecretLog provides the found secret raw data +type SecretLog struct { + Text string `json:"secret"` // detected secret or signature + Line string `json:"line"` // full line in the content + File string `json:"path"` // file path + RuleDesc string `json:"rule_desc"` // rule description +} + +/////// Secret Types +const ( + SecretPrivateKey string = "privatekey" // Private Key + SecretX509 string = "x.509" // X.509 certificates (ignored) + SecretProgram string = "program" // in specific program files + SecretRegular string = "regular" // in other regular files +) + +// CLUSSecretLog provides reports at scanner/enforcer layer +type CLUSSecretLog struct { + Type string `json:"type"` // secret type + Text string `json:"secret"` // detected secret or signature + Line string `json:"line"` // full line in the content + File string `json:"path"` // file path + RuleDesc string `json:"rule_desc"` // rule description + Suggestion string `json:"suggestion"` // suggestion to reduce the risk +} + +// CLUSBenchSecretReport provides reports at REST layer +type CLUSBenchSecretReport struct { + Status BenchStatus `json:"status"` + RunAt time.Time `json:"run_at"` + Items []CLUSSecretLog `json:"items"` +} + +// CLUSSetIdPermLog provides reports at scanner/enforcer layer +type CLUSSetIdPermLog struct { + Types string `json:"types"` // setuid, setgid + File string `json:"path"` // file path + Evidence string `json:"evidence"` // file attributes +} + +/////// For custom roles +func CLUSUserRoleKey(name string) string { + return fmt.Sprintf("%s%s", CLUSConfigUserRoleStore, name) +} + +type CLUSRolePermission struct { + ID string `json:"id"` + Read bool `json:"read"` + Write bool `json:"write"` +} + +type CLUSUserRole struct { + Name string `json:"name"` + Comment string `json:"comment"` + Reserved bool `json:"reserved"` // true for pre-defined non-hidden roles: fedAdmin/admin/reader + Permissions []*CLUSRolePermission `json:"permissions"` +} + +type CLUSUserRoleInternal struct { + Name string `json:"name"` + Comment string `json:"comment"` + Reserved bool `json:"reserved"` // true for pre-defined non-hidden roles: fedAdmin/admin/reader + ReadPermits uint64 `json:"read_permits"` // sum of all read permissions of this role + WritePermits uint64 `json:"write_permits"` // sum of all write permissions of this role +} + +type CLUSCIScanDummy struct{} // dummy type just for access control checking purpose +type CLUSSnifferDummy struct { + WorkloadDomain string `json:"workload_domain"` +} +type CLUSWorkloadScanDummy struct { + Domain string `json:"domain"` +} +type CLUSApplicationListDummy struct{} // dummy type just for access control checking purpose +type CLUSResponseRuleOptionsDummy struct{} // dummy type just for access control checking purpose +type CLUSRegistryTypeDummy struct{} // dummy type just for access control checking purpose + +// for password profile +const CLUSDefPwdProfileName = "default" +const CLUSSysPwdProfileName = "nvsyspwdprofile" // reserved just for referencing active password profile + +type CLUSActivePwdProfileConfig struct { + Name string `json:"name"` // name of the active password profile to use for the whole cluster +} + +type CLUSPwdProfile struct { + Name string `json:"name"` + Comment string `json:"comment"` + MinLen int `json:"min_len"` + MinUpperCount int `json:"min_uppercase_count"` // for alphabet characters + MinLowerCount int `json:"min_lowercase_count"` // for alphabet characters + MinDigitCount int `json:"min_digit_count"` + MinSpecialCount int `json:"min_special_count"` + EnablePwdExpiration bool `json:"enable_password_expiration"` + PwdExpireAfterDays int `json:"password_expire_after_days"` // must be > 0 when EnablePwdExpiration is true + EnablePwdHistory bool `json:"enable_password_history"` + PwdHistoryCount int `json:"password_keep_history_count"` + EnableBlockAfterFailedLogin bool `json:"enable_block_after_failed_login"` // for "Block X minutes after N times failed attempts" + BlockAfterFailedCount int `json:"block_after_failed_login_count"` // must be > 0 when EnableBlockAfterFailedLogin is true + BlockMinutes int `json:"block_minutes"` // must be > 0 when EnableBlockAfterFailedLogin is true +} + +// Import task +const ( + IMPORT_PREPARE = "preparing" + IMPORT_RUNNING = "importing" + IMPORT_DONE = "done" + IMPORT_NO_RESPONSE = "no_response" +) + +const ( + PREFIX_IMPORT_CONFIG = "import_" + PREFIX_IMPORT_GROUP_POLICY = "group_import_" + PREFIX_IMPORT_ADMCTRL = "admctrl_import_" + PREFIX_IMPORT_DLP = "dlp_import_" + PREFIX_IMPORT_WAF = "waf_import_" +) + +const ( + IMPORT_TYPE_CONFIG = "" + IMPORT_TYPE_GROUP_POLICY = "group" + IMPORT_TYPE_ADMCTRL = "admctrl" + IMPORT_TYPE_DLP = "dlp" + IMPORT_TYPE_WAF = "waf" +) + +const IMPORT_QUERY_INTERVAL = 30 +const CLUSImportStatusSubKey = "status" + +func CLUSImportOpKey(name string) string { + return fmt.Sprintf("%s%s", CLUSImportStore, name) +} + +type CLUSImportTask struct { + TID string `json:"tid"` + ImportType string `json:"import_type"` + CtrlerID string `json:"ctrler_id"` + TempFilename string `json:"temp_filename"` + Status string `json:"status"` + Percentage int `json:"percentage"` + TotalLines int `json:"total_lines"` + LastUpdateTime time.Time `json:"last_update_time"` + CallerFullname string `json:"caller_fullname"` + CallerRemote string `json:"caller_remote"` + CallerID string `json:"caller_id"` +} + +func CLUSNodeProfileStoreKey(nodeID string) string { + return fmt.Sprintf("%s%s/%s", CLUSNodeStore, nodeID, CLUSWorkloadProfileStore) +} + +func CLUSNodeProfileKey(nodeID, subkey string) string { + return fmt.Sprintf("%s%s/%s", CLUSNodeStore, nodeID, subkey) +} + +func CLUSNodeProfileSubkey(key string) string { + // sample: + // input: node/ubuntu:2YZB:5T5K:YVQL:7VNR:FRUB:N3IK:G6FQ:2E7O:UKR4:SDDN:5KQV:CMSF/profiles/process/nv.mtop + // return: profiles/process/nv.mtop + tokens := strings.Split(key, "/") + if len(tokens) == 5 { + return fmt.Sprintf("%s/%s/%s", tokens[2], tokens[3], tokens[4]) + } + return "" +} + +func CLUSNodeProfileGroupKey(nodeID, profile, group string) string { + return fmt.Sprintf("%s%s/%s/%s/%s", CLUSNodeStore, nodeID, CLUSWorkloadProfileStore, profile, group) +} + +// Import group +type TReviewType int + +const ( + ReviewTypeCRD = iota + 1 + ReviewTypeImportGroup // interactive import + ReviewTypeImportAdmCtrl // interactive import + ReviewTypeImportDLP // interactive import + ReviewTypeImportWAF // interactive import +) + +const ( + ReviewTypeDisplayCRD = "CRD" + ReviewTypeDisplayGroup = "Group Policy" // interactive import + ReviewTypeDisplayAdmission = "Admission Control Configurations" // interactive import + ReviewTypeDisplayDLP = "DLP Configurations" // interactive import + ReviewTypeDisplayWAF = "WAF Configurations" // interactive import +) diff --git a/share/common.pb.go b/share/common.pb.go new file mode 100644 index 0000000..4c32130 --- /dev/null +++ b/share/common.pb.go @@ -0,0 +1,402 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: common.proto + +/* +Package share is a generated protocol buffer package. + +It is generated from these files: + common.proto + controller_service.proto + enforcer_service.proto + scan.proto + scanner_service.proto + +It has these top-level messages: + RPCVoid + CLUSProfilingRequest + CLUSBoolean + CLUSMetry + CLUSStats + ScannerRegisterData + ScannerDeregisterData + CLUSFilePacket + CLUSAdmissionRequest + CLUSAdmissionResponse + CLUSProcProfileReq + CLUSProcProfileArray + CLUSFileAccessRuleReq + CLUSFileAccessRuleArray + CLUSConnection + CLUSConnectionArray + CLUSReportResponse + CLUSSyncRequest + CLUSSyncReply + CLUSControllerCounter + CLUSGraphOps + CLUSPolicyRuleCheck + CLUSPolicyRuleMismatch + CLUSPolicySyncStatus + CLUSStoreWatcherInfo + CLUSKickLoginSessionsRequest + CLUSLoginTokenInfo + CLUSKick + CLUSFilter + CLUSSession + CLUSSessionArray + CLUSSessionCounter + CLUSDatapathCounter + CLUSDerivedPolicyApp + CLUSDerivedPolicyRule + CLUSDerivedPolicyRuleArray + CLUSDerivedPolicyRuleMap + CLUSProbeSummary + CLUSProbeProcess + CLUSProbeProcessArray + CLUSProbeContainer + CLUSProbeContainerArray + CLUSFileMonitorFile + CLUSFileMonitorFileArray + CLUSSnifferRequest + CLUSSnifferResponse + CLUSSnifferFilter + CLUSSniffer + CLUSSnifferArray + CLUSSnifferDownload + CLUSSnifferPcap + CLUSContainerLogReq + CLUSContainerLogRes + CLUSProcess + CLUSProcessArray + CLUSDerivedDlpRule + CLUSDerivedDlpRuleArray + CLUSDerivedDlpRuleMap + CLUSDerivedDlpRuleEntry + CLUSDerivedDlpRuleEntryArray + CLUSDerivedDlpRuleMac + CLUSDerivedDlpRuleMacArray + CLUSDerivedProcessRule + CLUSDerivedProcessRuleArray + CLUSDerivedFileRule + CLUSDerivedFileRuleArray + CLUSWorkloadInterceptPort + CLUSWorkloadIntercept + CLUSMeter + CLUSMeterArray + ScanVulnerability + ScanLayerResult + ScanModule + ScanModuleVul + ScanSecretLog + ScanSecretResult + ScanSetIdPermLog + ScanResult + ScanRunningRequest + ScanData + ScanAppPackage + ScanAppRequest + ScanAwsLambdaRequest + ScanImageRequest +*/ +package share + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type ProfilingCmd int32 + +const ( + ProfilingCmd_StartProfiling ProfilingCmd = 0 + ProfilingCmd_StopProfiling ProfilingCmd = 1 +) + +var ProfilingCmd_name = map[int32]string{ + 0: "StartProfiling", + 1: "StopProfiling", +} +var ProfilingCmd_value = map[string]int32{ + "StartProfiling": 0, + "StopProfiling": 1, +} + +func (x ProfilingCmd) String() string { + return proto.EnumName(ProfilingCmd_name, int32(x)) +} +func (ProfilingCmd) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +type ProfilingMethod int32 + +const ( + ProfilingMethod_CPU ProfilingMethod = 0 + ProfilingMethod_Memory ProfilingMethod = 1 +) + +var ProfilingMethod_name = map[int32]string{ + 0: "CPU", + 1: "Memory", +} +var ProfilingMethod_value = map[string]int32{ + "CPU": 0, + "Memory": 1, +} + +func (x ProfilingMethod) String() string { + return proto.EnumName(ProfilingMethod_name, int32(x)) +} +func (ProfilingMethod) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +type RPCVoid struct { +} + +func (m *RPCVoid) Reset() { *m = RPCVoid{} } +func (m *RPCVoid) String() string { return proto.CompactTextString(m) } +func (*RPCVoid) ProtoMessage() {} +func (*RPCVoid) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +type CLUSProfilingRequest struct { + Cmd ProfilingCmd `protobuf:"varint,1,opt,name=Cmd,enum=share.ProfilingCmd" json:"Cmd,omitempty"` + Methods []ProfilingMethod `protobuf:"varint,2,rep,packed,name=Methods,enum=share.ProfilingMethod" json:"Methods,omitempty"` + Duration uint32 `protobuf:"varint,3,opt,name=Duration" json:"Duration,omitempty"` +} + +func (m *CLUSProfilingRequest) Reset() { *m = CLUSProfilingRequest{} } +func (m *CLUSProfilingRequest) String() string { return proto.CompactTextString(m) } +func (*CLUSProfilingRequest) ProtoMessage() {} +func (*CLUSProfilingRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *CLUSProfilingRequest) GetCmd() ProfilingCmd { + if m != nil { + return m.Cmd + } + return ProfilingCmd_StartProfiling +} + +func (m *CLUSProfilingRequest) GetMethods() []ProfilingMethod { + if m != nil { + return m.Methods + } + return nil +} + +func (m *CLUSProfilingRequest) GetDuration() uint32 { + if m != nil { + return m.Duration + } + return 0 +} + +type CLUSBoolean struct { + Value bool `protobuf:"varint,1,opt,name=Value" json:"Value,omitempty"` +} + +func (m *CLUSBoolean) Reset() { *m = CLUSBoolean{} } +func (m *CLUSBoolean) String() string { return proto.CompactTextString(m) } +func (*CLUSBoolean) ProtoMessage() {} +func (*CLUSBoolean) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *CLUSBoolean) GetValue() bool { + if m != nil { + return m.Value + } + return false +} + +type CLUSMetry struct { + CPU float64 `protobuf:"fixed64,1,opt,name=CPU" json:"CPU,omitempty"` + Memory uint64 `protobuf:"varint,2,opt,name=Memory" json:"Memory,omitempty"` + SessionIn uint32 `protobuf:"varint,3,opt,name=SessionIn" json:"SessionIn,omitempty"` + SessionOut uint32 `protobuf:"varint,4,opt,name=SessionOut" json:"SessionOut,omitempty"` + SessionCurIn uint32 `protobuf:"varint,5,opt,name=SessionCurIn" json:"SessionCurIn,omitempty"` + SessionCurOut uint32 `protobuf:"varint,6,opt,name=SessionCurOut" json:"SessionCurOut,omitempty"` + PacketIn uint64 `protobuf:"varint,7,opt,name=PacketIn" json:"PacketIn,omitempty"` + PacketOut uint64 `protobuf:"varint,8,opt,name=PacketOut" json:"PacketOut,omitempty"` + ByteIn uint64 `protobuf:"varint,9,opt,name=ByteIn" json:"ByteIn,omitempty"` + ByteOut uint64 `protobuf:"varint,10,opt,name=ByteOut" json:"ByteOut,omitempty"` +} + +func (m *CLUSMetry) Reset() { *m = CLUSMetry{} } +func (m *CLUSMetry) String() string { return proto.CompactTextString(m) } +func (*CLUSMetry) ProtoMessage() {} +func (*CLUSMetry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *CLUSMetry) GetCPU() float64 { + if m != nil { + return m.CPU + } + return 0 +} + +func (m *CLUSMetry) GetMemory() uint64 { + if m != nil { + return m.Memory + } + return 0 +} + +func (m *CLUSMetry) GetSessionIn() uint32 { + if m != nil { + return m.SessionIn + } + return 0 +} + +func (m *CLUSMetry) GetSessionOut() uint32 { + if m != nil { + return m.SessionOut + } + return 0 +} + +func (m *CLUSMetry) GetSessionCurIn() uint32 { + if m != nil { + return m.SessionCurIn + } + return 0 +} + +func (m *CLUSMetry) GetSessionCurOut() uint32 { + if m != nil { + return m.SessionCurOut + } + return 0 +} + +func (m *CLUSMetry) GetPacketIn() uint64 { + if m != nil { + return m.PacketIn + } + return 0 +} + +func (m *CLUSMetry) GetPacketOut() uint64 { + if m != nil { + return m.PacketOut + } + return 0 +} + +func (m *CLUSMetry) GetByteIn() uint64 { + if m != nil { + return m.ByteIn + } + return 0 +} + +func (m *CLUSMetry) GetByteOut() uint64 { + if m != nil { + return m.ByteOut + } + return 0 +} + +type CLUSStats struct { + ReadAt int64 `protobuf:"varint,1,opt,name=ReadAt" json:"ReadAt,omitempty"` + Interval uint32 `protobuf:"varint,2,opt,name=Interval" json:"Interval,omitempty"` + Total *CLUSMetry `protobuf:"bytes,3,opt,name=Total" json:"Total,omitempty"` + Span1 *CLUSMetry `protobuf:"bytes,4,opt,name=Span1" json:"Span1,omitempty"` + Span12 *CLUSMetry `protobuf:"bytes,5,opt,name=Span12" json:"Span12,omitempty"` + Span60 *CLUSMetry `protobuf:"bytes,6,opt,name=Span60" json:"Span60,omitempty"` +} + +func (m *CLUSStats) Reset() { *m = CLUSStats{} } +func (m *CLUSStats) String() string { return proto.CompactTextString(m) } +func (*CLUSStats) ProtoMessage() {} +func (*CLUSStats) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *CLUSStats) GetReadAt() int64 { + if m != nil { + return m.ReadAt + } + return 0 +} + +func (m *CLUSStats) GetInterval() uint32 { + if m != nil { + return m.Interval + } + return 0 +} + +func (m *CLUSStats) GetTotal() *CLUSMetry { + if m != nil { + return m.Total + } + return nil +} + +func (m *CLUSStats) GetSpan1() *CLUSMetry { + if m != nil { + return m.Span1 + } + return nil +} + +func (m *CLUSStats) GetSpan12() *CLUSMetry { + if m != nil { + return m.Span12 + } + return nil +} + +func (m *CLUSStats) GetSpan60() *CLUSMetry { + if m != nil { + return m.Span60 + } + return nil +} + +func init() { + proto.RegisterType((*RPCVoid)(nil), "share.RPCVoid") + proto.RegisterType((*CLUSProfilingRequest)(nil), "share.CLUSProfilingRequest") + proto.RegisterType((*CLUSBoolean)(nil), "share.CLUSBoolean") + proto.RegisterType((*CLUSMetry)(nil), "share.CLUSMetry") + proto.RegisterType((*CLUSStats)(nil), "share.CLUSStats") + proto.RegisterEnum("share.ProfilingCmd", ProfilingCmd_name, ProfilingCmd_value) + proto.RegisterEnum("share.ProfilingMethod", ProfilingMethod_name, ProfilingMethod_value) +} + +func init() { proto.RegisterFile("common.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 455 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x53, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0xae, 0xeb, 0x26, 0x4e, 0xa6, 0x49, 0x30, 0x43, 0x55, 0x59, 0x08, 0xa1, 0xc8, 0x40, 0x65, + 0xf5, 0x10, 0x85, 0x20, 0x7a, 0xa7, 0xe6, 0x62, 0x89, 0x88, 0x68, 0x4d, 0x7b, 0x5f, 0xea, 0x85, + 0x5a, 0xd8, 0xbb, 0x61, 0xbd, 0x46, 0xca, 0x33, 0xf0, 0x24, 0x3c, 0x17, 0x2f, 0x82, 0x76, 0xfc, + 0x93, 0xb6, 0x2a, 0xb7, 0xf9, 0x7e, 0xc6, 0x9e, 0xfd, 0x76, 0x16, 0x26, 0x37, 0xaa, 0x2c, 0x95, + 0x5c, 0x6c, 0xb5, 0x32, 0x0a, 0x07, 0xd5, 0x2d, 0xd7, 0x22, 0x1c, 0x83, 0xc7, 0x36, 0xf1, 0xb5, + 0xca, 0xb3, 0xf0, 0xb7, 0x03, 0x27, 0xf1, 0xa7, 0xab, 0x74, 0xa3, 0xd5, 0xb7, 0xbc, 0xc8, 0xe5, + 0x77, 0x26, 0x7e, 0xd6, 0xa2, 0x32, 0xf8, 0x06, 0xdc, 0xb8, 0xcc, 0x02, 0x67, 0xee, 0x44, 0xb3, + 0xd5, 0xb3, 0x05, 0x35, 0x2e, 0x7a, 0x57, 0x5c, 0x66, 0xcc, 0xea, 0xb8, 0x04, 0x6f, 0x2d, 0xcc, + 0xad, 0xca, 0xaa, 0xe0, 0x70, 0xee, 0x46, 0xb3, 0xd5, 0xe9, 0x43, 0x6b, 0x23, 0xb3, 0xce, 0x86, + 0xcf, 0x61, 0xf4, 0xb1, 0xd6, 0xdc, 0xe4, 0x4a, 0x06, 0xee, 0xdc, 0x89, 0xa6, 0xac, 0xc7, 0xe1, + 0x2b, 0x38, 0xb6, 0xc3, 0x5c, 0x2a, 0x55, 0x08, 0x2e, 0xf1, 0x04, 0x06, 0xd7, 0xbc, 0xa8, 0x05, + 0x4d, 0x31, 0x62, 0x0d, 0x08, 0xff, 0x1c, 0xc2, 0xd8, 0xba, 0xd6, 0xc2, 0xe8, 0x1d, 0xfa, 0xe0, + 0xc6, 0x9b, 0x2b, 0x72, 0x38, 0xcc, 0x96, 0x78, 0x0a, 0xc3, 0xb5, 0x28, 0x95, 0xde, 0x05, 0x87, + 0x73, 0x27, 0x3a, 0x62, 0x2d, 0xc2, 0x17, 0x30, 0x4e, 0x45, 0x55, 0xe5, 0x4a, 0x26, 0xdd, 0x9f, + 0xf7, 0x04, 0xbe, 0x04, 0x68, 0xc1, 0xe7, 0xda, 0x04, 0x47, 0x24, 0xdf, 0x61, 0x30, 0x84, 0x49, + 0x8b, 0xe2, 0x5a, 0x27, 0x32, 0x18, 0x90, 0xe3, 0x1e, 0x87, 0xaf, 0x61, 0xba, 0xc7, 0xf6, 0x33, + 0x43, 0x32, 0xdd, 0x27, 0x6d, 0x00, 0x1b, 0x7e, 0xf3, 0x43, 0x98, 0x44, 0x06, 0x1e, 0x4d, 0xd8, + 0x63, 0x3b, 0x63, 0x53, 0xdb, 0xee, 0x11, 0x89, 0x7b, 0xc2, 0x9e, 0xec, 0x72, 0x67, 0x44, 0x22, + 0x83, 0x71, 0x73, 0xb2, 0x06, 0x61, 0x00, 0x9e, 0xad, 0x6c, 0x0f, 0x90, 0xd0, 0xc1, 0xf0, 0xaf, + 0xd3, 0x64, 0x95, 0x1a, 0x6e, 0x2a, 0xdb, 0xcf, 0x04, 0xcf, 0x3e, 0x18, 0x8a, 0xcb, 0x65, 0x2d, + 0xb2, 0x13, 0x25, 0xd2, 0x08, 0xfd, 0x8b, 0x17, 0x94, 0xd9, 0x94, 0xf5, 0x18, 0xcf, 0x60, 0xf0, + 0x45, 0x19, 0x5e, 0x50, 0x62, 0xc7, 0x2b, 0xbf, 0xbd, 0xde, 0xfe, 0x02, 0x58, 0x23, 0x5b, 0x5f, + 0xba, 0xe5, 0xf2, 0x2d, 0x45, 0xf7, 0xa8, 0x8f, 0x64, 0x8c, 0x60, 0x48, 0xc5, 0x8a, 0x12, 0x7c, + 0xcc, 0xd8, 0xea, 0x9d, 0xf3, 0x62, 0x49, 0x31, 0xfe, 0xd7, 0x79, 0xb1, 0x3c, 0x7f, 0x0f, 0x93, + 0xbb, 0x9b, 0x89, 0x08, 0xb3, 0xd4, 0x70, 0x6d, 0x7a, 0xd2, 0x3f, 0xc0, 0xa7, 0x30, 0x4d, 0x8d, + 0xda, 0xee, 0x29, 0xe7, 0xfc, 0x0c, 0x9e, 0x3c, 0xd8, 0x52, 0xf4, 0x68, 0x9b, 0xfc, 0x03, 0x84, + 0x6e, 0x89, 0x7c, 0xe7, 0xeb, 0x90, 0x1e, 0xcf, 0xbb, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x45, + 0xad, 0x79, 0xaa, 0x4c, 0x03, 0x00, 0x00, +} diff --git a/share/scan.pb.go b/share/scan.pb.go new file mode 100644 index 0000000..64c479e --- /dev/null +++ b/share/scan.pb.go @@ -0,0 +1,1033 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: scan.proto + +package share + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +type ScanErrorCode int32 + +const ( + ScanErrorCode_ScanErrNone ScanErrorCode = 0 + ScanErrorCode_ScanErrNetwork ScanErrorCode = 1 + ScanErrorCode_ScanErrNotSupport ScanErrorCode = 2 + ScanErrorCode_ScanErrSizeOverLimit ScanErrorCode = 3 + ScanErrorCode_ScanErrPackage ScanErrorCode = 4 + ScanErrorCode_ScanErrDatabase ScanErrorCode = 5 + ScanErrorCode_ScanErrTimeout ScanErrorCode = 6 + ScanErrorCode_ScanErrInProgress ScanErrorCode = 7 + ScanErrorCode_ScanErrRegistryAPI ScanErrorCode = 8 + ScanErrorCode_ScanErrFileSystem ScanErrorCode = 9 + ScanErrorCode_ScanErrContainerAPI ScanErrorCode = 10 + ScanErrorCode_ScanErrXrayAPI ScanErrorCode = 11 + ScanErrorCode_ScanErrContainerExit ScanErrorCode = 12 + ScanErrorCode_ScanErrAuthentication ScanErrorCode = 13 + ScanErrorCode_ScanErrCertificate ScanErrorCode = 14 + ScanErrorCode_ScanErrCanceled ScanErrorCode = 15 + ScanErrorCode_ScanErrDriverAPINotSupport ScanErrorCode = 16 + ScanErrorCode_ScanErrImageNotFound ScanErrorCode = 17 + ScanErrorCode_ScanErrAwsDownloadErr ScanErrorCode = 18 + ScanErrorCode_ScanErrArgument ScanErrorCode = 19 +) + +var ScanErrorCode_name = map[int32]string{ + 0: "ScanErrNone", + 1: "ScanErrNetwork", + 2: "ScanErrNotSupport", + 3: "ScanErrSizeOverLimit", + 4: "ScanErrPackage", + 5: "ScanErrDatabase", + 6: "ScanErrTimeout", + 7: "ScanErrInProgress", + 8: "ScanErrRegistryAPI", + 9: "ScanErrFileSystem", + 10: "ScanErrContainerAPI", + 11: "ScanErrXrayAPI", + 12: "ScanErrContainerExit", + 13: "ScanErrAuthentication", + 14: "ScanErrCertificate", + 15: "ScanErrCanceled", + 16: "ScanErrDriverAPINotSupport", + 17: "ScanErrImageNotFound", + 18: "ScanErrAwsDownloadErr", + 19: "ScanErrArgument", +} +var ScanErrorCode_value = map[string]int32{ + "ScanErrNone": 0, + "ScanErrNetwork": 1, + "ScanErrNotSupport": 2, + "ScanErrSizeOverLimit": 3, + "ScanErrPackage": 4, + "ScanErrDatabase": 5, + "ScanErrTimeout": 6, + "ScanErrInProgress": 7, + "ScanErrRegistryAPI": 8, + "ScanErrFileSystem": 9, + "ScanErrContainerAPI": 10, + "ScanErrXrayAPI": 11, + "ScanErrContainerExit": 12, + "ScanErrAuthentication": 13, + "ScanErrCertificate": 14, + "ScanErrCanceled": 15, + "ScanErrDriverAPINotSupport": 16, + "ScanErrImageNotFound": 17, + "ScanErrAwsDownloadErr": 18, + "ScanErrArgument": 19, +} + +func (x ScanErrorCode) String() string { + return proto.EnumName(ScanErrorCode_name, int32(x)) +} +func (ScanErrorCode) EnumDescriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } + +type ScanObjectType int32 + +const ( + ScanObjectType_CONTAINER ScanObjectType = 0 + ScanObjectType_HOST ScanObjectType = 1 + ScanObjectType_IMAGE ScanObjectType = 2 + ScanObjectType_PLATFORM ScanObjectType = 3 + ScanObjectType_SERVERLESS ScanObjectType = 4 +) + +var ScanObjectType_name = map[int32]string{ + 0: "CONTAINER", + 1: "HOST", + 2: "IMAGE", + 3: "PLATFORM", + 4: "SERVERLESS", +} +var ScanObjectType_value = map[string]int32{ + "CONTAINER": 0, + "HOST": 1, + "IMAGE": 2, + "PLATFORM": 3, + "SERVERLESS": 4, +} + +func (x ScanObjectType) String() string { + return proto.EnumName(ScanObjectType_name, int32(x)) +} +func (ScanObjectType) EnumDescriptor() ([]byte, []int) { return fileDescriptor3, []int{1} } + +type ScanProvider int32 + +const ( + ScanProvider_Neuvector ScanProvider = 0 + ScanProvider_JFrogXray ScanProvider = 1 +) + +var ScanProvider_name = map[int32]string{ + 0: "Neuvector", + 1: "JFrogXray", +} +var ScanProvider_value = map[string]int32{ + "Neuvector": 0, + "JFrogXray": 1, +} + +func (x ScanProvider) String() string { + return proto.EnumName(ScanProvider_name, int32(x)) +} +func (ScanProvider) EnumDescriptor() ([]byte, []int) { return fileDescriptor3, []int{2} } + +type ScanVulStatus int32 + +const ( + ScanVulStatus_Unpatched ScanVulStatus = 0 + ScanVulStatus_FixExists ScanVulStatus = 1 + ScanVulStatus_WillNotFix ScanVulStatus = 2 + ScanVulStatus_Unaffected ScanVulStatus = 3 +) + +var ScanVulStatus_name = map[int32]string{ + 0: "Unpatched", + 1: "FixExists", + 2: "WillNotFix", + 3: "Unaffected", +} +var ScanVulStatus_value = map[string]int32{ + "Unpatched": 0, + "FixExists": 1, + "WillNotFix": 2, + "Unaffected": 3, +} + +func (x ScanVulStatus) String() string { + return proto.EnumName(ScanVulStatus_name, int32(x)) +} +func (ScanVulStatus) EnumDescriptor() ([]byte, []int) { return fileDescriptor3, []int{3} } + +type ScanVulnerability struct { + Name string `protobuf:"bytes,1,opt,name=Name" json:"Name,omitempty"` + Score float32 `protobuf:"fixed32,2,opt,name=Score" json:"Score,omitempty"` + Severity string `protobuf:"bytes,3,opt,name=Severity" json:"Severity,omitempty"` + Description string `protobuf:"bytes,4,opt,name=Description" json:"Description,omitempty"` + PackageName string `protobuf:"bytes,5,opt,name=PackageName" json:"PackageName,omitempty"` + PackageVersion string `protobuf:"bytes,6,opt,name=PackageVersion" json:"PackageVersion,omitempty"` + FixedVersion string `protobuf:"bytes,7,opt,name=FixedVersion" json:"FixedVersion,omitempty"` + Link string `protobuf:"bytes,8,opt,name=Link" json:"Link,omitempty"` + Vectors string `protobuf:"bytes,9,opt,name=Vectors" json:"Vectors,omitempty"` + ScoreV3 float32 `protobuf:"fixed32,10,opt,name=ScoreV3" json:"ScoreV3,omitempty"` + VectorsV3 string `protobuf:"bytes,11,opt,name=VectorsV3" json:"VectorsV3,omitempty"` + PublishedDate string `protobuf:"bytes,12,opt,name=PublishedDate" json:"PublishedDate,omitempty"` + LastModifiedDate string `protobuf:"bytes,13,opt,name=LastModifiedDate" json:"LastModifiedDate,omitempty"` + CPEs []string `protobuf:"bytes,14,rep,name=CPEs" json:"CPEs,omitempty"` + CVEs []string `protobuf:"bytes,15,rep,name=CVEs" json:"CVEs,omitempty"` + FeedRating string `protobuf:"bytes,16,opt,name=FeedRating" json:"FeedRating,omitempty"` + InBase bool `protobuf:"varint,17,opt,name=InBase" json:"InBase,omitempty"` + DBKey string `protobuf:"bytes,18,opt,name=DBKey" json:"DBKey,omitempty"` +} + +func (m *ScanVulnerability) Reset() { *m = ScanVulnerability{} } +func (m *ScanVulnerability) String() string { return proto.CompactTextString(m) } +func (*ScanVulnerability) ProtoMessage() {} +func (*ScanVulnerability) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } + +func (m *ScanVulnerability) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *ScanVulnerability) GetScore() float32 { + if m != nil { + return m.Score + } + return 0 +} + +func (m *ScanVulnerability) GetSeverity() string { + if m != nil { + return m.Severity + } + return "" +} + +func (m *ScanVulnerability) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *ScanVulnerability) GetPackageName() string { + if m != nil { + return m.PackageName + } + return "" +} + +func (m *ScanVulnerability) GetPackageVersion() string { + if m != nil { + return m.PackageVersion + } + return "" +} + +func (m *ScanVulnerability) GetFixedVersion() string { + if m != nil { + return m.FixedVersion + } + return "" +} + +func (m *ScanVulnerability) GetLink() string { + if m != nil { + return m.Link + } + return "" +} + +func (m *ScanVulnerability) GetVectors() string { + if m != nil { + return m.Vectors + } + return "" +} + +func (m *ScanVulnerability) GetScoreV3() float32 { + if m != nil { + return m.ScoreV3 + } + return 0 +} + +func (m *ScanVulnerability) GetVectorsV3() string { + if m != nil { + return m.VectorsV3 + } + return "" +} + +func (m *ScanVulnerability) GetPublishedDate() string { + if m != nil { + return m.PublishedDate + } + return "" +} + +func (m *ScanVulnerability) GetLastModifiedDate() string { + if m != nil { + return m.LastModifiedDate + } + return "" +} + +func (m *ScanVulnerability) GetCPEs() []string { + if m != nil { + return m.CPEs + } + return nil +} + +func (m *ScanVulnerability) GetCVEs() []string { + if m != nil { + return m.CVEs + } + return nil +} + +func (m *ScanVulnerability) GetFeedRating() string { + if m != nil { + return m.FeedRating + } + return "" +} + +func (m *ScanVulnerability) GetInBase() bool { + if m != nil { + return m.InBase + } + return false +} + +func (m *ScanVulnerability) GetDBKey() string { + if m != nil { + return m.DBKey + } + return "" +} + +type ScanLayerResult struct { + Digest string `protobuf:"bytes,1,opt,name=Digest" json:"Digest,omitempty"` + Vuls []*ScanVulnerability `protobuf:"bytes,2,rep,name=Vuls" json:"Vuls,omitempty"` + Cmds string `protobuf:"bytes,3,opt,name=Cmds" json:"Cmds,omitempty"` + Size int64 `protobuf:"varint,4,opt,name=Size" json:"Size,omitempty"` + Secrets *ScanSecretResult `protobuf:"bytes,5,opt,name=Secrets" json:"Secrets,omitempty"` +} + +func (m *ScanLayerResult) Reset() { *m = ScanLayerResult{} } +func (m *ScanLayerResult) String() string { return proto.CompactTextString(m) } +func (*ScanLayerResult) ProtoMessage() {} +func (*ScanLayerResult) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{1} } + +func (m *ScanLayerResult) GetDigest() string { + if m != nil { + return m.Digest + } + return "" +} + +func (m *ScanLayerResult) GetVuls() []*ScanVulnerability { + if m != nil { + return m.Vuls + } + return nil +} + +func (m *ScanLayerResult) GetCmds() string { + if m != nil { + return m.Cmds + } + return "" +} + +func (m *ScanLayerResult) GetSize() int64 { + if m != nil { + return m.Size + } + return 0 +} + +func (m *ScanLayerResult) GetSecrets() *ScanSecretResult { + if m != nil { + return m.Secrets + } + return nil +} + +type ScanModule struct { + Name string `protobuf:"bytes,1,opt,name=Name" json:"Name,omitempty"` + Version string `protobuf:"bytes,2,opt,name=Version" json:"Version,omitempty"` + Source string `protobuf:"bytes,3,opt,name=Source" json:"Source,omitempty"` + Vuls []*ScanModuleVul `protobuf:"bytes,4,rep,name=Vuls" json:"Vuls,omitempty"` + CPEs []string `protobuf:"bytes,5,rep,name=CPEs" json:"CPEs,omitempty"` +} + +func (m *ScanModule) Reset() { *m = ScanModule{} } +func (m *ScanModule) String() string { return proto.CompactTextString(m) } +func (*ScanModule) ProtoMessage() {} +func (*ScanModule) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{2} } + +func (m *ScanModule) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *ScanModule) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *ScanModule) GetSource() string { + if m != nil { + return m.Source + } + return "" +} + +func (m *ScanModule) GetVuls() []*ScanModuleVul { + if m != nil { + return m.Vuls + } + return nil +} + +func (m *ScanModule) GetCPEs() []string { + if m != nil { + return m.CPEs + } + return nil +} + +type ScanModuleVul struct { + Name string `protobuf:"bytes,1,opt,name=Name" json:"Name,omitempty"` + Status ScanVulStatus `protobuf:"varint,2,opt,name=Status,enum=share.ScanVulStatus" json:"Status,omitempty"` +} + +func (m *ScanModuleVul) Reset() { *m = ScanModuleVul{} } +func (m *ScanModuleVul) String() string { return proto.CompactTextString(m) } +func (*ScanModuleVul) ProtoMessage() {} +func (*ScanModuleVul) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{3} } + +func (m *ScanModuleVul) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *ScanModuleVul) GetStatus() ScanVulStatus { + if m != nil { + return m.Status + } + return ScanVulStatus_Unpatched +} + +type ScanSecretLog struct { + Type string `protobuf:"bytes,1,opt,name=Type" json:"Type,omitempty"` + Text string `protobuf:"bytes,2,opt,name=Text" json:"Text,omitempty"` + File string `protobuf:"bytes,3,opt,name=File" json:"File,omitempty"` + RuleDesc string `protobuf:"bytes,4,opt,name=RuleDesc" json:"RuleDesc,omitempty"` + Suggestion string `protobuf:"bytes,5,opt,name=Suggestion" json:"Suggestion,omitempty"` +} + +func (m *ScanSecretLog) Reset() { *m = ScanSecretLog{} } +func (m *ScanSecretLog) String() string { return proto.CompactTextString(m) } +func (*ScanSecretLog) ProtoMessage() {} +func (*ScanSecretLog) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{4} } + +func (m *ScanSecretLog) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *ScanSecretLog) GetText() string { + if m != nil { + return m.Text + } + return "" +} + +func (m *ScanSecretLog) GetFile() string { + if m != nil { + return m.File + } + return "" +} + +func (m *ScanSecretLog) GetRuleDesc() string { + if m != nil { + return m.RuleDesc + } + return "" +} + +func (m *ScanSecretLog) GetSuggestion() string { + if m != nil { + return m.Suggestion + } + return "" +} + +type ScanSecretResult struct { + Error ScanErrorCode `protobuf:"varint,1,opt,name=Error,enum=share.ScanErrorCode" json:"Error,omitempty"` + Logs []*ScanSecretLog `protobuf:"bytes,2,rep,name=Logs" json:"Logs,omitempty"` +} + +func (m *ScanSecretResult) Reset() { *m = ScanSecretResult{} } +func (m *ScanSecretResult) String() string { return proto.CompactTextString(m) } +func (*ScanSecretResult) ProtoMessage() {} +func (*ScanSecretResult) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{5} } + +func (m *ScanSecretResult) GetError() ScanErrorCode { + if m != nil { + return m.Error + } + return ScanErrorCode_ScanErrNone +} + +func (m *ScanSecretResult) GetLogs() []*ScanSecretLog { + if m != nil { + return m.Logs + } + return nil +} + +type ScanSetIdPermLog struct { + Type string `protobuf:"bytes,1,opt,name=Type" json:"Type,omitempty"` + File string `protobuf:"bytes,2,opt,name=File" json:"File,omitempty"` + Evidence string `protobuf:"bytes,3,opt,name=Evidence" json:"Evidence,omitempty"` +} + +func (m *ScanSetIdPermLog) Reset() { *m = ScanSetIdPermLog{} } +func (m *ScanSetIdPermLog) String() string { return proto.CompactTextString(m) } +func (*ScanSetIdPermLog) ProtoMessage() {} +func (*ScanSetIdPermLog) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{6} } + +func (m *ScanSetIdPermLog) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *ScanSetIdPermLog) GetFile() string { + if m != nil { + return m.File + } + return "" +} + +func (m *ScanSetIdPermLog) GetEvidence() string { + if m != nil { + return m.Evidence + } + return "" +} + +type ScanResult struct { + Version string `protobuf:"bytes,1,opt,name=Version" json:"Version,omitempty"` + Error ScanErrorCode `protobuf:"varint,2,opt,name=Error,enum=share.ScanErrorCode" json:"Error,omitempty"` + Namespace string `protobuf:"bytes,3,opt,name=Namespace" json:"Namespace,omitempty"` + Vuls []*ScanVulnerability `protobuf:"bytes,4,rep,name=Vuls" json:"Vuls,omitempty"` + ContainerID string `protobuf:"bytes,5,opt,name=ContainerID" json:"ContainerID,omitempty"` + HostID string `protobuf:"bytes,6,opt,name=HostID" json:"HostID,omitempty"` + Registry string `protobuf:"bytes,7,opt,name=Registry" json:"Registry,omitempty"` + Repository string `protobuf:"bytes,8,opt,name=Repository" json:"Repository,omitempty"` + Tag string `protobuf:"bytes,9,opt,name=Tag" json:"Tag,omitempty"` + Digest string `protobuf:"bytes,10,opt,name=Digest" json:"Digest,omitempty"` + ImageID string `protobuf:"bytes,11,opt,name=ImageID" json:"ImageID,omitempty"` + Layers []*ScanLayerResult `protobuf:"bytes,12,rep,name=Layers" json:"Layers,omitempty"` + Envs []string `protobuf:"bytes,13,rep,name=Envs" json:"Envs,omitempty"` + Labels map[string]string `protobuf:"bytes,14,rep,name=Labels" json:"Labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Platform string `protobuf:"bytes,15,opt,name=Platform" json:"Platform,omitempty"` + PlatformVersion string `protobuf:"bytes,16,opt,name=PlatformVersion" json:"PlatformVersion,omitempty"` + Author string `protobuf:"bytes,17,opt,name=Author" json:"Author,omitempty"` + CVEDBCreateTime string `protobuf:"bytes,18,opt,name=CVEDBCreateTime" json:"CVEDBCreateTime,omitempty"` + Modules []*ScanModule `protobuf:"bytes,19,rep,name=Modules" json:"Modules,omitempty"` + Secrets *ScanSecretResult `protobuf:"bytes,20,opt,name=Secrets" json:"Secrets,omitempty"` + Cmds []string `protobuf:"bytes,21,rep,name=Cmds" json:"Cmds,omitempty"` + SetIdPerms []*ScanSetIdPermLog `protobuf:"bytes,22,rep,name=SetIdPerms" json:"SetIdPerms,omitempty"` + Provider ScanProvider `protobuf:"varint,23,opt,name=Provider,enum=share.ScanProvider" json:"Provider,omitempty"` + Size int64 `protobuf:"varint,24,opt,name=Size" json:"Size,omitempty"` +} + +func (m *ScanResult) Reset() { *m = ScanResult{} } +func (m *ScanResult) String() string { return proto.CompactTextString(m) } +func (*ScanResult) ProtoMessage() {} +func (*ScanResult) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{7} } + +func (m *ScanResult) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *ScanResult) GetError() ScanErrorCode { + if m != nil { + return m.Error + } + return ScanErrorCode_ScanErrNone +} + +func (m *ScanResult) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *ScanResult) GetVuls() []*ScanVulnerability { + if m != nil { + return m.Vuls + } + return nil +} + +func (m *ScanResult) GetContainerID() string { + if m != nil { + return m.ContainerID + } + return "" +} + +func (m *ScanResult) GetHostID() string { + if m != nil { + return m.HostID + } + return "" +} + +func (m *ScanResult) GetRegistry() string { + if m != nil { + return m.Registry + } + return "" +} + +func (m *ScanResult) GetRepository() string { + if m != nil { + return m.Repository + } + return "" +} + +func (m *ScanResult) GetTag() string { + if m != nil { + return m.Tag + } + return "" +} + +func (m *ScanResult) GetDigest() string { + if m != nil { + return m.Digest + } + return "" +} + +func (m *ScanResult) GetImageID() string { + if m != nil { + return m.ImageID + } + return "" +} + +func (m *ScanResult) GetLayers() []*ScanLayerResult { + if m != nil { + return m.Layers + } + return nil +} + +func (m *ScanResult) GetEnvs() []string { + if m != nil { + return m.Envs + } + return nil +} + +func (m *ScanResult) GetLabels() map[string]string { + if m != nil { + return m.Labels + } + return nil +} + +func (m *ScanResult) GetPlatform() string { + if m != nil { + return m.Platform + } + return "" +} + +func (m *ScanResult) GetPlatformVersion() string { + if m != nil { + return m.PlatformVersion + } + return "" +} + +func (m *ScanResult) GetAuthor() string { + if m != nil { + return m.Author + } + return "" +} + +func (m *ScanResult) GetCVEDBCreateTime() string { + if m != nil { + return m.CVEDBCreateTime + } + return "" +} + +func (m *ScanResult) GetModules() []*ScanModule { + if m != nil { + return m.Modules + } + return nil +} + +func (m *ScanResult) GetSecrets() *ScanSecretResult { + if m != nil { + return m.Secrets + } + return nil +} + +func (m *ScanResult) GetCmds() []string { + if m != nil { + return m.Cmds + } + return nil +} + +func (m *ScanResult) GetSetIdPerms() []*ScanSetIdPermLog { + if m != nil { + return m.SetIdPerms + } + return nil +} + +func (m *ScanResult) GetProvider() ScanProvider { + if m != nil { + return m.Provider + } + return ScanProvider_Neuvector +} + +func (m *ScanResult) GetSize() int64 { + if m != nil { + return m.Size + } + return 0 +} + +type ScanRunningRequest struct { + Type ScanObjectType `protobuf:"varint,1,opt,name=Type,enum=share.ScanObjectType" json:"Type,omitempty"` + ID string `protobuf:"bytes,2,opt,name=ID" json:"ID,omitempty"` + AgentID string `protobuf:"bytes,3,opt,name=AgentID" json:"AgentID,omitempty"` + AgentRPCEndPoint string `protobuf:"bytes,4,opt,name=AgentRPCEndPoint" json:"AgentRPCEndPoint,omitempty"` +} + +func (m *ScanRunningRequest) Reset() { *m = ScanRunningRequest{} } +func (m *ScanRunningRequest) String() string { return proto.CompactTextString(m) } +func (*ScanRunningRequest) ProtoMessage() {} +func (*ScanRunningRequest) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{8} } + +func (m *ScanRunningRequest) GetType() ScanObjectType { + if m != nil { + return m.Type + } + return ScanObjectType_CONTAINER +} + +func (m *ScanRunningRequest) GetID() string { + if m != nil { + return m.ID + } + return "" +} + +func (m *ScanRunningRequest) GetAgentID() string { + if m != nil { + return m.AgentID + } + return "" +} + +func (m *ScanRunningRequest) GetAgentRPCEndPoint() string { + if m != nil { + return m.AgentRPCEndPoint + } + return "" +} + +type ScanData struct { + Error ScanErrorCode `protobuf:"varint,1,opt,name=Error,enum=share.ScanErrorCode" json:"Error,omitempty"` + Buffer []byte `protobuf:"bytes,2,opt,name=Buffer,proto3" json:"Buffer,omitempty"` +} + +func (m *ScanData) Reset() { *m = ScanData{} } +func (m *ScanData) String() string { return proto.CompactTextString(m) } +func (*ScanData) ProtoMessage() {} +func (*ScanData) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{9} } + +func (m *ScanData) GetError() ScanErrorCode { + if m != nil { + return m.Error + } + return ScanErrorCode_ScanErrNone +} + +func (m *ScanData) GetBuffer() []byte { + if m != nil { + return m.Buffer + } + return nil +} + +type ScanAppPackage struct { + AppName string `protobuf:"bytes,1,opt,name=AppName" json:"AppName,omitempty"` + ModuleName string `protobuf:"bytes,2,opt,name=ModuleName" json:"ModuleName,omitempty"` + Version string `protobuf:"bytes,3,opt,name=Version" json:"Version,omitempty"` + FileName string `protobuf:"bytes,4,opt,name=FileName" json:"FileName,omitempty"` +} + +func (m *ScanAppPackage) Reset() { *m = ScanAppPackage{} } +func (m *ScanAppPackage) String() string { return proto.CompactTextString(m) } +func (*ScanAppPackage) ProtoMessage() {} +func (*ScanAppPackage) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{10} } + +func (m *ScanAppPackage) GetAppName() string { + if m != nil { + return m.AppName + } + return "" +} + +func (m *ScanAppPackage) GetModuleName() string { + if m != nil { + return m.ModuleName + } + return "" +} + +func (m *ScanAppPackage) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *ScanAppPackage) GetFileName() string { + if m != nil { + return m.FileName + } + return "" +} + +type ScanAppRequest struct { + Packages []*ScanAppPackage `protobuf:"bytes,1,rep,name=Packages" json:"Packages,omitempty"` +} + +func (m *ScanAppRequest) Reset() { *m = ScanAppRequest{} } +func (m *ScanAppRequest) String() string { return proto.CompactTextString(m) } +func (*ScanAppRequest) ProtoMessage() {} +func (*ScanAppRequest) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{11} } + +func (m *ScanAppRequest) GetPackages() []*ScanAppPackage { + if m != nil { + return m.Packages + } + return nil +} + +type ScanAwsLambdaRequest struct { + ResType string `protobuf:"bytes,1,opt,name=ResType" json:"ResType,omitempty"` + FuncName string `protobuf:"bytes,2,opt,name=FuncName" json:"FuncName,omitempty"` + Region string `protobuf:"bytes,3,opt,name=Region" json:"Region,omitempty"` + FuncLink string `protobuf:"bytes,4,opt,name=FuncLink" json:"FuncLink,omitempty"` + ScanSecrets bool `protobuf:"varint,5,opt,name=ScanSecrets" json:"ScanSecrets,omitempty"` +} + +func (m *ScanAwsLambdaRequest) Reset() { *m = ScanAwsLambdaRequest{} } +func (m *ScanAwsLambdaRequest) String() string { return proto.CompactTextString(m) } +func (*ScanAwsLambdaRequest) ProtoMessage() {} +func (*ScanAwsLambdaRequest) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{12} } + +func (m *ScanAwsLambdaRequest) GetResType() string { + if m != nil { + return m.ResType + } + return "" +} + +func (m *ScanAwsLambdaRequest) GetFuncName() string { + if m != nil { + return m.FuncName + } + return "" +} + +func (m *ScanAwsLambdaRequest) GetRegion() string { + if m != nil { + return m.Region + } + return "" +} + +func (m *ScanAwsLambdaRequest) GetFuncLink() string { + if m != nil { + return m.FuncLink + } + return "" +} + +func (m *ScanAwsLambdaRequest) GetScanSecrets() bool { + if m != nil { + return m.ScanSecrets + } + return false +} + +func init() { + proto.RegisterType((*ScanVulnerability)(nil), "share.ScanVulnerability") + proto.RegisterType((*ScanLayerResult)(nil), "share.ScanLayerResult") + proto.RegisterType((*ScanModule)(nil), "share.ScanModule") + proto.RegisterType((*ScanModuleVul)(nil), "share.ScanModuleVul") + proto.RegisterType((*ScanSecretLog)(nil), "share.ScanSecretLog") + proto.RegisterType((*ScanSecretResult)(nil), "share.ScanSecretResult") + proto.RegisterType((*ScanSetIdPermLog)(nil), "share.ScanSetIdPermLog") + proto.RegisterType((*ScanResult)(nil), "share.ScanResult") + proto.RegisterType((*ScanRunningRequest)(nil), "share.ScanRunningRequest") + proto.RegisterType((*ScanData)(nil), "share.ScanData") + proto.RegisterType((*ScanAppPackage)(nil), "share.ScanAppPackage") + proto.RegisterType((*ScanAppRequest)(nil), "share.ScanAppRequest") + proto.RegisterType((*ScanAwsLambdaRequest)(nil), "share.ScanAwsLambdaRequest") + proto.RegisterEnum("share.ScanErrorCode", ScanErrorCode_name, ScanErrorCode_value) + proto.RegisterEnum("share.ScanObjectType", ScanObjectType_name, ScanObjectType_value) + proto.RegisterEnum("share.ScanProvider", ScanProvider_name, ScanProvider_value) + proto.RegisterEnum("share.ScanVulStatus", ScanVulStatus_name, ScanVulStatus_value) +} + +func init() { proto.RegisterFile("scan.proto", fileDescriptor3) } + +var fileDescriptor3 = []byte{ + // 1539 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0x4b, 0x73, 0xe3, 0xb8, + 0x11, 0x1e, 0x4a, 0xb2, 0x1e, 0x90, 0x2d, 0xc3, 0xf0, 0x63, 0x18, 0xd7, 0x64, 0x4a, 0xa5, 0x4a, + 0xa5, 0x1c, 0x67, 0xca, 0xa9, 0xf1, 0x54, 0x2a, 0x8f, 0x9b, 0x2c, 0xd1, 0x19, 0x25, 0xb2, 0xad, + 0x50, 0x1e, 0x25, 0x57, 0x58, 0x84, 0x65, 0xc4, 0x14, 0xa9, 0x00, 0xa0, 0x6d, 0xe5, 0x94, 0x5b, + 0x72, 0xdc, 0xcb, 0xd6, 0xde, 0xf7, 0x27, 0xec, 0x3f, 0xda, 0x7f, 0xb2, 0xd5, 0x00, 0x48, 0x41, + 0xf6, 0xd4, 0xee, 0xec, 0x0d, 0xfd, 0x40, 0xa3, 0x3f, 0x74, 0xf7, 0x47, 0x10, 0x21, 0x39, 0xa5, + 0xc9, 0xc9, 0x42, 0xa4, 0x2a, 0x25, 0x1b, 0xf2, 0x8e, 0x0a, 0xd6, 0xf9, 0xa6, 0x82, 0x76, 0xc6, + 0x53, 0x9a, 0x4c, 0xb2, 0x38, 0x61, 0x82, 0xde, 0xf0, 0x98, 0xab, 0x25, 0x21, 0xa8, 0x72, 0x49, + 0xe7, 0xcc, 0xf7, 0xda, 0xde, 0x51, 0x23, 0xd4, 0x6b, 0xb2, 0x87, 0x36, 0xc6, 0xd3, 0x54, 0x30, + 0xbf, 0xd4, 0xf6, 0x8e, 0x4a, 0xa1, 0x11, 0xc8, 0x21, 0xaa, 0x8f, 0xd9, 0x03, 0x13, 0x5c, 0x2d, + 0xfd, 0xb2, 0xf6, 0x2e, 0x64, 0xd2, 0x46, 0xcd, 0x3e, 0x93, 0x53, 0xc1, 0x17, 0x8a, 0xa7, 0x89, + 0x5f, 0xd1, 0x66, 0x57, 0x05, 0x1e, 0x23, 0x3a, 0xbd, 0xa7, 0x33, 0xa6, 0x8f, 0xdb, 0x30, 0x1e, + 0x8e, 0x8a, 0xfc, 0x1a, 0xb5, 0xac, 0x38, 0x61, 0x42, 0x42, 0x98, 0xaa, 0x76, 0x7a, 0xa6, 0x25, + 0x1d, 0xb4, 0x79, 0xce, 0x9f, 0x58, 0x94, 0x7b, 0xd5, 0xb4, 0xd7, 0x9a, 0x0e, 0x50, 0x0d, 0x79, + 0x72, 0xef, 0xd7, 0x0d, 0x2a, 0x58, 0x13, 0x1f, 0xd5, 0x26, 0x6c, 0xaa, 0x52, 0x21, 0xfd, 0x86, + 0x56, 0xe7, 0x22, 0x58, 0x34, 0xc4, 0xc9, 0x07, 0x1f, 0x69, 0xc4, 0xb9, 0x48, 0xde, 0xa0, 0x86, + 0x75, 0x9a, 0x7c, 0xf0, 0x9b, 0x7a, 0xd7, 0x4a, 0x41, 0x7e, 0x85, 0xb6, 0x46, 0xd9, 0x4d, 0xcc, + 0xe5, 0x1d, 0x8b, 0xfa, 0x54, 0x31, 0x7f, 0x53, 0x7b, 0xac, 0x2b, 0xc9, 0x31, 0xc2, 0x43, 0x2a, + 0xd5, 0x45, 0x1a, 0xf1, 0x5b, 0x6e, 0x1d, 0xb7, 0xb4, 0xe3, 0x0b, 0x3d, 0xe4, 0xdd, 0x1b, 0x05, + 0xd2, 0x6f, 0xb5, 0xcb, 0x90, 0x37, 0xac, 0xb5, 0x6e, 0x12, 0x48, 0x7f, 0xdb, 0xea, 0x26, 0x81, + 0x24, 0x6f, 0x11, 0x3a, 0x67, 0x2c, 0x0a, 0xa9, 0xe2, 0xc9, 0xcc, 0xc7, 0x3a, 0x9a, 0xa3, 0x21, + 0x07, 0xa8, 0x3a, 0x48, 0xce, 0xa8, 0x64, 0xfe, 0x4e, 0xdb, 0x3b, 0xaa, 0x87, 0x56, 0x82, 0xca, + 0xf6, 0xcf, 0xfe, 0xc6, 0x96, 0x3e, 0xd1, 0x5b, 0x8c, 0xd0, 0xf9, 0xce, 0x43, 0xdb, 0xd0, 0x19, + 0x43, 0xba, 0x64, 0x22, 0x64, 0x32, 0x8b, 0x15, 0x44, 0xe8, 0xf3, 0x19, 0x93, 0xca, 0x76, 0x86, + 0x95, 0xc8, 0x3b, 0x54, 0x99, 0x64, 0xb1, 0xf4, 0x4b, 0xed, 0xf2, 0x51, 0xf3, 0xd4, 0x3f, 0xd1, + 0xbd, 0x75, 0xf2, 0xa2, 0xaf, 0x42, 0xed, 0xa5, 0x73, 0x9f, 0x47, 0xd2, 0xf6, 0x8b, 0x5e, 0x83, + 0x6e, 0xcc, 0xff, 0xc3, 0x74, 0x93, 0x94, 0x43, 0xbd, 0x26, 0xef, 0x51, 0x6d, 0xcc, 0xa6, 0x82, + 0x29, 0xa9, 0x3b, 0xa3, 0x79, 0xfa, 0xda, 0x09, 0x6c, 0x2c, 0x26, 0xaf, 0x30, 0xf7, 0xeb, 0x7c, + 0xe5, 0x21, 0x04, 0xd6, 0x8b, 0x34, 0xca, 0x62, 0xf6, 0xd9, 0x3e, 0xd6, 0x15, 0x37, 0x4d, 0x52, + 0xca, 0x2b, 0x6e, 0xfa, 0xe3, 0x00, 0x55, 0xc7, 0x69, 0x26, 0xa6, 0xcc, 0x66, 0x66, 0x25, 0x72, + 0x64, 0xd1, 0x55, 0x34, 0xba, 0x3d, 0x27, 0x09, 0x73, 0xcc, 0x24, 0x8b, 0x1d, 0x64, 0x50, 0xa9, + 0x8d, 0x55, 0xa5, 0x3a, 0x7f, 0x47, 0x5b, 0x6b, 0xae, 0x9f, 0x4d, 0xea, 0x1d, 0xaa, 0x8e, 0x15, + 0x55, 0x99, 0xd4, 0x39, 0xb5, 0xd6, 0x0e, 0x99, 0x64, 0xb1, 0xb1, 0x85, 0xd6, 0xa7, 0xf3, 0x3f, + 0xcf, 0xc4, 0x34, 0xa8, 0x87, 0xe9, 0x0c, 0x62, 0x5e, 0x2f, 0x17, 0x45, 0x4c, 0x58, 0x6b, 0x1d, + 0x7b, 0x52, 0x16, 0xa5, 0x5e, 0x83, 0xee, 0x9c, 0xc7, 0x39, 0x40, 0xbd, 0x86, 0x11, 0x0e, 0xb3, + 0x98, 0xc1, 0x5c, 0xda, 0x19, 0x2d, 0x64, 0x68, 0xa9, 0x71, 0x36, 0x83, 0x1a, 0xc3, 0x7d, 0x99, + 0xf9, 0x74, 0x34, 0x9d, 0x3b, 0x84, 0x9f, 0x17, 0x83, 0x1c, 0xa3, 0x8d, 0x40, 0x88, 0x54, 0xe8, + 0x64, 0xd6, 0xa1, 0x68, 0x7d, 0x2f, 0x8d, 0x58, 0x68, 0x5c, 0xe0, 0x6a, 0x87, 0xe9, 0x2c, 0x6f, + 0x9c, 0xbd, 0x17, 0xf5, 0x1d, 0xa6, 0xb3, 0x50, 0x7b, 0x74, 0x26, 0xf9, 0x49, 0x6a, 0x10, 0x8d, + 0x98, 0x98, 0xff, 0x08, 0x6a, 0x8d, 0xb0, 0xb4, 0x8e, 0x30, 0x78, 0xe0, 0x11, 0x4b, 0x8a, 0xd2, + 0x16, 0x72, 0xe7, 0xff, 0x35, 0xd3, 0x31, 0x36, 0x79, 0xa7, 0x3b, 0xbc, 0xf5, 0xee, 0x28, 0x60, + 0x95, 0x7e, 0x1a, 0xd6, 0x1b, 0xd4, 0x80, 0xb2, 0xca, 0x05, 0x2d, 0x4e, 0x5c, 0x29, 0x8a, 0x69, + 0xa9, 0x7c, 0xd1, 0xb4, 0xb4, 0x51, 0xb3, 0x97, 0x26, 0x8a, 0xf2, 0x84, 0x89, 0x41, 0x3f, 0xe7, + 0x48, 0x47, 0x05, 0x7d, 0xfb, 0x31, 0x95, 0x6a, 0xd0, 0xb7, 0xdc, 0x68, 0x25, 0x5d, 0x58, 0x36, + 0xe3, 0x52, 0x89, 0xa5, 0xe5, 0xc3, 0x42, 0x86, 0xc2, 0x86, 0x6c, 0x91, 0x4a, 0xae, 0x52, 0xb1, + 0xb4, 0x8c, 0xe8, 0x68, 0x08, 0x46, 0xe5, 0x6b, 0x3a, 0xb3, 0x9c, 0x08, 0x4b, 0x67, 0xf6, 0xd1, + 0xda, 0xec, 0xfb, 0xa8, 0x36, 0x98, 0xd3, 0x19, 0x1b, 0xf4, 0x2d, 0x17, 0xe6, 0x22, 0x39, 0x41, + 0x55, 0x4d, 0x1e, 0xd2, 0xdf, 0xd4, 0x48, 0x0f, 0x1c, 0xa4, 0x0e, 0xab, 0x84, 0xd6, 0x0b, 0x4a, + 0x17, 0x24, 0x0f, 0xd2, 0xdf, 0x32, 0xd3, 0x03, 0x6b, 0xf2, 0x7b, 0x88, 0x71, 0xc3, 0x62, 0xc3, + 0x7e, 0xcd, 0xd3, 0x5f, 0x3a, 0x31, 0xcc, 0xf6, 0x13, 0x63, 0x0f, 0x12, 0x25, 0x96, 0xa1, 0x75, + 0x06, 0xe8, 0xa3, 0x98, 0xaa, 0xdb, 0x54, 0xcc, 0xfd, 0x6d, 0x03, 0x3d, 0x97, 0xc9, 0x11, 0xda, + 0xce, 0xd7, 0x79, 0xa9, 0x0d, 0x57, 0x3e, 0x57, 0x03, 0xe4, 0x6e, 0xa6, 0xee, 0x52, 0xa1, 0x09, + 0xb3, 0x11, 0x5a, 0x09, 0x22, 0xf4, 0x26, 0x41, 0xff, 0xac, 0x27, 0x18, 0x55, 0xec, 0x9a, 0xcf, + 0x99, 0xa5, 0xce, 0xe7, 0x6a, 0xf2, 0x5b, 0x54, 0x33, 0x83, 0x2f, 0xfd, 0x5d, 0x9d, 0xff, 0xce, + 0x0b, 0xf6, 0x08, 0x73, 0x0f, 0x97, 0xef, 0xf6, 0xbe, 0x8c, 0xef, 0x0a, 0x2a, 0xdd, 0xb7, 0x84, + 0x03, 0x54, 0xfa, 0x07, 0x84, 0x8a, 0x29, 0x91, 0xfe, 0x81, 0x3e, 0x76, 0x3d, 0xd2, 0x6a, 0x84, + 0x42, 0xc7, 0x95, 0xfc, 0x0e, 0xd5, 0x47, 0x22, 0x85, 0xc1, 0x10, 0xfe, 0x6b, 0xdd, 0xe4, 0xbb, + 0xce, 0xb6, 0xdc, 0x14, 0x16, 0x4e, 0x05, 0x69, 0xfb, 0x2b, 0xd2, 0x3e, 0xfc, 0x13, 0x6a, 0x3a, + 0x05, 0x81, 0x3e, 0xba, 0x67, 0x4b, 0x3b, 0x4b, 0xb0, 0x84, 0xaf, 0xcd, 0x03, 0x8d, 0xb3, 0x7c, + 0x42, 0x8d, 0xf0, 0xe7, 0xd2, 0x1f, 0xbd, 0xce, 0xd7, 0x1e, 0x22, 0xba, 0xae, 0x59, 0x92, 0xf0, + 0x64, 0x16, 0xb2, 0x7f, 0x67, 0xd0, 0x60, 0xbf, 0x71, 0xa6, 0xbc, 0x75, 0xba, 0xef, 0xa4, 0x74, + 0x75, 0xf3, 0x2f, 0x36, 0x55, 0x60, 0xb4, 0xc3, 0xdf, 0x42, 0xa5, 0x41, 0xdf, 0x06, 0x2e, 0x0d, + 0xfa, 0xd0, 0x9b, 0xdd, 0x19, 0x4b, 0x60, 0x34, 0xcc, 0x14, 0xe6, 0x22, 0x7c, 0x7f, 0xf5, 0x32, + 0x1c, 0xf5, 0x82, 0x24, 0x1a, 0xa5, 0x3c, 0x51, 0x96, 0xfc, 0x5e, 0xe8, 0x3b, 0x97, 0xa8, 0x0e, + 0xa7, 0xf5, 0xa9, 0xa2, 0x3f, 0x8b, 0xdc, 0x0e, 0x50, 0xf5, 0x2c, 0xbb, 0xbd, 0x65, 0x86, 0x32, + 0x36, 0x43, 0x2b, 0x75, 0xfe, 0xeb, 0xa1, 0x16, 0x6c, 0xe8, 0x2e, 0x16, 0xf6, 0x15, 0xa3, 0x13, + 0x5d, 0x2c, 0x9c, 0xcf, 0x42, 0x2e, 0xc2, 0xa0, 0x9a, 0xfe, 0xd0, 0x46, 0x03, 0xcd, 0xd1, 0xb8, + 0x84, 0x55, 0x5e, 0x27, 0xac, 0x43, 0x54, 0x07, 0xf6, 0xd3, 0xfb, 0x2c, 0xaf, 0xe7, 0x72, 0xa7, + 0x57, 0x64, 0x90, 0xdf, 0xf2, 0x7b, 0x54, 0xb7, 0xc9, 0x48, 0xdf, 0xd3, 0x3d, 0xe3, 0xde, 0xf4, + 0x2a, 0xd5, 0xb0, 0x70, 0xeb, 0x7c, 0xeb, 0xa1, 0x3d, 0x6d, 0x7c, 0x94, 0x43, 0x3a, 0xbf, 0x89, + 0x68, 0x1e, 0xcb, 0x47, 0xb5, 0x90, 0x49, 0x87, 0x9a, 0x73, 0x51, 0xe7, 0x94, 0x25, 0x53, 0x07, + 0x4b, 0x21, 0xc3, 0x75, 0x01, 0x3d, 0x15, 0x40, 0xac, 0x94, 0xef, 0xd1, 0x4f, 0xb7, 0xca, 0x6a, + 0x8f, 0x7e, 0xbe, 0xb5, 0x51, 0x73, 0x35, 0x1c, 0xe6, 0x99, 0x50, 0x0f, 0x5d, 0xd5, 0xf1, 0xf7, + 0x65, 0xf3, 0xad, 0x2c, 0xaa, 0x43, 0xb6, 0xcd, 0x9e, 0x40, 0x88, 0xcb, 0x34, 0x61, 0xf8, 0x15, + 0x21, 0xe6, 0x32, 0x40, 0xc1, 0xd4, 0x63, 0x2a, 0xee, 0xb1, 0x47, 0xf6, 0xcd, 0xb3, 0x58, 0x3b, + 0xa9, 0x71, 0xb6, 0x58, 0xa4, 0x42, 0xe1, 0x12, 0xf1, 0x0d, 0xe2, 0x40, 0x08, 0x68, 0xf6, 0xab, + 0x07, 0x26, 0x86, 0x7c, 0xce, 0x15, 0x2e, 0x3b, 0x41, 0xec, 0xfd, 0xe0, 0x0a, 0xd9, 0x35, 0x2f, + 0xa8, 0x40, 0x08, 0xe8, 0x9d, 0x1b, 0x2a, 0x19, 0xde, 0x70, 0x1c, 0x81, 0x21, 0xd2, 0x4c, 0xe1, + 0xaa, 0x73, 0xda, 0x00, 0xe6, 0x6c, 0x26, 0x98, 0x94, 0xb8, 0x46, 0x0e, 0xcc, 0x3c, 0x04, 0x42, + 0xe4, 0xbc, 0xdd, 0x1d, 0x0d, 0x70, 0xdd, 0x71, 0x87, 0x82, 0x8e, 0x97, 0x52, 0xb1, 0x39, 0x6e, + 0x90, 0xd7, 0x68, 0xd7, 0xaa, 0x8b, 0xaf, 0x03, 0xf8, 0x23, 0xe7, 0xc8, 0x7f, 0x0a, 0xaa, 0x63, + 0x34, 0x1d, 0x24, 0x85, 0x73, 0xf0, 0xc4, 0x15, 0xde, 0x24, 0xbf, 0x40, 0xfb, 0xd6, 0x02, 0x74, + 0xc7, 0x12, 0xc5, 0xa7, 0x14, 0x3e, 0xf6, 0x78, 0xcb, 0x49, 0xa8, 0xc7, 0x84, 0xe2, 0xb7, 0x60, + 0x61, 0xb8, 0xe5, 0x00, 0xed, 0xd1, 0x64, 0xca, 0x62, 0x16, 0xe1, 0x6d, 0xf2, 0x16, 0x1d, 0xe6, + 0xe8, 0x05, 0x7f, 0xd0, 0xb9, 0x38, 0x77, 0x89, 0x9d, 0x0c, 0xf4, 0x07, 0xe3, 0x32, 0x55, 0xe7, + 0x69, 0x96, 0x44, 0x78, 0xc7, 0xcd, 0xe0, 0x51, 0xf6, 0xd3, 0xc7, 0x24, 0x4e, 0x69, 0x14, 0x08, + 0x81, 0x89, 0x73, 0x52, 0x57, 0xcc, 0xb2, 0x39, 0x4b, 0x14, 0xde, 0x3d, 0x0e, 0x0d, 0xbe, 0x15, + 0x1d, 0x90, 0x2d, 0xd4, 0xe8, 0x5d, 0x5d, 0x5e, 0x77, 0x07, 0x97, 0x41, 0x88, 0x5f, 0x91, 0x3a, + 0xaa, 0x7c, 0xbc, 0x1a, 0x5f, 0x63, 0x8f, 0x34, 0xd0, 0xc6, 0xe0, 0xa2, 0xfb, 0x97, 0x00, 0x97, + 0xc8, 0x26, 0xaa, 0x8f, 0x86, 0xdd, 0xeb, 0xf3, 0xab, 0xf0, 0x02, 0x97, 0x49, 0x0b, 0xa1, 0x71, + 0x10, 0x4e, 0x82, 0x70, 0x18, 0x8c, 0xc7, 0xb8, 0x72, 0xfc, 0x0e, 0x6d, 0xba, 0xac, 0x07, 0x11, + 0x2f, 0x59, 0xf6, 0xa0, 0x9f, 0xf9, 0xf8, 0x15, 0x88, 0x7f, 0x3d, 0x17, 0xe9, 0x0c, 0x2e, 0x14, + 0x7b, 0xc7, 0x17, 0xa6, 0xc9, 0x8a, 0xa7, 0x1a, 0xd8, 0x3f, 0x25, 0x0b, 0xaa, 0xa6, 0x77, 0x2c, + 0x32, 0xee, 0xe7, 0xfc, 0x29, 0x78, 0xe2, 0x52, 0x49, 0xec, 0xc1, 0x61, 0xff, 0xe0, 0x71, 0x0c, + 0x90, 0xf9, 0x13, 0x2e, 0x81, 0xfc, 0x29, 0xa1, 0xb7, 0xb7, 0x6c, 0xaa, 0x58, 0x84, 0xcb, 0x37, + 0x55, 0xfd, 0x8f, 0xf6, 0xe1, 0x87, 0x00, 0x00, 0x00, 0xff, 0xff, 0x99, 0x4b, 0x0c, 0x35, 0xb1, + 0x0d, 0x00, 0x00, +}