AWS Lambda Terraform
AWS Lambda Deployment
Canary Deployment for AWS Lambda
Lambda VPC
AWS Lambda Security
AWS Lambda CloudFormation
AWS Lambda Terraform

Deploying AWS Lambda with Terraform

Serverless is a popular cloud computing architecture for applications in the AWS cloud. It enables developers to concentrate on building application logic rather than worry about infrastructure provisioning and maintenance.

The most common approach to building serverless applications is creating one or more Lambda functions and then exposing them using AWS API Gateway. These Lambda functions connect to other AWS services to serve the requests with data and other information. There are other use cases where an event can trigger a Lambda function asynchronously and do a batch operation based on the event passed to it.

You can build this serverless application flow manually using AWS Console or AWS CLI, however, that will be very painful to maintain for the enhancements, rollbacks, and when you need to recreate new environments for the same workload. Hashicorp’s Terraform is a popular automation scripting tool for building, changing, and versioning infrastructure safely and efficiently.

serverless automation workflow with terraform

Image Source

In this article, we will review what is Terraform, and how Terraform AWS modules can help automate and provision serverless application resources. We will focus on explaining how Terraform Lambda resources work.

What is Terraform

Terraform is a tool to implement Infrastructure-as-Code (IaC) for many cloud providers, including AWS, Google Cloud Platform (GCP), and Microsoft Azure. It can manage low-level components such as compute instances, storage, and networking, as well as high-level components such as DNS entries, SaaS features, and more.

Terraform and cloud providers such as AWS

Image Source

Terraform has a few main features:

Blueprint

In Terraform, infrastructure is described using high-level configuration. It eventually becomes a blueprint of your datacenter. It is versioned and treated like any other application code. This makes it a reusable asset for creating a new environment quickly.

 Execution Plans

Terraform generates an execution plan when you run the apply command. This plan describes the desired state and the steps it will take to reach it. It then executes those steps to build the configured infrastructure. If you need to make configuration changes and apply, Terraform is able to determine what has changed and create incremental execution plans.

Resource Graph

Terraform builds a dependency resource graph of all the resources in a template and works through this graph to generate plans, refresh state, and more. If there is no dependency between the resources, it parallelizes the creation and modification of those resources. This brings efficiency into building the infrastructure, and lets operators get insight into infrastructure dependencies.

Terraform Lambda Resources

Now that we have a basic understanding of Terraform, let’s take a deep look at Terraform Lambda resources and how they provision Lambda functions and other resources.

Aws_lambda_alias

The aws_lambda_alias resource creates a virtual identifier for a specific version of a Lambda function. It helps to upgrade the version of a function without asking the client to modify code at their end. You can also implement canary deployment by pointing the alias to multiple versions using routing config.

Below is a Terraform AWS example with the Lambda alias feature:

resource "aws_lambda_alias" "prod_lambda_alias" {
  name             = "your_alias"
  description      = "production version"
  function_name    = aws_lambda_function.lambda_function_prod.arn
  function_version = "1"
  routing_config {
    additional_version_weights = {
      "2" = 0.4
    }
  }
}

aws_lambda_event_source_mapping

The aws_lambda_event_source_mapping resource creates a mapping between an event source and a Lambda function. It configures the ARN of the event source that triggers the Lambda function. It also defines the properties to control the behaviour to trigger the function.

Below is a Terraform AWS example of a DynamoDB event source:

 resource "aws_lambda_event_source_mapping" "DynamoDBExample" {
  event_source_arn  = aws_dynamodb_table.dynamodbexample.stream_arn
  function_name     = aws_lambda_function.dynamodbexample.arn
  starting_position = "LATEST"
}

aws_lambda_function

A Lambda function needs code and an IAM role to run a function. Code is deployed on an S3 bucket as a deployment package (zip file).

Below is a sample Terraform AWS Lambda function:

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

resource "aws_lambda_function" "sample_lambda" {
filename      = "lambda_function_payload.zip"
function_name = "lambda_terraform_function_name"
role          = aws_iam_role.iam_role_for_lambda.arn
  handler       = "data.test"

# The filebase64sha256() function is available in Terraform 0.11.12 and later
# For Terraform 0.11.11 and earlier, use the base64sha256() function and the file() function:
# source_code_hash = "${base64sha256(file("lambda_function_payload.zip"))}"
  source_code_hash = filebase64sha256("lambda_function_payload.zip")

  runtime = "nodejs12.x"

environment {
   variables = {
     foo = "bar"
   }
}
}

}

