概要
- 今回は、terraform を使用して、aws_s3_bucket_notification (S3のイベント通知)を設定した際にハマってしまった事例を紹介します。
- シチュエーションとしては、既存に、S3 バケットおよびLambda、S3 のイベント通知が設定されている環境があるとします。こちらの既存環境は、terraform で管理されていません。この環境に、terraform を使用し、追加でLambda、S3 のイベント通知を設定します。目指すべき姿は、1つのS3 バケットに、2つのイベント通知が設定されている状態でした。しかし、aws_s3_bucket_notification は、既存のS3イベント通知を上書きしてしまいました。
前提条件
- 今回検証に使用した環境は、以下のTerraform を使用しています。
$ terraform providers -version Terraform v1.7.5 on linux_amd64 + provider registry.terraform.io/hashicorp/archive v2.4.2 + provider registry.terraform.io/hashicorp/aws v5.44.0
変更前
- 変更前は、既存のLambda(例: niikawa-tf-lambda-1)のトリガにS3 が設定されていることが分かります。
- S3 バケットにも既存のイベント通知が 1件設定されています。(フィルターにprefixの test1/ 設定され、送信先にniikawa-tf-lambda-1 が設定されている)
terraform が既存のS3イベント通知を上書きする流れ
- それでは、terraform を使用し、S3のイベント通知を設定します。S3のイベント通知に関するコードのサンプルを以下に記載します。設定対象のS3 バケット名は、”niikawa-tf-test” とします。
resource "aws_s3_bucket_notification" "resources_1" { bucket = "niikawa-tf-test" eventbridge = false lambda_function { events = ["s3:ObjectCreated:Put"] filter_prefix = "test2/" filter_suffix = null lambda_function_arn = "arn:aws:lambda:ap-northeast-1:111111111111:function:niikawa-tf-lambda-2" } }
- terraform apply を実行します。今回は説明の便宜上、aws_s3_bucket_notification のみ実行しています。
- terraform apply の実行は成功、結果は「Resources: 1 added, 0 changed, 0 destroyed.」となりました。1つのリソースが追加されただけで、特に変更や削除は発生していないように見受けられます。
Terraform will perform the following actions: # aws_s3_bucket_notification.resources_1 will be created + resource "aws_s3_bucket_notification" "resources_1" { + bucket = "niikawa-tf-test" + eventbridge = false + id = (known after apply) + lambda_function { + events = [ + "s3:ObjectCreated:Put", ] + filter_prefix = "test2/" + id = (known after apply) + lambda_function_arn = "arn:aws:lambda:ap-northeast-1:111111111111:function:niikawa-tf-lambda-2" } } Plan: 1 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes aws_s3_bucket_notification.resources_1: Creating... aws_s3_bucket_notification.resources_1: Creation complete after 1s [id=niikawa-tf-test] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
- それでは、AWS コンソールから対象のリソースを確認します。
- 期待と異なり、変更前は存在した既存のLambda(例: niikawa-tf-lambda-1)のトリガが削除されてしまいました。
- S3 バケットを確認します。イベント通知は 2件設定されている状態を期待しましたが、既存の設定は削除され、新規の1件のみが設定されています。(フィルターにprefixの test2/ 設定され、送信先にniikawa-tf-lambda-2 が設定されている)
なぜ既存のイベント通知設定が消えた?
- S3 のイベント通知は、S3 の仕様で単一の構成のみサポートされているようです。複数の通知を設定する場合は、1つのリソース内に複数の通知を定義する必要があります。
- つまり、aws_s3_bucket_notification (S3のイベント通知)は、上書きする前提でコードを作成する必要があるわけです。
S3 Buckets only support a single notification configuration. Declaring multiple aws_s3_bucket_notification resources to the same S3 Bucket will cause a perpetual difference in configuration. See the example “Trigger multiple Lambda functions” for an option.
(出典:https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_notification)
- せめて、terraform plan、terraform apply の実行結果で、changed, destroyed の表示があれば、回避できたかもしれません。AWSサービスの仕様を正しく理解する必要がありますね。
回避策
- 公式のサンプルを参考に、tf コードを修正します。
- 1つのaws_s3_bucket_notificationリソース内に複数のLambda 関数を指定します。
resource "aws_s3_bucket_notification" "resources_1" { bucket = "niikawa-tf-test" eventbridge = false lambda_function { events = ["s3:ObjectCreated:Put"] filter_prefix = "test1/" filter_suffix = null lambda_function_arn = "arn:aws:lambda:ap-northeast-1:111111111111:function:niikawa-tf-lambda-1" } lambda_function { events = ["s3:ObjectCreated:Put"] filter_prefix = "test2/" filter_suffix = null lambda_function_arn = "arn:aws:lambda:ap-northeast-1:111111111111:function:niikawa-tf-lambda-2" } }
- terraform apply を実行します。
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_s3_bucket_notification.resources_1 will be created + resource "aws_s3_bucket_notification" "resources_1" { + bucket = "niikawa-tf-test" + eventbridge = false + id = (known after apply) + lambda_function { + events = [ + "s3:ObjectCreated:Put", ] + filter_prefix = "test1/" + id = (known after apply) + lambda_function_arn = "arn:aws:lambda:ap-northeast-1:111111111111:function:niikawa-tf-lambda-1" } + lambda_function { + events = [ + "s3:ObjectCreated:Put", ] + filter_prefix = "test2/" + id = (known after apply) + lambda_function_arn = "arn:aws:lambda:ap-northeast-1:111111111111:function:niikawa-tf-lambda-2" } } Plan: 1 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes aws_s3_bucket_notification.resources_1: Creating... aws_s3_bucket_notification.resources_1: Creation complete after 1s [id=niikawa-tf-test] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
- S3 バケットを確認します。イベント通知は期待通り、2件設定されています。(既存の設定が保持されたわけではなく、上書きです)
- 今回は手動でtf コードを修正していますが、状況に応じてTerraform import ブロックを使用する方法もあります。Terraform import ブロックの使い方は、こちらの記事を参考ください。