Repository: bridgecrewio/checkov

Issue:
concatenated AWS policy statements fail with data type error
**Describe the issue**

When scanning an aws_s3_bucket_policy where the statements are the result of a "concat" operation, checkov errors with the following:

```
TypeError: string indices must be integers, not 'str'
```

**Examples**

The culprit resource is:

```
resource "aws_s3_bucket_policy" "logs" {
  bucket = aws_s3_bucket.logs.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = concat(
      jsondecode(data.aws_iam_policy_document.logs-cloudtrail-policy-acl-check.json).Statement,
      jsondecode(data.aws_iam_policy_document.s3-logs-cloudtrail-policy-write.json).Statement,
      jsondecode(data.aws_iam_policy_document.s3-logs-vpc-flow-logs-policy.json).Statement,
    )
  })
}
```

Each referenced aws_iam_policy_document is valid in of itself.  The problem appears to be that the statement is not evaluated to a real dict value before checkov attempts to introspect it.  Instead, checkov is looking at the string `concat(....)`, not a data structure.


**Exception Trace**

```
2025-04-08 12:52:24,558 [ThreadPoolEx] [ERROR]  Failed to run check CKV_AWS_70 on /s3.tf:aws_s3_bucket_policy.homeboost_logs
Traceback (most recent call last):
  File "/Users/myddryn/venv/localpy/lib/python3.11/site-packages/checkov/common/checks/base_check.py", line 68, in run
    check_result["result"] = self.scan_entity_conf(entity_configuration, entity_type)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/myddryn/venv/localpy/lib/python3.11/site-packages/checkov/terraform/checks/resource/base_resource_check.py", line 43, in scan_entity_conf
    return self.scan_resource_conf(conf)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/myddryn/venv/localpy/lib/python3.11/site-packages/checkov/terraform/checks/resource/aws/S3AllowsAnyPrincipal.py", line 86, in scan_resource_conf
    if statement['Effect'] == 'Deny' or 'Principal' not in statement:
       ~~~~~~~~~^^^^^^^^^^
TypeError: string indices must be integers, not 'str'
```

**Desktop (please complete the following information):**
 - OS: Mac OS, 15.3.2
 - Checkov Version: 3.2.400



Discussion:
@tsmithv11 this is reproduced in latest version. I'm not sure if this is a supported case since I don't think there's evaluation of referenced policy statements but looks like we can at least avoid the exception in the check.
@maxamel good call. I don't think we can support this yet, but we can avoid the exception. Let me know if you want to take it or want me to.
Sure @tsmithv11, I might be able to get to it sometime late next week, if you're able to take it before let me know.



Patch:
diff --git a/checkov/arm/checks/resource/StorageAccountName.py b/checkov/arm/checks/resource/StorageAccountName.py
index e5937cd06a..f6e28508c8 100644
--- a/checkov/arm/checks/resource/StorageAccountName.py
+++ b/checkov/arm/checks/resource/StorageAccountName.py
@@ -9,7 +9,7 @@
 
 STO_NAME_REGEX = re.compile(r"^[a-z0-9]{3,24}$")
 VARIABLE_REFS = ("local.", "module.", "var.", "random_string.", "random_id.", "random_integer.", "random_pet.",
-                 "azurecaf_name", "each.")
+                 "azurecaf_name", "each.", "substring")
 
 
 class StorageAccountName(BaseResourceCheck):
diff --git a/checkov/terraform/checks/graph_checks/aws/Route53ZoneEnableDNSSECSigning.yaml b/checkov/terraform/checks/graph_checks/aws/Route53ZoneEnableDNSSECSigning.yaml
index f1951949f3..e9262389ec 100644
--- a/checkov/terraform/checks/graph_checks/aws/Route53ZoneEnableDNSSECSigning.yaml
+++ b/checkov/terraform/checks/graph_checks/aws/Route53ZoneEnableDNSSECSigning.yaml
@@ -3,28 +3,30 @@ metadata:
   id: "CKV2_AWS_38"
   category: "NETWORKING"
 definition:
