aws-cdk: aws_secretsmanager: fromSecretNameV2 doesnt work

What is the problem?

Given this code:

my_secret = secretsmanager.Secret.from_secret_name_v2(
    self, "my_secret",
    secret_name="hello"
)
my_secret.grant_read(s3_event_handler)

the resulting iam policy has a bunch of question marks in it:

          - Action:
              - secretsmanager:GetSecretValue
              - secretsmanager:DescribeSecret
            Effect: Allow
            Resource:
              Fn::Join:
                - ""
                - - "arn:"
                  - Ref: AWS::Partition
                  - :secretsmanager:eu-west-1:123123123123:secret:hello-??????

which is invalid

Reproduction Steps

see above

What did you expect to happen?

valid iam policy

What actually happened?

invalid iam policy

CDK CLI Version

2.8.0 (build 8a5eb49)

Framework Version

2.8.0

Node.js Version

v14.18.3

OS

Ubuntu 20.04.3 LTS

Language

Python

Language Version

No response

Other information

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 30 (7 by maintainers)

Commits related to this issue

Most upvoted comments

This regression broke all of our new deployments - no change on our end, and existing deployments work fine (we’re using CDK to deploy into ECS Fargate). But anything new fails.

Similar issue here. The problem occurs when I want to add a secret to the environemnt via ContainerDefinitionOptions.

See: https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs.ContainerDefinitionOptions.html#secrets

The task fails to start and points to missing permission for the partial secret arn:

ResourceInitializationError: unable to pull secrets or registry auth: execution resource retrieval failed: unable to retrieve secret from asm: service call has been retried 1 time(s): failed to fetch secret $PARTIAL_ARN_HERE from secrets manager: AccessDeniedException: User: $USER is not authorized to perform: secretsmanager:GetSecretValue on resource: $PARTIAL_ARN_HERE because no identity-based policy allows the secretsmanager:GetSecretValue action status code: 400

The policy is in place and contains the correct resource arn. Because the message is pointing to the arn without suffix, I assume this might be related.

Please note according to this document, it is strongly not recommended to name your secret with a hyphen followed by 6 characters such as foo-abcdef.

image

Now let’s dive deep into this sample in CDK

    // create a new secret that comes with a hyphen(-)
    const mysecret = new secrets.Secret(this, 'Secret', {
      secretName: 'foo-abcdef',
      secretStringValue: SecretValue.unsafePlainText('BAR'),
    });
   
    // ISecret with partial ARN
    const importedSecretWithPartialArn = secrets.Secret.fromSecretNameV2(this, 'ImportedSecret', 'foo-abcdef');
    // ISecret with full ARN
    const importedSecretWithFullArn = secrets.Secret.fromSecretCompleteArn(this, 'ImportedSecretFullarn', mysecret.secretArn);

    new CfnOutput(this, 'importedSecretWithPartialArnValue', { value: importedSecretWithPartialArn.secretArn } );
    new CfnOutput(this, 'importedSecretWithFullArn', { value: importedSecretWithFullArn.secretArn } );

    const func = new lambda.Function(this, 'Func', {
      runtime: lambda.Runtime.PYTHON_3_9,
      code: lambda.Code.fromAsset(path.join(__dirname, '../lambda')),
      handler: 'index.handler',
      environment: {
        // this will pass full ARN to lambda so SDK can retrive the secret
        // SECRET_FULL_ARN: importedSecretWithFullArn.secretArn,
        // you should not pass partial ARN to lambda or you risk AccessDeniedException error when your secret name comes with a hyphen followed by 6 characters like foo-abcdef
        SECRET_FULL_ARN: importedSecretWithPartialArn.secretArn,
      },
    });

    // you can grant the secret read access to lambda either ways below
    importedSecretWithPartialArn.grantRead(func.role!);
    //importedSecretWithFullArn.grantRead(func.role!);    

And my lambda code in python

import boto3, os

def handler(event, context):
    client = boto3.client('secretsmanager')
    secretId = os.environ['SECRET_FULL_ARN']
    print(f'getting secret ARN={secretId}')
    response = client.get_secret_value(SecretId=secretId)
    try:
        secret_value = response.get('SecretString')
        print(f'secret value: {secret_value}')
    except:
        print("fail to get the secret")
    return

