Repository: bridgecrewio/checkov

Issue:
Checkov v2.3.259 fails with CKV_AWS_356 for actions that must specify "all resources"
**Describe the issue**
CKV_AWS_356: "Ensure IAM policies limit resource access" produces failures on policies that include statements containing wildcard resources; however, some actions require "All Resources".

**Examples**
```
➜  /tmp cat test.tf 
data "aws_iam_policy_document" "policy" {
  statement {

    actions = [
      "s3:ListAllMyBuckets",
    ]

    resources = [
      "*"
    ]
  }
}
➜  /tmp docker pull bridgecrew/checkov:latest && docker run --rm --volume /tmp:/work --workdir /tf bridgecrew/checkov:latest --directory /work --framework terraform --download-external-modules true --compact --quiet
latest: Pulling from bridgecrew/checkov
Digest: sha256:4a196403a81c9a4540410d6511491389515b6db700efc46d0dcdb7e08ac57523
Status: Image is up to date for bridgecrew/checkov:latest
docker.io/bridgecrew/checkov:latest
terraform scan results:

Passed checks: 9, Failed checks: 1, Skipped checks: 0

Check: CKV_AWS_356: "Ensure IAM policies limit resource access"
        FAILED for resource: aws_iam_policy_document.policy
        File: /test.tf:1-12
```
<img width="2127" alt="image" src="https://github.com/bridgecrewio/checkov/assets/107714840/cd2d88d9-ad59-48e3-9d89-604fee7d5ee1">


**Version (please complete the following information):**
 - 2.3.259

**Additional context**
This check was introduced in: https://github.com/bridgecrewio/checkov/pull/5015



Discussion:

Resolving patch:
diff --git a/checkov/terraform/checks/data/aws/ResourcePolicyDocument.py b/checkov/terraform/checks/data/aws/ResourcePolicyDocument.py
--- a/checkov/terraform/checks/data/aws/ResourcePolicyDocument.py
+++ b/checkov/terraform/checks/data/aws/ResourcePolicyDocument.py
@@ -1,38 +1,21 @@
-from typing import Dict, List, Any
+from __future__ import annotations
 
-from checkov.terraform.checks.data.base_check import BaseDataCheck
-from checkov.common.models.enums import CheckResult, CheckCategories
+from typing import Any, TYPE_CHECKING
 
+from checkov.terraform.checks.data.base_cloudsplaining_data_iam_check import BaseTerraformCloudsplainingDataIAMCheck
 
-class ResourcePolicyDocument(BaseDataCheck):
+if TYPE_CHECKING:
+    from cloudsplaining.scan.policy_document import PolicyDocument
+
+
+class ResourcePolicyDocument(BaseTerraformCloudsplainingDataIAMCheck):
     def __init__(self) -> None:
-        name = 'Ensure IAM policies limit resource access'
+        name = 'Ensure no IAM policies documents allow "*" as a statement\'s resource for restrictable actions'
         id = "CKV_AWS_356"
-        supported_data = ["aws_iam_policy_document"]
-        categories = [CheckCategories.IAM]
-        super().__init__(name=name, id=id, categories=categories, supported_data=supported_data)
-
-    def scan_data_conf(self, conf: Dict[str, List[Any]]) -> CheckResult:
-        """
-            validates iam policy document
-            https://learn.hashicorp.com/terraform/aws/iam-policy
-        :param conf: aws_kms_key configuration
-        :return: <CheckResult>
-        """
-
-        for statement in conf.get("statement", []):
-            if not isinstance(statement, list):
-                statement = [statement]
-            for stmt in statement:
-                if (
-                    isinstance(stmt, dict)
-                    and stmt.get("effect", ["Allow"]) == ["Allow"]
-                    and stmt.get("resources")
-                    and ["*"] == stmt["resources"][0]
-                ):
-                    return CheckResult.FAILED
-
-        return CheckResult.PASSED
+        super().__init__(name=name, id=id)
+
+    def cloudsplaining_analysis(self, policy: PolicyDocument) -> list[str] | list[dict[str, Any]]:
+        return policy.all_allowed_unrestricted_actions
 
 
 check = ResourcePolicyDocument()
diff --git a/checkov/terraform/checks/resource/aws/IAMStarResourcePolicyDocument.py b/checkov/terraform/checks/resource/aws/IAMStarResourcePolicyDocument.py
--- a/checkov/terraform/checks/resource/aws/IAMStarResourcePolicyDocument.py
+++ b/checkov/terraform/checks/resource/aws/IAMStarResourcePolicyDocument.py
@@ -1,57 +1,23 @@
 from __future__ import annotations
 
