This section explains how to deploy and invoke a lambda function using Terraform. Examples here will use NodeJS as the runtime. AWS Lambda supports other runtimes (Python, Ruby, Java, Go lang, .net) too. The document here AWS Lambda Runtimes lists them in detail.
Terraform Scripts and lambda source code for this section are available in Chapter 05.
This section will bundle the lambda source in a .zip
file. This will enable the Terraform script to upload the
lambda source zip file for deployment.
The helloWorldLambda.js
contains a simple nodejs AWS Lambda. Below snippet shows the same code. When invoked,
the lambda returns a json payload with the current timestamp and a message.
exports.handler = async (event) => {
const payload = {
date: new Date(),
message: 'Hello Terraform World'
};
return JSON.stringify(payload);
};
Note:
handler
module should be exported by the lambda js file.handler
function is async and takes anevent
object.event
object contains the request data from the caller.
Packaging the helloWorldLambda.js
file is done using the zip
command (on Mac). From the samples/05
directory,
run the following to create a .zip
file.
zip -r /tmp/helloWorldLambda.zip helloWorldLambda.js
The main terraform script for creating the lambda is located in Chapter 05 directory. This script creates the required IAM role for the lambda also.
For executing the lambda, it should be associated with a IAM role. Following section in samples/05/main.tf
uses the
lambda-role
module to create the IAM Role.
Note: No input variables are passed to the
lambda-role
module here. Because, this module will be reused for the other lambda that will be creates in this tutorial.
The next section will explain the lambda-role
module.
module "lambda_tf_way_role" {
source = "../modules/lambda-role"
}
The lambda-role
module is located at samples/modules/lambda-role
. This module creates a IAM Role with
assume-role-policy and also attaches the policies required for the lambda.
Following are the 2 resources created in this module.
resource "aws_iam_role" "lambda_tf_way_role" {
name = "tf_way_lambda_role"
assume_role_policy = file("${path.module}/lambda-assume-role-policy.json")
}
resource "aws_iam_role_policy" "tf_way_lambda_iam_role_policy" {
name = "tf_way_lambda_role_policy"
role = aws_iam_role.lambda_tf_way_role.id
policy = file("${path.module}/lambda-policy.json")
}
- The resource
lambda_tf_way_role
creates an IAM role with theassume-role-policy.json
content. - The
file
function assigns the contents oflambda-assume-role-policy.json
to assume_role_policy. - Assume role policy json allows the lambda service (lambda.amazonaws.com) to access other services on your IAM account behalf. These are service roles. Role Reference
- The name of the role created is
tf_way_lambda_role
- The resource
lambda_tf_way_role_policy
assigns policies to thetf_way_lambda_role
. Contents of thelambda-policy.json
file are assigned as policy to the role. - If you notice the
lambda-policy.json
file, it will allow access to the services S3, DynamoDB & SQS. For tutorial purpose we will allow access to all the resources and actions. In general, the good practice is to assign specific resources and actions.
The main.tf
in samples/05
creates hello_world_lambda
by using the lambda module in samples/modules/lambda
.
Following is the script you will find in it.
- Lambda name, zip file containing the archived source (from step 1.2 above), handler function are passed as input variables.
locals {
lambda_name = "helloWorldLambda"
zip_file_name = "/tmp/helloWorldLambda.zip"
handler_name = "helloWorldLambda.handler"
}
module "hello_world_lambda" {
source = "../modules/lambda"
lambda_function_name = local.lambda_name
lambda_function_handler = local.handler_name
lambda_role_arn = module.lambda_tf_way_role.lambda_role_arn
lambda_zip_filename = local.zip_file_name
}
The tf_way_lambda_function
resource is declared in the lambda module located at samples/module/lambda
. This
module creates the lambda function in AWS. The lambda module exports the function name and
function ARN (Amazon Resource Name).
Following is the script you will find there.
- The runtime is configured as nodejs.
- Layers are optional, and
lambda_tf_way_layer
var has an empty string as default.
resource "aws_lambda_function" "lambda_tf_way_function" {
filename = var.lambda_zip_filename
function_name = var.lambda_function_name
handler = var.lambda_function_handler
role = var.lambda_role_arn
runtime = "nodejs12.x"
layers = var.lambda_tf_way_layer == "" ? [] : [var.lambda_tf_way_layer]
}
Now we will run terraform script to create the Lambda with its IAM Role. You need to be in the samples/05
folder
to run the script.
Note: The
AWS_PROFILE
is configured aslambda-tf-user
export AWS_PROFILE=lambda-tf-user
terraform init
terraform apply --auto-approve
Note: Once terraform apply completes, it should print the Lambda and Role details as output. The output on the console should look similar to the one below.
module.lambda_tf_way_role.aws_iam_role.lambda_tf_way_role: Creating...
module.lambda_tf_way_role.aws_iam_role.lambda_tf_way_role: Creation complete after 4s [id=tf_way_lambda_role]
module.lambda_tf_way_role.aws_iam_role_policy.lambda_tf_way_role_policy: Creating...
module.hello_world_lambda.aws_lambda_function.lambda_tf_way_function: Creating...
module.lambda_tf_way_role.aws_iam_role_policy.lambda_tf_way_role_policy: Creation complete after 2s [id=tf_way_lambda_role:tf_way_lambda_role_policy]
module.hello_world_lambda.aws_lambda_function.lambda_tf_way_function: Still creating... [10s elapsed]
module.hello_world_lambda.aws_lambda_function.lambda_tf_way_function: Still creating... [20s elapsed]
module.hello_world_lambda.aws_lambda_function.lambda_tf_way_function: Creation complete after 22s [id=helloWorldLambda]
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:
lambda_arn = "arn:aws:lambda:ap-south-1:919191919191:function:helloWorldLambda"
lambda_name = "helloWorldLambda"
lambda_role_arn = "arn:aws:iam::919191919191:role/tf_way_lambda_role"
Now, we will invoke the function deployed using AWS CLI.
aws lambda invoke --function-name helloWorldLambda \
--log-type Tail \
--payload '{}' \
--profile "$AWS_PROFILE" outputfile.txt
cat outputfile.txt
You should see an output similar to the following after executing the lambda function.
output
"{\"date\":\"2019-01-01T12:00:00.000Z\",\"message\":\"Hello Terraform World\"}"
Now, we will delete the helloWorldLambda using terraform destroy. From the samples/05/
folder run the
following command. This will delete the lambda.
terraform destroy --auto-approve
Note: Once destroy completes, you should see a log similar to the one below.
module.lambda_tf_way_role.aws_iam_role_policy.tf_way_lambda_iam_role_policy: Destroying... [id=tf_way_lambda_role:tf_way_lambda_role_policy]
module.hello_world_lambda.aws_lambda_function.tf_way_lambda_function: Destroying... [id=helloWorldLambda]
module.hello_world_lambda.aws_lambda_function.tf_way_lambda_function: Destruction complete after 0s
module.lambda_tf_way_role.aws_iam_role_policy.tf_way_lambda_iam_role_policy: Destruction complete after 1s
module.lambda_tf_way_role.aws_iam_role.lambda_tf_way_role: Destroying... [id=tf_way_lambda_role]
module.lambda_tf_way_role.aws_iam_role.lambda_tf_way_role: Destruction complete after 2s
Destroy complete! Resources: 3 destroyed.
🏁 Congrats ! You deployed your first AWS Lambda function using Terraform and invoked it successfully. 🏁
Next: View Lambda Logs