There are number of Terraform Lambda tutorials which say you need an S3 bucket (for the Layer).

You don’t.

I recently implemented a POC, which had one job. To implement a Lambda Layer for some simple Node code, and wrap in Terraform.

Credit for the node code

Terraform and node code (github)

Create and zip source and dependencies:

cd layers/date-fns/nodejs
npm init -y
npm install date-fns@2.24.0
zip -r9 date-fns-layer.zip .

Zip the Lambda code:

zip -r9 lambda.zip index.js

Terraform:

terraform plan
terraform apply
terraform destroy

Terraform

The Layer:

resource "aws_lambda_layer_version" "simple_node_lambda-layer" {
  filename            = "layers/date-fns/date-fns-layer.zip"
  layer_name          = "simple_node_lambda-layer"
  source_code_hash    = "${filebase64sha256("layers/date-fns/date-fns-layer.zip")}"
  compatible_runtimes = ["nodejs14.x"]
}

The Lambda references the Layer:

resource "aws_lambda_function" "simple_node_lambda_function" {
  filename      = "lambda.zip"
  function_name = "SimpleNodeLambdaFunction"
  role          = aws_iam_role.simple-node-lambda_role.arn
  handler       = "index.handler"
  source_code_hash = filebase64sha256("lambda.zip")
  runtime = "nodejs14.x"
  layers = [aws_lambda_layer_version.simple_node_lambda-layer.arn]
}

I found a useful terraform module, aws_lambda_invocation:

resource "aws_lambda_invocation" "lambda_invocation" {
  function_name = "SimpleNodeLambdaFunction"

  input = jsonencode({
    hello = "world"
  })


  triggers = {
    redeployment = timestamp()
  }

  depends_on = [
    aws_lambda_function.simple_node_lambda_function
  ]
}

I created an output, which outputs the Lambda invocation:

output "lambda_invoke" {
  description = "Result of Lambda invocation"
  value       = aws_lambda_invocation.lambda_invocation.result
}

The Terraform apply, showing the invocation, and output:

aws_iam_role.simple-node-lambda_role: Creating...
aws_cloudwatch_log_group.main: Creating...
aws_lambda_layer_version.simple_node_lambda-layer: Creating...
aws_cloudwatch_log_group.main: Creation complete after 0s [id=SimpleNodeLambdaFunction]
aws_iam_role.simple-node-lambda_role: Creation complete after 1s [id=simple-node_role]
aws_iam_role_policy.lambda_basic_policy: Creating...
aws_iam_role_policy.lambda_basic_policy: Creation complete after 0s [id=simple-node_role:lambda_simple_node_basic_policy]
aws_lambda_layer_version.simple_node_lambda-layer: Still creating... [10s elapsed]
aws_lambda_layer_version.simple_node_lambda-layer: Creation complete after 15s [id=arn:aws:lambda:eu-west-1:457954557100:layer:simple_node_lambda-layer:7]
aws_lambda_function.simple_node_lambda_function: Creating...
aws_lambda_function.simple_node_lambda_function: Creation complete after 9s [id=SimpleNodeLambdaFunction]
aws_lambda_invocation.lambda_invocation: Creating...
aws_lambda_invocation.lambda_invocation: Creation complete after 1s [id=SimpleNodeLambdaFunction_$LATEST_fbc24bcc7a1794758fc1327fcfebdaf6]

Apply complete! Resources: 6 added, 0 changed, 0 destroyed.

Outputs:

lambda_invoke = "{\"statusCode\":200,\"body\":\"{\\\"today\\\":\\\"👉️ Today is a Sunday\\\"}\"}"

Terraform (continued):

IAM role:

resource "aws_iam_role" "simple-node-lambda_role" {
  name = "simple-node_role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

IAM Role Policy (for cloudwatch logs:)

resource "aws_iam_role_policy" "lambda_basic_policy" {
  name = "lambda_simple_node_basic_policy"
  role = aws_iam_role.simple-node-lambda_role.id

  policy = <<EOF
{
	  "Version": "2012-10-17",
	  "Statement": [
	    {
	      "Effect": "Allow",
	      "Action": [
	        "logs:CreateLogGroup",
	        "logs:CreateLogStream",
	        "logs:PutLogEvents"
	      ],
	      "Resource": [
	        "arn:aws:logs:*:*:*"
	      ]
	    }
	  ]
	}
	EOF
}

resource "aws_cloudwatch_log_group" "main" {
  name              = "SimpleNodeLambdaFunction"
  retention_in_days = 1
}