-from checkov.common.models.enums import CheckResult, CheckCategories
-from checkov.common.util.type_forcers import force_list, extract_policy_dict
-from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
-from typing import Any
+from typing import TYPE_CHECKING, Any
 
+from checkov.terraform.checks.resource.base_cloudsplaining_resource_iam_check import (
+    BaseTerraformCloudsplainingResourceIAMCheck,
+)
 
-class IAMStarResourcePolicyDocument(BaseResourceCheck):
-    def __init__(self) -> None:
-        name = 'Ensure no IAM policies documents allow "*" as a statement\'s resource'
+if TYPE_CHECKING:
+    from cloudsplaining.scan.policy_document import PolicyDocument
+
+
+class IAMStarResourcePolicyDocument(BaseTerraformCloudsplainingResourceIAMCheck):
+    def __init__(self):
+        name = 'Ensure no IAM policies documents allow "*" as a statement\'s resource for restrictable actions'
         id = "CKV_AWS_355"
-        supported_resources = (
-            "aws_iam_role_policy",
-            "aws_iam_user_policy",
-            "aws_iam_group_policy",
-            "aws_iam_policy",
-            "aws_ssoadmin_permission_set_inline_policy",
-        )
-        categories = (CheckCategories.IAM,)
-        super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)
-
-    def scan_resource_conf(self, conf: dict[str, list[Any]]) -> CheckResult:
-        policy_block = None
-
-        policy = conf.get("policy")
-        inline_policy = conf.get("inline_policy")
-        if policy and isinstance(policy, list):
-            policy_block = extract_policy_dict(policy[0])
-        elif inline_policy and isinstance(inline_policy, list):
-            policy_block = extract_policy_dict(inline_policy[0])
-
-        if policy_block and "Statement" in policy_block:
-            for statement in force_list(policy_block["Statement"]):
-                if "Resource" in statement:
-                    resources = force_list(statement["Resource"])
-                    if (
-                        isinstance(resources[0], str)
-                        and statement.get("Effect", "Allow") == "Allow"
-                        and "*" in resources
-                    ):
-                        # scanning a HCL file
-                        return CheckResult.FAILED
-                    elif (
-                        isinstance(resources[0], list)
-                        and statement.get("Effect", ["Allow"]) == ["Allow"]
-                        and "*" in resources[0]
-                    ):
-                        # scanning a TF plan file
-                        return CheckResult.FAILED
-        return CheckResult.PASSED
-
-    def get_evaluated_keys(self) -> list[str]:
-        return ["policy", "inline_policy"]
+        super().__init__(name=name, id=id)
+
+    def cloudsplaining_analysis(self, policy: PolicyDocument) -> list[str] | list[dict[str, Any]]:
+        return policy.all_allowed_unrestricted_actions
 
 
 check = IAMStarResourcePolicyDocument()
diff --git a/checkov/terraform/checks/resource/base_cloudsplaining_resource_iam_check.py b/checkov/terraform/checks/resource/base_cloudsplaining_resource_iam_check.py
--- a/checkov/terraform/checks/resource/base_cloudsplaining_resource_iam_check.py
+++ b/checkov/terraform/checks/resource/base_cloudsplaining_resource_iam_check.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from abc import ABC
 from typing import Dict, List, Any
 
@@ -10,7 +12,14 @@
 
 class BaseTerraformCloudsplainingResourceIAMCheck(BaseResourceCheck, BaseTerraformCloudsplainingIAMScanner, ABC):
     def __init__(self, name: str, id: str) -> None:
-        super().__init__(name=name, id=id, categories=[CheckCategories.IAM], supported_resources=["aws_iam_policy"])
+        supported_resources = (
+            "aws_iam_role_policy",
+            "aws_iam_user_policy",
+            "aws_iam_group_policy",
+            "aws_iam_policy",
+            "aws_ssoadmin_permission_set_inline_policy",
+        )
+        super().__init__(name=name, id=id, categories=(CheckCategories.IAM,), supported_resources=supported_resources)
 
     def scan_resource_conf(self, conf: Dict[str, List[Any]]) -> CheckResult:
         return self.scan_conf(conf)
@@ -20,8 +29,15 @@ def cache_key(self) -> str:
         return self.entity_path
 
     def should_scan_conf(self, conf: Dict[str, List[Any]]) -> bool:
-        return "policy" in conf.keys()
+        if self.entity_type == "aws_ssoadmin_permission_set_inline_policy":
+            return "inline_policy" in conf
+
+        return "policy" in conf
 
     def convert_to_iam_policy(self, conf: Dict[str, Any]) -> PolicyDocument:
