From bc2910d00fb6d1f8b95227f548d1e78b109f81a2 Mon Sep 17 00:00:00 2001 From: James Woolfenden Date: Mon, 23 Oct 2023 13:07:33 +0100 Subject: [PATCH 1/2] fix(terraform) cos image only relavent to gke <1.24 --- .../checks/resource/gcp/GKEUseCosImage.py | 46 +++-- .../gcp/example_GKEUseCosImage/main.tf | 174 ++++++++++++++++++ .../resource/gcp/test_GKEUseCosImage.py | 143 +++----------- 3 files changed, 224 insertions(+), 139 deletions(-) create mode 100644 tests/terraform/checks/resource/gcp/example_GKEUseCosImage/main.tf diff --git a/checkov/terraform/checks/resource/gcp/GKEUseCosImage.py b/checkov/terraform/checks/resource/gcp/GKEUseCosImage.py index b248f7d2ab9..210a2649b23 100644 --- a/checkov/terraform/checks/resource/gcp/GKEUseCosImage.py +++ b/checkov/terraform/checks/resource/gcp/GKEUseCosImage.py @@ -12,24 +12,36 @@ def __init__(self): def scan_resource_conf(self, conf): """ - Looks for password configuration at azure_instance: - https://www.terraform.io/docs/providers/google/r/compute_ssl_policy.html - :param conf: google_compute_ssl_policy configuration - :return: + CKV_GCP_22 + error creating NodePool: googleapi: Error 400: Creation of node pools using node images based on Docker + container runtimes is not supported in GKE v1.24+ clusters as Dockershim has been removed in Kubernetes v1.24. + + image_type = "COS" """ - if 'node_config' in conf: - node_config = conf.get('node_config', [{}])[0] - self.evaluated_keys = ['node_config'] - if not isinstance(node_config, dict): - return CheckResult.UNKNOWN - - if conf.get('node_config', [{}])[0].get('image_type', [''])[0].lower().startswith('cos'): - self.evaluated_keys = ['node_config/[0]/image_type'] - return CheckResult.PASSED - if conf.get('remove_default_node_pool', [{}])[0]: - self.evaluated_keys.append('remove_default_node_pool') - return CheckResult.PASSED - return CheckResult.FAILED + if conf.get('version') and isinstance(conf.get('version'), list): + raw = conf.get('version')[0] + splitter = raw.split(".") + + if len(splitter) >= 2: + version = float(splitter[0] + "." + splitter[1]) + if version >= 1.24: + return CheckResult.UNKNOWN + + if 'node_config' in conf: + node_config = conf.get('node_config', [{}])[0] + self.evaluated_keys = ['node_config'] + if not isinstance(node_config, dict): + return CheckResult.UNKNOWN + + if conf.get('node_config', [{}])[0].get('image_type', [''])[0].lower().startswith('cos'): + self.evaluated_keys = ['node_config/[0]/image_type'] + return CheckResult.PASSED + if conf.get('remove_default_node_pool', [{}])[0]: + self.evaluated_keys.append('remove_default_node_pool') + return CheckResult.PASSED + return CheckResult.FAILED + + return CheckResult.UNKNOWN check = GKEUseCosImage() diff --git a/tests/terraform/checks/resource/gcp/example_GKEUseCosImage/main.tf b/tests/terraform/checks/resource/gcp/example_GKEUseCosImage/main.tf new file mode 100644 index 00000000000..236c141fde1 --- /dev/null +++ b/tests/terraform/checks/resource/gcp/example_GKEUseCosImage/main.tf @@ -0,0 +1,174 @@ + +resource "google_container_node_pool" "fail" { + autoscaling { + max_node_count = "4" + min_node_count = "1" + } + + cluster = google_container_cluster.tfer.name + initial_node_count = "2" + location = "us-west1" + + management { + auto_repair = "true" + auto_upgrade = "true" + } + + max_pods_per_node = "110" + name = "async-pool-2" + + node_config { + disk_size_gb = "400" + disk_type = "pd-ssd" + image_type = "SomethingElse" + + labels = { + async = "true" + } + + local_ssd_count = "0" + machine_type = "custom-32-65536" + + metadata = { + async = "true" + disable-legacy-endpoints = "true" + } + + oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"] + preemptible = "false" + service_account = "default" + + shielded_instance_config { + enable_integrity_monitoring = "true" + enable_secure_boot = "true" + } + } + + node_count = "1" + node_locations = ["us-west1-b", "us-west1-a"] + project = "test-project" + + upgrade_settings { + max_surge = "1" + max_unavailable = "0" + } + + version = "1.14.10-gke.36" + zone = "us-west1" +} + + +resource "google_container_node_pool" "pass" { + autoscaling { + max_node_count = "4" + min_node_count = "1" + } + + cluster = google_container_cluster.tfer.name + initial_node_count = "2" + location = "us-west1" + + management { + auto_repair = "true" + auto_upgrade = "true" + } + + max_pods_per_node = "110" + name = "async-pool-2" + + node_config { + disk_size_gb = "400" + disk_type = "pd-ssd" + image_type = "COS" + + labels = { + async = "true" + } + + local_ssd_count = "0" + machine_type = "custom-32-65536" + + metadata = { + async = "true" + disable-legacy-endpoints = "true" + } + + oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"] + preemptible = "false" + service_account = "default" + + shielded_instance_config { + enable_integrity_monitoring = "true" + enable_secure_boot = "true" + } + } + + node_count = "1" + node_locations = ["us-west1-b", "us-west1-a"] + project = "test-project" + + upgrade_settings { + max_surge = "1" + max_unavailable = "0" + } + + version = "1.14.10-gke.36" + zone = "us-west1" +} + +resource "google_container_node_pool" "unknown" { + autoscaling { + max_node_count = "4" + min_node_count = "1" + } + + cluster = google_container_cluster.tfer.name + initial_node_count = "2" + location = "us-west1" + + management { + auto_repair = "true" + auto_upgrade = "true" + } + + max_pods_per_node = "110" + name = "async-pool-2" + + node_config { + disk_size_gb = "400" + disk_type = "pd-ssd" + + labels = { + async = "true" + } + + local_ssd_count = "0" + machine_type = "custom-32-65536" + + metadata = { + async = "true" + disable-legacy-endpoints = "true" + } + + oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"] + preemptible = "false" + service_account = "default" + + shielded_instance_config { + enable_integrity_monitoring = "true" + enable_secure_boot = "true" + } + } + + node_count = "1" + node_locations = ["us-west1-b", "us-west1-a"] + project = "test-project" + + upgrade_settings { + max_surge = "1" + max_unavailable = "0" + } + + version = "1.25.10-gke.36" + zone = "us-west1" +} diff --git a/tests/terraform/checks/resource/gcp/test_GKEUseCosImage.py b/tests/terraform/checks/resource/gcp/test_GKEUseCosImage.py index 9b25a8da6aa..36d47af8047 100644 --- a/tests/terraform/checks/resource/gcp/test_GKEUseCosImage.py +++ b/tests/terraform/checks/resource/gcp/test_GKEUseCosImage.py @@ -1,140 +1,39 @@ import unittest - -import hcl2 +import os from checkov.terraform.checks.resource.gcp.GKEUseCosImage import check -from checkov.common.models.enums import CheckResult +from checkov.runner_filter import RunnerFilter +from checkov.terraform.runner import Runner class TestGKEUseCosImage(unittest.TestCase): - def test_failure(self): - hcl_res = hcl2.loads(""" - resource "google_container_node_pool" "tfer" { - autoscaling { - max_node_count = "4" - min_node_count = "1" - } - - cluster = google_container_cluster.tfer.name - initial_node_count = "2" - location = "us-west1" - - management { - auto_repair = "true" - auto_upgrade = "true" - } + def test(self): + runner = Runner() + current_dir = os.path.dirname(os.path.realpath(__file__)) - max_pods_per_node = "110" - name = "async-pool-2" + test_files_dir = current_dir + "/example_GKEUseCosImage" + report = runner.run(root_folder=test_files_dir, runner_filter=RunnerFilter(checks=[check.id])) + summary = report.get_summary() - node_config { - disk_size_gb = "400" - disk_type = "pd-ssd" - image_type = "SomethingElse" - - labels = { - async = "true" + passing_resources = { + 'google_container_node_pool.pass', } - local_ssd_count = "0" - machine_type = "custom-32-65536" - - metadata = { - async = "true" - disable-legacy-endpoints = "true" + failing_resources = { + 'google_container_node_pool.fail', } - oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"] - preemptible = "false" - service_account = "default" - - shielded_instance_config { - enable_integrity_monitoring = "true" - enable_secure_boot = "true" - } - } - - node_count = "1" - node_locations = ["us-west1-b", "us-west1-a"] - project = "test-project" - - upgrade_settings { - max_surge = "1" - max_unavailable = "0" - } - - version = "1.14.10-gke.36" - zone = "us-west1" - } - """) - resource_conf = hcl_res['resource'][0]['google_container_node_pool']['tfer'] - scan_result = check.scan_resource_conf(conf=resource_conf) - self.assertEqual(CheckResult.FAILED, scan_result) - - def test_success(self): - hcl_res = hcl2.loads(""" -resource "google_container_node_pool" "tfer" { - autoscaling { - max_node_count = "4" - min_node_count = "1" - } - - cluster = google_container_cluster.tfer.name - initial_node_count = "2" - location = "us-west1" - - management { - auto_repair = "true" - auto_upgrade = "true" - } - - max_pods_per_node = "110" - name = "async-pool-2" - - node_config { - disk_size_gb = "400" - disk_type = "pd-ssd" - image_type = "COS" - - labels = { - async = "true" - } - - local_ssd_count = "0" - machine_type = "custom-32-65536" - - metadata = { - async = "true" - disable-legacy-endpoints = "true" - } - - oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"] - preemptible = "false" - service_account = "default" - - shielded_instance_config { - enable_integrity_monitoring = "true" - enable_secure_boot = "true" - } - } - - node_count = "1" - node_locations = ["us-west1-b", "us-west1-a"] - project = "test-project" + passed_check_resources = set([c.resource for c in report.passed_checks]) + failed_check_resources = set([c.resource for c in report.failed_checks]) - upgrade_settings { - max_surge = "1" - max_unavailable = "0" - } + self.assertEqual(summary['passed'], len(passing_resources)) + self.assertEqual(summary['failed'], len(failing_resources)) + self.assertEqual(summary['skipped'], 0) + self.assertEqual(summary['parsing_errors'], 0) - version = "1.14.10-gke.36" - zone = "us-west1" -} - """) - resource_conf = hcl_res['resource'][0]['google_container_node_pool']['tfer'] - scan_result = check.scan_resource_conf(conf=resource_conf) - self.assertEqual(CheckResult.PASSED, scan_result) + self.assertEqual(passing_resources, passed_check_resources) + self.assertEqual(failing_resources, failed_check_resources) if __name__ == '__main__': From d3668b624caa0689f8ed934838f4d2e4da2afa45 Mon Sep 17 00:00:00 2001 From: James Woolfenden Date: Wed, 20 Dec 2023 13:02:28 +0000 Subject: [PATCH 2/2] trim docs --- checkov/terraform/checks/resource/gcp/GKEUseCosImage.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/checkov/terraform/checks/resource/gcp/GKEUseCosImage.py b/checkov/terraform/checks/resource/gcp/GKEUseCosImage.py index 210a2649b23..5995d9771ed 100644 --- a/checkov/terraform/checks/resource/gcp/GKEUseCosImage.py +++ b/checkov/terraform/checks/resource/gcp/GKEUseCosImage.py @@ -13,10 +13,8 @@ def __init__(self): def scan_resource_conf(self, conf): """ CKV_GCP_22 - error creating NodePool: googleapi: Error 400: Creation of node pools using node images based on Docker + This a legacy check, Creation of node pools using node images based on Docker container runtimes is not supported in GKE v1.24+ clusters as Dockershim has been removed in Kubernetes v1.24. - - image_type = "COS" """ if conf.get('version') and isinstance(conf.get('version'), list): raw = conf.get('version')[0]