Repository: aws-cloudformation/cfn-lint

Issue:
Ignored policy size limitation 
### CloudFormation Lint Version

1.18.3

### What operating system are you using?

Debian GNU/Linux 12 (bookworm)

### Describe the bug

The `AWS::IAM::ManagedPolicy` has based on the CloudFormation specification a max size set as 131072, however the managed policy maximum size is 6144, which is a compact size limit ( IAM doesn't count white space when calculating the size of a policy against this limit. ) 

Reference documentations:

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html#reference_iam-quotas-entity-length
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-managedpolicy.html#cfn-iam-managedpolicy-policydocument

The error:
> Resource handler returned message: "Cannot exceed quota for PolicySize: 6144 (Service: Iam, Status Code: 409, Request ID: <id>)" (RequestToken: <token>, HandlerErrorCode: ServiceLimitExceeded)


### Expected behavior

cfn-lint mark these templates as invalid

### Reproduction template

```yaml
---
AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template for Amazon Bedrock Studio workspace setup'
Metadata:
  ReferenceDocs: https://docs.aws.amazon.com/bedrock/latest/userguide/administer-create-workspace.html
  PolicyDocs: https://docs.aws.amazon.com/bedrock/latest/userguide/security_iam_id-based-policy-examples-br-studio.html#bedrock-studio-provisioning-iam-role-permissions-boundaries

Resources:
  BedrockStudioServiceRolePolicy:
    Type: 'AWS::IAM::ManagedPolicy'
    Properties:
      ManagedPolicyName: 'BedrockServiceRolePolicy'
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: GetDataZoneDomain
            Effect: Allow
            Action: datazone:GetDomain
            Resource: '*'
            Condition:
              StringEquals:
                'aws:ResourceTag/AmazonBedrockManaged': 'true'
          - Sid: ManageDataZoneResources
            Effect: Allow
            Action:
              - datazone:ListProjects
              - datazone:GetProject
              - datazone:CreateProject
              - datazone:UpdateProject
              - datazone:DeleteProject
              - datazone:ListProjectMemberships
              - datazone:CreateProjectMembership
              - datazone:DeleteProjectMembership
              - datazone:ListEnvironments
              - datazone:GetEnvironment
              - datazone:CreateEnvironment
              - datazone:UpdateEnvironment
              - datazone:DeleteEnvironment
              - datazone:ListEnvironmentBlueprints
              - datazone:GetEnvironmentBlueprint
              - datazone:ListEnvironmentBlueprintConfigurations
              - datazone:GetEnvironmentBlueprintConfiguration
              - datazone:ListEnvironmentProfiles
              - datazone:GetEnvironmentProfile
              - datazone:CreateEnvironmentProfile
              - datazone:UpdateEnvironmentProfile
              - datazone:DeleteEnvironmentProfile
              - datazone:GetEnvironmentCredentials
              - datazone:ListGroupsForUser
              - datazone:SearchUserProfiles
              - datazone:SearchGroupProfiles
              - datazone:GetUserProfile
              - datazone:GetGroupProfile
            Resource: '*'
          - Sid: GetResourceShareAssociations
            Effect: Allow
            Action: ram:GetResourceShareAssociations
            Resource: '*'
          - Sid: InvokeBedrockModels
            Effect: Allow
            Action:
              - bedrock:GetFoundationModelAvailability
              - bedrock:InvokeModel
              - bedrock:InvokeModelWithResponseStream
            Resource: '*'
          - Sid: UseCustomerManagedKmsKey
            Effect: Allow
            Action:
              - kms:DescribeKey
              - kms:GenerateDataKey
              - kms:Decrypt
            Resource: '*'
            Condition:
              StringEquals:
                'aws:ResourceTag/EnableBedrock': 'true'
  BedrockStudioProvisioningRolePolicy:
    Type: 'AWS::IAM::ManagedPolicy'
    Properties:
      ManagedPolicyName: 'BedrockProvisioningRolePolicy'
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: CreateStacks
            Effect: Allow
            Action:
              - 'cloudformation:CreateStack'
              - 'cloudformation:TagResource'
            Resource: 'arn:aws:cloudformation:*:*:stack/DataZone*'
            Condition:
              'ForAnyValue:StringEquals':
                'aws:TagKeys': AmazonDataZoneEnvironment
              'Null':
                'aws:ResourceTag/AmazonDataZoneEnvironment': 'false'
          - Sid: ManageStacks
            Effect: Allow
            Action:
              - 'cloudformation:DescribeStacks'
              - 'cloudformation:DescribeStackEvents'
              - 'cloudformation:UpdateStack'
              - 'cloudformation:DeleteStack'
            Resource: 'arn:aws:cloudformation:*:*:stack/DataZone*'
          - Sid: DenyOtherActionsNotViaCloudFormation
            Effect: Deny
            NotAction:
              - 'cloudformation:DescribeStacks'
              - 'cloudformation:DescribeStackEvents'
              - 'cloudformation:CreateStack'
              - 'cloudformation:UpdateStack'
              - 'cloudformation:DeleteStack'
              - 'cloudformation:TagResource'
            Resource: '*'
            Condition:
              StringNotEqualsIfExists:
                'aws:CalledViaFirst': cloudformation.amazonaws.com
          - Sid: ListResources
            Effect: Allow
            Action:
              - 'iam:ListRoles'
              - 's3:ListAllMyBuckets'
              - 'aoss:ListCollections'
              - 'aoss:BatchGetCollection'
              - 'aoss:ListAccessPolicies'
              - 'aoss:ListSecurityPolicies'
              - 'aoss:ListTagsForResource'
              - 'bedrock:ListAgents'
              - 'bedrock:ListKnowledgeBases'
              - 'bedrock:ListGuardrails'
              - 'bedrock:ListPrompts'
              - 'bedrock:ListFlows'
              - 'bedrock:ListTagsForResource'
              - 'lambda:ListFunctions'
              - 'logs:DescribeLogGroups'
              - 'secretsmanager:ListSecrets'
            Resource: '*'
          - Sid: GetRoles
            Effect: Allow
            Action: 'iam:GetRole'
            Resource:
              - 'arn:aws:iam::*:role/DataZoneBedrockProject*'
              - 'arn:aws:iam::*:role/AmazonBedrockExecution*'
              - 'arn:aws:iam::*:role/BedrockStudio*'
          - Sid: CreateRoles
            Effect: Allow
            Action:
              - 'iam:CreateRole'
              - 'iam:PutRolePolicy'
              - 'iam:AttachRolePolicy'
              - 'iam:DeleteRolePolicy'
              - 'iam:DetachRolePolicy'
            Resource:
              - 'arn:aws:iam::*:role/DataZoneBedrockProject*'
              - 'arn:aws:iam::*:role/AmazonBedrockExecution*'
              - 'arn:aws:iam::*:role/BedrockStudio*'
            Condition:
              StringEquals:
                'aws:ResourceTag/AmazonBedrockManaged': 'true'
          - Sid: ManageRoles
            Effect: Allow
            Action:
              - 'iam:UpdateRole'
              - 'iam:DeleteRole'
              - 'iam:ListRolePolicies'
              - 'iam:GetRolePolicy'
              - 'iam:ListAttachedRolePolicies'
            Resource:
              - 'arn:aws:iam::*:role/DataZoneBedrockProject*'
              - 'arn:aws:iam::*:role/AmazonBedrockExecution*'
              - 'arn:aws:iam::*:role/BedrockStudio*'
            Condition:
              StringEquals:
                'aws:ResourceTag/AmazonBedrockManaged': 'true'
          - Sid: PassRoleToBedrockService
            Effect: Allow
            Action: 'iam:PassRole'
            Resource:
              - 'arn:aws:iam::*:role/AmazonBedrockExecution*'
              - 'arn:aws:iam::*:role/BedrockStudio*'
            Condition:
              StringEquals:
                'iam:PassedToService': bedrock.amazonaws.com
          - Sid: PassRoleToLambdaService
            Effect: Allow
            Action: 'iam:PassRole'
            Resource: 'arn:aws:iam::*:role/BedrockStudio*'
            Condition:
              StringEquals:
                'iam:PassedToService': lambda.amazonaws.com
          - Sid: CreateRoleForOpenSearchServerless
            Effect: Allow
            Action: 'iam:CreateServiceLinkedRole'
            Resource: '*'
            Condition:
              StringEquals:
                'iam:AWSServiceName': observability.aoss.amazonaws.com
          - Sid: GetDataZoneBlueprintCfnTemplates
            Effect: Allow
            Action: 's3:GetObject'
            Resource: '*'
            Condition:
              StringNotEquals:
                's3:ResourceAccount': '${aws:PrincipalAccount}'
          - Sid: CreateAndAccessS3Buckets
            Effect: Allow
            Action:
              - 's3:CreateBucket'
              - 's3:DeleteBucket'
              - 's3:GetBucketPolicy'
              - 's3:PutBucketPolicy'
              - 's3:DeleteBucketPolicy'
              - 's3:PutBucketTagging'
              - 's3:PutBucketCORS'
              - 's3:PutBucketLogging'
              - 's3:PutBucketVersioning'
              - 's3:PutBucketPublicAccessBlock'
              - 's3:PutEncryptionConfiguration'
              - 's3:PutLifecycleConfiguration'
              - 's3:GetObject'
              - 's3:GetObjectVersion'
            Resource: 'arn:aws:s3:::br-studio-*'
          - Sid: ManageOssAccessPolicies
            Effect: Allow
            Action:
              - 'aoss:GetAccessPolicy'
              - 'aoss:CreateAccessPolicy'
              - 'aoss:DeleteAccessPolicy'
              - 'aoss:UpdateAccessPolicy'
            Resource: '*'
            Condition:
              StringLikeIfExists:
                'aoss:collection': br-studio-*
                'aoss:index': br-studio-*
          - Sid: ManageOssSecurityPolicies
            Effect: Allow
            Action:
              - 'aoss:GetSecurityPolicy'
              - 'aoss:CreateSecurityPolicy'
              - 'aoss:DeleteSecurityPolicy'
              - 'aoss:UpdateSecurityPolicy'
            Resource: '*'
            Condition:
              StringLikeIfExists:
                'aoss:collection': br-studio-*
          - Sid: ManageOssCollections
            Effect: Allow
            Action:
              - 'aoss:CreateCollection'
              - 'aoss:UpdateCollection'
              - 'aoss:DeleteCollection'
            Resource: '*'
            Condition:
              StringEquals:
                'aws:ResourceTag/AmazonBedrockManaged': 'true'
          - Sid: GetBedrockResources
            Effect: Allow
            Action:
              - 'bedrock:GetAgent'
              - 'bedrock:GetKnowledgeBase'
              - 'bedrock:GetGuardrail'
              - 'bedrock:GetPrompt'
              - 'bedrock:GetFlow'
              - 'bedrock:GetFlowAlias'
            Resource: '*'
          - Sid: ManageBedrockResources
            Effect: Allow
            Action:
              - 'bedrock:CreateAgent'
              - 'bedrock:UpdateAgent'
              - 'bedrock:PrepareAgent'
              - 'bedrock:DeleteAgent'
              - 'bedrock:ListAgentAliases'
              - 'bedrock:GetAgentAlias'
              - 'bedrock:CreateAgentAlias'
              - 'bedrock:UpdateAgentAlias'
              - 'bedrock:DeleteAgentAlias'
              - 'bedrock:ListAgentActionGroups'
              - 'bedrock:GetAgentActionGroup'
              - 'bedrock:CreateAgentActionGroup'
              - 'bedrock:UpdateAgentActionGroup'
              - 'bedrock:DeleteAgentActionGroup'
              - 'bedrock:ListAgentKnowledgeBases'
              - 'bedrock:GetAgentKnowledgeBase'
              - 'bedrock:AssociateAgentKnowledgeBase'
              - 'bedrock:DisassociateAgentKnowledgeBase'
              - 'bedrock:UpdateAgentKnowledgeBase'
              - 'bedrock:CreateKnowledgeBase'
              - 'bedrock:UpdateKnowledgeBase'
              - 'bedrock:DeleteKnowledgeBase'
              - 'bedrock:ListDataSources'
              - 'bedrock:GetDataSource'
              - 'bedrock:CreateDataSource'
              - 'bedrock:UpdateDataSource'
              - 'bedrock:DeleteDataSource'
              - 'bedrock:CreateGuardrail'
              - 'bedrock:UpdateGuardrail'
              - 'bedrock:DeleteGuardrail'
              - 'bedrock:CreateGuardrailVersion'
              - 'bedrock:CreatePrompt'
              - 'bedrock:UpdatePrompt'
              - 'bedrock:DeletePrompt'
              - 'bedrock:CreatePromptVersion'
              - 'bedrock:CreateFlow'
              - 'bedrock:UpdateFlow'
              - 'bedrock:PrepareFlow'
              - 'bedrock:DeleteFlow'
              - 'bedrock:ListFlowAliases'
              - 'bedrock:GetFlowAlias'
              - 'bedrock:CreateFlowAlias'
              - 'bedrock:UpdateFlowAlias'
              - 'bedrock:DeleteFlowAlias'
              - 'bedrock:ListFlowVersions'
              - 'bedrock:GetFlowVersion'
              - 'bedrock:CreateFlowVersion'
              - 'bedrock:DeleteFlowVersion'
            Resource: '*'
            Condition:
              StringEquals:
                'aws:ResourceTag/AmazonBedrockManaged': 'true'
          - Sid: TagBedrockAgentAliases
            Effect: Allow
            Action: 'bedrock:TagResource'
            Resource: 'arn:aws:bedrock:*:*:agent-alias/*'
            Condition:
              StringEquals:
                'aws:RequestTag/AmazonBedrockManaged': 'true'
          - Sid: TagBedrockFlowAliases
            Effect: Allow
            Action: 'bedrock:TagResource'
            Resource: 'arn:aws:bedrock:*:*:flow/*/alias/*'
            Condition:
              'Null':
                'aws:RequestTag/AmazonDataZoneEnvironment': 'false'
          - Sid: CreateFunctions
            Effect: Allow
            Action:
              - 'lambda:GetFunction'
              - 'lambda:CreateFunction'
              - 'lambda:InvokeFunction'
              - 'lambda:DeleteFunction'
              - 'lambda:UpdateFunctionCode'
              - 'lambda:GetFunctionConfiguration'
              - 'lambda:UpdateFunctionConfiguration'
              - 'lambda:ListVersionsByFunction'
              - 'lambda:PublishVersion'
              - 'lambda:GetPolicy'
              - 'lambda:AddPermission'
              - 'lambda:RemovePermission'
              - 'lambda:ListTags'
            Resource: 'arn:aws:lambda:*:*:function:br-studio-*'
          - Sid: ManageLogGroups
            Effect: Allow
            Action:
              - 'logs:CreateLogGroup'
              - 'logs:DeleteLogGroup'
              - 'logs:PutRetentionPolicy'
              - 'logs:DeleteRetentionPolicy'
              - 'logs:GetDataProtectionPolicy'
              - 'logs:PutDataProtectionPolicy'
              - 'logs:DeleteDataProtectionPolicy'
              - 'logs:AssociateKmsKey'
              - 'logs:DisassociateKmsKey'
              - 'logs:ListTagsLogGroup'
              - 'logs:ListTagsForResource'
            Resource: 'arn:aws:logs:*:*:log-group:/aws/lambda/br-studio-*'
          - Sid: GetRandomPasswordForSecret
            Effect: Allow
            Action: 'secretsmanager:GetRandomPassword'
            Resource: '*'
          - Sid: ManageSecrets
            Effect: Allow
            Action:
              - 'secretsmanager:CreateSecret'
              - 'secretsmanager:DescribeSecret'
              - 'secretsmanager:UpdateSecret'
              - 'secretsmanager:DeleteSecret'
              - 'secretsmanager:GetResourcePolicy'
              - 'secretsmanager:PutResourcePolicy'
              - 'secretsmanager:DeleteResourcePolicy'
            Resource: 'arn:aws:secretsmanager:*:*:secret:br-studio/*'
          - Sid: UseCustomerManagedKmsKey
            Effect: Allow
            Action:
              - 'kms:DescribeKey'
              - 'kms:Encrypt'
              - 'kms:Decrypt'
              - 'kms:GenerateDataKey'
              - 'kms:CreateGrant'
              - 'kms:RetireGrant'
            Resource: '*'
            Condition:
              StringEquals:
                'aws:ResourceTag/EnableBedrock': 'true'
          - Sid: TagResources
            Effect: Allow
            Action:
              - 'iam:TagRole'
              - 'iam:UntagRole'
              - 'aoss:TagResource'
              - 'aoss:UntagResource'
              - 'bedrock:TagResource'
              - 'bedrock:UntagResource'
              - 'lambda:TagResource'
              - 'lambda:UntagResource'
              - 'logs:TagLogGroup'
              - 'logs:UntagLogGroup'
              - 'logs:TagResource'
              - 'logs:UntagResource'
              - 'secretsmanager:TagResource'
              - 'secretsmanager:UntagResource'
            Resource: '*'
            Condition:
              StringEquals:
                'aws:ResourceTag/AmazonBedrockManaged': 'true'


  PermissionsBoundaryPolicy:
    Type: 'AWS::IAM::ManagedPolicy'
    Properties:
      ManagedPolicyName: 'AmazonDataZoneBedrockPermissionsBoundary'
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: AccessS3Buckets
            Effect: Allow
            Action:
              - s3:ListBucket
              - s3:ListBucketVersions
              - s3:GetObject
              - s3:PutObject
              - s3:DeleteObject
              - s3:GetObjectVersion
              - s3:DeleteObjectVersion
            Resource: 'arn:aws:s3:::br-studio-${aws:PrincipalAccount}-*'
            Condition:
              StringEquals:
                aws:ResourceAccount: '${aws:PrincipalAccount}'
          - Sid: AccessOpenSearchCollections
            Effect: Allow
            Action: aoss:APIAccessAll
            Resource: '*'
            Condition:
              StringEquals:
                aws:ResourceAccount: '${aws:PrincipalAccount}'
          - Sid: InvokeBedrockModels
            Effect: Allow
            Action:
              - bedrock:InvokeModel
              - bedrock:InvokeModelWithResponseStream
            Resource: 'arn:aws:bedrock:*::foundation-model/*'
          - Sid: AccessBedrockResources
            Effect: Allow
            Action:
              - bedrock:InvokeAgent
              - bedrock:Retrieve
              - bedrock:StartIngestionJob
              - bedrock:GetIngestionJob
              - bedrock:ListIngestionJobs
              - bedrock:ApplyGuardrail
              - bedrock:ListPrompts
              - bedrock:GetPrompt
              - bedrock:CreatePrompt
              - bedrock:DeletePrompt
              - bedrock:CreatePromptVersion
              - bedrock:InvokeFlow
              - bedrock:ListTagsForResource
              - bedrock:TagResource
              - bedrock:UntagResource
            Resource: '*'
            Condition:
              StringEquals:
                aws:ResourceAccount: '${aws:PrincipalAccount}'
                aws:ResourceTag/AmazonBedrockManaged: 'true'
              "Null":
                aws:ResourceTag/AmazonDataZoneProject: 'false'
          - Sid: RetrieveAndGenerate
            Effect: Allow
            Action: bedrock:RetrieveAndGenerate
            Resource: '*'
          - Sid: WriteLogs
            Effect: Allow
            Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
            Resource: 'arn:aws:logs:*:*:log-group:/aws/lambda/br-studio-*'
            Condition:
              StringEquals:
                aws:ResourceAccount: '${aws:PrincipalAccount}'
                aws:ResourceTag/AmazonBedrockManaged: 'true'
              "Null":
                aws:ResourceTag/AmazonDataZoneProject: 'false'
          - Sid: InvokeLambdaFunctions
            Effect: Allow
            Action: lambda:InvokeFunction
            Resource: 'arn:aws:lambda:*:*:function:br-studio-*'
            Condition:
              StringEquals:
                aws:ResourceAccount: '${aws:PrincipalAccount}'
                aws:ResourceTag/AmazonBedrockManaged: 'true'
              "Null":
                aws:ResourceTag/AmazonDataZoneProject: 'false'
          - Sid: AccessSecretsManagerSecrets
            Effect: Allow
            Action:
              - secretsmanager:DescribeSecret
              - secretsmanager:GetSecretValue
              - secretsmanager:PutSecretValue
            Resource: 'arn:aws:secretsmanager:*:*:secret:br-studio/*'
            Condition:
              StringEquals:
                aws:ResourceAccount: '${aws:PrincipalAccount}'
                aws:ResourceTag/AmazonBedrockManaged: 'true'
              "Null":
                aws:ResourceTag/AmazonDataZoneProject: 'false'
          - Sid: UseKmsKeyWithBedrock
            Effect: Allow
            Action:
              - kms:Decrypt
              - kms:GenerateDataKey
            Resource: '*'
            Condition:
              StringEquals:
                aws:ResourceAccount: '${aws:PrincipalAccount}'
                aws:ResourceTag/EnableBedrock: 'true'
              "Null":
                'kms:EncryptionContext:aws:bedrock:arn': 'false'
          - Sid: UseKmsKeyWithAwsServices
            Effect: Allow
            Action:
              - kms:Decrypt
              - kms:GenerateDataKey
            Resource: '*'
            Condition:
              StringEquals:
                aws:ResourceAccount: '${aws:PrincipalAccount}'
                aws:ResourceTag/EnableBedrock: 'true'
              StringLike:
                kms:ViaService:
                  - s3.*.amazonaws.com
                  - secretsmanager.*.amazonaws.com
          - Sid: GetDataZoneEnvCfnStacks
            Effect: Allow
            Action:
              - cloudformation:GetTemplate
              - cloudformation:DescribeStacks
            Resource: 'arn:aws:cloudformation:*:*:stack/DataZone-Env-*'
            Condition:
              StringEquals:
                aws:ResourceAccount: '${aws:PrincipalAccount}'
              "Null":
                aws:ResourceTag/AmazonDataZoneProject: 'false'

  ServiceRole:
    Type: 'AWS::IAM::Role'
    # checkov:skip=CKV_AWS_111: As per .Metadata.PolicyDocs
    # checkov:skip=CKV_AWS_109: As per .Metadata.PolicyDocs
    Properties:
      RoleName: 'BedrockStudioServiceRole'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: 'datazone.amazonaws.com'
            Action: 'sts:AssumeRole'
            Condition:
              StringEquals:
                'aws:SourceAccount': !Ref "AWS::AccountId"
      ManagedPolicyArns:
        - !Ref BedrockStudioServiceRolePolicy

  ProvisioningRole:
    Type: 'AWS::IAM::Role'
    # checkov:skip=CKV_AWS_111: As per .Metadata.PolicyDocs
    # checkov:skip=CKV_AWS_109: As per .Metadata.PolicyDocs
    Properties:
      RoleName: 'BedrockStudioProvisioningRole'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: datazone.amazonaws.com
            Action:
              - sts:AssumeRole
              - sts:TagSession
            Condition:
              StringEquals:
                'aws:SourceAccount': !Ref "AWS::AccountId"
              ForAllValues:StringLike:
                'aws:TagKeys': 'datazone*'
      ManagedPolicyArns:
        - !Ref BedrockStudioProvisioningRolePolicy

Outputs:
  PermissionsBoundaryPolicyArn:
    Description: 'ARN of the Permissions Boundary Policy'
    Value: !Ref PermissionsBoundaryPolicy
  ServiceRoleArn:
    Description: 'ARN of the Service Role'
    Value: !GetAtt ServiceRole.Arn
  ProvisioningRoleArn:
    Description: 'ARN of the Provisioning Role'
    Value: !GetAtt ProvisioningRole.Arn
```


Discussion:

Patch:
diff --git a/src/cfnlint/rules/resources/properties/StringLength.py b/src/cfnlint/rules/resources/properties/StringLength.py
index 819ac11890..4f2f78d013 100644
--- a/src/cfnlint/rules/resources/properties/StringLength.py
+++ b/src/cfnlint/rules/resources/properties/StringLength.py
@@ -9,7 +9,7 @@
 
 import regex as re
 
-from cfnlint.helpers import FUNCTIONS
+from cfnlint.helpers import FUNCTIONS, ensure_list, is_function
 from cfnlint.jsonschema import ValidationError
 from cfnlint.rules import CloudFormationLintRule
 
@@ -80,8 +80,8 @@ def maxLength(self, validator, mL, instance, schema):
             return
         # there are scenarios where Fn::Sub may not predictable so use
         # best judgement
-        if validator.is_type(instance, "object") and len(instance) == 1:
-            key = list(instance.keys())[0]
+        key, value = is_function(instance)
+        if key is not None:
             if key == "Fn::Sub":
                 value = instance[key]
                 if isinstance(value, str):
@@ -93,7 +93,7 @@ def maxLength(self, validator, mL, instance, schema):
                         validator, mL, self._fix_sub_string(value[0]), schema
                     )
                 return
