Serverless applications are getting popular among the DevOps community because you do not have to worry about the application server infrastructure. AWS Lambda is an event-driven offering from AWS which can help you to run any application without the need for application servers.
In this blog post, we will talk about AWS Lambda and how to use Terraform to manage AWS Lambda functions. In the tutorial part, we will start with the basics of the AWS Lambda function, and then we will deploy a very simple Python app using AWS Lambda.
Table of Content:
- What is AWS Lambda Function in Terraform?
- What is AWS Lambda used for?
- Prerequisites
- Setting up the IAM Roles and Policies
- Writing the Python application
- Creating a ZIP of Python Application
- Adding aws_lambda_function
- Running and Executing Terraform main.tf
- Verifying the Lambda function from AWS console
Note: New versions of Terraform are placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that expands on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6.
Terraform provides the aws_lambda_function resource for managing the AWS Lambda functions. Although you can create and run Lambda functions from the AWS web console, Terraform is a great tool for managing Lambda functions via IaC.
AWS Lambda function is very flexible and supports various use cases:
- Event driven applications—AWS Lambda can be triggered from a number of different event sources. Examples include triggering when a database row is updated, and triggering when the message count in a queue is greater than a certain number.
- Web and mobile backends—For a Mobile touchscreen, GUI event can be integrated with AWS Lambda using AWS API Gateway to trigger the Lambda function by calling the microservice-http-endpoint. (Learn how to create API Gateway using Terraform)
- Machine learning and data processing—As AWS Lambda supports Python, it is well suited for machine learning as well as data analytics applications, because ML and Data Analytics applications rely heavily on Python and its libraries (Numpy, TensorFlow, MatPlotlib Scipy etc.)
Let’s start with the prerequisites for this tutorial.
- You should have Terraform installed onto your machine (see our tutorial here: How to Download and Install Terraform on Windows, Linux & macOS)
- You must have an AWS account.Â
Before proceeding further, make sure Terraform is installed by running the command – $ terraform -version
Now, here’s how to manage AWS Lambda functions:
The next step is to set up an IAM Role for your Lambda function, along with any policies that the Lambda function requires. The exact policies required will depend on what your function does, and what services it needs to access. Since this article is mainly focused on explaining how to manage Lambda functions via Terraform, we will keep the IAM Roles and Policies very basic.
Create main.tf and add IAM Role
Let’s start by creating a main.tf file and inside the main.tf file create a role Spacelift_Test_Lambda_Function_Role.
resource "aws_iam_role" "lambda_role" {
name = "Spacelift_Test_Lambda_Function_Role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
Add IAM Policy
After creating the IAM Role, let’s create an IAM Policy to manage the permissions associated with the role. As this is a basic application, we will be assigning the following permissions:Â
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Add the following IAM Policy resource block to main.tf:
resource "aws_iam_policy" "iam_policy_for_lambda" {
name = "aws_iam_policy_for_terraform_aws_lambda_role"
path = "/"
description = "AWS IAM Policy for managing aws lambda role"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*",
"Effect": "Allow"
}
]
}
EOF
}
Attach IAM Policy to IAM Role
Now that we have created an IAM Policy and IAM Role for the Terraform managed AWS Lambda function, let’s attach both IAM Policy and IAM Role to each other:
resource "aws_iam_role_policy_attachment" "attach_iam_policy_to_iam_role" {
role = aws_iam_role.lambda_role.name
policy_arn = aws_iam_policy.iam_policy_for_lambda.arn
}
Read more about Creating IAM Policies with Terraform.
Since the IAM Role and IAM Policy have now been created, let’s call on the Python application which we will be running on AWS Lambda.
- Create a directory python parallel to main.tf.
- Inside the directory python, create a file index.py.
- Add the following python function to it:
def lambda_handler(event, context):
message = 'Hello {} !'.format(event['key1'])
return {
'message' : message
}
As in the previous step, we have created a python file index.py. Now, we need to create a ZIP file because aws_lambda_function
needs the code to be stored in a ZIP file in order to upload to AWS.
This ZIP file we are going to upload and submit to AWS Lambda function:
data "archive_file" "zip_the_python_code" {
type = "zip"
source_dir = "${path.module}/python/"
output_path = "${path.module}/python/hello-python.zip"
}
Alright. Now we have everything (IAM Role, IAM Policy, Python Code) in place. Let’s write down the aws_lambda_function resource block:
resource "aws_lambda_function" "terraform_lambda_func" {
filename = "${path.module}/python/hello-python.zip"
function_name = "Spacelift_Test_Lambda_Function"
role = aws_iam_role.lambda_role.arn
handler = "index.lambda_handler"
runtime = "python3.8"
depends_on = [aws_iam_role_policy_attachment.attach_iam_policy_to_iam_role]
}
Here are a few things you should keep in mind while writing aws_lambda_function resource block:
- Runtime—You should mention correction runtime which AWS Lambda is going to use for running your Lambda function. Currently, AWS Lambda supports Node.js, Python, JAVA, Ruby, Go, .NET.
- IAM Role—Always mention the correct IAM role which you have created for the Lambda function.
- Depends_on—Mention the correct IAM policy attachment block where you have attached the IAM role to IAM policy. It is a sanity check to make sure that IAM Policy and IAM roles are in place before lambda function is created.
Here is the complete main.tf file:
provider "aws" {
region = "eu-central-1"
}
resource "aws_iam_role" "lambda_role" {
name = "Spacelift_Test_Lambda_Function_Role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_policy" "iam_policy_for_lambda" {
name = "aws_iam_policy_for_terraform_aws_lambda_role"
path = "/"
description = "AWS IAM Policy for managing aws lambda role"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*",
"Effect": "Allow"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "attach_iam_policy_to_iam_role" {
role = aws_iam_role.lambda_role.name
policy_arn = aws_iam_policy.iam_policy_for_lambda.arn
}
data "archive_file" "zip_the_python_code" {
type = "zip"
source_dir = "${path.module}/python/"
output_path = "${path.module}/python/hello-python.zip"
}
resource "aws_lambda_function" "terraform_lambda_func" {
filename = "${path.module}/python/hello-python.zip"
function_name = "Spacelift_Test_Lambda_Function"
role = aws_iam_role.lambda_role.arn
handler = "index.lambda_handler"
runtime = "python3.8"
depends_on = [aws_iam_role_policy_attachment.attach_iam_policy_to_iam_role]
}
Let’s run the following commands in sequence:
1. $ terraform init
2. $ terraform plan
Here is the remaining output of terraform plan:
3. $ terraform apply
Here is the remaining output of terraform apply :
Let’s head over to AWS Console and do the test run. From the AWS dashboard you can start by searching Lambda from the search bar:
Click on Lambda to see the Lambda function we have provisioned using Terraform:
Click on it, then use the Test button to run the Lambda function:
A new window will open where you need to specify the event name. As you can see in the below pic name, I have assigned the event name as MyCustomMessage and entered a custom message as key1.
Now, click on the Test tab and then on the orange Test Button:
As you can see, it has returned the message Hello Spacelift, which we have written inside the python file.
This article is meant to get you familiar with using Terraform to manage AWS Lambda functions. Although the article uses Python, you can use other programming languages such as GO, Java, Ruby, .NET to satisfy your business needs. The core concepts of setting AWS Lambda with Terraform still remain the same regardless of your language choice.
We encourage you also to explore how Spacelift makes it easy to work with Terraform. If you need any help managing your Terraform infrastructure, building more complex workflows based on Terraform, and managing AWS credentials per run, instead of using a static pair on your local machine, Spacelift is a fantastic tool for this. It supports Git workflows, policy as code, programmatic configuration, context sharing, drift detection, and many more great features right out of the box.
Terraform Management Made Easy
Spacelift effectively manages Terraform state, more complex workflows, supports policy as code, programmatic configuration, context sharing, drift detection, resource visualization and includes many more features.