I am creating a secret named foo-abcdef with its dummy value BAR, which is not recommended in the doc above. Let’s see the partial and full ARNs:

IssueTriageStack.importedSecretWithFullArn = arn:aws:secretsmanager:us-east-1:<decucted>:secret:foo-abcdef-Rba0z7
IssueTriageStack.importedSecretWithPartialArnValue = arn:aws:secretsmanager:us-east-1:<deducted>:secret:foo-abcdef

As you can see, the partial ARN now ends with foo-abcdef which is NOT supposed to be used in CLI/SDK.

OK, if we pass this confusing ARN an env var to lambda and let the SDK get secret value in Lambda. You get AccessDeniedException error:

[ERROR] ClientError: An error occurred (AccessDeniedException) when calling the GetSecretValue operation: User: arn:aws:sts::<deducted>:assumed-role/IssueTriageStack-FuncServiceRole49680D06-N6ES193B5GVM/IssueTriageStack-Func217E03A4-jubYV78I9D9d is not authorized to perform: secretsmanager:GetSecretValue on resource: arn:aws:secretsmanager:us-east-1:<deducted>secret:foo-abcdef because no identity-based policy allows the secretsmanager:GetSecretValue action

The AccessDeniedException is not due to lambda role not having sufficient permission to the secret, but the SDK is getting incorrect secret.

Conslusion

  1. Avoid creating your secret names that end with a hyphen followed by 6 characters as the doc advises.
  2. Always pass the full ARN from fromSecretCompleteArn() method to other services or CLI/SDK whenever possible. You may pass partial ARN only when your secrets do not end with a hyphen and 6 characters. But it is a risk you definitely should avoid.
  3. You can grantRead() from a full ARN or partial ARN(in this case, -?????? will be appended)
  4. Do not grant your lambda role the access to all secrets with resources=["*"] for security reason.

If this function should not be used it would be best to deprecate and delete it.

This really shouldn’t be closed. I’m encountering the same error. Trying to import using fromSecretNameV2 result in an incomplete ARN.

I am currently facing the exact same issue. const secret = sm.Secret.fromSecretNameV2(this, “db-credentials”, secretName); resources: [secret.secretArn],

secretArn does not return fullArn. It is missing the last random suffix. Is this fixed or is there a better way to get the Arn?

Thanks Sanjay

I am also having this problem now for some reason. This used to work.

@mkesper We’ll bring it up to the core team maintainers for discussion and see what is the best for the customers.

Because the secrets always have the suffix, secret from name V2 does sufficient permissions but you must loopup the actual ARN in your function or whatever.

import { SecretsManagerClient, GetSecretValueCommandInput, GetSecretValueCommandOutput, GetSecretValueCommand, DescribeSecretCommand, DescribeSecretCommandInput, DescribeSecretCommandOutput } from "@aws-sdk/client-secrets-manager";

const description = await secretClient.send<DescribeSecretCommandInput, DescribeSecretCommandOutput>(new DescribeSecretCommand({
  SecretId: process.env.SECRET_NAME
}))
const result = await secretClient.send<GetSecretValueCommandInput, GetSecretValueCommandOutput>(new GetSecretValueCommand({
  SecretId: description.ARN
}));```

This should be reopened. Just encountered this on Decemeber, 2022. Workaround is using fromSecretCompleteArn()

I just discovered that importing a secret with from_secret_name_v2 does NOT check that the secret exists and allows both the synth operation and deployment, even though it is used for grant_read operations, etc.

My current use case is that I need to give a Lambda execution role the ability to get a secret value using the SDK. For me, both “secretArn” and “secretFullArn” does not return the full ARN with the secret-manager suffix from the “fromSecretNameV2” function. The full ARN with the suffix is needed in the execution role for the Lambda to access the secret value.

I’m not sure if this is what was inferred from the comments above, but my current workaround for this is to append the “???” wildcard onto the “secretArn” value that is returned from “fromSecretNameV2”, like so:

inlinePolicies: { accessStackSecrets: new iam.PolicyDocument({ statements: [new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [ "secretsmanager:GetSecretValue", ], resources: [${stackSecret.secretArn}-???] })], }) }

It seems a bit strange that “secretFullArn” is an option, but returns nothing despite the ARN containing the secret-manager suffix.