- and :
-    - cond_type: filter
-      attribute: resource_type
-      value:
-      - aws_route53_zone
-      operator: within
-    - cond_type: connection
-      resource_types:
-      - aws_route53_zone
-      connected_resource_types:
-      - aws_route53_hosted_zone_dnssec
-      - aws_route53_key_signing_key
-      operator: exists
-    - or:
+  or:
+    - and:
       - cond_type: attribute
         resource_types:
           - aws_route53_zone
-        attribute: vpc
-        operator: not_exists
+        attribute: vpc  # This indicates a private zone that can't have DNSSEC enabled
+        operator: exists
+      - cond_type: attribute
+        resource_types:
+          - aws_route53_zone
+        attribute: vpc  # This indicates a private zone that can't have DNSSEC enabled
+        operator: not_equals
+        value: []
+    - and:
+      - cond_type: filter
+        attribute: resource_type
+        value:
+        - aws_route53_zone
+        operator: within
       - cond_type: connection
         resource_types:
         - aws_route53_zone
         connected_resource_types:
-        - aws_route53_zone_association
-        operator: not_exists
+        - aws_route53_hosted_zone_dnssec
+        - aws_route53_key_signing_key
+        - aws_route53_zone_association  # This indicates a private zone that can't have DNSSEC enabled
+        operator: exists
diff --git a/checkov/terraform/checks/resource/aws/S3AllowsAnyPrincipal.py b/checkov/terraform/checks/resource/aws/S3AllowsAnyPrincipal.py
index 46c3201687..f5ddbb587a 100644
--- a/checkov/terraform/checks/resource/aws/S3AllowsAnyPrincipal.py
+++ b/checkov/terraform/checks/resource/aws/S3AllowsAnyPrincipal.py
@@ -82,8 +82,11 @@ def scan_resource_conf(self, conf):
                     return CheckResult.UNKNOWN
 
         if isinstance(policy_block, dict) and 'Statement' in policy_block.keys():
-            for statement in force_list(policy_block['Statement']):
-                if statement['Effect'] == 'Deny' or 'Principal' not in statement:
+            statements = force_list(policy_block['Statement'])
+            if all('Effect' not in statement for statement in statements):
+                return CheckResult.UNKNOWN
+            for statement in statements:
+                if 'Effect' not in statement or statement['Effect'] == 'Deny' or 'Principal' not in statement:
                     continue
                 principal = statement['Principal']
                 if principal == '*':


Test patch:
diff --git a/tests/arm/checks/resource/example_StorageAccountName/substring.bicep b/tests/arm/checks/resource/example_StorageAccountName/substring.bicep
new file mode 100644
index 0000000000..de16c2f72d
--- /dev/null
+++ b/tests/arm/checks/resource/example_StorageAccountName/substring.bicep
@@ -0,0 +1,52 @@
+@description('Name of the environment')
+param environmentName string
+
+@description('Name of the Storage account')
+param storageAccountName string = substring('abcdefgh${environmentName}${uniqueString(resourceGroup().id)}', 0, 24)
+
+@description('Provide a location for the resources.')
+param location string = resourceGroup().location
+
+resource dataStorageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = {
+  name: storageAccountName
+  location: location
+  sku: {
+    name: 'Standard_LRS'
+  }
+  kind: 'StorageV2'
+  identity: {
+    type: 'SystemAssigned'
+  }
+  properties: {
+    accessTier: 'Hot'
+    allowBlobPublicAccess: false
+    allowSharedKeyAccess: true
+    allowCrossTenantReplication: false
+    isHnsEnabled: true
+    allowedCopyScope: 'AAD'
+    defaultToOAuthAuthentication: false
+    encryption: {
+      keySource: 'Microsoft.Storage'
+      requireInfrastructureEncryption: false
+      services: {
+        blob: {
+          enabled: true
+          keyType: 'Account'
+        }
+      }
+    }
+    minimumTlsVersion: 'TLS1_2'
+    largeFileSharesState: 'Disabled'
+    sasPolicy: {
+      expirationAction: 'Log'
+      sasExpirationPeriod: '00.00:10:00'
+    }
+    supportsHttpsTrafficOnly: true
+    networkAcls: {
+      bypass: 'AzureServices'
+      virtualNetworkRules: []
+      ipRules: []
+      defaultAction: 'Allow'
+    }
+  }
+}
diff --git a/tests/terraform/checks/resource/aws/example_S3AllowsAnyPrincipal/main.tf b/tests/terraform/checks/resource/aws/example_S3AllowsAnyPrincipal/main.tf
index 93ecbef233..65bf771a41 100644
--- a/tests/terraform/checks/resource/aws/example_S3AllowsAnyPrincipal/main.tf
+++ b/tests/terraform/checks/resource/aws/example_S3AllowsAnyPrincipal/main.tf
@@ -483,4 +483,17 @@ resource "aws_s3_bucket" "pass_w_condition6" {
   ]
 }
 POLICY
