Repository: bridgecrewio/checkov

Issue:
CKV_AWS_139 - RDS cluster deletion protection
**Is your feature request related to a problem? Please describe.**
I think it is great to check, if deletion protection is enabled or not, but is there a reason, why it is only checking for `aws_rds_cluster` and not includes `aws_db_instance`? They are quite similar.

I'm happy to either extend this check to include DB instances or add a new one to check separately for them. 

**Additional context**
https://github.com/bridgecrewio/checkov/blob/caafcbb83d6901b57c9a39464673670c150f0a33/checkov/terraform/checks/resource/aws/RDSDeletionProtection.py#L7-L15



Discussion:
Hi @gruebel !

The reason behind this decision is that compute sizes might need to change, and removing compute resources does not endanger the cluster. In essence, a cluster saves the your data if it has 0 instances.
So to preserve data we recommend enabling deletion protection on those clusters. On the instances - it might just make it harder to scale that way
@nimrodkor 
sure, that makes sense, but I'm not talking about cluster instances, which are `aws_rds_cluster_instance`. I mean the good old single or multi-az instances `aws_db_instance`.
@gruebel 
Me neither :)
I'm talking about the cluster (`aws_rds_cluster`) vs any instance (`aws_rds_cluster_instance` / `aws_db_instance`)
The cluster should have deletion protection. The instance is replaceable - and enabling deletion protection on it can be limiting for no good security reason
Thanks for contributing to Checkov!  We've automatically marked this issue as stale to keep our issues list tidy,  because it has not had any activity for 6 months.  It will be closed in 14 days if no further activity occurs.  Commenting on this issue will remove the stale tag. If you want to talk through the issue or help us understand the priority and context,  feel free to add a comment or join us in the Checkov slack channel at https://slack.bridgecrew.io
Thanks! 

Thanks for contributing to Checkov!  We've automatically marked this issue as stale to keep our issues list tidy,  because it has not had any activity for 6 months.  It will be closed in 14 days if no further activity occurs.  Commenting on this issue will remove the stale tag. If you want to talk through the issue or help us understand the priority and context,  feel free to add a comment or join us in the Checkov slack channel at https://slack.bridgecrew.io
Thanks! 

Closing issue due to inactivity. If you feel this is in error, please re-open, or reach out to the community via slack: https://slack.bridgecrew.io Thanks!

I am interested in this issue, could you assign this issue to me please?
hey @CrypticBantu sure go ahead 🙂 
here you can find the related test file
https://github.com/bridgecrewio/checkov/blob/main/tests/terraform/checks/resource/aws/test_RDSDeletionProtection.py

Resolving patch:
diff --git a/checkov/terraform/checks/resource/aws/RDSInstanceDeletionProtection.py b/checkov/terraform/checks/resource/aws/RDSInstanceDeletionProtection.py
new file mode 100644
--- /dev/null
+++ b/checkov/terraform/checks/resource/aws/RDSInstanceDeletionProtection.py
@@ -0,0 +1,18 @@
+from checkov.terraform.checks.resource.base_resource_value_check import BaseResourceValueCheck
+from checkov.common.models.enums import CheckCategories
+
+
+class RDSInstanceDeletionProtection(BaseResourceValueCheck):
+
+    def __init__(self):
+        name = "Ensure that AWS database instances have deletion protection enabled"
+        id = "CKV_AWS_293"
+        supported_resources = ['aws_db_instance']
+        categories = [CheckCategories.GENERAL_SECURITY]
+        super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)
+
+    def get_inspected_key(self):
+        return 'deletion_protection'
+
+
+check = RDSInstanceDeletionProtection()


Test patch:
diff --git a/tests/terraform/checks/resource/aws/example_RDSInstanceDeletionProtection/main.tf b/tests/terraform/checks/resource/aws/example_RDSInstanceDeletionProtection/main.tf
new file mode 100644
--- /dev/null
+++ b/tests/terraform/checks/resource/aws/example_RDSInstanceDeletionProtection/main.tf
@@ -0,0 +1,35 @@
+
+resource "aws_db_instance" "fail" {
+    cluster_identifier      = "aurora-cluster-demo"
+    availability_zones      = ["us-west-2a", "us-west-2b", "us-west-2c"]
+  database_name           = "mydb"
+    master_username         = "foo"
+    master_password         = "bar"
+    backup_retention_period = 5
+    preferred_backup_window = "07:00-09:00"
+    deletion_protection = false
+  instance_class            = "m4.large"
+}
+
+resource "aws_db_instance" "fail2" {
+    cluster_identifier      = "aurora-cluster-demo"
+    availability_zones      = ["us-west-2a", "us-west-2b", "us-west-2c"]
+    database_name           = "mydb"
+    master_username         = "foo"
+    master_password         = "bar"
+    backup_retention_period = 5
+    preferred_backup_window = "07:00-09:00"
+    instance_class            = "m4.large"
+}
+
+resource "aws_db_instance" "pass" {
+    cluster_identifier      = "aurora-cluster-demo"
+    availability_zones      = ["us-west-2a", "us-west-2b", "us-west-2c"]
+    database_name           = "mydb"
+    master_username         = "foo"
+    master_password         = "bar"
+    backup_retention_period = 5
+    preferred_backup_window = "07:00-09:00"
+    deletion_protection = true
+    instance_class            = "m4.large"
+}
diff --git a/tests/terraform/checks/resource/aws/test_RDSInstanceDeletionProtection.py b/tests/terraform/checks/resource/aws/test_RDSInstanceDeletionProtection.py
new file mode 100644
--- /dev/null
+++ b/tests/terraform/checks/resource/aws/test_RDSInstanceDeletionProtection.py
@@ -0,0 +1,39 @@
+import os
+import unittest
+
+from checkov.runner_filter import RunnerFilter
+from checkov.terraform.checks.resource.aws.RDSInstanceDeletionProtection import check
+from checkov.terraform.runner import Runner
+
+
+class TestRDSInstanceDeletionProtection(unittest.TestCase):
+    def test(self):
+        runner = Runner()
+        current_dir = os.path.dirname(os.path.realpath(__file__))
+
+        test_files_dir = current_dir + "/example_RDSInstanceDeletionProtection"
+        report = runner.run(root_folder=test_files_dir, runner_filter=RunnerFilter(checks=[check.id]))
+        summary = report.get_summary()
+
+        passing_resources = {
+            "aws_db_instance.pass",
+        }
+        failing_resources = {
+            "aws_db_instance.fail",
+            "aws_db_instance.fail2",
+        }
+
+        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"], len(passing_resources))
+        self.assertEqual(summary["failed"], len(failing_resources))
+        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()