diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..33f4a5c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,27 @@ +name: Test + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + - cron: '0 6 * * *' + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + ruby-version: ['2.6', '2.7', '3.0'] + + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - name: Run tests + run: bundle exec rake diff --git a/.rubocop.yml b/.rubocop.yml index 7c8f0bd..e836519 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,9 +1,10 @@ --- +AllCops: + Exclude: + - vendor/**/* Documentation: Enabled: false -AlignParameters: - Enabled: true -Encoding: +Layout/ParameterAlignment: Enabled: true HashSyntax: Enabled: true @@ -11,16 +12,25 @@ LineLength: Enabled: false EmptyLinesAroundBlockBody: Enabled: false +Style/Encoding: + Enabled: false MethodLength: Max: 40 +NumericLiterals: + MinDigits: 10 Metrics/BlockLength: - Max: 30 + Max: 45 # needed for 6.1.1 Metrics/CyclomaticComplexity: Max: 10 Metrics/PerceivedComplexity: Max: 10 Metrics/AbcSize: - Max: 29 -Style/MethodMissing: - Exclude: - - 'libraries/process_env_var.rb' + Max: 30 +# Lint/AmbiguousBlockAssociation is incompatible with RSpec +# https://github.com/rubocop-hq/rubocop/issues/4222 +Lint/AmbiguousBlockAssociation: + Enabled: false +Lint/AmbiguousRegexpLiteral: + Enabled: false +Style/NumericPredicate: + Enabled: false diff --git a/Gemfile b/Gemfile index 311912b..a076fc4 100644 --- a/Gemfile +++ b/Gemfile @@ -1,11 +1,18 @@ +# frozen_string_literal: true + source 'https://rubygems.org' -gem 'highline', '~> 1.6.0' -gem 'inspec', '~> 3' -gem 'rack', '>= 1.6.11' +gem 'highline' +gem 'rack' gem 'rake' -gem 'rubocop', '~> 0.49.0' +gem 'rubocop' group :tools do - gem 'github_changelog_generator', '~> 1.12.0' + gem 'github_changelog_generator' + gem 'pry-coolline' +end + +source 'https://packagecloud.io/cinc-project/stable' do + gem 'chef-config' + gem 'cinc-auditor-bin' end diff --git a/Rakefile b/Rakefile index 7dd39b5..ed8b932 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rake/testtask' require 'rubocop/rake_task' @@ -17,23 +19,9 @@ task default: [:lint, 'test:check'] namespace :test do # run inspec check to verify that the profile is properly configured task :check do - dir = File.join(File.dirname(__FILE__)) - sh("bundle exec inspec check #{dir}") - end -end - -# Automatically generate a changelog for this project. Only loaded if -# the necessary gem is installed. By default its picking up the version from -# inspec.yml. You can override that behavior with s`rake changelog to=1.2.0` -begin - require 'yaml' - metadata = YAML.load_file('inspec.yml') - v = ENV['to'] || metadata['version'] - puts "Generate changelog for version #{v}" - require 'github_changelog_generator/task' - GitHubChangelogGenerator::RakeTask.new :changelog do |config| - config.future_release = v + require 'inspec' + puts "Checking profile with InSpec Version: #{Inspec::VERSION}" + profile = Inspec::Profile.for_target('.', backend: Inspec::Backend.create(Inspec::Config.mock)) + pp profile.check end -rescue LoadError - puts '>>>>> GitHub Changelog Generator not loaded, omitting tasks' end diff --git a/controls/1_1_master_node_configuration_files.rb b/controls/1_1_master_node_configuration_files.rb index addc5c2..740075a 100755 --- a/controls/1_1_master_node_configuration_files.rb +++ b/controls/1_1_master_node_configuration_files.rb @@ -1,14 +1,16 @@ +# frozen_string_literal: true + title '1.1 Master Node: Configuration Files' -apiserver_manifest = attribute('apiserver-manifest') -controller_manager_manifest = attribute('controller_manager-manifest') -scheduler_manifest = attribute('scheduler-manifest') -etcd_manifest = attribute('etcd-manifest') -etcd_regex = Regexp.new(attribute('etcd')) -admin_conf = attribute('admin-conf') -scheduler_conf = attribute('scheduler-conf') -controller_manager_conf = attribute('controller_manager-conf') -kubernetes_pki = attribute('kubernetes-pki') +apiserver_manifest = input('apiserver-manifest') +controller_manager_manifest = input('controller_manager-manifest') +scheduler_manifest = input('scheduler-manifest') +etcd_manifest = input('etcd-manifest') +etcd_regex = Regexp.new(input('etcd')) +admin_conf = input('admin-conf') +scheduler_conf = input('scheduler-conf') +controller_manager_conf = input('controller_manager-conf') +kubernetes_pki = input('kubernetes-pki') control 'cis-kubernetes-benchmark-1.1.1' do title 'Ensure that the API server pod specification file permissions are set to 644 or more restrictive' diff --git a/controls/1_2_master_node_api_server.rb b/controls/1_2_master_node_api_server.rb index b8b8740..716009c 100755 --- a/controls/1_2_master_node_api_server.rb +++ b/controls/1_2_master_node_api_server.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + title '1.2 Master Node: API Server' -apiserver = attribute('apiserver') +apiserver = input('apiserver') # fallback if apiserver attribute is not defined apiserver = kubernetes.apiserver_bin if apiserver.empty? diff --git a/controls/1_3_master_node_controller_manager.rb b/controls/1_3_master_node_controller_manager.rb index 96eb561..7eeac71 100644 --- a/controls/1_3_master_node_controller_manager.rb +++ b/controls/1_3_master_node_controller_manager.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + title '1.3 Master Node: Controller Manager' -controller_manager = attribute('controller_manager') +controller_manager = input('controller_manager') # fallback if scheduler attribute is not defined controller_manager = kubernetes.controllermanager_bin if controller_manager.empty? diff --git a/controls/1_4_master_node_scheduler.rb b/controls/1_4_master_node_scheduler.rb index adcf4dc..49438b8 100644 --- a/controls/1_4_master_node_scheduler.rb +++ b/controls/1_4_master_node_scheduler.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + title '1.4 Master Node: Scheduler' -scheduler = attribute('scheduler') +scheduler = input('scheduler') # fallback if scheduler attribute is not defined scheduler = kubernetes.scheduler_bin if scheduler.empty? diff --git a/controls/2_etcd_node.rb b/controls/2_etcd_node.rb index d5b4993..883e6a4 100755 --- a/controls/2_etcd_node.rb +++ b/controls/2_etcd_node.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + title '2 Etcd Node' -etcd_regex = Regexp.new(attribute('etcd')) +etcd_regex = Regexp.new(input('etcd')) etcd_process = processes(etcd_regex) etcd_env_vars = process_env_var(etcd_regex) diff --git a/controls/3_1_control_plane_authn_and_authz.rb b/controls/3_1_control_plane_authn_and_authz.rb index aa79bd2..d4e1d4b 100644 --- a/controls/3_1_control_plane_authn_and_authz.rb +++ b/controls/3_1_control_plane_authn_and_authz.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + title '3.1 Control Plane Configuration' control 'cis-kubernetes-benchmark-3.1.1' do diff --git a/controls/3_2_control_plane_logging.rb b/controls/3_2_control_plane_logging.rb index 8279642..fd890d2 100644 --- a/controls/3_2_control_plane_logging.rb +++ b/controls/3_2_control_plane_logging.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + title '3.2 Logging' -apiserver = attribute('apiserver') +apiserver = input('apiserver') # fallback if apiserver attribute is not defined apiserver = kubernetes.apiserver_bin if apiserver.empty? diff --git a/controls/4_1_worker_node_configuration_files.rb b/controls/4_1_worker_node_configuration_files.rb index 5e4786e..0378288 100755 --- a/controls/4_1_worker_node_configuration_files.rb +++ b/controls/4_1_worker_node_configuration_files.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + title '4.1.1 Worker Node: Configuration Files' -kubelet = attribute('kubelet') +kubelet = input('kubelet') # fallback if kubelet attribute is not defined kubelet = kubernetes.kubelet_bin if kubelet.empty? -kubelet_conf = attribute('kubelet-conf') +kubelet_conf = input('kubelet-conf') only_if('kubelet not found') do processes(kubelet).exists? diff --git a/controls/4_2_worker_node_kubelet.rb b/controls/4_2_worker_node_kubelet.rb index f3769b1..ec6ed19 100755 --- a/controls/4_2_worker_node_kubelet.rb +++ b/controls/4_2_worker_node_kubelet.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + title '4.2 Worker Node: Kubelet' -kubelet = attribute('kubelet') +kubelet = input('kubelet') # fallback if kubelet attribute is not defined kubelet = kubernetes.kubelet_bin if kubelet.empty? diff --git a/controls/5_1_policies_rbac_and_service_accounts.rb b/controls/5_1_policies_rbac_and_service_accounts.rb index 42d479a..e89c80f 100755 --- a/controls/5_1_policies_rbac_and_service_accounts.rb +++ b/controls/5_1_policies_rbac_and_service_accounts.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + title '5.1 Policies: RBAC and Service Accounts' control 'cis-kubernetes-benchmark-5.1.1' do diff --git a/controls/5_2_policies_pod_security_policies.rb b/controls/5_2_policies_pod_security_policies.rb index 1740bdb..df06c46 100755 --- a/controls/5_2_policies_pod_security_policies.rb +++ b/controls/5_2_policies_pod_security_policies.rb @@ -1,4 +1,6 @@ -cis_level = attribute('cis_level') +# frozen_string_literal: true + +cis_level = input('cis_level') title '5.2 Policies: Pod Security Policies' diff --git a/controls/5_3_policies_network_policies_and_cni.rb b/controls/5_3_policies_network_policies_and_cni.rb index 7ff01d9..c84ee7e 100644 --- a/controls/5_3_policies_network_policies_and_cni.rb +++ b/controls/5_3_policies_network_policies_and_cni.rb @@ -1,4 +1,6 @@ -cis_level = attribute('cis_level') +# frozen_string_literal: true + +cis_level = input('cis_level') title '5.3 Policies: Network Policies and CNI' diff --git a/controls/5_4_policies_secrets_management.rb b/controls/5_4_policies_secrets_management.rb index a5be887..c51e5c3 100644 --- a/controls/5_4_policies_secrets_management.rb +++ b/controls/5_4_policies_secrets_management.rb @@ -1,4 +1,6 @@ -cis_level = attribute('cis_level') +# frozen_string_literal: true + +cis_level = input('cis_level') title '5.4 Policies: Secrets Management' diff --git a/controls/5_5_policies_extensible_admission_control.rb b/controls/5_5_policies_extensible_admission_control.rb index 3fdf611..d99bcd5 100644 --- a/controls/5_5_policies_extensible_admission_control.rb +++ b/controls/5_5_policies_extensible_admission_control.rb @@ -1,4 +1,6 @@ -cis_level = attribute('cis_level') +# frozen_string_literal: true + +cis_level = input('cis_level') title '5.5 Policies: Extensible Admission Control' diff --git a/controls/5_6_policies_general_policies.rb b/controls/5_6_policies_general_policies.rb index aaa57b5..7263c9b 100644 --- a/controls/5_6_policies_general_policies.rb +++ b/controls/5_6_policies_general_policies.rb @@ -1,4 +1,6 @@ -cis_level = attribute('cis_level') +# frozen_string_literal: true + +cis_level = input('cis_level') title '5.6 Policies: General Policies' diff --git a/inspec.yml b/inspec.yml index ac3a21a..f88c928 100755 --- a/inspec.yml +++ b/inspec.yml @@ -7,7 +7,7 @@ copyright_email: kvlaardingerbroek@schubergphilis.com license: Apache-2.0 summary: An InSpec Compliance profile for the CIS Kubernetes Benchmark version: 1.0.2 -inspec_version: '>= 2.3.5' +inspec_version: '>= 4.6.3' supports: - platform-family: unix attributes: diff --git a/libraries/kubernetes.rb b/libraries/kubernetes.rb index 0132fe7..e1fc28d 100644 --- a/libraries/kubernetes.rb +++ b/libraries/kubernetes.rb @@ -1,8 +1,11 @@ +# frozen_string_literal: true + class Kubernetes < Inspec.resource(1) name 'kubernetes' desc 'Custom resource which abstracts the various kubernetes runtimes like hyperkube' def initialize + super @is_hyperkube = inspec.file('/usr/bin/hyperkube').file? Log.debug("The kubernetes installation uses hyperkube: #{@is_hyperkube}") end diff --git a/libraries/process_env_var.rb b/libraries/process_env_var.rb index a1b18af..e6b315a 100644 --- a/libraries/process_env_var.rb +++ b/libraries/process_env_var.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProcessEnvVar < Inspec.resource(1) name 'process_env_var' desc 'Custom resource to lookup environment variables for a process' @@ -7,15 +9,23 @@ class ProcessEnvVar < Inspec.resource(1) end " + # As described here https://github.com/inspec/inspec/blob/main/lib/inspec/resource.rb#L111 + # Inspec has a weird behaviour concerning super + # rubocop:disable Lint/MissingSuper def initialize(process) @process = inspec.processes(process) end + # rubocop:enable Lint/MissingSuper + + def respond_to_missing?(name) + Log.debug("Missing #{name}") + end def method_missing(name) read_params[name.to_s] || '' end - def read_params + def params return @params if defined?(@params) @file = inspec.file("/proc/#{@process.pids.first}/environ")