Terraform recipe: S3 Bucket with notification to Lambda Function
It might come handy to quickly have setup a bucket that notifies a lambda function on any operation, like for example putting a new object.
It’s a mix of aws_s3, aws_lambda and aws_iam definitions that altogether
deploys this in a matter of seconds. The only precondition is to have completed
the AWS CLI
setup.
With this minimal folder:
.
├── lambda
│ ├── index.js
│ ├── lambda.zip
│ └── package.json
├── s3.tf
And in less than 100 lines, you’ll have all this ready:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
provider "aws" {
region = "eu-central-1"
}
data "aws_caller_identity" "current" {}
resource "aws_s3_bucket" "bucket" {
bucket = "your-bucket"
}
data "aws_iam_policy_document" "assume_role" {
statement {
effect = "Allow"
principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}
actions = [
"sts:AssumeRole"
]
}
}
data "aws_iam_policy_document" "access_cloudwatch" {
statement {
effect = "Allow"
actions = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
resources = ["arn:aws:logs:*:${data.aws_caller_identity.current.account_id}:log-group:*"]
}
}
resource "aws_iam_role" "iam_for_lambda" {
name = "iam_for_lambda"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}
resource "aws_iam_role_policy" "iam_role_policy_for_lambda" {
name = "cloudwatch-access"
role = aws_iam_role.iam_for_lambda.id
policy = data.aws_iam_policy_document.access_cloudwatch.json
}
data "archive_file" "lambda" {
type = "zip"
source_file = "${path.module}/lambda/index.js"
output_path = "${path.module}/lambda/lambda.zip"
}
resource "aws_lambda_permission" "allow_bucket" {
statement_id = "AllowExecutionFromS3Bucket"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.func.arn
principal = "s3.amazonaws.com"
source_arn = aws_s3_bucket.bucket.arn
}
resource "aws_lambda_function" "func" {
filename = data.archive_file.lambda.output_path
function_name = "func-name"
role = aws_iam_role.iam_for_lambda.arn
handler = "index.handler"
runtime = "nodejs24.x"
code_sha256 = data.archive_file.lambda.output_base64sha256
}
resource "aws_s3_bucket_notification" "bucket_notification" {
bucket = aws_s3_bucket.bucket.id
lambda_function {
lambda_function_arn = aws_lambda_function.func.arn
events = ["s3:ObjectCreated:*"]
filter_prefix = "path-to-prefix-if-needed/"
filter_suffix = ".suffix-if-needed"
}
depends_on = [aws_lambda_permission.allow_bucket]
}
lambda/lambda.zip being simply a bundle of both index.js and
package.json. You can generate or update anytime with zip -r lambda.zip .
while sitting in the lambda directory.
You can start with a minimal index.js like:
exports.handler = async (event, context) => {
console.log('Event: ', JSON.stringify(event));
};
As a result, a log is pushed to CloudWatch anytime an object is pushed into the S3 bucket. It’s handy for me to have it here, I’ll reuse that pretty soon. More later!