module KubeAutoAnalyzer def self.test_api_server @log.debug("Entering the test API Server Method") target = @options.target_server @log.debug("target is #{target}") @results[target]['api_server'] = Hash.new pods = @client.get_pods pods.each do |pod| #Ok this is a bit naive as a means of hitting the API server but hey it's a start if pod['metadata']['name'] =~ /kube-apiserver/ @api_server = pod end end unless @api_server @results[target]['api_server']['API Server Pod Not Found'] = "Error" return end api_server_command_line = @api_server['spec']['containers'][0]['command'] #Check for Anonymous Auth unless api_server_command_line.index{|line| line =~ /--anonymous-auth=false/} @results[target]['api_server']['CIS 1.1.1 - Ensure that the --anonymous-auth argument is set to false'] = "Fail" else @results[target]['api_server']['CIS 1.1.1 - Ensure that the --anonymous-auth argument is set to false'] = "Pass" end #Check for Basic Auth if api_server_command_line.index{|line| line =~ /--basic-auth-file/} @results[target]['api_server']['CIS 1.1.2 - Ensure that the --basic-auth-file argument is not set'] = "Fail" else @results[target]['api_server']['CIS 1.1.2 - Ensure that the --basic-auth-file argument is not set'] = "Pass" end #Check for Insecure Allow Any Token if api_server_command_line.index{|line| line =~ /--insecure-allow-any-token/} @results[target]['api_server']['CIS 1.1.3 - Ensure that the --insecure-allow-any-token argument is not set'] = "Fail" else @results[target]['api_server']['CIS 1.1.3 - Ensure that the --insecure-allow-any-token argument is not set'] = "Pass" end #Check to confirm that Kubelet HTTPS isn't set to false if api_server_command_line.index{|line| line =~ /--kubelet-https=false/} @results[target]['api_server']['CIS 1.1.4 - Ensure that the --kubelet-https argument is set to true'] = "Fail" else @results[target]['api_server']['CIS 1.1.4 - Ensure that the --kubelet-https argument is set to true'] = "Pass" end #Check for Insecure Bind Address if api_server_command_line.index{|line| line =~ /--insecure-bind-address/} @results[target]['api_server']['CIS 1.1.5 - Ensure that the --insecure-bind-address argument is not set'] = "Fail" else @results[target]['api_server']['CIS 1.1.5 - Ensure that the --insecure-bind-address argument is not set'] = "Pass" end #Check for Insecure Bind port unless api_server_command_line.index{|line| line =~ /--insecure-port=0/} @results[target]['api_server']['CIS 1.1.6 - Ensure that the --insecure-port argument is set to 0'] = "Fail" else @results[target]['api_server']['CIS 1.1.6 - Ensure that the --insecure-port argument is set to 0'] = "Pass" end #Check Secure Port isn't set to 0 if api_server_command_line.index{|line| line =~ /--secure-port=0/} @results[target]['api_server']['CIS 1.1.7 - Ensure that the --secure-port argument is not set to 0'] = "Fail" else @results[target]['api_server']['CIS 1.1.7 - Ensure that the --secure-port argument is not set to 0'] = "Pass" end # unless api_server_command_line.index{|line| line =~ /--profiling=false/} @results[target]['api_server']['CIS 1.1.8 - Ensure that the --profiling argument is set to false'] = "Fail" else @results[target]['api_server']['CIS 1.1.8 - Ensure that the --profiling argument is set to false'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--repair-malformed-updates/} @results[target]['api_server']['CIS 1.1.9 - Ensure that the --repair-malformed-updates argument is set to false'] = "Fail" else @results[target]['api_server']['CIS 1.1.9 - Ensure that the --repair-malformed-updates argument is set to false'] = "Pass" end if api_server_command_line.index{|line| line =~ /--admission-control\S*AlwaysAdmit/} @results[target]['api_server']['CIS 1.1.10 - Ensure that the admission control policy is not set to AlwaysAdmit'] = "Fail" else @results[target]['api_server']['CIS 1.1.10 - Ensure that the admission control policy is not set to AlwaysAdmit'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--admission-control\S*AlwaysPullImages/} @results[target]['api_server']['CIS 1.1.11 - Ensure that the admission control policy is set to AlwaysPullImages'] = "Fail" else @results[target]['api_server']['CIS 1.1.11 - Ensure that the admission control policy is set to AlwaysPullImages'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--admission-control\S*DenyEscalatingExec/} @results[target]['api_server']['CIS 1.1.12 - Ensure that the admission control policy is set to DenyEscalatingExec'] = "Fail" else @results[target]['api_server']['CIS 1.1.12 - Ensure that the admission control policy is set to DenyEscalatingExec'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--admission-control\S*SecurityContextDeny/} @results[target]['api_server']['CIS 1.1.13 - Ensure that the admission control policy is set to SecurityContextDeny'] = "Fail" else @results[target]['api_server']['CIS 1.1.13 - Ensure that the admission control policy is set to SecurityContextDeny'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--admission-control\S*NamespaceLifecycle/} @results[target]['api_server']['CIS 1.1.14 - Ensure that the admission control policy is set to NamespaceLifecycle'] = "Fail" else @results[target]['api_server']['CIS 1.1.14 - Ensure that the admission control policy is set to NamespaceLifecycle'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--audit-log-path/} @results[target]['api_server']['CIS 1.1.15 - Ensure that the --audit-log-path argument is set as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.15 - Ensure that the --audit-log-path argument is set as appropriate'] = "Pass" end #TODO: This check needs to do something with the number of days but for now lets just check whether it's present. unless api_server_command_line.index{|line| line =~ /--audit-log-maxage/} @results[target]['api_server']['CIS 1.1.16 - Ensure that the --audit-log-maxage argument is set to 30 or as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.16 - Ensure that the --audit-log-maxage argument is set to 30 or as appropriate'] = "Pass" end #TODO: This check needs to do something with the number of backups but for now lets just check whether it's present. unless api_server_command_line.index{|line| line =~ /--audit-log-maxbackup/} @results[target]['api_server']['CIS 1.1.17 - Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.17 - Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate'] = "Pass" end #TODO: This check needs to do something with the size of backups but for now lets just check whether it's present. unless api_server_command_line.index{|line| line =~ /--audit-log-maxsize/} @results[target]['api_server']['CIS 1.1.18 - Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.18 - Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate'] = "Pass" end if api_server_command_line.index{|line| line =~ /--authorization-mode\S*AlwaysAllow/} @results[target]['api_server']['CIS 1.1.19 - Ensure that the --authorization-mode argument is not set to AlwaysAllow'] = "Fail" else @results[target]['api_server']['CIS 1.1.19 - Ensure that the --authorization-mode argument is not set to AlwaysAllow'] = "Pass" end if api_server_command_line.index{|line| line =~ /--token-auth-file/} @results[target]['api_server']['CIS 1.1.20 - Ensure that the --token-auth-file argument is not set'] = "Fail" else @results[target]['api_server']['CIS 1.1.20 - Ensure that the --token-auth-file argument is not set'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--kubelet-certificate-authority/} @results[target]['api_server']['CIS 1.1.21 - Ensure that the --kubelet-certificate-authority argument is set as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.21 - Ensure that the --kubelet-certificate-authority argument is set as appropriate'] = "Pass" end unless (api_server_command_line.index{|line| line =~ /--kubelet-client-certificate/} && api_server_command_line.index{|line| line =~ /--kubelet-client-key/}) @results[target]['api_server']['CIS 1.1.22 - Ensure that the --kubelet-client-certificate and --kubelet-client-key arguments are set as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.22 - Ensure that the --kubelet-client-certificate and --kubelet-client-key arguments are set as appropriate'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--service-account-lookup=true/} @results[target]['api_server']['CIS 1.1.23 - Ensure that the --service-account-lookup argument is set to true'] = "Fail" else @results[target]['api_server']['CIS 1.1.23 - Ensure that the --service-account-lookup argument is set to true'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--admission-control\S*PodSecurityPolicy/} @results[target]['api_server']['CIS 1.1.24 - Ensure that the admission control policy is set to PodSecurityPolicy'] = "Fail" else @results[target]['api_server']['CIS 1.1.24 - Ensure that the admission control policy is set to PodSecurityPolicy'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--service-account-key-file/} @results[target]['api_server']['CIS 1.1.25 - Ensure that the --service-account-key-file argument is set as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.25 - Ensure that the --service-account-key-file argument is set as appropriate'] = "Pass" end unless (api_server_command_line.index{|line| line =~ /--etcd-certfile/} && api_server_command_line.index{|line| line =~ /--etcd-keyfile/}) @results[target]['api_server']['CIS 1.1.26 - Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.26 - Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--admission-control\S*ServiceAccount/} @results[target]['api_server']['CIS 1.1.27 - Ensure that the admission control policy is set to ServiceAccount'] = "Fail" else @results[target]['api_server']['CIS 1.1.27 - Ensure that the admission control policy is set to ServiceAccount'] = "Pass" end unless (api_server_command_line.index{|line| line =~ /--tls-cert-file/} && api_server_command_line.index{|line| line =~ /--tls-private-key-file/}) @results[target]['api_server']['CIS 1.1.28 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.28 - Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--client-ca-file/} @results[target]['api_server']['CIS 1.1.29 - Ensure that the --client-ca-file argument is set as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.29 - Ensure that the --client-ca-file argument is set as appropriate'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--etcd-cafile/} @results[target]['api_server']['CIS 1.1.30 - Ensure that the --etcd-cafile argument is set as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.30 - Ensure that the --etcd-cafile argument is set as appropriate'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--authorization-mode\S*Node/} @results[target]['api_server']['CIS 1.1.31 - Ensure that the --authorization-mode argument is set to Node'] = "Fail" else @results[target]['api_server']['CIS 1.1.31 - Ensure that the --authorization-mode argument is set to Node'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--admission-control\S*NodeRestriction/} @results[target]['api_server']['CIS 1.1.32 - Ensure that the admission control policy is set to NodeRestriction'] = "Fail" else @results[target]['api_server']['CIS 1.1.32 - Ensure that the admission control policy is set to NodeRestriction'] = "Pass" end unless api_server_command_line.index{|line| line =~ /--experimental-encryption-provider-config/} @results[target]['api_server']['CIS 1.1.33 - Ensure that the --experimental-encryption-provider-config argument is set as appropriate'] = "Fail" else @results[target]['api_server']['CIS 1.1.33 - Ensure that the --experimental-encryption-provider-config argument is set as appropriate'] = "Pass" end #1.1.34 can't be checked using this methodology so it's TBD unless api_server_command_line.index{|line| line =~ /--admission-control\S*EventRateLimit/} @results[target]['api_server']['CIS 1.1.35 - Ensure that the admission control policy is set to EventRateLimit'] = "Fail" else @results[target]['api_server']['CIS 1.1.35 - Ensure that the admission control policy is set to EventRateLimit'] = "Pass" end if api_server_command_line.index{|line| line =~ /--feature-gates=AdvancedAuditing=false/} @results[target]['api_server']['CIS 1.1.36 - Ensure that the AdvancedAuditing argument is not set to false'] = "Fail" else @results[target]['api_server']['CIS 1.1.36 - Ensure that the AdvancedAuditing argument is not set to false'] = "Pass" end #1.1.37 This one is dubious for a pass/fail test as the value should be evaluated against the relity of the cluster. end def self.test_scheduler target = @options.target_server @results[target]['scheduler'] = Hash.new pods = @client.get_pods pods.each do |pod| #Ok this is a bit naive as a means of hitting the API server but hey it's a start if pod['metadata']['name'] =~ /kube-scheduler/ @scheduler = pod end end unless @scheduler @results[target]['scheduler']['Scheduler Pod Not Found'] = "Error" return end scheduler_command_line = @scheduler['spec']['containers'][0]['command'] unless scheduler_command_line.index{|line| line =~ /--profiling=false/} @results[target]['scheduler']['CIS 1.2.1 - Ensure that the --profiling argument is set to false'] = "Fail" else @results[target]['scheduler']['CIS 1.2.1 - Ensure that the --profiling argument is set to false'] = "Pass" end @results[target]['evidence']['Scheduler'] = scheduler_command_line end def self.test_controller_manager target = @options.target_server @results[target]['controller_manager'] = Hash.new pods = @client.get_pods pods.each do |pod| #Ok this is a bit naive as a means of hitting the API server but hey it's a start if pod['metadata']['name'] =~ /kube-controller-manager/ @controller_manager = pod end end unless @controller_manager @results[target]['controller_manager']['Controller Manager Pod Not Found'] = "Error" return end controller_manager_command_line = @controller_manager['spec']['containers'][0]['command'] unless controller_manager_command_line.index{|line| line =~ /--terminated-pod-gc-threshold/} @results[target]['controller_manager']['CIS 1.3.1 - Ensure that the --terminated-pod-gc-threshold argument is set as appropriate'] = "Fail" else @results[target]['controller_manager']['CIS 1.3.1 - Ensure that the --terminated-pod-gc-threshold argument is set as appropriate'] = "Pass" end unless controller_manager_command_line.index{|line| line =~ /--profiling=false/} @results[target]['controller_manager']['CIS 1.3.2 - Ensure that the --profiling argument is set to false'] = "Fail" else @results[target]['controller_manager']['CIS 1.3.2 - Ensure that the --profiling argument is set to false'] = "Pass" end if controller_manager_command_line.index{|line| line =~ /--insecure-experimental-approve-all-kubelet-csrs-for-group/} @results[target]['controller_manager']['CIS 1.3.3 - Ensure that the --insecure-experimental-approve-all-kubelet-csrs-for-group argument is not set'] = "Fail" else @results[target]['controller_manager']['CIS 1.3.3 - Ensure that the --insecure-experimental-approve-all-kubelet-csrs-for-group argument is not set'] = "Pass" end unless controller_manager_command_line.index{|line| line =~ /--use-service-account-credentials=true/} @results[target]['controller_manager']['CIS 1.3.3 - Ensure that the --use-service-account-credentials argument is set to true'] = "Fail" else @results[target]['controller_manager']['CIS 1.3.3 - Ensure that the --use-service-account-credentials argument is set to true'] = "Pass" end unless controller_manager_command_line.index{|line| line =~ /--service-account-private-key-file/} @results[target]['controller_manager']['CIS 1.3.4 - Ensure that the --service-account-private-key-file argument is set as appropriate'] = "Fail" else @results[target]['controller_manager']['CIS 1.3.4 - Ensure that the --service-account-private-key-file argument is set as appropriate'] = "Pass" end unless controller_manager_command_line.index{|line| line =~ /--root-ca-file/} @results[target]['controller_manager']['CIS 1.3.5 - Ensure that the --root-ca-file argument is set as appropriate'] = "Fail" else @results[target]['controller_manager']['CIS 1.3.5 - Ensure that the --root-ca-file argument is set as appropriate'] = "Pass" end unless controller_manager_command_line.index{|line| line =~ /RotateKubeletServerCertificate=true/} @results[target]['controller_manager']['CIS 1.3.7 - Ensure that the RotateKubeletServerCertificate argument is set to true'] = "Fail" else @results[target]['controller_manager']['CIS 1.3.7 - Ensure that the RotateKubeletServerCertificate argument is set to true'] = "Pass" end @results[target]['evidence']['Controller Manager'] = controller_manager_command_line end def self.test_etcd target = @options.target_server @results[target]['etcd'] = Hash.new pods = @client.get_pods pods.each do |pod| #Ok this is a bit naive as a means of hitting the API server but hey it's a start if pod['metadata']['name'] =~ /etcd/ @etcd = pod end end unless @etcd @results[target]['etcd']['etcd Pod Not Found'] = "Error" return end etcd_command_line = @etcd['spec']['containers'][0]['command'] unless (etcd_command_line.index{|line| line =~ /--cert-file/} && etcd_command_line.index{|line| line =~ /--key-file/}) @results[target]['etcd']['CIS 1.5.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate'] = "Fail" else @results[target]['etcd']['CIS 1.5.1 - Ensure that the --cert-file and --key-file arguments are set as appropriate'] = "Pass" end unless etcd_command_line.index{|line| line =~ /--client-cert-auth=true/} @results[target]['etcd']['CIS 1.5.2 - Ensure that the --client-cert-auth argument is set to true'] = "Fail" else @results[target]['etcd']['CIS 1.5.2 - Ensure that the --client-cert-auth argument is set to true'] = "Pass" end if etcd_command_line.index{|line| line =~ /--auto-tls argument=true/} @results[target]['etcd']['CIS 1.5.3 - Ensure that the --auto-tls argument is not set to true'] = "Fail" else @results[target]['etcd']['CIS 1.5.3 - Ensure that the --auto-tls argument is not set to true'] = "Pass" end unless (etcd_command_line.index{|line| line =~ /--peer-cert-file/} && etcd_command_line.index{|line| line =~ /--peer-key-file/}) @results[target]['etcd']['CIS 1.5.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate'] = "Fail" else @results[target]['etcd']['CIS 1.5.4 - Ensure that the --peer-cert-file and --peer-key-file arguments are set as appropriate'] = "Pass" end unless etcd_command_line.index{|line| line =~ /--peer-client-cert-auth=true/} @results[target]['etcd']['CIS 1.5.5 - Ensure that the --peer-client-cert-auth argument is set to true'] = "Fail" else @results[target]['etcd']['CIS 1.5.5 - Ensure that the --peer-client-cert-auth argument is set to true'] = "Pass" end if etcd_command_line.index{|line| line =~ /--peer-auto-tls argument=true/} @results[target]['etcd']['CIS 1.5.6 - Ensure that the --peer-auto-tls argument is not set to true'] = "Fail" else @results[target]['etcd']['CIS 1.5.6 - Ensure that the --peer-auto-tls argument is not set to true'] = "Pass" end #This isn't quite right as we should really check the dir. but as that's not easily done lets start with an existence check unless etcd_command_line.index{|line| line =~ /--wal-dir/} @results[target]['etcd']['CIS 1.5.7 - Ensure that the --wal-dir argument is set as appropriate'] = "Fail" else @results[target]['etcd']['CIS 1.5.7 - Ensure that the --wal-dir argument is set as appropriate'] = "Pass" end unless etcd_command_line.index{|line| line =~ /--max-wals=0/} @results[target]['etcd']['CIS 1.5.8 - Ensure that the --max-wals argument is set to 0'] = "Fail" else @results[target]['etcd']['CIS 1.5.8 - Ensure that the --max-wals argument is set to 0'] = "Pass" end @results[target]['evidence']['etcd'] = etcd_command_line end end