Repository: bridgecrewio/checkov

Issue:
AWS Route 53 checks (CKV2_AWS_38 and CKV_AWS_39) false positive in Terraform Plan framework
**Describe the issue**
AWS Route 53 DNSSEC and Query Logging checks flag as false positive in Terraform Plan framework.

**Examples**
Use Hashicorp's basic example to reproduce

**Version (please complete the following information):**
 - 2.1.226

**Additional context**
Create a new file/project using the Hashicorp example given
Run a vanilla check: `checkov -f foo.tf --quiet --compact -c CKV2_AWS_39`. Observe no issues.
Create a plan and format it with json: `terraform plan -out tfplan.bin && terraform state show tfplan.bin > tfplan.json`
Check it with terraform_plan framework: `checkov -f tfplan.json --framework terraform_plan --compact --quiet -c CKV2_AWS_39`. Observe it fail.

This same behavior occurs with CKV2_AWS_38 as well using the same basic example, and again--only with Terraform Plan: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_hosted_zone_dnssec



Discussion:
hey @citrix-eg thanks for reaching out. I can't reproduce it for `CKV2_AWS_38`, but for `CKV2_AWS_39` I found the reason, probably it will be the same for the other one. The problem is that the resource `aws_route53_query_log` has no values initially in the TF plan and therefore we exclude it, because we think it is not a real resource.

