Is it safe to pass sensitive values as environment variables into an aws-cdk custom resource

Viewed 1169

I want to save an initial admin user to my dynamodb table when initializing a cdk stack through a custom resource and am unsure of the best way to securely pass through values for that user. My code uses dotEnv and passes the values as environment variables right now:

import * as cdk from "@aws-cdk/core";
import * as lambda from "@aws-cdk/aws-lambda";
import * as dynamodb from "@aws-cdk/aws-dynamodb";
import * as customResource from "@aws-cdk/custom-resources";

require("dotenv").config();

export class CDKBackend extends cdk.Construct {
    public readonly handler: lambda.Function;
    constructor(scope: cdk.Construct, id: string) {
        super(scope, id);

        const tableName = "CDKBackendTable";

        // not shown here but also:
        // creates a dynamodb table for tableName and a seedData lambda with access to it
        // also some lambdas for CRUD operations and an apiGateway.RestApi for them

        const seedDataProvider = new customResource.Provider(this, "seedDataProvider", {
            onEventHandler: seedDataLambda
        });

        new cdk.CustomResource(this, "SeedDataResource", {
            serviceToken: seedDataProvider.serviceToken,
            properties: {
                tableName,
                user: process.env.ADMIN,
                password: process.env.ADMINPASSWORD,
                salt: process.env.SALT
            }
        });
    }
}

This code works, but is it safe to pass through ADMIN, ADMINPASSWORD and SALT in this way? What are the security differences between this approach and accessing those values from AWS secrets manager? I also plan on using that SALT value when generating passwordDigest values for all new users, not just this admin user.

1 Answers

The properties values will be evaluated at deployment time. As such they will become part of CloudFormation template. The CloudFormation template can be viewed inside AWS Web Console. As such passing secrets around this way is questionable from security standpoint.

One way to overcome this is to store the secrets using AWS Secrets Manager. aws-cdk has good integration with it Secrets Manager. Once you create a secret you can import it via:

const mySecretFromName = secretsmanager.Secret.fromSecretNameV2(stack, 'SecretFromName', 'MySecret')

Unfortunately there's no support for resolving CloudFormation dynamic references in AWS Custom Resources. You can resolve the secret yourself though inside your lambda (seedDataLambda). The SqlRun repository provides an example.

Please remember to grant access to the secret for the custom resource lambda (seedLambda) e.g.

secret.grantRead(seedDataProvider.executionRole)
Related