CloudFront and Lambda function URLs
In April 2022, AWS Lambda announced the launch of function URLs - a
way to invoke websites powered by Lambda functions without needing API Gateway.
A common complaint was the lack of support for custom domains: it only supported
the URLs it would generate that look like lprqaxgvt4f6ab3dbj3ixftr640uzgie.lambda-url.ap-southeast-2.on.aws
.
But that’s where CloudFront comes in useful. Not only can it provide us with custom domain functionality, but we get caching, WAF support, etc as well. Here’s a template I’ve been using for my apps:
Transform: AWS::Serverless-2016-10-31
Parameters:
CertificateArn:
Type: String
HostedZoneId:
Type: String
Domain:
Type: String
Resources:
Function:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./webapp
AutoPublishAlias: live
MemorySize: 1024
Timeout: 30
Architectures: [arm64]
Runtime: provided.al2
Handler: unused
FunctionUrlConfig:
AuthType: AWS_IAM
CloudFront:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
HttpVersion: http2and3
Aliases:
- !Ref Domain
ViewerCertificate:
AcmCertificateArn: !Ref CertificateArn
MinimumProtocolVersion: TLSv1.2_2021
SslSupportMethod: sni-only
DefaultCacheBehavior:
ViewerProtocolPolicy: redirect-to-https
Compress: true
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # Managed-CachingOptimized
OriginRequestPolicyId: 59781a5b-3903-41f3-afcb-af62929ccde1 # Managed-CORS-CustomOrigin
TargetOriginId: web
Origins:
- Id: web
DomainName: !Select [2, !Split ["/", !GetAtt FunctionUrl.FunctionUrl]]
OriginAccessControlId: !Ref OAC
CustomOriginConfig:
OriginProtocolPolicy: https-only
OriginSSLProtocols: [TLSv1.2]
OriginShield:
Enabled: true
OriginShieldRegion: !Ref AWS::Region
Permission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunctionUrl
FunctionName: !Ref Function.Alias
FunctionUrlAuthType: AWS_IAM
Principal: cloudfront.amazonaws.com
SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFront}
OAC:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: !Ref AWS::StackName
OriginAccessControlOriginType: lambda
SigningBehavior: always
SigningProtocol: sigv4
Record:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: !Ref HostedZoneId
Name: !Ref Domain
Type: A
AliasTarget:
DNSName: !GetAtt CloudFront.DomainName
HostedZoneId: Z2FDTNDATAQYW2 # this is documented as the cloudfront hosted zone id
Update 24/07/2024: CloudFront added support for AWS IAM authentication when connecting to Lambda function URLs. I have updated the template to use that. This means that even if an attacker discovers your Lambda function URL, they can’t bypass CloudFront - this is useful if you rely on WAF protections.