Repository navigation
(lambda-web-function-alpha): add L2 constructs for Lambda Web Functions #39234
Description
Describe the feature
Add an L2 construct library for Lambda Web Functions, which run a standard HTTP server on Lambda
without rewriting it as an event handler.
CloudFormation already exposes the resources (AWS::Lambda::WebFunction, AWS::Lambda::WebFunctionRevision,
AWS::Lambda::WebFunctionEndpoint, AWS::Lambda::ResourcePolicy), but CDK has no higher-level construct for them.
I have a prototype in an alpha package, @aws-cdk/aws-lambda-web-function-alpha, and I plan to open a PR for it.
Use Case
Deploying an HTTP application (for example Express) on Lambda currently means writing an event handler or
adapter. With an L2 the application can be deployed as-is, with an endpoint, traffic splitting and access
control expressed in code:
const fn = new WebFunction(this, 'WebFunction', {
code: WebFunctionCode.fromAsset(path.join(__dirname, 'app')),
timeout: Duration.seconds(30),
});
const endpoint = new WebFunctionEndpoint(this, 'Endpoint', { webFunction: fn });
endpoint.grants.invoke(role);Proposed Solution
Prototype (alpha package):
WebFunction: function, revision (code, runtime, timeout, environment, logging, KMS) and execution role.WebFunctionEndpoint:HomeRegion/MultiRegion/PerRegion,IamAuth/ApplicationManaged, revision
weights, scaling and throttling, with validation at synth time.grants.invoke()on endpoints (lambda:InvokeWebFunctionEndpoint).- Import methods for existing functions and endpoints.
- Resource-based policies through the L1
CfnResourcePolicy.
Workaround to be removed: the Web Functions service cannot read assets in the CDK bootstrap bucket, and the
current bootstrap template does not grant that access. Deploying an asset fails with
lambda service principal lambda.amazonaws.com does not have s3:GetObject ... on s3://cdk-hnb659fds-assets-....
Until bootstrap grants the access, fromAsset copies the asset into a versioned bucket owned by the web function.
A bootstrap update that grants the service read access would let this copy be removed.
Other Information
- I verified the CloudFormation side in a test account in eu-west-1: an
AWS::Lambda::ResourcePolicywith a web
function ARN asResourceArnis accepted, and it reads back with the CloudControl API. - Rerunning the bootstrap does not fix the asset issue: the current bootstrap template (version 32) does not grant
the service read access to the asset bucket. - Open questions: whether the bootstrap template should grant the Web Functions service read access to the asset
bucket, and where the alpha package should live long term.
Acknowledgements
- I may be able to implement this feature request
- This feature might incur a breaking change
AWS CDK Library version (aws-cdk-lib)
main at 805bfbe (unreleased, built from source)
AWS CDK CLI version
2.1129.0
Environment details (OS name and version, etc.)
macOS (Darwin 23.6.0), Node.js 22.13.1, Apple Silicon
Update
- The prototype now also requires
authTypeon endpoints (no default), grantskms:Decryptto the service on a
customer managed key, validates versioning and encryption forfromBucket, and limits the code bucket policy to
the function's revisions (aws:SourceArn). - The prototype now includes
NetworkConnectorand VPC egress (egressNetworkConnector), which pins the revision
to the connector'sLatestVersionArn. The connector must be in the same stack as the function. - Temporary: the pinned
@aws-cdk/aws-service-spec(0.1.218) does not have the revision's
EgressNetworkConnectorArn, and its validator does not know theWebFunctioncompute type or the connector's
LatestVersionArn. The CloudFormation registry schemas forAWS::Lambda::NetworkConnectorand
AWS::Lambda::WebFunctionRevisionare therefore kept intools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/.
The latest published spec (0.1.221) has these, so the maintainers can remove the schema files once it is bumped.
We have verified the connector and egress with a deploy in a test account.
Update 2
- The code bucket is now shared by the web functions of a stack, and
fromAssetToProvidedBucketcopies code into a
bucket the caller provides. NetworkConnector.fromNetworkConnectorVersionArnimports a connector version, including from another stack.- Egress is rejected at synth for endpoints other than
HomeRegion. - The prototype is an alpha package on purpose: the maintainers can decide whether to adopt it
Update 3
- Implementation is in PR feat(lambda): add alpha module for Lambda Web Functions #39235 (alpha package
@aws-cdk/aws-lambda-web-function-alpha). - Revisions are retained on removal (
DeletionPolicyandUpdateReplacePolicyset toRetain). Without this, replacing
a revision that an endpoint still routes to, for example a canary, fails with409 ConflictException. We reproduced
the failure and confirmed the fix in a test account. - The service read statement is now added to buckets passed to
fromAssetToProvidedBucketandfromBucket, not only to
the shared code bucket. - Callers of
IamAuthendpoints must send theX-Amz-Content-SHA256header when signing requests. Without it the
endpoint answers403even with a valid signature. The README documents this. - Verified in
eu-west-1: the integration test deploys and destroys cleanly, a signed request to anIamAuthendpoint
returns200, and an unsigned one returns403.
Update 4
- The copy custom resource handler is now written in TypeScript and compiled by the package build, instead of hand-written
JavaScript. Its tests cover the copy, the missing version ID error, and the no-op on delete. - Checked again in
eu-west-1after the change: a web function fromfromAsset, one fromfromAssetToProvidedBucket,
and anIamAuthendpoint with a resource policy. The endpoints answer as expected, and the test stacks were destroyed. - Six
prefer-ref-interfaceexclusions remain, each marked in the JSDoc of its property with the reason it keeps the full
interface. autoDeploymentModeis not exposed: it is not in the service spec or the CloudFormation registry schema, and
CloudFormation rejects it as an unsupported property.
Update 5 — CloudFront follow-up (planned)
CloudFront origin for web function endpoints (follow-up)
This work is not in this PR. It is a separate change built on top of this one, because it uses the WebFunctionEndpoint types defined here. main does not have these types yet.
Goal: let a CloudFront distribution front an IamAuth endpoint with origin access control (OAC), so that callers reach the endpoint through CloudFront without signing requests themselves.
API (in this alpha package):
WebFunctionEndpointOrigin.withOriginAccessControl(endpoint: IWebFunctionEndpoint, props?: WebFunctionEndpointOriginProps): cloudfront.IOrigin, modelled onFunctionUrlOrigin.withOriginAccessControlinaws-cdk-lib/aws-cloudfront-origins.WebFunctionEndpointOriginPropsextends the standard origin props used byOriginBase:originAccessControl?,originPath?,customHeaders?,connectionAttempts?,connectionTimeout?,readTimeout?,keepaliveTimeout?. Each one carries a@defaulttag.- When no OAC is passed, the origin creates a
cloudfront.CfnOriginAccessControlwith origin typelambda, signing behavioralways-amz-auth, and signing protocolsigv4.
Behavior:
- The origin domain is the endpoint's
DomainName. - In
bind(), the origin adds one statement to the resource policy of the web function:Principal: cloudfront.amazonaws.com,Action: lambda:InvokeWebFunctionEndpoint,Resource: the endpoint ARN,Condition:StringEqualsonaws:SourceArn= the distribution ARN, usingoptions.distributionId, asFunctionUrlOrigindoes. - The web function has one resource policy, and
put-resource-policyreplaces the whole policy. So the statements of all origins on the same function go into oneAWS::Lambda::ResourcePolicyowned by the function, not one resource per origin. Each origin registers its statement with a shared object on the function (the same pattern as the code bucket policy incode.ts). That object emits the single policy once, at synth.
Validation (synth time):
- The endpoint must be
IamAuth. AnApplicationManagedendpoint is not evaluated against the resource policy, so the origin fails with a clear error. - The endpoint must be
HomeRegionorPerRegion.MultiRegionuses SigV4a, and CloudFront support for it is not verified, so it is out of scope for this change.
Tests:
- Unit: the OAC has origin type
lambda,always-amz-authandsigv4. The resource policy has the CloudFront principal and theaws:SourceArncondition for the distribution. - Unit: two distributions on the same function produce one resource policy with two statements.
- Unit: an
ApplicationManagedendpoint fails at synth; aMultiRegionendpoint fails at synth. - Integration (
integ.web-function-cloudfront.ts): oneIamAuthendpoint behind one distribution. Deployed ineu-west-1, checked, destroyed. Check that a request through the distribution returns200and a direct unsigned request to the endpoint returns403.
Docs: a "CloudFront" section in the README with a compiling example (rosetta), and a note that the CloudFront origin must forward the Authorization header, as the Lambda access control guide describes.
Acceptance criteria:
- All tests above pass, and the integration test passes with a real deployment.
- No change to the existing API of this package.
- awslint shows no new errors.
Out of scope: MultiRegion endpoints, custom domains on the function (CloudFront is the documented way to add one), caching policy design beyond the defaults, and the stable aws-cloudfront-origins package. Moving the origin to aws-cdk-lib would be a separate proposal, after this one is in use.
Dependencies and open points:
- Depends on this PR being merged, or on a stacked PR.
- No spec bump is needed: the
cloudfrontOAC typelambdais already inaws-cdk-lib. - Open: whether the resource policy merge should live on the web function (proposed) or in a small helper in this package. This needs a maintainer decision before implementation.
Activity
pahud commentedon Oct 23, 2026
Hi @davide-desio-eleva,
Thanks for the very detailed work here and in #39235, especially the deploy-verified findings. As @matboros mentioned on #39235, the service team's #39210 covers the same L2 in
aws-cdk-lib/aws-lambda, so let's consolidate there and keep this issue as the tracking issue for the feature (#39210 doesn't link one yet).From a quick look at #39210's patches, a few of your findings may not be covered yet. Bringing them over as review comments there would be very valuable:
409 ConflictExceptionwhen an endpoint still routes to the old revisionX-Amz-Content-SHA256note forIamAuthcallersThe bootstrap asset-bucket access is a separate question for
aws/aws-cdk-cli, and a dedicated issue there would help both implementations drop the code copy.davide-desio-eleva commentedon Oct 26, 2026
Thanks @pahud. I've opened the three points as review comments on #39210: revision retention with the 409 reproduction, the single resource-based policy statement collector needed for CloudFront, and the
X-Amz-Content-SHA256requirement forIamAuthcallers.I'll keep this issue as the reference for the feature. If the maintainers want to link it to #39210, that works for me, and I'm fine with closing #39235 in favour of #39210.