Policy contains a statement with one or more invalid principals - AWS Cloudformation error

I have a CF template as shown below

 AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: gtm platform Lampda application deployment for ELasticCloud
Parameters:
  SystemUserAccount:
    Description: The syatem user account used to assume deployment role
    Type: String
    Default: usr-test1
  DeploymentRoleName:
    Description: The deployment role used to deploy cloudformation template
    Type: String
    Default: gtm-platform-deployment-role
  GTMPlatformLambdaRoleName:
    Description: The execution role for gtm platform
    Type: String
    Default: gtm-platform-lambda-role
  GTMPlatformKMSKeyAliasName:
    Description: The lambda function name for gtm platform
    Type: String
    Default: gtm-platform-kms-key
Resources:
  GTMPlatformLambdaRole:
    Type: AWS::IAM::Role
    DependsOn:
      - GTMPlatformKMSKey
    Properties:
      RoleName: !Ref GTMPlatformLambdaRoleName
      AssumeRolePolicyDocument:
        Version: '2008-10-17'
        Statement:
          - Sid: ''
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/CloudWatchFullAccess
        - arn:aws:iam::aws:policy/AmazonVPCFullAccess
      Policies:
        - PolicyName: GTMPlatformLambdaPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: cloudwatch:*
                Resource: "*"
              - Effect: Allow
                Action:
                  - kms:EnableKeyRotation
                  - kms:EnableKey
                  - kms:ImportKeyMaterial
                  - kms:Decrypt
                  - kms:UntagResource
                  - kms:UpdateKeyDescription
                  - kms:GetKeyPolicy
                  - kms:GenerateDataKeyWithoutPlaintext
                  - kms:CancelKeyDeletion
                  - kms:ListResourceTags
                  - kms:DeleteImportedKeyMaterial
                  - kms:DisableKey
                  - kms:DisableKeyRotation
                  - kms:ListGrants
                  - kms:UpdateAlias
                  - kms:GetParametersForImport
                  - kms:TagResource
                  - kms:Encrypt
                  - kms:GetKeyRotationStatus
                  - kms:ScheduleKeyDeletion
                  - kms:CreateAlias
                  - kms:DescribeKey
                  - kms:DeleteAlias
                Resource: !GetAtt GTMPlatformKMSKey.Arn
              - Effect: Allow
                Action:
                  - kms:GenerateRandom
                  - kms:GenerateDataKey
                  - kms:ReEncryptTo
                  - kms:ReEncryptFrom
                Resource: "*"
  GTMPlatformKMSKey:
    Type: AWS::KMS::Key
    Properties:
      Description: Key used to encrypt decrypt EBS volumes at rest
      Enabled: true
      KeyPolicy:
        Version: '2012-10-17'
        Statement:
          - Sid: Enable permissions for admin
            Effect: Allow
            Principal:
              AWS: !Join
                - ''
                - - 'arn:aws:iam::'
                  - !Ref 'AWS::AccountId'
                  - ':root'
            Action:
              - 'kms:*'
            Resource: '*'
          - Sid: Allow access for Key Administrators
            Effect: Allow
            Principal:
              AWS:
                - !Sub
                  - 'arn:aws:iam::${accountId}:role/${gtmDeploymentRoleName}'
                  - accountId: !Ref 'AWS::AccountId'
                    gtmDeploymentRoleName: !Ref 'DeploymentRoleName'
            Action:
              - kms:Create*
              - kms:Describe*
              - kms:Enable*
              - kms:List*
              - kms:Put*
              - kms:Update*
              - kms:Revoke*
              - kms:Disable*
              - kms:Get*
              - kms:Delete*
              - kms:TagResource
              - kms:UntagResource
            Resource: "*"
          - Sid: Allow use of the key
            Effect: Allow
            Principal:
              AWS:
                - !Sub
                  - 'arn:aws:iam::${accountId}:role/${gtmPlatformLambdaRoleName}'
                  - accountId: !Ref 'AWS::AccountId'
                    gtmPlatformLambdaRoleName: !Ref 'GTMPlatformLambdaRoleName'
            Action:
              - kms:Encrypt
              - kms:Decrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
              - kms:DescribeKey
            Resource: "*"
          - Sid: Allow attachment of persistent resources
            Effect: Allow
            Principal:
              AWS:
                - !Sub
                  - 'arn:aws:iam::${accountId}:role/${gtmPlatformLambdaRoleName}'
                  - accountId: !Ref 'AWS::AccountId'
                    gtmPlatformLambdaRoleName: !Ref 'GTMPlatformLambdaRoleName'
            Action:
              - kms:CreateGrant
              - kms:ListGrants
              - kms:RevokeGrant
            Resource: "*"
            Condition:
              Bool:
                kms:GrantIsForAWSResource: 'true'
  GTMPlatformKMSKeyAlias:
    Type: AWS::KMS::Alias
    DependsOn:
      - GTMPlatformKMSKey
    Properties:
      AliasName: !Join ['/', ['alias', !Ref GTMPlatformKMSKeyAliasName]]
      TargetKeyId: !GetAtt GTMPlatformKMSKey.Arn

I am getting an error when the resource GTMPlatformKMSKey is getting created. It fails with CREATE_FAILED and error message

Policy contains a statement with one or more invalid principals. (Service: AWSKMS; Status Code: 400; Error Code: MalformedPolicyDocumentException; Request ID: 5673456f-b458-45c6-854b-9ed63c737772)

If I remove the Sid Allow use of the key and Allow attachment of persistent resources from GTMPlatformKMSKey the template runs fine. Not sure what I am missing here. Any help is much appreciated

P.S. - Resources SystemUserAccount and DeploymentRoleName already exists in the environment

Edit - As per the suggestion reduced the template to just include the failing resource


In my case, I was trying to deploy a CdkPipeline stack that had stages with multiple accounts. I needed to run cdk bootstrap ${account}/${region} on each account and region where my stack was deployed.

cdk bootstrap 123456789012/us-west-2
cdk bootstrap 123456789012/us-east-1
cdk bootstrap 987654321098/us-east-1

I also had to give the second account permission as per this link.

  1. Go to the Role in IAM
  2. Select the Trust Relationships tab ...
  3. Then Edit Trust Relationship to include codepipeline
  4. Also add the arn of the other account's root
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "codepipeline.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::123456789012:root",
          "arn:aws:iam::987654321098:root"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

You need to confirm that all the principal arn that you are assigning the resources to are available in your AWS account or have been referenced properly or they have the correct spelling in the template. Atleast these are what I experienced.


You can set up the trust relationship from the cli with a flag in cdk bootstrap call:

npx cdk bootstrap \
--profile PROFILE2 \
--trust ACCOUNT1 \
--cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess aws://ACCOUNT2/us-east-1

Reference article