こんにちは。自称ソフトウェアエンジニアの橋本 (@hassaku_63)です。
最近社内で良いきっかけをいただき AWS CDK へのコントリビューションにデビューを果たしました。ようやく L2 の利用者にもメリットのあるまとまりがリリースできましたので、OSS 活動の報告がてら追加された新機能をご紹介します。
どのバージョンから、何が使えるようになった?
v2.200.0
から利用可能です。
この記事で紹介するのは(そして私が実装したのは)以下の機能です。
s3: add
grantReplicationPermission
for IAM Role permissions (#34138) (bfa6490), closes #34119
s3.Bucket クラスに grantReplicationPermission
メソッドが追加されました。
リファレンスは以下のリンク先を参考にしてください。
なにがどう嬉しい?
S3 バケット間のレプリケーションを実装するには、以下のような設定が必要です。
- src/dest のバケットを作成(バージョニング有効化が必須)
- src 側のバケット
- レプリケーションルールの設定
- どこにどんなルールでレプリケーションするかの設定の記述
- 必要な権限を備えたサービスロールを1つ作成し、レプリケーションの設定項目に指定する
- レプリケーションルールの設定
- dest 側のバケット
- src からのレプリケーション操作を受け入れるためのバケットポリシーを追加
- (optional) KMS 暗号化を用いている場合の追加設定
- src 側の暗号化を有効にしている場合は、レプリケーション用のサービスロールに src 側のバケットオブジェクトを Decrypt する権限が必要
- dest 側の暗号化を有効にしている場合は、レプリケーション用のサービスロールに dest 側でのバケットオブジェクトを Encrypt する権限が必要
このうち、src 側の設定要件である「必要な権限を備えたサービスロールを1つ作成し、レプリケーションの設定項目に指定する」ですが、従来の L2 においてはサポートされないユースケースが存在しました。
従来の実装では、Bucker クラスの構築時に replicationRules: ReplicationRule[]
プロパティを指定することで自動的に IAM Role を作成する仕様が存在していました*1。IAM Role 作成は CDK にお任せ!で問題ないのであればこれだけで十分なのですが、この場合は IAM Role の物理名が決め打ちになります。また、当時の仕様では replicationRules を指定した場合、IAM Role は自動作成され、これを L2 ユーザー側で抑制することは不可能でした。こうした仕様を嫌うのであれば開発者が自前で IAM Role を定義して持ち込むしかないのですが、当時の L2 実装では自前の IAM Role をレプリケーション設定に持ち込むニーズには対応しておらず、L1 を使用して該当の設定を入れる必要がありました。
そうした経緯から、少し前のバージョンで Bucket クラスのコンストラクタプロパティに replicationRole: iam.IRole
が導入されました。この機能追加は issue#33974 でディスカッションされ、v2.190.0 から導入されています*2。
s3: allow specifying a custom IAM Role for bucket replication (#33978) (615f626), closes #33974
しかし、このプロパティの追加は自前で作成した IAM Role の適用を L2 レベルで可能にしたものの、必要な権限のアタッチに関しては CDK ユーザーが明示的にポリシーを書く必要がありました。CDK の慣例的なパターンである grant 系メソッドによる簡易的な方法はサポートされていませんでした。これは単純に不便で面倒ですし、手間や設定ミスを誘発しやすくなります。このあたりの問題意識は issue#34119 の "Describe the feature" や "Use Case" のセクションにも提言している通りです。
今回導入された機能は、上記のような課題を解決するべく追加されました。レプリケーション用のサービスロールに対する権限付与の実装を、CDK 的な grant 系メソッドという手段の提供によって解決し、ユーザーの負担を減らすものです。
使い方
前述したリファレンスにだいたいのことは書いてあるのですが、ここでもざっくりと説明します。
レプリケーションを設定するには、src 側でのルール作成が必要です。これは Bucket クラスのコンストラクタプロパティで指定します。
実装例は以下です。レプリケーションに関係しているプロパティのみを抜粋して記載します。
/** * 任意の Construct クラス内の実装 */ // dest 側のバケット。この Stack のデプロイ先とは異なるアカウントで構築済みのものにレプリケーションする想定で、fromBucketArn 経由で IBucket を作成している declare destBucket: s3.IBucket; // src 側のバケットで指定するレプリケーションルールのうち、サービスロールとして指定する IAM Role の構築 const replicationRole = new iam.Role(this, 'ReplicationRole', { assumedBy: new iam.ServicePrincipal('s3.amazonaws.com'), }); // レプリケーションルールを指定した Bucket の構築。replicationRole が未指定である場合は CDK L2 が内部的に特定の物理名を持った IAM Role を自動的に構成する。 // この例のように replicationRole を明示した場合は、このロールに対する権限付与は開発者側で責任を負う必要がある。 const srcBucket = new s3.Bucket(this, 'SrcBucket', { versioned: true, replicationRole, replicationRules: [ { destination: destBucket, }, ], }); // 今回追加した機能で、IAM Role への権限付与を行う。解釈は他の grant 系メソッドと同じで、このメソッドの呼び出しは「srcBucket に対するレプリケーション操作の許可を replicationRole に付与する」意味を持つ、と読んでもらうと良い srcBucket.grantReplicationPermission(replicationRole, { destinations: [ { bucket: destBucket }, ], });
KMS 暗号化は src/dest ともに使っていない想定で記載していますが、それらをサポートする場合の書き方を見たい場合は s3 モジュールのリファレンス により具体的な例示がありますのでそちらをご確認ください。もしくは、CDK レポジトリ内の integ test の記述内容を眺めてみるのも良い材料になると思います。v2.200.0 時点の実装であれば packages/@aws-cdk-testing/framework-integ/test/aws-s3/test/integ.bucket-replication-use-custom-role.ts の TestStack
の実装あたりをかいつまんでみると良いと思います。
まとめ
レプリケーション構成を L2 で行う際、暗黙的にレプリケーション用のサービスロールが作成されることに問題がない場合は、Bucket の構築時のプロパティに replicationRules
を指定し、かつ replicationRole
を未指定にすると良いです。適切な権限を持った IAM Role がよしなに作成されます。
もし「暗黙的にレプリケーション用のサービスロールが作成されること」を良しとしない要件がある場合は、サービスロールの権限構成に grantReplicationPermission メソッドを使ってください。
クロスアカウントでのレプリケーションや src/dest のいずれか(あるいは両方)での KMS 暗号化が絡むと、このあたりの設定は地味にややこしいです。関連ドキュメントが複数ページにわたることもあり、初見では時間がかかる作業になると思います。そのあたりの手間がショートカットできるようになります。
...ユースケースが些か限定的な気もしないではないですが、要件に見合う方は是非使ってみてください。
裏話
最後に。このセクションは機能の紹介というより OSS 活動報告の一環として書いたものです。実装時に考えていたことを紹介するエピソードトークとして見ていただけたら。
grantReplicationPermission のパラメータ仕様では、destinations を明示する必要があります。この仕様が少々冗長に見える方もあるかと思います。「おいおい、そこは今構築した Bucket オブジェクトからいい感じに読み取ってくれよ」と。
正直、このへんは内部実装の都合に引っ張られた部分があります。とはいえ、そもそもこのメソッドのユースケースが「自前で IAM Role を定義して、持ち込みたい」という前提に立っていますので、根本的なコンセプトとしてこの機能追加はユーザーが明示的にコントロールできる方向性を目指したものとも言えます。grant 操作をやるにしても「どこに対するレプリケーションを許可したいのか」の情報がパラメータとして明示的に見えてる書き味の方が、根っこの設計指針にも沿うだろうと(少々強引に)考えて、受け入れました。指定すべき値も既知である場合が多いでしょうし、実用上それほど問題にならないと考えました。
もう少し自己弁護させてもらうとするならば、destinations を明示的に指定する仕様にしたのは(一応の)想定ユースケースを踏まえつつ、CDK の共通実装パターンを踏まえた判断でした。CDK の共通実装パターンとして、grant 系メソッドは固有リソースに対応する(IXxxx の命名規則を持つ)インタフェースにも実装する方針が一貫しています。今回の機能追加も、このパターンに準拠する必要がありました。要するに、CDK の既存実装のデザインを踏襲しようとしたらこうなりました。
IBucket は Bucket リソースの「ガワ」を持ったインタフェースに過ぎず、実際のバケットに適用されている諸々の設定値を基本的に保持していません。CDK App 外で作成されたバケットを fromBucketArn などで読み込んだ場合、そのバケットの設定情報はレプリケーション関連の値も含め CDK の実装的に参照できないのです。そういうわけで、今回追加した grant メソッドには destinations のパラメータが必要になりました。
grantReplicationPermission のパラメータ仕様が今のようになったのはこのような背景事情によります。メンテナから PR レビューで指摘されたら、そんな感じで回答するつもりでした(実際に触れられることはありませんでしたが)。
*1:ちなみに、この時点でクロスアカウントのレプリケーションにも対応しているので大変便利です。クロスアカウントのシナリオも含めたレプリケーションの構成方法については、関連機能を実装された御本人である badmintoncryer さんの記事「S3のレプリケーションをCDKで設定する (2025年度版) が詳しいです。是非こちらもご覧ください
*2:こちらの実装も私が担当しました。本記事の機能追加の布石として、issue 分割して先行着手していた格好です