aws / aws/aws-cdk

@aws-cdk/aws-redshift-alpha: If secret has KMS key there is a circular dependency with tables in different stacks

Open
#22,515 2 comments 0 reactions 0 assignees View on GitHub
@aws-cdk/aws-redshift bug effort/small p2
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
1d 19h
Merged PRs (30d)
74

Description

### Describe the bug

On `bin/wh14.ts`:

```
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { RsStack } from '../lib/rs-stack';
import {TablesStack} from "../lib/tables-stack";
import VpcStack from "../lib/vpc-stack";

const app = new cdk.App();
const vpcStack = new VpcStack(app, 'VpcStack')
const rsStack = new RsStack(app, 'RSStack', vpcStack.vpc);
new TablesStack(app, 'TablesStack', rsStack.cluster);
```

On `lib/vpc-stack.ts`:

```
import {Stack, StackProps} from 'aws-cdk-lib';
import {Construct} from 'constructs';
import {Vpc} from 'aws-cdk-lib/aws-ec2';

export default class VpcStack extends Stack {
vpc: Vpc;

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

this.vpc = new Vpc(this, 'vpc', {
cidr: '10.0.0.0/16',
});
}
}
```

On `lib/rs-stack.ts`:

```
import {Stack, StackProps} from 'aws-cdk-lib';
import {Construct} from 'constructs';
import {Vpc} from 'aws-cdk-lib/aws-ec2';
import {Cluster} from "@aws-cdk/aws-redshift-alpha";
import {Key} from "aws-cdk-lib/aws-kms";

export class RsStack extends Stack {
public readonly cluster: Cluster;

constructor(scope: Construct, id: string, vpc: Vpc, props?: StackProps) {

super(scope, id, props);

const secretKmsKey = new Key(this, 'SecretKMSKey', {
enableKeyRotation: true,
})

const rsKmsKey = new Key(this, 'RSKMSKey', {
enableKeyRotation: true,
})

this.cluster = new Cluster(this, 'Cluster', {
masterUser: {
masterUsername: 'admin',
encryptionKey: secretKmsKey,
},
vpc,
encryptionKey: rsKmsKey,
});
}
}
```

On `lib/tables-stack.ts`:

```
import {Stack, StackProps} from 'aws-cdk-lib';
import {Construct} from 'constructs';
import {Cluster, Table, TableDistStyle} from "@aws-cdk/aws-redshift-alpha";

export class TablesStack extends Stack {

constructor(scope: Construct, id: string, cluster: Cluster, props?: StackProps) {

super(scope, id, props);

new Table(this, 'Table', {
tableColumns: [
{name: 'col1', dataType: 'varchar(4)', distKey: true},
{name: 'col2', dataType: 'float'},
],
cluster: cluster,
databaseName: 'databaseName',
distStyle: TableDistStyle.KEY,
});
}
}
```

Then I run:

```
npm run build && cdk synth
```

And I get:

```
Error: 'RSStack' depends on 'TablesStack' (RSStack -> TablesStack/Query Redshift
Database3de5bea727da479686625efb56431b5f/ServiceRole/Resource.Arn). Adding this
dependency (TablesStack -> RSStack/Cluster/Resource.Ref) would create a cyclic
reference.
at TablesStack._addAssemblyDependency (C:\Users\rodri\Documents\wh14\node_mo
dules\aws-cdk-lib\core\lib\stack.js:1:8027)
at Object.addDependency (C:\Users\rodri\Documents\wh14\node_modules\aws-cdk-
lib\core\lib\deps.js:1:926)
at TablesStack.addDependency (C:\Users\rodri\Documents\wh14\node_modules\aws
-cdk-lib\core\lib\stack.js:1:5351)
at resolveValue (C:\Users\rodri\Documents\wh14\node_modules\aws-cdk-lib\core
\lib\private\refs.js:1:1683)
at Object.resolveReferences (C:\Users\rodri\Documents\wh14\node_modules\aws-
cdk-lib\core\lib\private\refs.js:1:627)
at Object.prepareApp (C:\Users\rodri\Documents\wh14\node_modules\aws-cdk-lib
\core\lib\private\prepare-app.js:1:564)
at Object.synthesize (C:\Users\rodri\Documents\wh14\node_modules\aws-cdk-lib
\core\lib\private\synthesis.js:1:557)
at App.synth (C:\Users\rodri\Documents\wh14\node_modules\aws-cdk-lib\core\li
b\stage.js:1:1883)
at process. (C:\Users\rodri\Documents\wh14\node_modules\aws-cdk-l
ib\core\lib\app.js:1:1208)
at Object.onceWrapper (events.js:482:26)

Subprocess exited with error 1

C:\Users\rodri\Documents\wh14>
```

However, if in `lib/rs-stack.ts` I comment out this line:

```
encryptionKey: secretKmsKey,
```

It works. Also, if the tables were on the same stack, this problem does not happen, but having the tables on the same stack is restrictive because a single table creates more than one resource and the 500 Cloudformation limit is reached easily and real data warehouses have a lot of tables.

### Expected Behavior

Not encrypting secrets is a bad security practice. Also, having tables in the same stack is restrictive in DW sizes. We should be able to encrypt the secret and be able to have the tables ins separate stacks.

### Current Behavior

If the secret is encrypted, the build fails with a circular dependency.

### Reproduction Steps

See issue description.

### Possible Solution

not sure :(

### Additional Information/Context

_No response_

### CDK CLI Version

2.46.0 (build 5a0595e)

### Framework Version

_No response_

### Node.js Version

v14.17.3

### OS

Windows

### Language

Typescript

### Language Version

"typescript": "~3.9.7"

### Other information

_No response_

Contributor guide

Open the contributing guide

Research direction

Reproduce the failure with bin/wh14.ts, lib/vpc-stack.ts, lib/rs-stack.ts, and lib/tables-stack.ts using npm run build && cdk synth. Start by tracing how the Cluster's encrypted secret and Table references create cross-stack dependencies. Done means the example synthesizes successfully with secretKmsKey enabled while keeping the tables in a separate stack.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.