+}
+
+# Handle error
+resource "aws_s3_bucket_policy" "logs" {
+  bucket = aws_s3_bucket.logs.id
+  policy = jsonencode({
+    Version = "2012-10-17"
+    Statement = concat(
+      jsondecode(data.aws_iam_policy_document.logs-cloudtrail-policy-acl-check.json).Statement,
+      jsondecode(data.aws_iam_policy_document.s3-logs-cloudtrail-policy-write.json).Statement,
+      jsondecode(data.aws_iam_policy_document.s3-logs-vpc-flow-logs-policy.json).Statement,
+    )
+  })
 }
\ No newline at end of file
diff --git a/tests/terraform/graph/checks/resources/Route53ZoneEnableDNSSECSigning/expected.yaml b/tests/terraform/graph/checks/resources/Route53ZoneEnableDNSSECSigning/expected.yaml
index 38b94d65bb..3322d8c079 100644
--- a/tests/terraform/graph/checks/resources/Route53ZoneEnableDNSSECSigning/expected.yaml
+++ b/tests/terraform/graph/checks/resources/Route53ZoneEnableDNSSECSigning/expected.yaml
@@ -2,5 +2,6 @@ pass:
   - "aws_route53_zone.pass"
   - "aws_route53_zone.private_with_inline_vpc"
   - "aws_route53_zone.private_with_zone_association"
+  - "aws_route53_zone.pass_signing_key"
 fail:
-  - "aws_route53_zone.fail"
\ No newline at end of file
+  - "aws_route53_zone.fail2"
\ No newline at end of file
diff --git a/tests/terraform/graph/checks/resources/Route53ZoneEnableDNSSECSigning/main.tf b/tests/terraform/graph/checks/resources/Route53ZoneEnableDNSSECSigning/main.tf
index 4bafc203c5..d1134c49a9 100644
--- a/tests/terraform/graph/checks/resources/Route53ZoneEnableDNSSECSigning/main.tf
+++ b/tests/terraform/graph/checks/resources/Route53ZoneEnableDNSSECSigning/main.tf
@@ -34,13 +34,14 @@ resource "aws_route53_zone_association" "private" {
   vpc_id  = "vpc-1a2b3c4d"
 }
 
-#fail
-resource "aws_route53_zone" "fail" {
-  name = "fail"
+#pass with signing key
+resource "aws_route53_zone" "pass_signing_key" {
+  name = "pass"
 }
+
 resource "aws_route53_key_signing_key" "fail" {
-  hosted_zone_id             = aws_route53_zone.fail.id
-  key_management_service_arn = aws_kms_key.fail.arn
+  hosted_zone_id             = aws_route53_zone.pass_signing_key.id
+  key_management_service_arn = aws_kms_key.pass_signing_key.arn
   name                       = "pass"
 }
 
diff --git a/tests/terraform/graph/checks/test_yaml_policies.py b/tests/terraform/graph/checks/test_yaml_policies.py
index 54767c02d8..13ef0cc4a7 100644
--- a/tests/terraform/graph/checks/test_yaml_policies.py
+++ b/tests/terraform/graph/checks/test_yaml_policies.py
@@ -568,6 +568,9 @@ def test_OSSBucketPublic(self):
     def test_Route53ZoneHasMatchingQueryLog(self):
         self.go("Route53ZoneHasMatchingQueryLog")
 
+    def test_Route53ZoneEnableDNSSECSigning(self):
+        self.go("Route53ZoneEnableDNSSECSigning")
+
 
     def test_registry_load(self):
         registry = Registry(parser=GraphCheckParser(), checks_dir=str(