module KubeAutoAnalyzer def self.json_report require 'json' @log.debug("Starting Report") @json_report_file.puts JSON.generate(@results) end def self.html_report logo_path = File.join(__dir__, "data-logo.b64") logo = File.open(logo_path).read @log.debug("Starting HTML Report") @html_report_file << ' Kubernetes Auto Analyzer Report ' chartkick_path = File.join(__dir__, "js_files/chartkick.js") chartkick = File.open(chartkick_path).read highcharts_path = File.join(__dir__, "js_files/highcharts.js") highcharts = File.open(highcharts_path).read @html_report_file.puts "" @html_report_file.puts "" @html_report_file.puts '" @html_report_file.puts "

Kubernetes Auto Analyzer

" @html_report_file.puts "
Server Reviewed : #{@options.target_server}" @html_report_file.puts '

Master Node Results


' #Charting setup counts for the passes and fails api_server_pass = 0 api_server_fail = 0 @results[@options.target_server]['api_server'].each do |test, result| if result == "Pass" api_server_pass = api_server_pass + 1 elsif result == "Fail" api_server_fail = api_server_fail + 1 end end #Not a lot of point in scheduler when there's only one check... #scheduler_pass = 0 #scheduler_fail = 0 #@results[@options.target_server]['scheduler'].each do |test, result| # if result == "Pass" # scheduler_pass = scheduler_pass + 1 # elsif result == "Fail" # scheduler_fail = scheduler_fail + 1 # end #end controller_manager_pass = 0 controller_manager_fail = 0 @results[@options.target_server]['controller_manager'].each do |test, result| if result == "Pass" controller_manager_pass = controller_manager_pass + 1 elsif result == "Fail" controller_manager_fail = controller_manager_fail + 1 end end etcd_pass = 0 etcd_fail = 0 @results[@options.target_server]['etcd'].each do |test, result| if result == "Pass" etcd_pass = etcd_pass + 1 elsif result == "Fail" etcd_fail = etcd_fail + 1 end end #Start of Chart Divs @html_report_file.puts '
' #API Server Chart @html_report_file.puts '
' @html_report_file.puts '' #Scheduler Chart #@html_report_file.puts '
' #@html_report_file.puts '' #Controller Manager Chart @html_report_file.puts '
' @html_report_file.puts '' #etcd Chart @html_report_file.puts '
' @html_report_file.puts '' #End of Chart Divs @html_report_file.puts '
' @html_report_file.puts "

API Server

" @html_report_file.puts "" @results[@options.target_server]['api_server'].each do |test, result| if result == "Fail" result = 'Fail' elsif result == "Pass" result = 'Pass' end @html_report_file.puts "" end @html_report_file.puts "
Checkresult
#{test}#{result}
" @html_report_file.puts "

" @html_report_file.puts "

Scheduler

" @html_report_file.puts "" @results[@options.target_server]['scheduler'].each do |test, result| if result == "Fail" result = 'Fail' elsif result == "Pass" result = 'Pass' end @html_report_file.puts "" end @html_report_file.puts "
Checkresult
#{test}#{result}
" @html_report_file.puts "

" @html_report_file.puts "

Controller Manager

" @html_report_file.puts "" @results[@options.target_server]['controller_manager'].each do |test, result| if result == "Fail" result = 'Fail' elsif result == "Pass" result = 'Pass' end @html_report_file.puts "" end @html_report_file.puts "
Checkresult
#{test}#{result}
" @html_report_file.puts "

" @html_report_file.puts "

etcd

" @html_report_file.puts "" @results[@options.target_server]['etcd'].each do |test, result| if result == "Fail" result = 'Fail' elsif result == "Pass" result = 'Pass' end @html_report_file.puts "" end @html_report_file.puts "
Checkresult
#{test}#{result}
" #Show what cluster authentication modes are supported. @html_report_file.puts "

" @html_report_file.puts "

Kubernetes Authentication Options

