diff --git a/checkov/cloudformation/checks/resource/aws/DocDBBackupRetention.py b/checkov/cloudformation/checks/resource/aws/DocDBBackupRetention.py new file mode 100644 index 00000000000..b3db3e802e1 --- /dev/null +++ b/checkov/cloudformation/checks/resource/aws/DocDBBackupRetention.py @@ -0,0 +1,25 @@ +from checkov.common.models.enums import CheckCategories, CheckResult +from checkov.cloudformation.checks.resource.base_resource_value_check import BaseResourceValueCheck + + +class DocDBBackupRetention(BaseResourceValueCheck): + def __init__(self) -> None: + name = "Ensure DocDB has an adequate backup retention period" + id = "CKV_AWS_360" + supported_resources = ("AWS::DocDB::DBCluster",) + categories = (CheckCategories.BACKUP_AND_RECOVERY,) + super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources) + + def get_inspected_key(self) -> str: + return "Properties/BackupRetentionPeriod" + + def scan_resource_conf(self, conf) -> CheckResult: + properties = conf.get("Properties") + if properties: + backup_retention_period = properties.get("BackupRetentionPeriod", 1) + if backup_retention_period >= 7: + return CheckResult.PASSED + return CheckResult.FAILED + + +check = DocDBBackupRetention() diff --git a/checkov/terraform/checks/resource/aws/DocDBBackupRetention.py b/checkov/terraform/checks/resource/aws/DocDBBackupRetention.py new file mode 100644 index 00000000000..c04dbf772bf --- /dev/null +++ b/checkov/terraform/checks/resource/aws/DocDBBackupRetention.py @@ -0,0 +1,22 @@ +from checkov.common.models.enums import CheckCategories, CheckResult +from checkov.terraform.checks.resource.base_resource_value_check import BaseResourceValueCheck + + +class DocDBBackupRetention(BaseResourceValueCheck): + def __init__(self): + name = "Ensure DocDB has an adequate backup retention period" + id = "CKV_AWS_360" + supported_resources = ['aws_docdb_cluster'] + categories = [CheckCategories.BACKUP_AND_RECOVERY] + super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources) + + def get_inspected_key(self): + return "backup_retention_period" + + def scan_resource_conf(self, conf): + if conf.get("backup_retention_period", [1])[0] >= 7: + return CheckResult.PASSED + return CheckResult.FAILED + + +check = DocDBBackupRetention() diff --git a/tests/cloudformation/checks/resource/aws/example_DocDBBackupRetention/DocDBBackupRetention-FAILED.yaml b/tests/cloudformation/checks/resource/aws/example_DocDBBackupRetention/DocDBBackupRetention-FAILED.yaml new file mode 100644 index 00000000000..aee5895419d --- /dev/null +++ b/tests/cloudformation/checks/resource/aws/example_DocDBBackupRetention/DocDBBackupRetention-FAILED.yaml @@ -0,0 +1,13 @@ +AWSTemplateFormatVersion: "2010-09-09" +Resources: + DocDBDefault: + Type: AWS::DocDB::DBCluster + Properties: + MasterUsername: name + MasterUserPassword: password + DocDBNotAdequate: + Type: AWS::DocDB::DBCluster + Properties: + MasterUsername: name + MasterUserPassword: password + BackupRetentionPeriod: 3 \ No newline at end of file diff --git a/tests/cloudformation/checks/resource/aws/example_DocDBBackupRetention/DocDBBackupRetention-PASSED.yaml b/tests/cloudformation/checks/resource/aws/example_DocDBBackupRetention/DocDBBackupRetention-PASSED.yaml new file mode 100644 index 00000000000..1d9bb3f3ee9 --- /dev/null +++ b/tests/cloudformation/checks/resource/aws/example_DocDBBackupRetention/DocDBBackupRetention-PASSED.yaml @@ -0,0 +1,8 @@ +AWSTemplateFormatVersion: "2010-09-09" +Resources: + DocDBAdequate: + Type: AWS::DocDB::DBCluster + Properties: + MasterUsername: name + MasterUserPassword: password + BackupRetentionPeriod: 7 diff --git a/tests/cloudformation/checks/resource/aws/test_DocDBBackupRetention.py b/tests/cloudformation/checks/resource/aws/test_DocDBBackupRetention.py new file mode 100644 index 00000000000..a8d309961d9 --- /dev/null +++ b/tests/cloudformation/checks/resource/aws/test_DocDBBackupRetention.py @@ -0,0 +1,39 @@ +import os +import unittest + +from checkov.cloudformation.checks.resource.aws.DocDBBackupRetention import check +from checkov.cloudformation.runner import Runner +from checkov.runner_filter import RunnerFilter + + +class TestDocDBAuditLogs(unittest.TestCase): + def test_summary(self): + runner = Runner() + current_dir = os.path.dirname(os.path.realpath(__file__)) + + test_files_dir = current_dir + "/example_DocDBBackupRetention" + report = runner.run(root_folder=test_files_dir, runner_filter=RunnerFilter(checks=[check.id])) + summary = report.get_summary() + + passing_resources = { + "AWS::DocDB::DBCluster.DocDBAdequate", + } + failing_resources = { + "AWS::DocDB::DBCluster.DocDBDefault", + "AWS::DocDB::DBCluster.DocDBNotAdequate", + } + + passed_check_resources = set([c.resource for c in report.passed_checks]) + failed_check_resources = set([c.resource for c in report.failed_checks]) + + self.assertEqual(summary["passed"], 1) + self.assertEqual(summary["failed"], 2) + self.assertEqual(summary["skipped"], 0) + 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() diff --git a/tests/terraform/checks/resource/aws/example_DocDBBackupRetention/main.tf b/tests/terraform/checks/resource/aws/example_DocDBBackupRetention/main.tf new file mode 100644 index 00000000000..f32dd0036b5 --- /dev/null +++ b/tests/terraform/checks/resource/aws/example_DocDBBackupRetention/main.tf @@ -0,0 +1,31 @@ +# pass + +resource "aws_docdb_cluster" "pass" { + cluster_identifier = "my-docdb-cluster" + engine = "docdb" + master_username = "foo" + master_password = "mustbeeightchars" # checkov:skip=CKV_SECRET_6 test secret + + backup_retention_period = 7 +} + + + +# fail + +resource "aws_docdb_cluster" "fail_no_value" { + cluster_identifier = "my-docdb-cluster" + engine = "docdb" + master_username = "foo" + master_password = "mustbeeightchars" # checkov:skip=CKV_SECRET_6 test secret +} + + +resource "aws_docdb_cluster" "fail_value_not_adequate" { + cluster_identifier = "my-docdb-cluster" + engine = "docdb" + master_username = "foo" + master_password = "mustbeeightchars" # checkov:skip=CKV_SECRET_6 test secret + + backup_retention_period = 3 +} \ No newline at end of file diff --git a/tests/terraform/checks/resource/aws/test_DocDBBackupRetention.py b/tests/terraform/checks/resource/aws/test_DocDBBackupRetention.py new file mode 100644 index 00000000000..cd4c2494521 --- /dev/null +++ b/tests/terraform/checks/resource/aws/test_DocDBBackupRetention.py @@ -0,0 +1,43 @@ +import unittest + +from pathlib import Path + +from checkov.runner_filter import RunnerFilter +from checkov.terraform.runner import Runner +from checkov.common.models.enums import CheckResult +from checkov.terraform.checks.resource.aws.DocDBBackupRetention import check + + +class TestDocDBBackupRetention(unittest.TestCase): + + def test(self): + # given + test_files_dir = Path(__file__).parent / "example_DocDBBackupRetention" + + # when + report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id])) + + # then + summary = report.get_summary() + + passing_resources = { + "aws_docdb_cluster.pass", + } + failing_resources = { + "aws_docdb_cluster.fail_no_value", + "aws_docdb_cluster.fail_value_not_adequate" + } + + 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["parsing_errors"], 0) + self.assertEqual(summary["resource_count"], 3) + + self.assertEqual(passing_resources, passed_check_resources) + self.assertEqual(failing_resources, failed_check_resources) + +if __name__ == '__main__': + unittest.main()