概要

  • 今回は、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 ブロックの使い方は、こちらの記事を参考ください。