How many times have you had to create an API Gateway resource on AWS just to get through to your Lambda Function? I love using the serverless stack (AWS Lambda + API Gateway + DynamoDB) for running small applications. The Lambda and APIGateway combo has served its purpose really well. Last week, AWS announced Lambda Function URLs. A new Lambda feature that allows you to directly create an HTTPS endpoint for your Function.
Let's walk through how we can quickly set this up with terraform.
First, create the provider and terraform blocks in provider.tf.
touch provider.tf
terraform {
required_providers {
aws = {
version = ">= 4.9.0”
source = "hashicorp/aws"
}
}
}
provider "aws" {
profile = “your_cli_profile”
region = "us-east-1"
}
The most recent release of the terraform-provider-aws (v4.9.0) by Hashicorp has the lambda functions URLs functionality. Make sure to replace profile with your cli profile. If you don’t already have an AWS access profile setup refer to the AWS documentation to set it up.
Creating the Lambda URL resource
Now we will go ahead and create the lambda functions URL resource.
touch main.tf
resource "aws_lambda_function_url" "url1" {
function_name = aws_lambda_function.myfunc.function_name
authorization_type = "NONE"
cors {
allow_credentials = true
allow_origins = ["*"]
allow_methods = ["*"]
allow_headers = ["date", "keep-alive"]
expose_headers = ["keep-alive", "date"]
max_age = 86400
}
}
Note that the authorization_type = 'NONE'
makes your URL publicly accessible. This might be fine for testing. In higher environments, however, this must be avoided. We set our familiar CORS values including allow_methods
which can be set to "GET", "POST", "DELETE"
.
Before we can run this, we need a full lambda function resource, myfunc
.
resource "aws_lambda_function" "myfunc" {
filename = data.archive_file.zip.output_path
source_code_hash = data.archive_file.zip.output_base64sha256
function_name = "myfunc"
role = aws_iam_role.iam_for_lambda.arn
handler = "func.handler"
runtime = "python3.8"
}
resource "aws_iam_role" "iam_for_lambda" {
name = "iam_for_lambda"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
data "archive_file" "zip" {
type = "zip"
source_dir = "${path.module}/lambda/"
output_path = "${path.module}/packedlambda.zip"
}
We will use Python for the handler function.
mkdir lambda && touch lambda/func.py
def handler(event, context):
body = "hello"
response = {
"statusCode": 200,
"statusDescription": "200 OK",
"isBase64Encoded": False,
"headers": {"Content-Type": "text/json; charset=utf-8"},
"body": body
}
return response
Let's run terraform
To run terraform we go through the workflow steps:
terraform init
terraform plan
terraform apply
Now let's go into the console to look at, and try out our new Lambda Function URL.
Final thoughts
Congrats! you just created a Lambda Function URL, a simple API to your serverless lambda function.
Lambda Function URLs do not have native APIGateway capabilities such as rate limiting, throttling, IP whitelisting / blacklisting, authorizers. There has been a lot of talk about this in the wider developer community and concerns about how security best practices can be implemented.
On the plus side they:
have no added cost on top of Lambda
are quicker to implement than API Gateway
can be paired with CloudFront to tap some of its inherent benefits such as WAF, Logging, geo targeting - targeting delivery to specific end-users.
Here's the github code for the project.