(events): EventBusPolicy fails with circular reference if PolicyStatement is not already resolved to JSON
#24,031 opened on Feb 6, 2023
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:
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:
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:
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:
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:
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