🕵️

AWS CDKの裏側を覗いてみた 〜CDKはS3イベント通知の上書き問題をどう防いでいるのか?〜

2025/01/28に公開

こんにちは、普段はAWS上でアプリケーションを開発しているエンジニアです。
今回はAWS CDKでS3のイベント通知を設定したときに、裏側でどのようなことが起こっているか深掘りしてみました。

はじめに

AWS CDKでS3のイベント通知を設定する際、CDK内部で実行される PutBucketNotificationConfiguration APIが既存の設定を上書きしてしまう問題があります。
この問題をCDKがどのように解決しているのか気になったため、実際にコードを書いて cdk synth でテンプレートを生成し、その内容を確認してみました。

S3イベント設定は上書き問題に注意

CDKでS3イベントを設定する際に注意しなければならないのが、PutBucketNotificationConfiguration APIの挙動です。
AWSのブログ、"CloudFormation を使用して既存の S3 バケットに Lambda 用の Amazon S3 通知設定を作成する方法を教えてください。"であげられている通り、このAPIは、バケットに設定されている通知設定をすべて上書きしてしまいます。

重要: 以下の手順は、既存の通知設定がない S3 バケットの Amazon S3 通知設定にのみ適用されます。S3 バケットに既存の通知設定または手動で作成された通知設定がある場合、次の手順により、それらの設定が上書きされます。

そのため、CDKもCloudFormationを利用しており、もしCDKが何も考慮せずにこのAPIを実行していたら、既存の通知設定が消えてしまうという問題が発生しまいます。

結論から言うとCDKではうまくこの問題を回避してCloudFormationのテンプレートを作成していました。
続けてどうなっているかを見ていきたいと思います。

CDKはどのように問題を解決しているのか?

この問題を解決するために、CDKはカスタムリソースを利用しています。
cdk synth で生成されたテンプレートを確認すると、CDKは以下のようなワークアラウンドを取っていることがわかりました。

  1. カスタムリソースの作成: 通知設定作成用のLambda関数を自動生成するカスタムリソースを作成します。
  2. 既存設定の取得: Lambda関数内で s3.get_bucket_notification_configuration() を使用し、既存の通知設定を取得します。
  3. 新規設定のマージと反映: 取得した既存通知設定と新たに追加する通知設定をマージし s3.put_bucket_notification_configurations() を用いて設定を反映します。

生成されるLambda関数のコードは以下のようになっています。

https://github.com/aws/aws-cdk/blob/v2.175.1/packages/%40aws-cdk/custom-resource-handlers/lib/aws-s3/notifications-resource-handler/index.py

このLambda関数では、Managed プロパティの値によって処理を分けています。
このプロパティは、Cfnテンプレート上で設定されており、既存のバケットに対し通知設定を追加した場合は false に設定されていました。

s3.Bucket で作成したS3バケットの場合(Managedtrue

PutBucketNotificationConfiguration をそのまま実行し、設定を上書きしています。

def handle_managed(request_type, notification_configuration):
    if request_type == 'Delete':
        return {}
    return notification_configuration

s3.Bucket.fromBucketName() などで取得した既存のS3バケットの場合(Managedfalse

既存の通知設定を取得した上で、新しい通知設定を追加してから PutBucketNotificationConfiguration を実行しています。

# コードより抜粋、コメントは全て執筆者注
def handle_unmanaged(bucket, stack_id, request_type, notification_configuration, old):
    # 既存の通知設定を取得
    existing_notifications = s3.get_bucket_notification_configuration(Bucket=bucket)
    if EVENTBRIDGE_CONFIGURATION in existing_notifications:
        external_notifications[EVENTBRIDGE_CONFIGURATION] = existing_notifications[EVENTBRIDGE_CONFIGURATION]

    notifications = {}
    for t in CONFIGURATION_TYPES:
        external = external_notifications.get(t, [])
        incoming = [with_id(n) for n in notification_configuration.get(t, [])]
        # 既存の設定と新しい設定をマージし返却している
        notifications[t] = external + incoming
    return notifications

このように、CDKは既存のS3バケットに対するイベント設定では、既存の設定を維持しつつ新しい設定を追加するようなLambda関数を生成することで、上書き問題を回避しています。

実際に試してみた

AWS マネジメントコンソールからS3通知を設定してみました。この状態でCDKをデプロイするとどうなるか確認してみます。

before

after

既存の設定そのままに通知設定が追加できました!!🎉

まとめ

CloudFormationでS3イベントを設定する際には、裏側で PutBucketNotificationConfiguration APIが実行され、既存の設定を上書きしてしまう問題があります。
しかし、CDKではこの問題をカスタムリソースとして設定しているLambda関数内で工夫することで解決していました。

CDKを利用することで、このような複雑な処理を意識することなくS3イベントの設定を簡単に行うことができるということがわかりました。
ただ、CDKに限らず、あまり理解せずにものを利用すると思わぬ影響を与えてしまうことがあります。しっかりご自身で検証するという癖をつけるといいですね🙌

今回の記事が、CDKでS3イベントを設定する際の参考になれば幸いです。

いかがだったでしょうか?いいねやコメントをいただけると励みになります!
Happy Development!!

Discussion