AWS Lambda is a serverless compute service that allows you to run code without provisioning or managing servers. However, the default Lambda environment does not include all Python libraries, such as requests
. To resolve this, AWS provides Lambda Layers, which allow us to package dependencies separately from the function code, making deployment more efficient.
Why Does AWS Lambda Require Layers?
AWS Lambda has a constrained execution environment with a pre-configured set of runtime libraries. If your function requires additional dependencies (e.g., requests for making HTTP calls), you must either:
- Bundle dependencies within your deployment package, or
- Use Lambda Layers, which provide a modular approach for managing dependencies across multiple Lambda functions.
Using layers helps:
- Reduce deployment package size.
- Promote reusability across multiple Lambda functions.
- Improve maintainability by keeping dependencies separate from function code.
What Are Lambda Function URLs?
Lambda Function URLs allow users to invoke Lambda functions directly via an HTTP(S) endpoint without needing an API Gateway. This feature simplifies web service development, reducing complexity and cost. Function URLs are useful for creating lightweight APIs, webhooks, and integrations where API Gateway might be unnecessary.
In this blog, we will provision an AWS Lambda function using Terraform that fetches a joke from Chuck Norris API using Lambda Layers for dependency management and expose it using a Function URL.
Architecture
Step 1: Define IAM Role and Policy
First, we need an AWS IAM role that grants permissions to the Lambda function.
################################################################################
# Lambda IAM role to assume the role
################################################################################
resource "aws_iam_role" "lambda_role" {
name = "lambda_execution_role"
assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [{
"Effect" : "Allow",
"Principal" : {
"Service" : "lambda.amazonaws.com"
},
"Action" : "sts:AssumeRole"
}]
})
}
################################################################################
# Assign policy to the role
################################################################################
resource "aws_iam_policy_attachment" "lambda_basic_execution" {
name = "lambda_basic_execution"
roles = [aws_iam_role.lambda_role.name]
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
Step 2: Create a Lambda Layer for requests
Library
Since AWS Lambda does not include the requests library by default, we need to create a layer.
- Open AWS CloudShell and execute the following commands to prepare the layer. I have used cloudshell as I am using windows which did not have pip/python etc. The packages must be installed in a folder named
python
otherwise the layer will not work as expected. Once its done, therequests_layer.zip
was downloaded and saved on project directory for upload in next step.
mkdir python
pip install requests -t python/
zip -r -q requests_layer.zip python/
- Upload and create the layer using Terraform:
################################################################################
# Creating lambda layer for requests python library
################################################################################
resource "aws_lambda_layer_version" "requests_layer" {
filename = "${path.module}/requests_layer.zip"
layer_name = "requests_layer"
compatible_runtimes = ["python3.12"]
source_code_hash = filebase64sha256("${path.module}/requests_layer.zip")
}
Step 3: Define Lambda Function Code
Prepare the chucknorris_jokes.py
file with the following content in lambda
folder:
import json
import requests
import os
def lambda_handler(event, context):
response = requests.get(os.environ['API_URL'])
joke = response.json().get("value", "No joke found.")
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps(joke)
}
and prepare the zip file for the code
################################################################################
# Compressing lambda_handler function code
################################################################################
data "archive_file" "lambda_function_archive" {
type = "zip"
source_dir = "${path.module}/lambda"
output_path = "${path.module}/lambda_function.zip"
}
Step 4: Define the Lambda Function
Now, create the Lambda function using Terraform. It will use the function code zip file, layer ARN and other parameters.
################################################################################
# Creating Lambda Function
################################################################################
resource "aws_lambda_function" "get_joke_lambda_function" {
function_name = "ChuckNorrisJokes_Lambda"
filename = "${path.module}/lambda_function.zip"
runtime = "python3.12"
handler = "chucknorris_jokes.lambda_handler"
layers = [aws_lambda_layer_version.requests_layer.arn]
memory_size = 128
timeout = 10
environment {
variables = {
API_URL = "https://api.chucknorris.io/jokes/random"
}
}
source_code_hash = data.archive_file.lambda_function_archive.output_base64sha256
role = aws_iam_role.lambda_role.arn
}
Step 5: Create a Lambda Function URL
To expose the Lambda function via a URL:
################################################################################
# Creating Lambda Function URL for accessing it via browser
################################################################################
resource "aws_lambda_function_url" "chucknorris_function_url" {
function_name = aws_lambda_function.get_joke_lambda_function.function_name
authorization_type = "NONE" # Change to "AWS_IAM" for restricted access
}
Also create a Cloudwatch Log Group
################################################################################
# Creating CloudWatch Log group for Lambda Function
################################################################################
resource "aws_cloudwatch_log_group" "get_joke_lambda_function_cloudwatch" {
name = "/aws/lambda/${aws_lambda_function.get_joke_lambda_function.function_name}"
retention_in_days = 30
}
Steps to Run Terraform
Follow these steps to execute the Terraform configuration:
terraform init
terraform plan
terraform apply -auto-approve
Upon successful completion, Terraform will provide relevant outputs.
Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
Outputs:
lambda_function_url = "https://khpjd5gawsrgpjoo5ayqffr5c40udyuw.lambda-url.us-east-1.on.aws/"
Testing
Lambda Function, showing (1) layer, function URL and code
Lambda Layer
Lambda Function URL
Cleanup
Remember to stop AWS components to avoid large bills.
terraform destroy -auto-approve
Conclusion
By following these steps, we provisioned an AWS Lambda function using Terraform that fetches Chuck Norris jokes using the requests library. We used Lambda Layers to manage dependencies efficiently and exposed our function using a Function URL, enabling seamless HTTP access without an API Gateway.
References
- AWS Lambda Layers https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html
- Lambda Function URLs https://docs.aws.amazon.com/lambda/latest/dg/urls-configuration.html
- Chuck Norris API https://api.chucknorris.io/
- GitHub Repo https://github.com/chinmayto/terraform-aws-lambda-with-layers
Top comments (0)