Repository: aws-cloudformation/cfn-lint

Issue:
CDK generated cfn template resulting in Cfn-lint errors thrown
### CloudFormation Lint Version

cfn-lint 1.3.4

### What operating system are you using?

Mac, linux (Rocky)

### Describe the bug

A latest version of cfn-lint is throwing errors on cdk defined policy (works fine on version 0.87.4)
we define a load balancer and log bucket and connect the two with
`loadBalancer.logAccessLogs(accessLogBucket);`

When cfn-lint is ran on the output template from cdk synth
the AWS::S3::BucketPolicy which we don’t define throws:
```

E3002 '*' was expected
cdk.out/XXStack.template.json:115:8

E3512 {'AWS': {'Fn::Join': ['', ['arn:', {'Ref': 'AWS::Partition'}, ':iam::XXXX:root']]}} is not valid under any of the given schemas
cdk.out/XXStack.template.json:115:8
```

note replace naming and iam roles with XXs 

### Expected behavior

Cfn lint should hopefully not flag error from cdk generated stacks. 

### Reproduction template

```
"XXAccessLogsBucketPolicyXXXXX": {
   "Type": "AWS::S3::BucketPolicy",
   "Properties": {
    "Bucket": {
     "Ref": "XXXAccessLogsBucketXXXXXX"
    },
    "PolicyDocument": {
     "Statement": [
      {
       "Action": "s3:PutObject",
       "Effect": "Allow",
       "Principal": {
        "AWS": {
         "Fn::Join": [
          "",
          [
           "arn:",
           {
            "Ref": "AWS::Partition"
           },
           ":iam::XXXXXX:root"
          ]
         ]
        }
       },
```


Discussion:

Patch:
diff --git a/src/cfnlint/data/schemas/other/iam/policy.json b/src/cfnlint/data/schemas/other/iam/policy.json
index 49829b32c7..e462c6d8af 100644
--- a/src/cfnlint/data/schemas/other/iam/policy.json
+++ b/src/cfnlint/data/schemas/other/iam/policy.json
@@ -151,31 +151,33 @@
    "type": "object"
   },
   "Principal": {
-   "anyOf": [
-    {
-     "$ref": "#/definitions/Wildcard"
+   "if": {
+    "type": "string"
+   },
+   "properties": {
+    "AWS": {
+     "scalarOrArray": {
+      "$ref": "#/definitions/AwsPrincipalArn"
+     }
     },
-    {
-     "properties": {
-      "AWS": {
-       "scalarOrArray": {
-        "$ref": "#/definitions/AwsPrincipalArn"
-       }
-      },
-      "CanonicalUser": {
-       "$ref": "#/definitions/StringOrStringArray"
-      },
-      "Federated": {
-       "$ref": "#/definitions/StringOrStringArray"
-      },
-      "Service": {
-       "scalarOrArray": {
-        "type": "string"
-       }
-      }
-     },
-     "type": "object"
+    "CanonicalUser": {
+     "$ref": "#/definitions/StringOrStringArray"
+    },
+    "Federated": {
+     "$ref": "#/definitions/StringOrStringArray"
+    },
+    "Service": {
+     "scalarOrArray": {
+      "type": "string"
+     }
     }
+   },
+   "then": {
+    "$ref": "#/definitions/Wildcard"
+   },
+   "type": [
+    "object",
+    "string"
    ]
   },
   "Resource": {
diff --git a/src/cfnlint/rules/functions/SubNotJoin.py b/src/cfnlint/rules/functions/SubNotJoin.py
index 135d1507ba..56ced7461f 100644
--- a/src/cfnlint/rules/functions/SubNotJoin.py
+++ b/src/cfnlint/rules/functions/SubNotJoin.py
@@ -44,6 +44,9 @@ def _check_elements(self, elements):
     def validate(
         self, validator: Validator, s: Any, instance: Any, schema: Any
     ) -> ValidationResult:
+        if validator.cfn.is_cdk_template():
+            return
+
         key = list(instance.keys())[0]
         value = instance.get(key)
 


Test patch:
diff --git a/test/unit/module/jsonschema/test_keywords.py b/test/unit/module/jsonschema/test_keywords.py
new file mode 100644
index 0000000000..ea3e968647
--- /dev/null
+++ b/test/unit/module/jsonschema/test_keywords.py
@@ -0,0 +1,85 @@
+"""
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: MIT-0
+"""
+
+from collections import deque
+
+import pytest
+
+from cfnlint.jsonschema import ValidationError, _keywords
+from cfnlint.jsonschema.validators import CfnTemplateValidator
+from cfnlint.rules import CloudFormationLintRule
+
+
+class Error(CloudFormationLintRule):
+    id = "E1111"
+
+    def validate(self, validator, s, instance, schema):
+        print(instance)
+        if s:
+            yield ValidationError(
+                "Error",
+                rule=self,
+            )
+
+
+@pytest.fixture
+def validator():
+    validator = CfnTemplateValidator(schema={})
+    validator = validator.extend(
+        validators={
+            "error": Error().validate,
+        }
+    )
+    return validator({})
+
+
+@pytest.mark.parametrize(
+    "name,instance,schema,expected",
+    [
+        (
+            "Valid anyOf",
+            "foo",
+            [{"const": "foo"}, {"const": "bar"}],
+            [],
+        ),
+        (
+            "Valid anyOf with error rule",
+            "foo",
+            [{"const": "foo"}, {"error": True}],
+            [],
+        ),
+        (
+            "Invalid anyOf with error rule",
+            "foo",
+            [{"error": True}, {"error": True}],
+            [
+                ValidationError(
+                    "'foo' is not valid under any of the given schemas",
+                    path=deque([]),
+                    schema_path=deque([]),
+                    context=[
+                        ValidationError(
+                            "Error",
+                            rule=Error(),
+                            path=deque([]),
+                            validator="error",
+                            schema_path=deque([0, "error"]),
+                        ),
+                        ValidationError(
+                            "Error",
+                            rule=Error(),
+                            path=deque([]),
+                            validator="error",
+                            schema_path=deque([1, "error"]),
+                        ),
+                    ],
+                ),
+            ],
+        ),
+    ],
+)
+def test_anyof(name, instance, schema, validator, expected):
+    errs = list(_keywords.anyOf(validator, schema, instance, schema))
+    assert errs == expected, f"{name!r} got errors {errs!r}"
diff --git a/test/unit/rules/functions/test_sub_not_join_cdk.py b/test/unit/rules/functions/test_sub_not_join_cdk.py
new file mode 100644
index 0000000000..ebc45ca079
--- /dev/null
+++ b/test/unit/rules/functions/test_sub_not_join_cdk.py
@@ -0,0 +1,44 @@
+"""
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: MIT-0
+"""
+
+import pytest
+
+from cfnlint.rules.functions.SubNotJoin import SubNotJoin
+
+
+@pytest.fixture(scope="module")
+def rule():
+    rule = SubNotJoin()
+    yield rule
+
+
+@pytest.fixture
+def template():
+    return {
+        "Resources": {
+            "MyResource": {
+                "Type": "AWS::S3::Bucket",
+            },
+            "CDK": {
+                "Type": "AWS::CDK::Metadata",
+            },
+        },
+    }
+
+
+@pytest.mark.parametrize(
+    "name,instance,schema,expected",
+    [
+        (
+            "Invalid Fn::Join with an empty string",
+            {"Fn::Join": ["", ["foo", "bar"]]},
+            {"type": "string"},
+            [],
+        ),
+    ],
+)
+def test_validate(name, instance, schema, expected, rule, validator):
+    errs = list(rule.validate(validator, schema, instance, {}))
+    assert errs == expected, f"Test {name!r} got {errs!r}"
diff --git a/test/unit/rules/resources/iam/test_resource_policy.py b/test/unit/rules/resources/iam/test_resource_policy.py
index b88accf9b7..b56635507e 100644
--- a/test/unit/rules/resources/iam/test_resource_policy.py
+++ b/test/unit/rules/resources/iam/test_resource_policy.py
@@ -180,3 +180,47 @@ def test_string_statements(self):
             errs[2].message, "'2012-10-18' is not one of ['2008-10-17', '2012-10-17']"
         )
         self.assertListEqual(list(errs[2].path), ["Version"])
+
+    def test_principal_wildcard(self):
+        validator = CfnTemplateValidator({}).evolve(
+            context=Context(functions=FUNCTIONS)
+        )
+
+        policy = {
+            "Version": "2012-10-17",
+            "Statement": [
+                {
+                    "Effect": "Allow",
+                    "Action": "*",
+                    "Resource": {
+                        "Fn::Sub": "arn:${AWS::Partition}:iam::123456789012:role/object-role"
+                    },
+                    "Principal": "*",
+                },
+                {
+                    "Effect": "Allow",
+                    "Action": "*",
+                    "Resource": {
+                        "Fn::Sub": "arn:${AWS::Partition}:iam::123456789012:role/object-role"
+                    },
+                    "Principal": {
+                        "AWS": "*",
+                    },
+                },
+                {
+                    "Effect": "Allow",
+                    "Action": "*",
+                    "Resource": {
+                        "Fn::Sub": "arn:${AWS::Partition}:iam::123456789012:role/object-role"
+                    },
+                    "Principal": {"Fn::Sub": "*"},
+                },
+            ],
+        }
+
+        errs = list(
+            self.rule.validate(
+                validator=validator, policy=policy, schema={}, policy_type=None
+            )
+        )
+        self.assertListEqual(errs, [])