-        policy = conf['policy'][0]  # type: Dict[str, Any]
+        if self.entity_type == "aws_ssoadmin_permission_set_inline_policy":
+            policy: dict[str, Any] = conf['inline_policy'][0]
+        else:
+            policy = conf['policy'][0]
+
         return PolicyDocument(policy)


Test patch:
diff --git a/tests/terraform/checks/data/aws/example_ResourcePolicyDocument/main.tf b/tests/terraform/checks/data/aws/example_ResourcePolicyDocument/main.tf
--- a/tests/terraform/checks/data/aws/example_ResourcePolicyDocument/main.tf
+++ b/tests/terraform/checks/data/aws/example_ResourcePolicyDocument/main.tf
@@ -71,4 +71,18 @@ data "aws_iam_policy_document" "pass" {
       "arn:aws:s3:::${var.s3_bucket_name}/home/&{aws:username}/*",
     ]
   }
-}
\ No newline at end of file
+}
+
+data "aws_iam_policy_document" "pass_unrestrictable" {
+  version = "2012-10-17"
+
+  statement {
+    effect = "Allow"
+    actions = [
+      "s3:ListAllMyBuckets",
+    ]
+    resources = [
+      "*",
+    ]
+  }
+}
diff --git a/tests/terraform/checks/data/aws/test_ResourcePolicyDocument.py b/tests/terraform/checks/data/aws/test_ResourcePolicyDocument.py
--- a/tests/terraform/checks/data/aws/test_ResourcePolicyDocument.py
+++ b/tests/terraform/checks/data/aws/test_ResourcePolicyDocument.py
@@ -10,19 +10,20 @@ class TestResourcePolicyDocument(unittest.TestCase):
     def test(self):
         test_files_dir = Path(__file__).parent / "example_ResourcePolicyDocument"
 
-        report = Runner().run(root_folder=test_files_dir, runner_filter=RunnerFilter(checks=[check.id]))
+        report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[check.id]))
         summary = report.get_summary()
 
         passing_resources = {
             "aws_iam_policy_document.pass",
-            "aws_iam_policy_document.pass2"
+            "aws_iam_policy_document.pass2",
+            "aws_iam_policy_document.pass_unrestrictable",
         }
         failing_resources = {
             "aws_iam_policy_document.fail",
         }
 
-        passed_check_resources = set([c.resource for c in report.passed_checks])
-        failed_check_resources = set([c.resource for c in report.failed_checks])
+        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))
diff --git a/tests/terraform/checks/resource/aws/example_IAMStarResourcePolicyDocument/main.tf b/tests/terraform/checks/resource/aws/example_IAMStarResourcePolicyDocument/main.tf
--- a/tests/terraform/checks/resource/aws/example_IAMStarResourcePolicyDocument/main.tf
+++ b/tests/terraform/checks/resource/aws/example_IAMStarResourcePolicyDocument/main.tf
@@ -35,6 +35,25 @@ resource "aws_iam_policy" "pass" {
   })
 }
 
+resource "aws_iam_policy" "pass_unrestrictable" {
+  name        = "test_policy"
+  path        = "/"
+  description = "My test policy"
+
+  policy = jsonencode({
+    Version = "2012-10-17"
+    Statement = [
+      {
+        Action = [
+          "s3:ListAllMyBuckets",
+        ]
+        Effect   = "Allow"
+        Resource = "*"
+      },
+    ]
+  })
+}
+
 resource "aws_iam_role_policy" "fail" {
   name = "test_policy"
   role = aws_iam_role.test_role.id
diff --git a/tests/terraform/checks/resource/aws/test_IAMStarResourcePolicyDocument.py b/tests/terraform/checks/resource/aws/test_IAMStarResourcePolicyDocument.py
--- a/tests/terraform/checks/resource/aws/test_IAMStarResourcePolicyDocument.py
+++ b/tests/terraform/checks/resource/aws/test_IAMStarResourcePolicyDocument.py
@@ -19,6 +19,7 @@ def test(self):
 
         passing_resources = {
             "aws_iam_policy.pass",
+            "aws_iam_policy.pass_unrestrictable",
             "aws_iam_role_policy.pass",
             "aws_iam_user_policy.pass",
             "aws_iam_group_policy.pass",
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
@@ -695,7 +695,7 @@ def test_runner_with_iam_policies(self):
         summary = report.get_summary()
 
         self.assertEqual(summary["passed"], 2)  # "aws_iam_policy.policy_pass" passes both checks
-        self.assertEqual(summary["failed"], 3)
+        self.assertEqual(summary["failed"], 6)  # the rest fails both checks
 
         passed_check_resources = {c.resource for c in report.passed_checks}
         failed_check_resources = {c.resource for c in report.failed_checks}