LoginSignup
5
5

More than 5 years have passed since last update.

[Terraform] DynamoDBをトリガーとしたLambdaの設定方法

Posted at

やりたいこと

記事タイトルそのままです。
DynamoDBのデータ更新をトリガーとして起動されるLambdaを、Terraformで設定したい。

tfファイルの記述例

IAM

aws.iam.tf
// Lambda用ロール
resource "aws_iam_role" "sample-lambda-role" {
    name = "sample-lambda-dynamodb-trigger"
    assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "sts:AssumeRole",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Effect": "Allow",
            "Sid": ""
        }
    ]
}
EOF
}

// Lambdaログ出力権限
resource "aws_iam_role_policy" "sample-lambda-log-output" {
    role = "${aws_iam_role.sample-lambda-role.id}"
    name = "lambda-log-output"
    policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*",
            "Effect": "Allow"
        }
    ]
}
EOF
}

// DynamoDB Stream の読み込み権限
resource "aws_iam_role_policy" "sample-dynamodb-stream" {
    role = "${aws_iam_role.sample-lambda-role.id}"
    name = "dynamodb-stream"
    policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "dynamodb:DescribeStream",
                "dynamodb:GetRecords",
                "dynamodb:GetShardIterator",
                "dynamodb:ListStreams"
            ],
            "Resource": "${aws_dynamodb_table.sample-table.stream_arn}",
            "Effect": "Allow"
        }
    ]
}
EOF
}
  • DynamoDB Stream からデータを読み取るためのポリシーが必要です。この権限が付いていないと、トリガー設定でコケます。

Lambda

aws.lambda.tf
// Lambda Function を ZIP化
data "archive_file" "lambda-zip_sample-function" {
    type        = "zip"
    output_path = "./_zip/sample-function.zip"
    source {
        filename = "lambda_function.py"
        content  = <<EOF
import json
def lambda_handler(event, context):
    result = json.dumps(event)
    print(result)
    return result
EOF
    }
}

// Lambda Function 作成
resource "aws_lambda_function" "sample-function" {
    function_name      = "sample-function-name"
    handler            = "lambda_function.lambda_handler"
    filename           = "${data.archive_file.lambda-zip_sample-function.output_path}"
    source_code_hash   = "${data.archive_file.lambda-zip_sample-function.output_base64sha256}"
    memory_size        = 128
    timeout            = 300
    runtime            = "python3.6"
    role               = "${aws_iam_role.sample-lambda-role.arn}"
    description        = "Dynamo Trigger Test"
}
  • この記述例ではイベント情報を出力するだけの Lambda Function をtfファイルに直書きしています。 zipファイルの置き場として、ディレクトリ ./_zip/ が必要。
  • functionファイルを作成しておいて archive_file でZIP化しても、あらかじめzipファイルを用意しておいても構いません。

DynamoDB

aws.dynamodb.tf

resource "aws_dynamodb_table" "sample-table" {
  name           = "sample-table-name"
  read_capacity  = 1
  write_capacity = 1
  hash_key       = "key1"
  range_key      = "key2"
  attribute {
    name = "key1"
    type = "S"
  }
  attribute {
    name = "key2"
    type = "S"
  }
  stream_enabled   = true
  stream_view_type = "NEW_AND_OLD_IMAGES"
}


//
resource "aws_lambda_event_source_mapping" "sample-table-trigger" {
    depends_on         = ["aws_dynamodb_table.sample-table", "aws_iam_role_policy.sample-dynamodb-stream"]
    batch_size         = 100
    event_source_arn   = "${aws_dynamodb_table.sample-table.stream_arn}"
    enabled            = true
    function_name      = "${aws_lambda_function.sample-function.arn}"
    starting_position  = "TRIM_HORIZON"
}
  • aws_dynamodb_table に下記のパラメータを記述して、DynamoDB Stream を有効化。
    • stream_enabled = true
    • stream_view_type = (任意)
  • aws_lambda_event_source_mapping で Lambdaのトリガーとして DynamoDB Stream を追加。
  • aws_lambda_event_source_mapping は Lambda が主語のような気はするものの、DynamoDB Stream の存在に依存する設定なので、DynamoDB用のtfファイルにまとめてます。個人的な好みです。

注意事項

一発目はこれでOK。

Terraform実行一発目から上記内容で設定する場合は、問題なく設定できるはずです。

DynamoDB Stream を後付けする場合はNG。

既にDynamoDBのTableを作成済みで、後から stream_enabled = true を追加設定する場合は、単純にtfファイルに上記の通り記述して実行しても上手く行きません。(Terraform v0.11.3 時点)
下記のようなエラーが発生するはずです。

aws_iam_role_policy.sample-dynamodb-stream: Resource 'aws_dynamodb_table.sample-table' does not have attribute 'stream_arn' for variable 'aws_dynamodb_table.sample-table.stream_arn'

aws_dynamodb_tablestream_arn が無いよ!」と怒られてます。

なぜ?

Terraform は、Terraform を利用して設定したリソースの情報をtfstateファイルに保持しています。
そして次回実行するときは、tfstateファイルに保持されている現在のリソース情報と、新たなtfファイルの内容を突き合わせて最小限のアップデートをします。
その時、リソース情報の整合性チェック等(Plan)を行ってから、設定反映(Apply)を実行する仕組みになっています。
DynamoDB Stream の後付けと同時にmappingをしようとすると、現状としては stream_arn が存在しないのにそれを利用してリソースを設定しようとしているため、Plan の段階でNGになります。
「Planで stream_arn を補完してくれればいいのに」とは思いますが、Stream名には作成日時が自動的に入るので、実際に作ってからでないと確定できないんですよね。

... というのが原因と考えられます。
Terraform のソースを見れば原因がハッキリわかるんでしょうが、私にはそこまでのモチベーションは無いです。

では、どうすれば?

段階を踏んで実行しましょう。
1. stream_enabled = true で実行しDynamoDB Stream を有効化する。これで次回から stream_arn が参照できるようになる。
2. DynamoDB Stream の ARN に依存するリソース設定を追加する。

もしかしたら Terraform の実行オプションで回避出来る等、他に方法があるかもしれませんが、私には見つけられませんでした。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5