aws / aws/aws-cdk

(events): EventBusPolicy fails with circular reference if PolicyStatement is not already resolved to JSON

Open
#24,031 8 comments 1 reaction 0 assignees View on GitHub
@aws-cdk/aws-iam bug documentation 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 creating a `PolicyStatement` object that grants permissions to a principal, CDK throws an error with circular dependency on `grantPrincipal` method.

A PolicyStatement could be required when trying to give cross-account permissions in a `ResourcePolicy`.

### Expected Behavior

Policy is created successfully and principal is granted as specified.

### Current Behavior

Error throw when trying to synth any stack that contains the issue:

```shell
Error: Resolution error: Resolution error: Unable to resolve object tree with circular reference. Path: /Resources/${Token[EventbusPolicyTestStack.CFN.LogicalID.25]}/Properties/policyDocument/_principals/array/0/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal/grantPrincipal..
at resolve (/Users/neovasili/workspace/lab/eventbus-policy-test/node_modules/aws-cdk-lib/core/lib/private/resolve.js:1:1073)
at Object.resolve (/Users/neovasili/workspace/lab/eventbus-policy-test/node_modules/aws-cdk-lib/core/lib/private/resolve.js:1:892)
at resolve (/Users/neovasili/workspace/lab/eventbus-policy-test/node_modules/aws-cdk-lib/core/lib/private/resolve.js:1:2755)
at Object.resolve (/Users/neovasili/workspace/lab/eventbus-policy-test/node_modules/aws-cdk-lib/core/lib/private/resolve.js:1:892)
at resolve (/Users/neovasili/workspace/lab/eventbus-policy-test/node_modules/aws-cdk-lib/core/lib/private/resolve.js:1:2755)
at Object.resolve (/Users/neovasili/workspace/lab/eventbus-policy-test/node_modules/aws-cdk-lib/core/lib/private/resolve.js:1:892)
at resolve (/Users/neovasili/workspace/lab/eventbus-policy-test/node_modules/aws-cdk-lib/core/lib/private/resolve.js:1:2755)
at Object.resolve (/Users/neovasili/workspace/lab/eventbus-policy-test/node_modules/aws-cdk-lib/core/lib/private/resolve.js:1:892)
at resolve (/Users/neovasili/workspace/lab/eventbus-policy-test/node_modules/aws-cdk-lib/core/lib/private/resolve.js:1:2755)
at Object.resolve (/Users/neovasili/workspace/lab/eventbus-policy-test/node_modules/aws-cdk-lib/core/lib/private/resolve.js:1:892)
```

### Reproduction Steps

Here is a minimum Stack definition using `EventBusPolicy` that reproduces the issue when trying to do `cdk ls` or `cdk synth`:

```typescript
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import * as iam from "aws-cdk-lib/aws-iam";
import * as events from "aws-cdk-lib/aws-events";

export class EventbusPolicyTestStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

const defaultEventBus = events.EventBus.fromEventBusName(this, "Default", "default");

new events.EventBusPolicy(this, "MyPolicy", {
eventBus: defaultEventBus,
statementId: "MyStatement",
statement: new iam.PolicyStatement({
principals: [
new iam.AccountPrincipal("123456789010"),
],
actions: [
"events:PutEvents",
],
resources: [
defaultEventBus.eventBusArn,
],
}),
});
}
}
```

Another example:

```typescript
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import * as iam from "aws-cdk-lib/aws-iam";
import * as events from "aws-cdk-lib/aws-events";

export class EventbusPolicyTestStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

const defaultEventBus = events.EventBus.fromEventBusName(this, "Default", "default");
const policyFromJson = iam.PolicyStatement.fromJson({
Principal: {
AWS: "123456789010",
},
Action: [
"events:PutEvents",
],
Resource: [
defaultEventBus.eventBusArn,
],
});
new events.EventBusPolicy(this, "MyPolicy", {
eventBus: defaultEventBus,
statementId: "MyStatement",
statement: policyFromJson,
});
}
}
```

Another one for `BucketPolicy`:

```typescript
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as iam from "aws-cdk-lib/aws-iam";

export class EventbusPolicyTestStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

const policyFromJson = iam.PolicyStatement.fromJson({
Principal: {
AWS: "123456789010",
},
Action: [
"events:PutEvents",
],
Resource: [
defaultEventBus.eventBusArn,
],
});
const testBucket = new s3.Bucket(this, "MyTestBucket");
new s3.CfnBucketPolicy(this, "CFN", {
bucket: testBucket.bucketName,
policyDocument: policyFromJson,
});
}
}
```

### Possible Solution

_No response_

### Additional Information/Context

In the case of `EventBusPolicy` is possible to pass principal in a different way using L1 construct that does not cause the issue:

```typescript
new events.CfnEventBusPolicy(this, "MyPolicy", {
statementId: "MyStatement",
action: "events:PutEvents",
principal: "123456789010",
});
```

### CDK CLI Version

2.63.2 (build e08e34a)

### Framework Version

_No response_

### Node.js Version

v16.14.2

### OS

Mac Ventura/Monterrey

### Language

Typescript

### Language Version

any version >= 4.6.x

### Other information

_No response_

Contributor guide

Open the contributing guide

Research direction

Start by running the TypeScript reproduction with cdk ls or cdk synth, focusing on EventBusPolicy, PolicyStatement principals, and the circular grantPrincipal path in the error. Compare the object-based statement with PolicyStatement.fromJson and the L1 CfnEventBusPolicy example. Done means synthesis succeeds for the object-based policy and preserves the specified principal.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.