【CloudFormation】S3のバケットの中身をCloudFormationで作成する

はじめに

CloudFormationでシステムのようなものを組んでいるうちに、本当で適当で良いから入力フォームみたいなものが必要になってきた。 こうしたときに便利なのがS3の静的ホスティング機能だろう。

qiita.com

ただ、CloudFormationは、S3の中身までは作成できないという欠点があった。

強力なS3Objectsマクロ

しかし、このS3Objectsを利用すれば、CloudFormationでS3内のファイルを作成することができる github.com

デプロイ

使い方は非常に簡単で、上記のサイトの手順に従ってマクロをデプロイする。適当なアーティファクトバケットを作成する。 次に、git cloneかファイルのダウンロードし*1、以下のコマンドを実行する。

aws cloudformation package \
    --template-file macro.template \
    --s3-bucket <your bucket name> \
    --output-template-file packaged.template

aws cloudformation deploy \
    --stack-name s3objects-macro \
    --template-file packaged.template \
    --capabilities CAPABILITY_IAM

これで、デプロイしたアカウント内ならばこのマクロを利用することができるようになった。 なお、私はコマンドをうつのが面倒だったため、CodeStarを利用した。

テスト

テスト用のコードも用意されているため、実行して有効性を確認する。

aws cloudformation deploy \
    --stack-name s3objects-macro-example \
    --template-file example.template \
    --capabilities CAPABILITY_IAM

使い方

CloudFormationが利用するIAMロールにS3Fullをアタッチし*2、CloudFormationテンプレートの頭に以下のブロックを置くことで、マクロが有効化される。

2019/12/21追記:マクロを動作させるためには、CloudFormationが利用するRoleにAWSLambdaExecuteポリシーをアタッチする必要がある。

Transform: S3Objects

サーバーレス変換など、他のマクロを合わせて利用する場合は、以下のようにリスト表記する。

Transform:
- S3Objects
- AWS::Serverless-2016-10-31

公式ドキュメントによると、以下の使い方があるようだ。 なお、いずれの項目でも

Target:
  Bucket: 
  Key:

は必須項目で、アップロード先のバケットとキー名を指定している。

テキストの内容をベタ書き

Transform: S3Objects
Resources:
  Bucket:
    Type: AWS::S3::Bucket

  Object:
    Type: AWS::S3::Object
    Properties:
      Target:
        Bucket: !Ref Bucket
        Key: README.md
        ContentType: text/plain
      Body: Hello, world!

Body以下に書かれた内容がそのままファイルの内部に反映される。 非常に短いコードならば問題にならないが、長文になると修正も非常に面倒になるほか、コードを変更した際にテストが行えない点に注意すること。

エンコードされた文字列を記載する

SinglePixel:
  Type: AWS::S3::Object
  Properties:
    Target:
      Bucket: !Ref TargetBucket
      Key: 1pixel.gif
    Base64Body: R0lGODdhAQABAIABAP///0qIbCwAAAAAAQABAAACAkQBADs=

ここでは、Base64の文字列をテンプレート中に記載する。

S3にアップロードされているファイルを指定する。

CopiedObject:
  Type: AWS::S3::Object
  Properties:
    Source:
      Bucket: !Ref SourceBucket
      Key: index.html
    Target:
      Bucket: !Ref TargetBucket
      Key: index.html
      ACL: public-read

予め他のS3にアップロードしておいたファイルを指定してコピーする。 aws-cliaws s3 cp ~~~をcloudFormationで実行していると考えて良いだろう。

結論

S3Objects変換を利用することで、S3バケットの中身をCloudFormationで作成することができるようになった。 工夫すれば、静的サイトをCloudFormationで作成することができるようになると考えられる。 ただし、アップロードする方法がテキストのベタ書き、または他のs3オブジェクトへのリンクのみという弱点もある。*3

*1:いずれも、他のマクロテンプレートなどが大量に入っているため時間がかかる点に注意

*2:何もフルアクセスでなくともよいが、とりあえず

*3:これはCodeBuildと組み合わせればゴリ押しで解決できる気がするのであまり気にしていない。