aws / aws/aws-cdk

aws-secretsmanager: grantRead should add Decrypt Policy for kms key

Open
#20,087 5 comments 4 reactions 0 assignees View on GitHub
@aws-cdk/aws-secretsmanager bug effort/small good first issue p2
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
2d 3h
Merged PRs (30d)
83

Description

### Describe the bug

When I use `fromSecretAttributes` and add a encryptionKey, cdk should automatically add a decrypt policy to the roles default policy when I grant a read access to a role. This is working for example on dynamodb Tables.

```TS
export interface TestStack2Props extends StackProps {
secretArn: string,
secretKeyArn: string,
}

export class TestStack2 extends Stack {
public constructor(scope: Construct, id: string, props: TestStack2Props) {
super(scope,id,props);

const key = Key.fromKeyArn(this, 'key', props.secretKeyArn);

const secret = Secret.fromSecretAttributes(this,'secret',{
secretCompleteArn: props.secretArn,
encryptionKey: key
})

const role = new Role(this,'role',{
assumedBy: new AccountPrincipal('111122223333')
})
secret.grantRead(role);
key.grantDecrypt(role); // <-- should not be necessary
}
}
```
This solution with dynamo db is working well:
```TS
export interface TestStack2Props extends StackProps {
tableName: string,
tableKeyArn: string,
}

export class TestStack2 extends Stack {
public constructor(scope: Construct, id: string, props: TestStack2Props) {
super(scope, id, props);

const key = Key.fromKeyArn(this, 'key', props.tableKeyArn);

const table = Table.fromTableAttributes(this, 'table', {
encryptionKey: key,
tableName: props.tableName
})

const role = new Role(this, 'role', {
assumedBy: new AccountPrincipal('111122223333')
})
table.grantReadData(role);
// key.grantDecrypt(role); // <-- is not necessary
}
}
```

### Expected Behavior

This policy statement should exist in the template
```JSON
{
"Action": "kms:Decrypt",
"Effect": "Allow",
"Resource": {
"Fn::ImportValue": "stack1:ExportsOutputFnGetAttkeyFEDD6EC0Arn6AD68239"
}
}
```

Or other statements depending on the grant action.

### Current Behavior

it does not add a policy statement to allow decryption of the secret using the given kms encryptionKey.

### Reproduction Steps

```TS
import {App, Stack, StackProps} from "aws-cdk-lib";
import {Construct} from "constructs";
import {Secret} from "aws-cdk-lib/aws-secretsmanager";
import {AccountPrincipal, Role} from "aws-cdk-lib/aws-iam";
import {Key} from "aws-cdk-lib/aws-kms";

export class TestStack1 extends Stack {
public secretArn: string;
public secretKeyArn: string;

public constructor(scope?: Construct, id?: string, props?: StackProps) {
super(scope, id, props);

const key = new Key(this, 'key')
this.secretKeyArn = key.keyArn;
const secret = new Secret(this, 'secret', {
encryptionKey: key,
})
this.secretArn = secret.secretArn
}
}

export interface TestStack2Props extends StackProps {
secretArn: string,
secretKeyArn: string,
}

export class TestStack2 extends Stack {
public constructor(scope: Construct, id: string, props: TestStack2Props) {
super(scope, id, props);

const key = Key.fromKeyArn(this, 'key', props.secretKeyArn);

const secret = Secret.fromSecretAttributes(this, 'secret', {
secretCompleteArn: props.secretArn,
encryptionKey: key
})

const role = new Role(this, 'role', {
assumedBy: new AccountPrincipal('111122223333')
})
secret.grantRead(role);
// key.grantDecrypt(role); // <-- should not be necessary
}
}

const app = new App({
outdir: 'cdk.test.out'
})
const stack1 = new TestStack1(app, 'stack1');
new TestStack2(app, 'stack2', {
secretArn: stack1.secretArn,
secretKeyArn: stack1.secretKeyArn,
})

app.synth();

```

### Possible Solution

_No response_

### Additional Information/Context

_No response_

### CDK CLI Version

2.21.1 (build a6ee543)

### Framework Version

_No response_

### Node.js Version

v14.17.6

### OS

Linux Ubuntu 21.10

### Language

Typescript

### Language Version

TypeScript (4.6.3)

### Other information

_No response_

Contributor guide

Open the contributing guide

Research direction

Start by locating the aws-secretsmanager implementation of fromSecretAttributes and grantRead, then compare its behavior with the DynamoDB encryptionKey grant path. Run the provided two-stack TypeScript reproduction and inspect the synthesized template; done means the imported secret's encryption key permissions appear for the granted role without an explicit key.grantDecrypt(role).

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, typescript
Domain
cloud, infrastructure, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.