-        if schema.get("type") == "object":
+        if "object" in ensure_list(schema.get("type")):
             yield from self._non_string_max_length(instance, mL)
 
     # pylint: disable=unused-argument, arguments-renamed
@@ -105,8 +105,8 @@ def minLength(self, validator, mL, instance, schema):
 
         # there are scenarios where Fn::Sub may not predictable so use
         # best judgement
-        if validator.is_type(instance, "object") and len(instance) == 1:
-            key = list(instance.keys())[0]
+        key, value = is_function(instance)
+        if key is not None:
             if key == "Fn::Sub":
                 value = instance[key]
                 if isinstance(value, str):
@@ -118,5 +118,6 @@ def minLength(self, validator, mL, instance, schema):
                         validator, mL, self._fix_sub_string(value[0]), schema
                     )
                 return
-        if schema.get("type") == "object":
+
+        if "object" in ensure_list(schema.get("type")):
             yield from self._non_string_min_length(instance, mL)


Test patch:
diff --git a/test/unit/rules/resources/properties/test_string_length.py b/test/unit/rules/resources/properties/test_string_length.py
index ebd161542f..77a3e55aab 100644
--- a/test/unit/rules/resources/properties/test_string_length.py
+++ b/test/unit/rules/resources/properties/test_string_length.py
@@ -37,6 +37,12 @@ def rule():
         ({"foo": 1, "bar": {"Fn::Sub": "2"}}, 20, {"type": "object"}, 1),
         ({"foo": 1, "bar": {"Fn::Sub": ["2", {}]}}, 10, {"type": "object"}, 0),
         ({"foo": 1, "bar": {"Fn::Sub": ["2", {}]}}, 20, {"type": "object"}, 1),
+        (
+            {"foo": 1, "bar": {"Fn::Sub": ["2", {}]}},
+            20,
+            {"type": ["string", "object"]},
+            1,
+        ),
     ],
 )
 def test_min_length(instance, mL, expected, rule, schema, validator):
@@ -65,6 +71,12 @@ def test_min_length(instance, mL, expected, rule, schema, validator):
         ({"foo": 1, "bar": {"Fn::Sub": "2"}}, 4, {"type": "object"}, 1),
         ({"foo": 1, "bar": {"Fn::Sub": ["2", {}]}}, 20, {"type": "object"}, 0),
         ({"foo": 1, "bar": {"Fn::Sub": ["2", {}]}}, 4, {"type": "object"}, 1),
+        (
+            {"foo": 1, "bar": {"Fn::Sub": ["2", {}]}},
+            4,
+            {"type": ["string", "object"]},
+            1,
+        ),
     ],
 )
 def test_max_length(instance, mL, expected, rule, schema, validator):