CDK で Amplify 読み取り用 S3 を作る際のはまりどころ
CDK で Amplify Hosting 手動デプロイ用の S3 バケットを作ったときにつまずいた点の記録。バケット名の 63 文字制限、SourceArn への encodeURIComponent、スタックの env 明示の 3 つ。
目次
AWS Amplify Hosting の手動デプロイ(BUCKET_PREFIX)向けに、CDK で S3 バケットと Amplify 読み取り用のバケットポリシーを作りました。その際に引っかかった点についていくつかまとめました。
1: バケット名は 63 文字以内
S3 バケット名は 63 文字以内です。スタック ID 全体の UUID(36 文字)をサフィックスに含めると、すぐ上限を超えます。
例えばプレフィックス amplify-s3-deploy-123456789012- の時点で 30 文字を超えており、UUID 全体を足すとデプロイが失敗します。
CREATE_FAILED | AWS::S3::Bucket | ArtifactBucket
"Bucket name should be between 3 and 63 characters long"
回避策として、スタック ID から取り出すサフィックスを UUID の先頭セグメント(8 文字)だけにします。
const stackId = cdk.Stack.of(this).stackId;
// スタック ID の UUID 先頭セグメント(8 文字)のみ使う
const stackSuffix = cdk.Fn.select(
0,
cdk.Fn.split("-", cdk.Fn.select(2, cdk.Fn.split("/", stackId))),
);
const bucketName = `amplify-s3-deploy-${this.account}-${stackSuffix}`;
2: SourceArn では encodeURIComponent を使わない
スタックに env を指定しないと、CDK は cdk synth の時点でデプロイ先のアカウント ID とリージョンを知りません。
このとき cdk.Stack.of(this).account が返すのは、本物のアカウント ID ではなく ${Token[AWS.AccountId.0]} という仮の文字列です。region も同じです。CDK はこの仮の文字列を、テンプレート出力時に { "Ref": "AWS::AccountId" } に置き換えます。
ここに encodeURIComponent を通すと、仮の文字列が %24%7BToken%5B... のように変換されます。CDK はこれを仮の文字列として認識できず、置き換えられないままテンプレートに残ります。バケットポリシーの aws:SourceArn は、デプロイ時の値が必要な箇所です。ここは cdk.Fn.sub() に切り替えると安全です。
conditions: {
StringEquals: {
"aws:SourceArn": cdk.Fn.sub(
"arn:aws:amplify:${AWS::Region}:${AWS::AccountId}:apps/${AppId}/branches/*",
{ AppId: props.amplifyAppId },
),
},
},
まとめ
バケット名のサフィックスに UUID 全体を使うと 63 文字の上限を超えるので、先頭の 8 文字だけを使います。
aws:SourceArn のようにデプロイ時の値が必要な箇所では、アカウント ID やリージョンの文字列に encodeURIComponent をつかわず、cdk.Fn.sub() を使いましょう。