" @html_report_file.puts "" if @results[@options.target_server]['api_server']['CIS 1.1.2 - Ensure that the --basic-auth-file argument is not set'] == "Fail" @html_report_file.puts "" else @html_report_file.puts "" end if @results[@options.target_server]['api_server']['CIS 1.1.20 - Ensure that the --token-auth-file argument is not set'] == "Fail" @html_report_file.puts "" else @html_report_file.puts "" end if @results[@options.target_server]['api_server']['CIS 1.1.29 - Ensure that the --client-ca-file argument is set as appropriate'] == "Pass" @html_report_file.puts "" else @html_report_file.puts "" end if @results[@options.target_server]['evidence']['API Server'].index{|line| line =~ /--oidc-issuer-url/} @html_report_file.puts "" else @html_report_file.puts "" end if @results[@options.target_server]['evidence']['API Server'].index{|line| line =~ /--authentication-token-webhook-config-file/} @html_report_file.puts "" else @html_report_file.puts "" end if @results[@options.target_server]['evidence']['API Server'].index{|line| line =~ /--requestheader-username-headers/} @html_report_file.puts "" else @html_report_file.puts "" end @html_report_file.puts "
Authentication OptionEnabled?
Basic AuthenticationEnabled
Basic AuthenticationDisabled
Token AuthenticationEnabled
Token AuthenticationDisabled
Client Certificate AuthenticationEnabled
Client Certificate AuthenticationDisabled
OpenID Connect AuthenticationEnabled
OpenID Connect AuthenticationDisabled
Webhook AuthenticationEnabled
Webhook AuthenticationDisabled
Proxy AuthenticationEnabled
Proxy AuthenticationDisabled
" #Show what cluster authorization modes are supported. @html_report_file.puts "

" @html_report_file.puts "

Kubernetes Authorization Options

" @html_report_file.puts "" if @results[@options.target_server]['evidence']['API Server'].index{|line| line =~ /--authorization-mode\S*RBAC/} @html_report_file.puts "" else @html_report_file.puts "" end if @results[@options.target_server]['evidence']['API Server'].index{|line| line =~ /--authorization-mode\S*ABAC/} @html_report_file.puts "" else @html_report_file.puts "" end if @results[@options.target_server]['evidence']['API Server'].index{|line| line =~ /--authorization-mode\S*Webhook/} @html_report_file.puts "" else @html_report_file.puts "" end @html_report_file.puts "
Authorization OptionEnabled?
Role Based AuthorizationEnabled
Role Based AuthorizationDisabled
Attribute Based AuthorizationEnabled
Attribute Based AuthorizationDisabled
Webhook AuthorizationEnabled
Webhook AuthorizationDisabled
" @html_report_file.puts "

Evidence


" @html_report_file.puts "" @results[@options.target_server]['evidence'].each do |area, output| @html_report_file.puts "" end #Close the master Node Div @html_report_file.puts "
AreaOutput
#{area}#{output}
" if @options.agent_checks @html_report_file.puts '

Worker Node Results

' #Start of Chart Divs @html_report_file.puts '
' @results[@options.target_server]['kubelet_checks'].each do |node, results| node_kubelet_pass = 0 node_kubelet_fail = 0 results.each do |test, result| if result == "Fail" node_kubelet_fail = node_kubelet_fail + 1 elsif result == "Pass" node_kubelet_pass = node_kubelet_pass + 1 end end #Create the Chart @html_report_file.puts '
' @html_report_file.puts '' end #End of Chart Divs @html_report_file.puts '
' @results[@options.target_server]['kubelet_checks'].each do |node, results| @html_report_file.puts "
#{node} Kubelet Checks" @html_report_file.puts "" results.each do |test, result| if result == "Fail" result = 'Fail' elsif result == "Pass" result = 'Pass' end @html_report_file.puts "" end @html_report_file.puts "
Checkresult
#{test}#{result}
" end @html_report_file.puts "

Evidence


" @html_report_file.puts "" @results[@options.target_server]['node_evidence'].each do |node, evidence| evidence.each do |area, data| @html_report_file.puts "" end end @html_report_file.puts "
HostAreaOutput
#{node}#{area}#{data}
" end #Close the Worker Node Div @html_report_file.puts '
' if @options.agent_checks @html_report_file.puts '

Node File Permissions

' @results[@options.target_server]['node_files'].each do |node, results| @html_report_file.puts "
#{node}
" @html_report_file.puts "" results.each do |file| @html_report_file.puts "" end @html_report_file.puts "
fileusergrouppermissions
#{file[0]}#{file[1]}#{file[2]}#{file[3]}
" end end @html_report_file.puts '

