Open icelava opened 5 days ago
investigating
Yes I noticed the changes between 2.141.0 and 2.142.0 and this could due to this fix https://github.com/aws/aws-cdk/pull/30023
Given the code below:
const principal = iam.User.fromUserArn(this, 'User', `arn:aws:iam::${Stack.of(this).account}:user/foo`);
new kms.Key(this, 'DummyKey', {
admins: [principal]
})
In 2.141.0, this would create both IAM Policy for the User as well as the KMS key policy
Key Policy added:
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT_ID:user/foo"
},
"Action": [
"kms:CancelKeyDeletion",
"kms:Create*",
"kms:Delete*",
"kms:Describe*",
"kms:Disable*",
"kms:Enable*",
"kms:Get*",
"kms:List*",
"kms:Put*",
"kms:Revoke*",
"kms:ScheduleKeyDeletion",
"kms:TagResource",
"kms:UntagResource",
"kms:Update*"
],
"Resource": "*"
}
In 2.142.0, this would ONLY add the IAM policy to the User. No additional key policy would be added.
Please note this is consist with the behavior of IAM Role with KMS Key. For example if I import an IAM role like this and deploy in 2.141.0
const principal = iam.Role.fromRoleArn(this, 'Role', `arn:aws:iam::${Stack.of(this).account}:role/foo`);
new kms.Key(this, 'DummyKey', {
admins: [principal]
})
You will notice no key policy would be added. Only IAM policy for the role would be added. If you upgrade from 2.141.0 to 2.142.0 or even the latest 2.159.1 and run cdk diff
. There would be no differences.
So I am pretty sure this is a consistent behavior with what is happening for the kms key with an IAM role.
I will continue investigate and update here.
Hi @icelava
var admins = this._platConfig.UploadsBucket.Admins.Select(u => User.FromUserArn(this, u, u));
Can you let me know, if the UserArn is from the same account of the deploying stack or different account?
OK I think I found the root cause.
Because of this bug in 2.141.0, which was fixed in https://github.com/aws/aws-cdk/pull/30023, when we import User from same account like
const userPrincipal = iam.User.fromUserArn(this, 'User', `arn:aws:iam::123456789012:user/foo`);
CDK would always use Aws.AccountId
to represent the grantee principal account and will always run this code logic
If we check addToPrincipalOrResource(), it first addToPrincipal(), which will succeed but sameAccount
would be false here:
So it moves on to create resource policy here:
This explains why in 2.141.0 it would create both principal policy as well as resource policy.
In 2.142.0, because of the fix, sameAccount
would be true so it won't move on to create the resource policy. This explains why it would be removed when upgrading from 2.141.0 to 2.142.0
Can you let me know, if the UserArn is from the same account of the deploying stack or different account?
Yes the admin user is from the same AWS account.
So the key policy is redundant since the IAM user personal policy permits it?
UPDATE
I checked said user and it does not have any policy statement to access said key. Neither did cdk diff attempt to add new policy for the user.
UPDATE
Think I know what's happening. When the KMS key adds admins, the resultant CloudFormation template assigns the seemingly random name arnawsiamACCOUNTIDuserUSERNAMEPolicyBAA0AB37
for the inline policy to said user.
Thing is, when we have multiple application stacks using the same code patterns to assign admins to keys, the same user gets the same policy name and gets overwritten over and over. While the original stack doesn't know anything has happened to the inline policy, it has in fact "drifted" to match the policy of the last deploy stack. That's why the original key ARN that was to be permitted for has gone missing.
How the random identifier suffix is generated is problematic.
UPDATE
To break this cycle of repitition, looks like a more unique name for the CDK construct has to be fashioned.
var admins = this._platConfig.UploadsBucket.Admins.Select(u => User.FromUserArn(this, $"{_platConfig.ProductName}-appuploads-key-{u}-{_platConfig.Environment}", u));
When admins
is defined, the Key construct essentially runs grantAdmin() on the principals which runs grant() on them with admin permissions. The whole implementation is here.
Basically, when CDK grants resource access permission to an IAM principal, if they both belong to the same account with the deploying stack, which I believe is your case, CDK would run addToPrincipalOrResource() which will first add an IAM Policy for that identity principal and won't add resource-based policy if the previous add is successful. That explains why you'd see identity-based policy only but no resource-based policy.
And you are right, if you have multiple Keys granting to the same principal, you would end up with multiple AWS::IAM::Policy
resources being associated with a single IAM principal and that might not be something you expect. In this case, I won't recommend using admins
prop, instead, you probably want to create a single iam.Policy for that IAM principal and attach all necessary statements to that policy. You have full control about all the required policy for that.
That will be difficult. Each application stack is not aware of each other and being self-contained assigns permissions to their respective administrators/developers. Anyway making the IUser construct ID unique across all stacks lets them maintain their own inine policies.
(Although the 2048 character limit on all inline policies is very restrictive.)
Describe the bug
Previously with CDK 2.133, we were able to define additional IAM user ARNs for reference and adding them to a Key Admins array. They ended up in the key policy as expected.
Now with 2.159.1 (build c66f4e3) it appears to ignore the array thus removing the previously defined users in the key policy. Even though the admins IEnumerable has IUser objects.
Regression Issue
Last Known Working CDK Version
1.133
Expected Behavior
The referenced IUsers added to Key.Admins array end up in key policy.
Current Behavior
Referenced IUsers removed from key policy.
Reproduction Steps
Possible Solution
No response
Additional Information/Context
No response
CDK CLI Version
2.159.1 (build c66f4e3)
Framework Version
No response
Node.js Version
v22.3.0
OS
Windows 11 23H2
Language
.NET
Language Version
C# 10
Other information
No response