Open cheruvian opened 4 months ago
I should also mention (let me know if this should be a separate issue) using the instance.availabilityZone
results in another circular dependency since the availabilityZone
uses a CF attribute.
Change above to repro:
const volume = new ec2.Volume(this, `volume`, {
size: Size.gibibytes(8),
availabilityZone: ec2Instance.instanceAvailabilityZone
});
❌ Deployment failed: Error [ValidationError]: Circular dependency between resources: [InstanceInstanceRoleDefaultPolicy4ACE9290, InstanceC1063A87, volume438BCE83]
This is a little bit less obvious of a solution, but AWS should consider setting this to the resolved AZ (and other props) rather than the instance attribute:
https://github.com/aws/aws-cdk/blob/v2.130.0/packages/aws-cdk-lib/aws-ec2/lib/instance.ts#L479
// current
this.instanceAvailabilityZone = this.instance.attrAvailabilityZone;
/// tentative proposal
this.instanceAvailabilityZone = subnet.availabilityZone; // comes from props or first subnet in vpc and what is used for the underlying CfnInstance constructor
The underlying attribute would still be accessible from this.instance.attrAvailabilityZone
but would not cause any circular dependencies. Unclear if this would be considered a breaking change or not.
Looks like we have to break this circular dependency but I have so solution off the top of my head:
instance -> role -> policy -> instance
According to the document, we probably should not specify the instance ID but the condition instead.
Being said, I guess you will need to create the policy like this and optionally apply your own condition like this:
ec2Instance.addToRolePolicy(new iam.PolicyStatement({
actions: ['ec2:AttachVolume'],
resources: [
`arn:${stack.partition}:ec2:${stack.region}:${stack.account}:volume/${volume.volumeId}`,
],
}));
ec2Instance.addToRolePolicy(new iam.PolicyStatement({
actions: ['ec2:AttachVolume'],
resources: [
`arn:${stack.partition}:ec2:${stack.region}:${stack.account}:instance/*`,
],
conditions: {
"StringEquals": {"aws:ResourceTag/Department": "Development"}
},
}));
Sorry I might be missing something but I think creating a separate policy would break the dependency loop
-> instance -> role
/ /
policy ----------------------
The role doesn't actually need to depend on the policy it just happens in the way this is implemented (default inline policy on role) if we create a separate Policy
then it can reference both the role and the instance
This is to make it super obvious but the instanceRole can also get create in the instance code and referenced as a property since it's not actually a CF Attr of the underlying CF resource
const role = new iam.Role(this, 'aws-storage-performance-role', {
assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
});
const ec2Instance = new ec2.Instance(
this,
'CDKRepro',
{
vpc,
role,
securityGroup,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
machineImage: new ec2.AmazonLinuxImage({
generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
}),
}
);
new Policy(this, 'policy', {
statements: [
new iam.PolicyStatement({
actions: ['thing:*'],
resources: [`PREFIX/${ec2Instance.instanceId}`],
}),
],
roles: [role],
})
Describe the bug
When creating an ec2 instance and then granting attach volume, it results in a circular dependency because it tries to add to the role's default policy which the instance depends on, and then the grant depends on the instance to include the instance id in the policy.
Expected Behavior
It should not result in a circular dependency
Current Behavior