Vulnerability Checks

' @html_report_file.puts '

External Unauthenticated Access to the Kubelet

' @html_report_file.puts "" @results[@options.target_server]['vulns']['unauth_kubelet'].each do |node, result| unless (result =~ /Forbidden/ || result =~ /Not Open/) output = "Vulnerable" else output = result end @html_report_file.puts "" end @html_report_file.puts "
Node IP AddressResult
#{node}#{output}
" if @options.agent_checks @html_report_file.puts '

Internal Unauthenticated Access to the Kubelet

' @html_report_file.puts "" @results[@options.target_server]['vulns']['internal_kubelet'].each do |node, result| unless (result =~ /Forbidden/ || result =~ /Not Open/) output = "Vulnerable" else output = result end @html_report_file.puts "" end @html_report_file.puts "
Node IP AddressResult
#{node}#{output}
" end @html_report_file.puts '

External Insecure API Port Exposed

' @html_report_file.puts "" @results[@options.target_server]['vulns']['insecure_api_external'].each do |node, result| unless (result =~ /Forbidden/ || result =~ /Not Open/) output = "Vulnerable" else output = result end @html_report_file.puts "" end @html_report_file.puts "
Node IP AddressResult
#{node}#{output}
" if @options.agent_checks @html_report_file.puts '

Internal Insecure API Port Exposed

' @html_report_file.puts "" @results[@options.target_server]['vulns']['insecure_api_internal'].each do |node, result| unless (result =~ /Forbidden/ || result =~ /Not Open/) output = "Vulnerable" else output = result end @html_report_file.puts "" end @html_report_file.puts "
Node IP AddressResult
#{node}#{output}
" end if @options.agent_checks @html_report_file.puts '

Default Service Token In Use

' @html_report_file.puts "" @results[@options.target_server]['vulns']['service_token'].each do |node, result| unless (result =~ /Forbidden/ || result =~ /Not Open/) output = "Vulnerable" else output = result end @html_report_file.puts "" end @html_report_file.puts "
API endpointResult
#{node}#{output}
" end if @options.agent_checks @html_report_file.puts '

Container Configuration checks

' @results[@options.target_server]['vulns']['amicontained'].each do |node, result| @html_report_file.puts "
#{node} Container Checks" @html_report_file.puts "" @html_report_file.puts "" @html_report_file.puts "" @html_report_file.puts "" @html_report_file.puts "" @html_report_file.puts "" @html_report_file.puts "" @html_report_file.puts "" @html_report_file.puts "" @html_report_file.puts "
Container itemResult
Runtime in Use#{result['runtime']}
Host PID namespace used?#{result['hostpid']}
AppArmor Profile#{result['apparmor']}
User Namespaces in use?#{result['uid_map']}
Inherited Capabilities#{result['cap_inh']}
Effective Capabilities#{result['cap_eff']}
Permitted Capabilities#{result['cap_per']}
Bounded Capabilities#{result['cap_bnd']}
" end end @html_report_file.puts "

Vulnerability Evidence


" @html_report_file.puts "" @results[@options.target_server]['vulns']['unauth_kubelet'].each do |node, result| @html_report_file.puts "" end if @options.agent_checks @results[@options.target_server]['vulns']['internal_kubelet'].each do |node, result| @html_report_file.puts "" end end @results[@options.target_server]['vulns']['insecure_api_external'].each do |node, result| @html_report_file.puts "" end if @options.agent_checks @results[@options.target_server]['vulns']['insecure_api_internal'].each do |node, result| @html_report_file.puts "" end end if @options.agent_checks @results[@options.target_server]['vulns']['service_token'].each do |node, result| @html_report_file.puts "" end end if @options.agent_checks @results[@options.target_server]['vulns']['amicontained'].each do |node, result| @html_report_file.puts "" end end @html_report_file.puts "
VulnerabilityHostOutput
External Unauthenticated Kubelet Access#{node}#{result}
Internal Unauthenticated Kubelet Access#{node}#{result}
External Insecure API Server Access#{node}#{result}
Internal Insecure API Server Access#{node}#{result}
Default Service Token In Use#{node}#{result}
Am I Contained Output#{node}#{result}
" #Closing the report off @html_report_file.puts '' end end