Skip to main content

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:

Get started with this example
git clone --filter=blob:none --sparse https://github.com/pulumi/examples pulumi-examples
git -C pulumi-examples sparse-checkout set aws-ts-esc-external-adapter-lambda
cd pulumi-examples/aws-ts-esc-external-adapter-lambda

A 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#

  1. Install dependencies:

    Terminal window
    npm install
  2. Create a new Pulumi stack:

    Terminal window
    pulumi stack init dev
  3. Configure your AWS region:

    Terminal window
    pulumi config set aws:region us-west-2
  4. Deploy:

    Terminal window
    pulumi up
  5. 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:

Terminal window
esc open <your-org>/external-demo

Expected 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:

  1. Copy the ESCRequestValidator class into your adapter

  2. Replace the TODO comment in the Lambda handler with your secret fetching logic:

    const { claims, requestBody } = await validator.validateRequest(event);
    // Use claims to further authorize the request
    if (claims.org !== "YOUR-PULUMI-ORG") {
    return { statusCode: 401 };
    }
    // Fetch from your secret source
    const 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:

Terminal window
pulumi logs --follow

Or use the AWS CLI:

Terminal window
aws logs tail /aws/lambda/$(pulumi stack output functionName) --follow

The handler logs JWT claims to CloudWatch for debugging.

Clean up#

Terminal window
pulumi destroy
pulumi stack rm dev

Additional resources#

Related

The infrastructure as code platform for any cloud.