DEV Community

Cover image for Configuring an AWS Lambda Function with Lambda Layers and Function URL Using Terraform
Chinmay Tonape
Chinmay Tonape

Posted on

Configuring an AWS Lambda Function with Lambda Layers and Function URL Using Terraform

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:

  1. Bundle dependencies within your deployment package, or
  2. Use Lambda Layers, which provide a modular approach for managing dependencies across multiple Lambda functions.

Using layers helps:

  1. Reduce deployment package size.
  2. Promote reusability across multiple Lambda functions.
  3. 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

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"
}
Enter fullscreen mode Exit fullscreen mode

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.

  1. 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, the requests_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/
Enter fullscreen mode Exit fullscreen mode

Create Layer Archive on Cloudshell

  1. 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")
}
Enter fullscreen mode Exit fullscreen mode

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)
    }
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

Steps to Run Terraform

Follow these steps to execute the Terraform configuration:

terraform init
terraform plan 
terraform apply -auto-approve
Enter fullscreen mode Exit fullscreen mode

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/"
Enter fullscreen mode Exit fullscreen mode

Testing

Lambda Function, showing (1) layer, function URL and code

Lambda Function

Lambda Function Details

Lambda Layer

Lambda Layer

Lambda Function URL

Lambda Function URL

Lambda Basic Execution Role

Resource Based Policy Statement

CloudWatch Logs

Cleanup

Remember to stop AWS components to avoid large bills.

terraform destroy -auto-approve
Enter fullscreen mode Exit fullscreen mode

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

  1. AWS Lambda Layers https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html
  2. Lambda Function URLs https://docs.aws.amazon.com/lambda/latest/dg/urls-configuration.html
  3. Chuck Norris API https://api.chucknorris.io/
  4. GitHub Repo https://github.com/chinmayto/terraform-aws-lambda-with-layers

Top comments (0)