S3 encryption cross-stack permission causes cyclic reference
See original GitHub issueI’m submitting a …
- 🪲 bug report
- 🚀 feature request
- 📚 construct library gap
- 📕 documentation issue => If regarding developer guide, please create issue here
- ☎️ security issue or vulnerability => Please see policy
- ❓ support request => Please see note at the top of this template.
What is the current behavior?
When attempting to grant read/write access to an encrypted S3 bucket exported from a separate stack, I’m receiving a “cyclic reference” error.
Minimal sample code:
#!/usr/bin/env node
import "source-map-support/register";
import cdk = require("@aws-cdk/core");
import iam = require("@aws-cdk/aws-iam");
import s3 = require("@aws-cdk/aws-s3");
class S3HostStack extends cdk.Stack {
public readonly bucket: s3.Bucket;
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
this.bucket = new s3.Bucket(this, "EncryptedBucket", {
encryption: s3.BucketEncryption.KMS
});
}
}
interface S3ConsumerStackProps extends cdk.StackProps {
readonly bucket: s3.Bucket;
}
class S3ConsumerStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props: S3ConsumerStackProps) {
super(scope, id, props);
const accessRole = new iam.Role(this, "Access", {
assumedBy: new iam.ServicePrincipal("ecs-tasks.amazonaws.com")
});
props.bucket.grantRead(accessRole);
}
}
const app = new cdk.App();
const host = new S3HostStack(app, 'S3HostStack');
new S3ConsumerStack(app, 'S3ConsumerStack', {
bucket: host.bucket
});
Error output:
$ cdk synth
.../node_modules/@aws-cdk/core/lib/stack.ts:273
throw new Error(`'${stack.node.path}' depends on '${this.node.path}' (${dep.join(', ')}). Adding this dependency (${reason}) would create a cyclic reference.`);
^
Error: 'S3ConsumerStack' depends on 'S3HostStack' (S3ConsumerStack/Access/DefaultPolicy/Resource -> S3HostStack/EncryptedBucket/Resource.Arn). Adding this dependency (S3HostStack/EncryptedBucket/Key/Resource -> S3ConsumerStack/Access/Resource.Arn) would create a cyclic reference.
at S3HostStack.addDependency (.../node_modules/@aws-cdk/core/lib/stack.ts:273:15)
at CfnReference.consumeFromStack (.../node_modules/@aws-cdk/core/lib/private/cfn-reference.ts:131:22)
at S3HostStack.prepare (.../node_modules/@aws-cdk/core/lib/stack.ts:490:23)
at Function.prepare (.../node_modules/@aws-cdk/core/lib/construct.ts:84:28)
at Function.synth (.../node_modules/@aws-cdk/core/lib/construct.ts:41:10)
at App.synth (.../node_modules/@aws-cdk/core/lib/app.ts:128:36)
at process.App.process.once (.../node_modules/@aws-cdk/core/lib/app.ts:111:45)
at Object.onceWrapper (events.js:285:13)
at process.emit (events.js:197:13)
at process.EventEmitter.emit
What is the expected behavior (or behavior of feature suggested)?
Granting access to a bucket from a separate stack should not cause a cyclic reference. I believe what’s happening is that CDK is trying to modify the KMS key’s Resource Policy to reference the Role’s ARN. Is there any way to do that in the context of the consumer stack, or avoid that all together? In particular, I think this code is what’s causing the cyclic reference, so even if I supplied my own KMS key to the S3 bucket it would probably have a similar effect if I simply called grantEncryptDecrypt
from the consumer stack. Previously in CloudFormation I would simply export the KMS Key ARN and grant my IAM Role access without modifying the Key’s Resource Policy. Is there any way to get that behavior by default in CDK?
What is the motivation / use case for changing the behavior or adding this feature?
Environment
- CDK CLI Version: 1.4.0 (build 175471f)
- Module Version: 1.4.0
- OS: OSX High Sierra
- Language: TypeScript
Issue Analytics
- State:
- Created 4 years ago
- Reactions:6
- Comments:9 (5 by maintainers)
Unless I’m mistaken, it looks like Adam’s commit (#3694) covers this case. From the commit message:
Thanks to this code snippet, as long as
S3ConsumerStack
declares a dependency onS3HostStack
beforeIBucket.grantRead
is invoked, the KMS key’s policy will only reference the consumer stack’s account (rather than its role), avoiding the cyclic reference. Here’s an updated version of yourS3ConsumerStack
example class that should synthesize correctly:Seems like this was resolved in https://github.com/aws/aws-cdk/pull/3694