【CloudFormation】Error: The policy failed legacy parsing

やりたい事

以下のページを参考に、別アカウントのCodePipelineに、CodeCommitの変更を配信したい。また、これをCloudFormationを使ってできる限り省力化したい。

dev.classmethod.jp

発生したエラー

開発アカウント側で、IAM Policyを作成する際にエラーが発生した。以下がテンプレートである。

AllowTargetAccessPolicy:
    Type: AWS::IAM::Policy
    Properties: 
      Roles: 
        - !Ref AllowTargetAccessRole
      PolicyName: 
        !Join
          - ""
          - - !Ref AWS::Region
            - !Ref AWS::AccountId
            - To
            - !Ref TargetAccountID
            - CodeCommitAccessPolicy
      PolicyDocument:
        Version: 2012-10-17
        Statement: 
          - 
            Effect: Allow
            Action: 
              - s3:PutObject
              - s3:PutObjectAcl
            
            Resource: !Sub arn:aws:s3:::artifact-bucket-for-${TargetAccountID}-from-${AWS::AccountId}
      
          - 
            Effect: Allow
            Action: 
              - kms:DescribeKey
              - "kms:GenerateDataKey*"
              - kms:Encrypt
              - "kms:ReEncrypt*"
              - kms:Decrypt
            
            Resource: !Sub "arn:aws:kms:${AWS::Region}:${TargetAccountID}:key/${KMS_ID}

          - 
            Effect: Allow
            Action: 
              - codecommit:GetBranch
              - codecommit:GetCommit
              - codecommit:UploadArchive
              - codecommit:GetUploadArchiveStatus
              - codecommit:CancelUploadArchive
            
            Resource:
              !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}

すると、以下のエラーが発生した。

The policy failed legacy parsing (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument;)

リソースをコメントアウトして、問題がKMSに関するポリシードキュメントブロックにあることがわかった。

解決方法

なぜか、!Sub の代わりに!Joinを使用することでエラーが回避できた。 (参考) tycoh.hatenablog.com

AllowTargetAccessPolicy:
    Type: AWS::IAM::Policy
    Properties: 
      Roles: 
        - !Ref AllowTargetAccessRole
      PolicyName: 
        !Join
          - ""
          - - !Ref AWS::Region
            - !Ref AWS::AccountId
            - To
            - !Ref TargetAccountID
            - CodeCommitAccessPolicy
      PolicyDocument:
        Version: 2012-10-17
        Statement: 
          - 
            Effect: Allow
            Action: 
              - s3:PutObject
              - s3:PutObjectAcl
            
            Resource: !Sub arn:aws:s3:::artifact-bucket-for-${TargetAccountID}-from-${AWS::AccountId}
      
          - 
            Effect: Allow
            Action: 
              - kms:DescribeKey
              - "kms:GenerateDataKey*"
              - kms:Encrypt
              - "kms:ReEncrypt*"
              - kms:Decrypt
            
            Resource: |
              !Join
                - ""
                - - arn:aws:kms
                  - !Ref AWS::Region
                  - ":"
                  - !Ref TargetAccountID
                  - "key/"
                  - !Ref KMSArn

          - 
            Effect: Allow
            Action: 
              - codecommit:GetBranch
              - codecommit:GetCommit
              - codecommit:UploadArchive
              - codecommit:GetUploadArchiveStatus
              - codecommit:CancelUploadArchive
            
            Resource:
              !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${RepositoryName}

原因は後日AWS Forumに質問してみることにする。