External secrets adapter for Pulumi ESC on AWS Lambda
External secrets adapter for Pulumi ESC using AWS Lambda with JWT authentication
This example lives in the pulumi/examples repository. Check out just this directory to use it:
git clone --filter=blob:none --sparse https://github.com/pulumi/examples pulumi-examplesgit -C pulumi-examples sparse-checkout set aws-ts-esc-external-adapter-lambdacd pulumi-examples/aws-ts-esc-external-adapter-lambdaA reference implementation showing how to build a secure external secrets adapter for Pulumi ESC. This example validates JWT authentication and request integrity, making it easy to integrate custom or proprietary secret sources with ESC.
For complete documentation on ESC Connect, see the external provider documentation.
Deploying the adapter#
-
Install dependencies:
Terminal window npm install -
Create a new Pulumi stack:
Terminal window pulumi stack init dev -
Configure your AWS region:
Terminal window pulumi config set aws:region us-west-2 -
Deploy:
Terminal window pulumi up -
Copy the adapter URL from the output:
Terminal window export ADAPTER_URL=$(pulumi stack output adapterUrl)
Using with Pulumi ESC#
Create a Pulumi ESC environment:
values: demo: fn::open::external: url: https://YOUR-API-ID.execute-api.us-west-2.amazonaws.com/stage/ request: message: "Hello from ESC!"Open the environment:
esc open <your-org>/external-demoExpected output:
{ "demo": { "response": { "message": "External secrets adapter responding successfully!", "requestEcho": { "message": "Hello from ESC!" }, "timestamp": "2025-11-26T12:00:00.000Z" } }}Building your own adapter#
The ESCRequestValidator class in index.ts handles request integrity validation. To integrate your own secret source:
-
Copy the
ESCRequestValidatorclass into your adapter -
Replace the
TODOcomment in the Lambda handler with your secret fetching logic:const { claims, requestBody } = await validator.validateRequest(event);// Use claims to further authorize the requestif (claims.org !== "YOUR-PULUMI-ORG") {return { statusCode: 401 };}// Fetch from your secret sourceconst secret = await fetchFromYourSecretStore(requestBody.secretName);return {statusCode: 200,body: JSON.stringify(secret),};
See the external provider documentation for complete implementation guidance and examples in other languages.
Monitoring#
View Lambda logs:
pulumi logs --followOr use the AWS CLI:
aws logs tail /aws/lambda/$(pulumi stack output functionName) --followThe handler logs JWT claims to CloudWatch for debugging.
Clean up#
pulumi destroypulumi stack rm dev