Happy Dussehra! May good always win. Happy Diwali! Wishing you a bright year ahead. Merry Christmas! Warm wishes from Vizag. Happy New Year! Here’s to a great year ahead.

Archive · AWS

Lambda Function URLs

Expose a Lambda function over HTTPS without API Gateway: create a function URL, choose the auth type, set CORS, secure it with IAM, and know when API Gateway is still better.

3 min read

  • AWS Lambda
  • Python 3.9
  • AWS CLI 2.7
  • Function URL
  • IAM auth

Until this year, giving a Lambda function an HTTP endpoint meant adding API Gateway or an Application Load Balancer. Since April 2022, a function can have a built-in function URL: a dedicated HTTPS endpoint of the form https://<url-id>.lambda-url.<region>.on.aws, with no extra service to configure and no per-request API Gateway charge (you pay for the Lambda invocations).

Versions in use on this date. Python 3.9 on Lambda and AWS CLI 2.7. Function URLs support two authorization modes (NONE and AWS_IAM), CORS configuration, and the same request and response payload format as API Gateway HTTP APIs (version 2.0).

Request path

flowchart TB
  C[Client] -->|HTTPS| FU[Function URL<br/>https id lambda-url ap-south-1 on.aws]
  FU --> AUTH{Auth type}
  AUTH -->|AWS_IAM| SIG[Requires SigV4 signed request<br/>caller needs lambda InvokeFunctionUrl]
  AUTH -->|NONE| PUB[Open to the internet<br/>app must authenticate]
  SIG --> FN
  PUB --> FN[Lambda function handler]
  FN --> DB[(DynamoDB, S3, RDS)]
  FN --> RESP[Response JSON status headers body]
  RESP --> C
  FN -.-> CW[CloudWatch Logs and metrics]

Create a function and URL

# lambda_function.py
import json

def lambda_handler(event, context):
    method = event["requestContext"]["http"]["method"]
    path = event["rawPath"]
    body = json.loads(event["body"]) if event.get("body") else {}
    return {
        "statusCode": 200,
        "headers": {"Content-Type": "application/json"},
        "body": json.dumps({"method": method, "path": path, "echo": body}),
    }
zip fn.zip lambda_function.py
aws iam create-role --role-name hello-fn-role --assume-role-policy-document file://lambda-trust.json
aws iam attach-role-policy --role-name hello-fn-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws lambda create-function --function-name hello-url --runtime python3.9 --handler lambda_function.lambda_handler \
  --zip-file fileb://fn.zip --role arn:aws:iam::111111111111:role/hello-fn-role --timeout 10 --memory-size 256

aws lambda create-function-url-config --function-name hello-url --auth-type AWS_IAM \
  --cors 'AllowOrigins=https://app.example.com,AllowMethods=GET,POST,AllowHeaders=content-type,MaxAge=3600'
aws lambda get-function-url-config --function-name hello-url

The output includes FunctionUrl. With AWS_IAM, you must sign requests:

curl --aws-sigv4 "aws:amz:ap-south-1:lambda" --user "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \
  -H "x-amz-security-token: $AWS_SESSION_TOKEN" -H "content-type: application/json" \
  -d '{"hello":"world"}' https://abcd1234.lambda-url.ap-south-1.on.aws/test

(--aws-sigv4 needs curl 7.75 or newer.) Allow a specific role to call it:

aws lambda add-permission --function-name hello-url --statement-id invoke-url \
  --action lambda:InvokeFunctionUrl --principal arn:aws:iam::111111111111:role/client-role \
  --function-url-auth-type AWS_IAM

Public endpoints (NONE)

aws lambda create-function-url-config --function-name hello-public --auth-type NONE
aws lambda add-permission --function-name hello-public --statement-id public-url \
  --action lambda:InvokeFunctionUrl --principal "*" --function-url-auth-type NONE

NONE means anyone can call it. Only use it when the function authenticates callers itself (a signed webhook secret, a JWT it validates) or the data is public. Add input validation, rate awareness and logging, because there is no WAF, throttling plan or API key in front.

Function URL, API Gateway or ALB?

Need Function URL API Gateway (HTTP/REST) ALB
Simple endpoint, webhooks, internal tools Best More than needed More than needed
Custom domain with your TLS certificate No (put CloudFront in front) Yes Yes
Usage plans, API keys, request validation, throttling per client No Yes (REST API) No
JWT/Cognito authorizers No (do in code) Yes Via OIDC action
WAF integration Via CloudFront Yes Yes
Multiple routes mapped to many functions One function handles all routes Yes Path rules
Cost Lambda only + per-request charge + hourly and LCU

For a custom domain on a function URL, front it with CloudFront (with an origin access control or custom header the function checks), which also gives caching and WAF.

Operational notes

  • Concurrency and throttling: set reserved concurrency to cap cost and protect downstream systems, and alert on Throttles, Errors and Duration metrics.
  • Timeouts: the function URL allows up to the function’s timeout (maximum 15 minutes), but clients and proxies usually give up sooner.
  • Payload limits: 6 MB request and response (synchronous invocation limit).
  • Logging: log the request ID, path and status; do not log whole bodies containing personal data.
  • Infrastructure as code: CloudFormation AWS::Lambda::Url, Terraform aws_lambda_function_url, and the permission resource, so the setting is reviewed and repeatable.
  • Delete unused URLs: aws lambda delete-function-url-config --function-name hello-public; an open public URL on a forgotten function is an easy target.