It has several other properties such as vpc_config, file_system_config, and more.

The function might need several other optional resources such as aws_efs_file_system, aws_efs_mount_target, and aws_efs_access_point.

aws_cloudwatch_log_group

This resource is required to create a log group for a function and configure a retention policy for it. You need this for logging and monitoring the Lambda function.

resource "aws_cloudwatch_log_group" "example" {
  name              = "/aws/lambda/${var.lambda_function_name}"
  retention_in_days = 14
}

aws_lambda_function_event_invoke_config

This resource is required to invoke a Lambda function for asynchronous flow.

resource "aws_lambda_function_event_invoke_config" "lambdaexample" {
  function_name = aws_lambda_alias.example.function_name
 maximum_event_age_in_seconds = 60
  maximum_retry_attempts       = 0
  qualifier     = aws_lambda_alias.example.name

  destination_config {
    on_failure {
      destination = aws_sqs_queue.example.arn
    }

    on_success {
      destination = aws_sns_topic.example.arn
    }
  }
}

aws_lambda_layer_version

This provides a Lambda Layer Version resource. Lambda Layers allow you share the reusable code through layers across multiple Lambda functions.

resource "aws_lambda_layer_version" "lambda_nodejs_layer" {
  filename   = "lambda_nodejs_layer_payload.zip"
  layer_name = "lambda_layer_nodejs"

  compatible_runtimes = ["nodejs12.0"]
}

aws_lambda_permission

This resource provides other AWS services, such as S3 and DynamoDB, access to the Lambda function.

resource "aws_lambda_permission" "allow_s3" {
  statement_id  = "AllowExecutionFromS3"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.s3_lambda.function_name
  principal     = "events.amazonaws.com"
  source_arn    = "arn:aws:events:ap-east-2:121112424343:rule/RunDaily"
  qualifier     = aws_lambda_alias.s3_alias.name
}

aws_api_gateway

API Gateway is the most important resource for synchronous flow. Terraform can be used to create and integrate it with a Lambda function.

Below are the four resources required to create API Gateway and it’s integration with a function:

resource "aws_api_gateway_rest_api" "APIexample" {
  name        = "ServerlessAppExample"
  description = "Terraform Serverless Application Example"
}

resource "aws_api_gateway_resource" "apiproxy" {
   rest_api_id = aws_api_gateway_rest_api.example.id
   parent_id   = aws_api_gateway_rest_api.example.root_resource_id
   path_part   = "{proxy+}"
}

resource "aws_api_gateway_method" "methodproxy" {
   rest_api_id   = aws_api_gateway_rest_api.example.id
   resource_id   = aws_api_gateway_resource.proxy.id
   http_method   = "ANY"
   authorization = "NONE"
 }

resource "aws_api_gateway_integration" "apilambda" {
   rest_api_id = aws_api_gateway_rest_api.example.id
   resource_id = aws_api_gateway_method.proxy.resource_id
   http_method = aws_api_gateway_method.proxy.http_method

   integration_http_method = "POST"
   type                    = "AWS_PROXY"
   uri                     = aws_lambda_function.example.invoke_arn
 }

Terraform vs. CloudFormation

So far we discussed how Terraform works and how it can help automate the provisioning of serverless application resources. Now, let’s compare it with a native alternative solution: AWS CloudFormation.

  • CloudFormation is an AWS managed service so it does the state management by itself. With Terraform, you can store the state in AWS S3 but you have to configure it manually.
  • Terraform is agnostic to the cloud platform vs CloudFormation that is specific to AWS. You cannot easily provision or coordinate non-AWS resources with CloudFormation.
  • Terraform uses data sources supplied by the specific cloud provider that enables it to fetch data defined outside of Terraform.
  • CloudFormation uses parameters, and has a maximum of 60 parameters per template. Each parameter must be declared and referenced from within the same template.
  • Terraform uses the HashiCorp Configuration Language (HCL) and is compatible with JSON. CloudFormation supports JSON and YAML.

Both are very powerful tools for infrastructure provisioning. If you are using AWS tools and don’t plan to have a hybrid/multi-cloud environment, CloudFormation is a better option as it is always in sync with all the latest AWS releases.

Conclusion

In this article, we reviewed Terraform and the Terraform Lambda modules in detail. Terraform is a good option when using multiple cloud providers, as it supports other clouds such as GCP and Azure. CloudFormation is an alternative that can be used for AWS Lambda resource provisioning and is limited to the AWS ecosystem.