question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

S3 encryption cross-stack permission causes cyclic reference

See original GitHub issue

I’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:closed
  • Created 4 years ago
  • Reactions:6
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

8reactions
petermeansrockcommented, Jan 7, 2020

Unless I’m mistaken, it looks like Adam’s commit (#3694) covers this case. From the commit message:

Granting permissions to a key works if the principal belongs to a stack that is a dependent of the key stack

Thanks to this code snippet, as long as S3ConsumerStack declares a dependency on S3HostStack before IBucket.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 your S3ConsumerStack example class that should synthesize correctly:

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")
    });

    this.addDependency(cdk.Stack.of(props.bucket));
    props.bucket.grantRead(accessRole);
  }
}
0reactions
iliapolocommented, Aug 29, 2020

Seems like this was resolved in https://github.com/aws/aws-cdk/pull/3694

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to solve circular dependency between AWS resources ...
The S3 bucket depends on the KMS key for encryption, and the KMS key has a condition that ... Delete the circular reference...
Read more >
Setting default server-side encryption behavior for Amazon S3 ...
For more information about permissions required for default encryption, see PutBucketEncryption in the Amazon Simple Storage Service API Reference.
Read more >
Catalyst 3750 Switch Command Reference (full book in PDF ... - Cisco
Using the online TAC Service Request Tool is the fastest way to open S3 and S4 service requests ... Authorization, and Accounting >...
Read more >
@aws-cdk/app-delivery | Yarn - Package Manager
... for S3 destination encryption on DeliveryStream (#15558 (3888773), closes #15555 ... with cross-stack buckets cause cyclic references (#10696 (0ec4588), ...
Read more >
AWS Certified Developer Official Study Guide (Associate Exam ...
... to grant time-limited permission to download objects from an Amazon S3 bucket. ... Option D is incorrect because cross-stack references are not...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found