@aws-cdk/aws-redshift-alpha: If secret has KMS key there is a circular dependency with tables in different stacks
- 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
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