CloudFormation で AWS::Include Transform 利用時にハマってしまった件について

2022.09.28

こんにちは、森田です。

CloudFormationの一部のリソースをコンポーネント化するため、AWS::Include Transformを利用して記述したところ結構ハマってしまったのでその原因をご紹介できればと思います。

ハマった現象

テンプレートをデプロイしたところ、以下のエラーが発生しました

Failed to create the changeset: Waiter ChangeSetCreateComplete failed: 
Waiter encountered a terminal failure state: For expression "Status" we matched expected path: 
"FAILED" Status: FAILED. Reason: Transform AWS::Include failed with: 
The specified S3 object's content should be valid Yaml/JSON

なお、記述したテンプレートは以下の通りです。

main.yml

Description: Time Delte Item
Parameters:
  BucketName:
    Type: String
    Default: "morita112hogefugaxx2"

Resources:
  Fn::Transform:
    Name: AWS::Include
    Parameters:
      Location: s3.yml

s3.yml

MyBucket:
  Type: AWS::S3::Bucket
  Properties:
    BucketName: !Ref BucketName

main.ymlより、s3.ymlを読み込んで、S3バケットの作成を行うようになっております。

s3.ymlを読み込むために、事前にS3バケットへアップロード、LocationをS3パスとする必要があるため、以下のコマンドを実行し、
main_output.ymlを作成し、デプロイしたところ、エラーが発生しました。

aws cloudformation package --template-file main.yml --s3-bucket morita-custom-cfn --output-template-file main_output.yml
aws cloudformation deploy --template-file main_output.yml --stack-name s3-sample

エラー内容を見たところ、s3.ymlがYAMLではないと言っているようですが、何度確認しても、YAMLの誤りを見つけることができず、原因の特定までに結構時間を要してしまいました...

原因

!Refのように短縮形の構文を利用していたことが原因でした。

原因切り分けのために、BucketNameに対して実値を与えて実行したところ、うまく実行できたので、!Ref BucketNameあたりが原因と推測をたて、
よくよく考えてみると、!Refの書き方は、通常のYAML構文のものではなく、CloudFormation独自のものであることに気づきました。
なので、以下のように、通常のYAML構文に則って記述するとエラーは生じなくなります。

s3.yml

MyBucket:
  Type: AWS::S3::Bucket
  Properties:
    BucketName: 
      Ref: BucketName

最後に

YAMLは、CloudFormationを利用するためになんとなくで書いてましたが、しっかり理解していないため原因特定までに時間を要してしまいました。
AWS::Include Transform を利用される方は、短縮系の組み込み関数は利用できないことをご注意ください。