Resolving patch:
diff --git a/checkov/terraform/plan_parser.py b/checkov/terraform/plan_parser.py
--- a/checkov/terraform/plan_parser.py
+++ b/checkov/terraform/plan_parser.py
@@ -70,7 +70,11 @@ def _hclify(obj: DictNode, conf: Optional[DictNode] = None, parent_key: Optional
     if conf and isinstance(conf, dict):
         found_ref = False
         for conf_key in conf.keys() - obj.keys():
-            ref = next((x for x in conf[conf_key].get("references", []) if not x.startswith(("var.", "local."))), None)
+            conf_value = conf[conf_key]
+            if not isinstance(conf_value, dict):
+                continue
+
+            ref = next((x for x in conf_value.get("references", []) if not x.startswith(("var.", "local."))), None)
             if ref:
                 ret_dict[conf_key] = [ref]
                 found_ref = True
@@ -104,10 +108,10 @@ def _prepare_resource_block(
         mode = resource.get("mode")
     # Rare cases where data block appears in resources with same name as resource block and only partial values
     # and where *_module resources don't have values field
-    if mode == "managed" and "values" in resource:
+    if mode == "managed":
         expressions = conf.get("expressions") if conf else None
 
-        resource_conf = _hclify(resource["values"], expressions)
+        resource_conf = _hclify(resource.get("values", {}), expressions)
         resource_address = resource.get("address")
         resource_conf[TF_PLAN_RESOURCE_ADDRESS] = resource_address
 


Test patch:
diff --git a/tests/terraform/runner/resources/plan_root_module_resources_no_values/tfplan_route53.json b/tests/terraform/runner/resources/plan_root_module_resources_no_values/tfplan_route53.json
new file mode 100644
--- /dev/null
+++ b/tests/terraform/runner/resources/plan_root_module_resources_no_values/tfplan_route53.json
@@ -0,0 +1,391 @@
+{
+  "format_version": "1.0",
+  "terraform_version": "1.1.5",
+  "planned_values": {
+    "root_module": {
+      "resources": [
+        {
+          "address": "aws_cloudwatch_log_group.aws_route53_example_com",
+          "mode": "managed",
+          "type": "aws_cloudwatch_log_group",
+          "name": "aws_route53_example_com",
+          "provider_name": "registry.terraform.io/hashicorp/aws",
+          "schema_version": 0,
+          "values": {
+            "kms_key_id": null,
+            "name": "/aws/route53/example.com",
+            "name_prefix": null,
+            "retention_in_days": 30,
+            "tags": null
+          },
+          "sensitive_values": {
+            "tags_all": {}
+          }
+        },
+        {
+          "address": "aws_cloudwatch_log_resource_policy.route53-query-logging-policy",
+          "mode": "managed",
+          "type": "aws_cloudwatch_log_resource_policy",
+          "name": "route53-query-logging-policy",
+          "provider_name": "registry.terraform.io/hashicorp/aws",
+          "schema_version": 0,
+          "values": {
+            "policy_document": "{\"Statement\":[{\"Action\":[\"logs:PutLogEvents\",\"logs:CreateLogStream\"],\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"route53.amazonaws.com\"},\"Resource\":\"arn:aws:logs:*:*:log-group:/aws/route53/*\",\"Sid\":\"\"}],\"Version\":\"2012-10-17\"}",
+            "policy_name": "route53-query-logging-policy"
+          },
+          "sensitive_values": {}
+        },
+        {
+          "address": "aws_route53_query_log.example_com",
+          "mode": "managed",
+          "type": "aws_route53_query_log",
+          "name": "example_com",
+          "provider_name": "registry.terraform.io/hashicorp/aws",
+          "schema_version": 0,
+          "sensitive_values": {}
+        },
+        {
+          "address": "aws_route53_zone.example_com",
+          "mode": "managed",
+          "type": "aws_route53_zone",
+          "name": "example_com",
+          "provider_name": "registry.terraform.io/hashicorp/aws",
+          "schema_version": 0,
+          "values": {
+            "comment": "Managed by Terraform",
+            "delegation_set_id": null,
+            "force_destroy": false,
+            "name": "example.com",
+            "tags": null,
+            "vpc": []
+          },
+          "sensitive_values": {
+            "name_servers": [],
+            "tags_all": {},
+            "vpc": []
+          }
+        }
+      ]
+    }
+  },
+  "resource_changes": [
+    {
+      "address": "aws_cloudwatch_log_group.aws_route53_example_com",
+      "mode": "managed",
+      "type": "aws_cloudwatch_log_group",
+      "name": "aws_route53_example_com",
+      "provider_name": "registry.terraform.io/hashicorp/aws",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "kms_key_id": null,
+          "name": "/aws/route53/example.com",
+          "name_prefix": null,
+          "retention_in_days": 30,
+          "tags": null
+        },
+        "after_unknown": {
+          "arn": true,
+          "id": true,
+          "tags_all": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {
+          "tags_all": {}
+        }
+      }
+    },
+    {
+      "address": "aws_cloudwatch_log_resource_policy.route53-query-logging-policy",
+      "mode": "managed",
+      "type": "aws_cloudwatch_log_resource_policy",
+      "name": "route53-query-logging-policy",
+      "provider_name": "registry.terraform.io/hashicorp/aws",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "policy_document": "{\"Statement\":[{\"Action\":[\"logs:PutLogEvents\",\"logs:CreateLogStream\"],\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"route53.amazonaws.com\"},\"Resource\":\"arn:aws:logs:*:*:log-group:/aws/route53/*\",\"Sid\":\"\"}],\"Version\":\"2012-10-17\"}",
+          "policy_name": "route53-query-logging-policy"
+        },
+        "after_unknown": {
+          "id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "aws_route53_query_log.example_com",
+      "mode": "managed",
+      "type": "aws_route53_query_log",
+      "name": "example_com",
+      "provider_name": "registry.terraform.io/hashicorp/aws",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {},
+        "after_unknown": {
+          "arn": true,
+          "cloudwatch_log_group_arn": true,
+          "id": true,
+          "zone_id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {}
+      }
+    },
+    {
+      "address": "aws_route53_zone.example_com",
+      "mode": "managed",
+      "type": "aws_route53_zone",
+      "name": "example_com",
+      "provider_name": "registry.terraform.io/hashicorp/aws",
+      "change": {
+        "actions": [
+          "create"
+        ],
+        "before": null,
+        "after": {
+          "comment": "Managed by Terraform",
+          "delegation_set_id": null,
+          "force_destroy": false,
+          "name": "example.com",
+          "tags": null,
+          "vpc": []
+        },
+        "after_unknown": {
+          "arn": true,
+          "id": true,
+          "name_servers": true,
+          "tags_all": true,
+          "vpc": [],
+          "zone_id": true
+        },
+        "before_sensitive": false,
+        "after_sensitive": {
+          "name_servers": [],
+          "tags_all": {},
+          "vpc": []
+        }
+      }
+    }
+  ],
+  "prior_state": {
+    "format_version": "1.0",
+    "terraform_version": "1.1.5",
+    "values": {
+      "root_module": {
+        "resources": [
+          {
+            "address": "data.aws_iam_policy_document.route53-query-logging-policy",
+            "mode": "data",
+            "type": "aws_iam_policy_document",
+            "name": "route53-query-logging-policy",
+            "provider_name": "registry.terraform.io/hashicorp/aws",
+            "schema_version": 0,
+            "values": {
+              "id": "1584671853",
+              "json": "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"\",\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"logs:PutLogEvents\",\n        \"logs:CreateLogStream\"\n      ],\n      \"Resource\": \"arn:aws:logs:*:*:log-group:/aws/route53/*\",\n      \"Principal\": {\n        \"Service\": \"route53.amazonaws.com\"\n      }\n    }\n  ]\n}",
+              "override_json": null,
+              "override_policy_documents": null,
+              "policy_id": null,
+              "source_json": null,
+              "source_policy_documents": null,
+              "statement": [
+                {
+                  "actions": [
+                    "logs:CreateLogStream",
+                    "logs:PutLogEvents"
+                  ],
+                  "condition": [],
+                  "effect": "Allow",
+                  "not_actions": [],
+                  "not_principals": [],
+                  "not_resources": [],
+                  "principals": [
+                    {
+                      "identifiers": [
+                        "route53.amazonaws.com"
+                      ],
+                      "type": "Service"
+                    }
+                  ],
+                  "resources": [
+                    "arn:aws:logs:*:*:log-group:/aws/route53/*"
+                  ],
+                  "sid": ""
+                }
+              ],
+              "version": "2012-10-17"
+            },
+            "sensitive_values": {
+              "statement": [
+                {
+                  "actions": [
+                    false,
+                    false
+                  ],
+                  "condition": [],
+                  "not_actions": [],
+                  "not_principals": [],
+                  "not_resources": [],
+                  "principals": [
+                    {
+                      "identifiers": [
+                        false
+                      ]
+                    }
+                  ],
+                  "resources": [
+                    false
+                  ]
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  },
+  "configuration": {
+    "provider_config": {
+      "aws.us-east-1": {
+        "name": "aws",
+        "alias": "us-east-1",
+        "expressions": {
+          "profile": {
+            "constant_value": "dev"
+          },
+          "region": {
+            "constant_value": "us-east-1"
+          }
+        }
+      }
+    },
+    "root_module": {
+      "resources": [
+        {
+          "address": "aws_cloudwatch_log_group.aws_route53_example_com",
+          "mode": "managed",
+          "type": "aws_cloudwatch_log_group",
+          "name": "aws_route53_example_com",
+          "provider_config_key": "aws.us-east-1",
+          "expressions": {
+            "name": {
+              "references": [
+                "aws_route53_zone.example_com.name",
+                "aws_route53_zone.example_com"
+              ]
+            },
+            "retention_in_days": {
+              "constant_value": 30
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "aws_cloudwatch_log_resource_policy.route53-query-logging-policy",
+          "mode": "managed",
+          "type": "aws_cloudwatch_log_resource_policy",
+          "name": "route53-query-logging-policy",
+          "provider_config_key": "aws.us-east-1",
+          "expressions": {
+            "policy_document": {
+              "references": [
+                "data.aws_iam_policy_document.route53-query-logging-policy.json",
+                "data.aws_iam_policy_document.route53-query-logging-policy"
+              ]
+            },
+            "policy_name": {
+              "constant_value": "route53-query-logging-policy"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "aws_route53_query_log.example_com",
+          "mode": "managed",
+          "type": "aws_route53_query_log",
+          "name": "example_com",
+          "provider_config_key": "aws",
+          "expressions": {
+            "cloudwatch_log_group_arn": {
+              "references": [
+                "aws_cloudwatch_log_group.aws_route53_example_com.arn",
+                "aws_cloudwatch_log_group.aws_route53_example_com"
+              ]
+            },
+            "zone_id": {
+              "references": [
+                "aws_route53_zone.example_com.zone_id",
+                "aws_route53_zone.example_com"
+              ]
+            }
+          },
+          "schema_version": 0,
+          "depends_on": [
+            "aws_cloudwatch_log_resource_policy.route53-query-logging-policy"
+          ]
+        },
+        {
+          "address": "aws_route53_zone.example_com",
+          "mode": "managed",
+          "type": "aws_route53_zone",
+          "name": "example_com",
+          "provider_config_key": "aws",
+          "expressions": {
+            "name": {
+              "constant_value": "example.com"
+            }
+          },
+          "schema_version": 0
+        },
+        {
+          "address": "data.aws_iam_policy_document.route53-query-logging-policy",
+          "mode": "data",
+          "type": "aws_iam_policy_document",
+          "name": "route53-query-logging-policy",
+          "provider_config_key": "aws",
+          "expressions": {
+            "statement": [
+              {
+                "actions": {
+                  "constant_value": [
+                    "logs:CreateLogStream",
+                    "logs:PutLogEvents"
+                  ]
+                },
+                "principals": [
+                  {
+                    "identifiers": {
+                      "constant_value": [
+                        "route53.amazonaws.com"
+                      ]
+                    },
+                    "type": {
+                      "constant_value": "Service"
+                    }
+                  }
+                ],
+                "resources": {
+                  "constant_value": [
+                    "arn:aws:logs:*:*:log-group:/aws/route53/*"
+                  ]
+                }
+              }
+            ]
+          },
+          "schema_version": 0
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/terraform/runner/test_plan_runner.py b/tests/terraform/runner/test_plan_runner.py
--- a/tests/terraform/runner/test_plan_runner.py
+++ b/tests/terraform/runner/test_plan_runner.py
@@ -297,6 +297,29 @@ def test_runner_root_module_resources_no_values(self):
 
         assert failed_check_ids == expected_failed_check_ids
 
+    def test_runner_root_module_resources_no_values_route53(self):
+        #given
+        plan_file = Path(__file__).parent / "resources/plan_root_module_resources_no_values/tfplan_route53.json"
+
+        # when
+        report = Runner().run(
+            root_folder=None,
+            files=[str(plan_file)],
+            external_checks_dir=None,
+            runner_filter=RunnerFilter(framework=["terraform_plan"], checks=["CKV2_AWS_38", "CKV2_AWS_39"]),
+        )
+
+        # then
+        summary = report.get_summary()
+
+        self.assertEqual(summary["failed"], 1)
+        self.assertEqual(summary["passed"], 1)
+
+        passed_check_ids = set(c.check_id for c in report.passed_checks)
+        expected_passed_check_ids = {"CKV2_AWS_39"}
+
+        self.assertCountEqual(passed_check_ids, expected_passed_check_ids)
+
     def test_runner_data_resource_partial_values(self):
         # In rare circumstances a data resource with partial values in the plan could cause false negatives
         # Often 'data' does not even appear in the *_modules[x].resouces field within planned_values and is not scanned as expected