Skip to content

Commit

Permalink
feat(terraform): Adding Python based build time policies for correspo…
Browse files Browse the repository at this point in the history
…nding PC runtime policies (#5762)

* adding 2 YAML policies - S3 & Neptune security config

* adding 2 YAML policies

* adding 2 YAML policies

* adding 2 YAML policies

* added 2 YAML policies

* updated the pass and fail cases

* Updated terraform pass and fail cases

* Deleted - AWS S3 global ACL view check

* added policy "Ensure Elastic Search has dedicated master node enabled"

CKV2_AWS_59: Ensure Elastic Search has dedicated master node enabled

* added policy "CKV2_AWS_60: Ensure RDS instance with copy tags to snapshots is enabled"

Ensure RDS instance with copy tags to snapshots is enabled

* [New Policy]: CKV2_AZURE_23: Ensure Azure spring cloud is configured with Virtual network (Vnet)

CKV2_AZURE_23: Ensure Azure spring cloud is configured with Virtual network (Vnet)

* [2 new Policies]: CKV2_AZURE_24, CKV2_AZURE_25

CKV2_AZURE_24: Ensure Azure automation account is NOT overly permissive

CKV2_AZURE_25: Ensure Azure SQL database Transparent Data Encryption (TDE) is enabled

* Update checkov/terraform/checks/graph_checks/aws/ElasticSearchDedicatedMasterEnabled.yaml

Added opensearch check capability

Co-authored-by: Anton Grübel <[email protected]>

* Modified CKV2_AWS_59: Ensure ElasticSearch/OpenSearch has dedicated master node enabled

* Renamed/Modified CKV2_AZURE_24: Ensure Azure automation account does NOT have overly permissive network access

* Renamed/Modified CKV2_AZURE_24: Ensure Azure automation account does NOT have overly permissive network access

* Modified CKV2_AZURE_23: Ensure Azure spring cloud is configured with Virtual network (Vnet)

* CKV2_AZURE_25: Ensure Azure SQL database Transparent Data Encryption (TDE) is enabled

* Modified CKV2_AWS_60: Ensure RDS instance with copy tags to snapshots is enabled

* Added 5 YAML policies

* Modified CKV2_AWS_60: Ensure RDS instance with copy tags to snapshots is enabled

* Added 2 policies related to customer ask (GIC)

* Optimised the policy name for CKV2_AWS_66

* Added the 2 policies records to test_yaml_policies.py

* Modified policies as per suggestions

* fix resource references

* Added 1 Azure policy CKV_AZURE_233: AzureDefenderDisabledForResManager

* Added new Azure policy CKV_AZURE_234: AzureContainerInstanceEnvVarSecureValueType

* Updated CKV_AZURE_234 test file with pass & fail use-cases

* Added skip comments

* Added skip comment for CKV_SECRET_6

* Optimised comments for CKV_SECRET_6

* Updated policy ID due to conflicts

* Optimised policy AzureContainerInstanceEnvVarSecureValueType

* Updated the files as per changes mentioned

---------

Co-authored-by: Anton Grübel <[email protected]>
  • Loading branch information
praveen-panw and gruebel authored Dec 4, 2023
1 parent 7021c0c commit 1d561f7
Show file tree
Hide file tree
Showing 7 changed files with 283 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from __future__ import annotations
from typing import Any
from checkov.common.models.enums import CheckCategories, CheckResult
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck

import itertools


class AzureContainerInstanceEnvVarSecureValueType(BaseResourceCheck):
def __init__(self) -> None:
name = "Ensure that Azure container environment variables are configured with secure values only"
id = "CKV_AZURE_235"
supported_resources = ("azurerm_container_group",)
categories = (CheckCategories.GENERAL_SECURITY,)
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def scan_resource_conf(self, conf: dict[str, list[Any]]) -> CheckResult:

for container in itertools.chain(conf.get('container', {}), conf.get('init_container', {})):
if "environment_variables" in container:
return CheckResult.FAILED
return CheckResult.PASSED


check = AzureContainerInstanceEnvVarSecureValueType()
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from __future__ import annotations

from typing import Any

from checkov.common.models.enums import CheckCategories, CheckResult
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck


class AzureDefenderDisabledForResManager(BaseResourceCheck):
def __init__(self) -> None:
name = "Ensure that Azure Defender for cloud is set to On for Resource Manager"
id = "CKV_AZURE_234"
supported_resources = ("azurerm_security_center_subscription_pricing",)
categories = (CheckCategories.GENERAL_SECURITY,)
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def scan_resource_conf(self, conf: dict[str, list[Any]]) -> CheckResult:
return (
CheckResult.PASSED
if conf.get("resource_type", [""])[0].lower() == "arm" and conf.get("tier", [""])[0].lower() == "standard"
else CheckResult.FAILED
)

def get_evaluated_keys(self) -> list[str]:
return ["resource_type", "tier"]


check = AzureDefenderDisabledForResManager()
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Variables declaration:

variable "pud_default_var" {
default = "pud_default_value"
}

resource "random_string" "pud-random-str" {
length = 10
special = false
numeric = false
}

# Case 1: Pass: 'secure_environment_variables' exists in 'container' block and just 'environment_variables' doesn't exist

resource "azurerm_container_group" "pass_1" {
name = "pud_pass_1_container"
location = var.pud_default_var
resource_group_name = var.pud_default_var
ip_address_type = "Public"
dns_name_label = "aci-label"
os_type = "Linux"

container {
name = "hello-world"
image = "mcr.microsoft.com/azuredocs/aci-helloworld:latest"
cpu = "0.5"
memory = "1.5"

ports {
port = 443
protocol = "TCP"
}
}

container {
name = "een_le_pa"
image = "mcr.microsoft.com/azuredocs/aci-tutorial-sidecar"
cpu = "0.5"
memory = "1.5"

secure_environment_variables = {
SEC_CONT_PASS_1 = random_string.pud-random-str
}
}
}

# case 2: Pass: No environment variables exists

resource "azurerm_container_group" "pass_2" {
name = "pud_pass_2_container"
location = "westus2"
resource_group_name = var.pud_default_var
os_type = "Linux"

init_container {
name = "init-container"
image = "init-image:latest"
cpu = 0.5
memory = 512

}
}

# Case 3: Fail: 'environment_variables' exists in 'init_container' block

resource "azurerm_container_group" "fail_1" {
name = "pud_fail_1_container"
location = "westus2"
resource_group_name = var.pud_default_var
os_type = "Linux"

init_container {
name = "init-container"
image = "init-image:latest"
cpu = 0.5
memory = 512


environment_variables = {
ENV_INIT_FAIL_1 = random_string.pud-random-str
}

secure_environment_variables = {
SEC_INIT_FAIL_1 = random_string.pud-random-str
}
}
}

# Case 4: Fail: 'environment_variables' exists in 'container' block

resource "azurerm_container_group" "fail_2" {
name = "pud_pass_2_container"
location = "westus2"
resource_group_name = var.pud_default_var
os_type = "Linux"

init_container {
name = "pud-init-container"
image = "init-image:latest"
cpu = 0.5
memory = 512

secure_environment_variables = {
SEC_INIT_FAIL_2 = random_string.pud-random-str
}
}

container {
name = "pud-container"
image = "my-image:latest"
cpu = 1
memory = 1024

ports {
port = 80
protocol = "TCP"
}

environment_variables = {
ENV_CONT_FAIL_2 = random_string.pud-random-str
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

# Case 1: Pass: tier is Standard and resource_type is Arm

resource "azurerm_security_center_subscription_pricing" "pass" {
tier = "Standard"
resource_type = "Arm"
}

# Case 2: Fails as "tier" should be "Standard"

resource "azurerm_security_center_subscription_pricing" "fail_1" {
tier = "Free"
resource_type = "arm"
}

# Case 3: Fails as "resource_type" should be "Arm"

resource "azurerm_security_center_subscription_pricing" "fail_2" {
tier = "Standard"
resource_type = "Dns"
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import os
import unittest

from checkov.runner_filter import RunnerFilter
from checkov.terraform.runner import Runner
from checkov.terraform.checks.resource.azure.AzureContainerInstanceEnvVarSecureValueType import check


class TestAzureContainerInstanceEnvVarSecureValueType(unittest.TestCase):
def test(self):
runner = Runner()
current_dir = os.path.dirname(os.path.realpath(__file__))

test_files_dir = os.path.join(current_dir, "example_AzureContainerInstanceEnvVarSecureValueType")
report = runner.run(root_folder=test_files_dir,
runner_filter=RunnerFilter(checks=[check.id]))
summary = report.get_summary()

passing_resources = {
'azurerm_container_group.pass_1',
'azurerm_container_group.pass_2',
}
failing_resources = {
'azurerm_container_group.fail_1',
'azurerm_container_group.fail_2',
}
skipped_resources = {}

passed_check_resources = {c.resource for c in report.passed_checks}
failed_check_resources = {c.resource for c in report.failed_checks}

self.assertEqual(summary['passed'], len(passing_resources))
self.assertEqual(summary['failed'], len(failing_resources))
self.assertEqual(summary['skipped'], len(skipped_resources))
self.assertEqual(summary['parsing_errors'], 0)

self.assertEqual(passing_resources, passed_check_resources)
self.assertEqual(failing_resources, failed_check_resources)


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import os
import unittest

from checkov.runner_filter import RunnerFilter
from checkov.terraform.runner import Runner
from checkov.terraform.checks.resource.azure.AzureDefenderDisabledForResManager import check


class TestAzureDefenderDisabledForResManager(unittest.TestCase):
def test(self):
runner = Runner()
current_dir = os.path.dirname(os.path.realpath(__file__))

test_files_dir = os.path.join(current_dir, "example_AzureDefenderDisabledForResManager")
report = runner.run(root_folder=test_files_dir,
runner_filter=RunnerFilter(checks=[check.id]))
summary = report.get_summary()

passing_resources = {
'azurerm_security_center_subscription_pricing.pass',
}
failing_resources = {
'azurerm_security_center_subscription_pricing.fail_1',
'azurerm_security_center_subscription_pricing.fail_2',
}
skipped_resources = {}

passed_check_resources = {c.resource for c in report.passed_checks}
failed_check_resources = {c.resource for c in report.failed_checks}

self.assertEqual(summary['passed'], len(passing_resources))
self.assertEqual(summary['failed'], len(failing_resources))
self.assertEqual(summary['skipped'], len(skipped_resources))
self.assertEqual(summary['parsing_errors'], 0)

self.assertEqual(passing_resources, passed_check_resources)
self.assertEqual(failing_resources, failed_check_resources)


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def test_containers_resources(mocker: MockerFixture, graph_framework):
sca_image_report = next(report for report in reports if report.check_type == CheckType.SCA_IMAGE)

assert len(tf_report.resources) == 1
assert len(tf_report.passed_checks) == 0
assert len(tf_report.passed_checks) == 1
assert len(tf_report.failed_checks) == 2
assert len(tf_report.skipped_checks) == 0
assert len(tf_report.parsing_errors) == 0
Expand Down

0 comments on commit 1d561f7

Please sign in to comment.