Search code examples
aws-cdkaws-secrets-manager

Accessing AWS SecretsManager in CDK 2.0.0: Errors with software.amazon.awscdk.services.secretsmanager.Secret are in unnamed module


I've recently upgraded from AWS CDK v1.x to v2.0.0. My stack uses SecretsManager to access a string payload on json containing a number of secrets.

In CDK 1.x I used the sample code in the SecretsManager console to access the secret string and it worked fine. However in CDK v2.0.0 those classes are no longer available, so I need to port the code into CDK v2.0.0 classes.

Following the sample in the CDK guide (https://docs.aws.amazon.com/cdk/v2/guide/get_secrets_manager_value.html) I've created a SecretsManagerStack in my app like this:

public class SecretsManagerStack extends Stack {

    private String secretValue;

    public String getSecretValue() { 
        return this.secretValue; 
    }

    public SecretsManagerStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public SecretsManagerStack(final Construct scope, final String id, final SecretsManagerStackProps props) {
        super(scope, id, props.getStackProps());

        String secretName = ConfigManager.getInstance().get("$.aws.secrets.secretName");

        //Note this throws throws errors like:
        // java.lang.ClassCastException: class software.amazon.awscdk.services.secretsmanager.ISecret$Jsii$Proxy cannot be cast to class software.amazon.awscdk.services.secretsmanager.Secret
        // (software.amazon.awscdk.services.secretsmanager.ISecret$Jsii$Proxy and software.amazon.awscdk.services.secretsmanager.Secret are in unnamed module of loader 'app')

        Secret secret = (Secret)Secret.fromSecretAttributes(this, "sm-stack", 
             SecretAttributes.builder()
                .secretCompleteArn(secretName)
                .build());

        // Attempt to set a role on the secret - but this 'should' not be necessary?
        String accountId = ConfigManager.getInstance().get("$.aws.account");
        AccountPrincipal accountPrincipal = new AccountPrincipal(accountId);
        RoleProps roleProps = RoleProps.builder()
                .assumedBy(accountPrincipal)
                .build();
        Role secretAccessRole = new Role(this, "SecretsAccessRole", roleProps);
        secret.grantRead(secretAccessRole);

        this.secretValue = secret.getSecretValue().toString();

        //Ideally if this worked we would pass the stack as properties into other stacks so they
        // could access this secretValue and parse the json into what it needs to do. But alas no.

    }
}

It seems pretty stock standard as per the guide, but to no luck. At run time it returns:

java.lang.ClassCastException: class software.amazon.awscdk.services.secretsmanager.ISecret$Jsii$Proxy cannot be cast to class software.amazon.awscdk.services.secretsmanager.Secret 
(software.amazon.awscdk.services.secretsmanager.ISecret$Jsii$Proxy and software.amazon.awscdk.services.secretsmanager.Secret are in unnamed module of loader 'app')

Attempting to add a role to the secret to read the role has no affect either (as per code). My assumption was that not should be necessary as I'm running as the account owner.

Attempting to use the Secret.fromSecretCompleteArn style:

secret = (Secret) Secret.fromSecretCompleteArn(this, "SecretsManagerStack", secretName);

also yields same result.

As CDK v2.0.0 seems pretty new I'm not finding any similar results in searches, so time to reach out. Any clues? Anybody seen this before in AWS CDK v2.0.0?


Solution

  • This is not possible, and it never was.

    A Secrets Manager secret can not be read as plain text in CDK. CDK can only pass references to the secret around, which would get resolved by CloudFormation during deployment.

    You can hack around this by using the SDK (and it seems that that's what you were doing before), but this is not a good practice. You shouldn't deal with plaintext secrets in your CDK code.

    To be clear, there's no difference in this regard between CDK v1 and v2.