[aws-s3] Bucket.grantRead do nothing with an imported ec2.Instance
See original GitHub issueI expected that the code below would add a policy to the bucket or the EC2 instance.
const bucket = new s3.Bucket(this, 'Bucket', { ... });
bucket.grantRead(someImportedEC2Instance);
However, the policy was not added to either of them. Other grant methods also have the same issue.
Reproduction Steps
- Create an EC2 instance in one stack (call it Stack A)
- Pass the EC2 instance created in Stack A to another stack (Stack B)
- Create an S3 bucket in Stack B
- Call
bucket.grantRead
with the EC2 instance from Stack A.
What did you expect to happen?
A new policy is added to the EC2 instance’s role (i.e. principal) or to the bucket (i.e. resource).
What actually happened?
A new policy is not added to either of them and resource cannot be read from the EC2 instance.
Environment
- CLI Version : 1.58.0
- Framework Version: 1.58.0
- Node.js Version: 14.7.0
- OS : Ubuntu 18.04
- Language (Version): TypeScript (3.8.3)
Other
I investigated a bit why it happened and it turned out that iam.Role.addToPrincipalPolicy
associated with the EC2 instance always returns an object having statementAdded: true
regardless of whether it’s imported or not. Because of that, iam.Grant.addToPrincipalOrResource
, which internally calls addToPrincipalPolicy
, never tries to add a policy to a resource. At the same time, a policy that seemed to be added to the EC2 instance didn’t take effect. As a result, a newly created policy is not added to anywhere.
As a workaround, I’m adding a resource policy to the bucket with an explicit principal. So, this issue isn’t too critical, but it was quite confusing as it didn’t report any error or warning.
This is 🐛 Bug Report
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (3 by maintainers)
@nobu-k
Yeah, in general, if the code you write in
StackB
interacts with resources fromStackA
, it might create additional resources inStackA
, which meansStackA
needs to be redeployed.However, if
StackB
depends onStackA
, CDK will detect that and automatically redeployStackA
for you. The “problem” here is that actuallyStackB
doesn’t depend onStackA
since the policy is added to the instance principal rather than the resource. So in fact,StackA
actually depends onStackB
, which means that if you had just deployedStackA
again after implementingStackB
, it would have deployed both stacks.I would recommend to always deploy all stacks in the application (or at least with a pattern), CDK will deploy the stacks in the correct order, and skip stacks that haven’t changed.
You’ll have to explicitly add the relevant policy using
bucket.addToResourcePolicy
.I’m gonna go ahead and close this issue out, feel free to reach out if something still isn’t clear.
Thank you for pointing this out. I messed up the example during trial and errors I did. I originally passed the instance as
IGrantable
, but later I changed it toIPrincipal
and passedstackA.instance.grantPrincipal
to Stack B instead to see if it could make any difference. Then, I mixed up two versions into the example above.I prepared the repository at https://github.com/nobu-k/cdk-reproduction-9661 . What I’ve done is
These steps don’t add any permission to the instance in StackA. However, I noticed that, after deploying StackB, I had to deploy StackA again to make the
grantRead
in StackB to take effect. I think this was my misunderstanding, but I thought everything I wrote in a stack would only affect that stack. In other words, I didn’t think writing some code in StackB would required StackA to be deployed again.So, I now understand what I need to do with the issue I had, but I want to confirm if this is an intended behavior.
Also, what is the best way to do something equivalent to this without affecting StackA (i.e. to add resource-based policy to the bucket rather than adding a policy to IGrantable from other stacks)? Please feel free to redirect me to the AWS support if this isn’t the right place to ask this kind of questions.