Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aws-iam: Updating CDK version removes SQS IAM policy #33577

Closed
1 task
jacobrasmuson opened this issue Feb 25, 2025 · 7 comments
Closed
1 task

aws-iam: Updating CDK version removes SQS IAM policy #33577

jacobrasmuson opened this issue Feb 25, 2025 · 7 comments
Labels
@aws-cdk/aws-iam Related to AWS Identity and Access Management bug This issue is a bug. effort/medium Medium work item – several days of effort p3 response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.

Comments

@jacobrasmuson
Copy link

jacobrasmuson commented Feb 25, 2025

Describe the bug

When updating CDK from 2.141.0 to a version beyond 2.142.1 it removes the IAM policy of a user setup to read the SQS queue from a user created outside of the CDK project connected using fromUserName or fromUserArn.

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Version

2.141.0

Expected Behavior

When running with CDK version 2.141.0 it behaves as expected for changes:

cdk diff TestFromUserArnStack
Stack TestFromUserArnStack
Hold on while we create a read-only change set to get a diff with accurate replacement information (use --no-change-set to use a less accurate but faster template-only diff)
Resources
[~] AWS::SQS::Queue TestQueue TestQueue6F0069AA 
 └─ [-] VisibilityTimeout
     └─ 300

Outputs
[+] Output MyStackAccount MyStackAccount: {"Description":"Account of this stack","Value":"XXX"}


✨  Number of stacks with differences: 1

Current Behavior

When using a version of the CDK beyond 2.142.1 it takes away the permissions that were expected.

cdk diff TestFromUserArnStack
Stack TestFromUserArnStack
Hold on while we create a read-only change set to get a diff with accurate replacement information (use --no-change-set to use a less accurate but faster template-only diff)
IAM Statement Changes
┌───┬──────────────────┬────────┬─────────────────────────────────────────────────────┬─────────────────────────────────────────────────────┬───────────┐
│   │ Resource         │ Effect │ Action                                              │ Principal                                           │ Condition │
├───┼──────────────────┼────────┼─────────────────────────────────────────────────────┼─────────────────────────────────────────────────────┼───────────┤
│ - │ ${TestQueue.Arn} │ Allow  │ sqs:ChangeMessageVisibility                         │ AWS:arn:aws:iam::XXX:user/SandboxCaminoRea │           │
│   │                  │        │ sqs:DeleteMessage                                   │ dWrite                                              │           │
│   │                  │        │ sqs:GetQueueAttributes                              │                                                     │           │
│   │                  │        │ sqs:GetQueueUrl                                     │                                                     │           │
│   │                  │        │ sqs:ReceiveMessage                                  │                                                     │           │
└───┴──────────────────┴────────┴─────────────────────────────────────────────────────┴─────────────────────────────────────────────────────┴───────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Resources
[-] AWS::SQS::QueuePolicy TestQueue/Policy TestQueuePolicyA65327BC destroy
[~] AWS::SQS::Queue TestQueue TestQueue6F0069AA 
 └─ [-] VisibilityTimeout
     └─ 300

Outputs
[+] Output MyStackAccount MyStackAccount: {"Description":"Account of this stack","Value":"XXX"}


✨  Number of stacks with differences: 1

Reproduction Steps

Can recreate with a basic example

const app = new cdk.App();
new TestFromUserArnStack(app, 'TestFromUserArnStack', {
    env: {
        account: 'XXX',
        region: 'us-east-2'
    },
});

and

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

    const sqsQueue = new sqs.Queue(this, 'TestQueue', {
      // visibilityTimeout: Duration.seconds(300),
    })

    const user = iam.User.fromUserName(this,'user','SandboxCaminoReadWrite')
    sqsQueue.grantConsumeMessages(user)

    new cdk.CfnOutput(this, "MyStackAccount", {
      description: "Account of this stack",
      value: this.account
    });
  }
}

With package.json changing aws-cdk and aws-cdk-lib from 2.141.0 to 2.142.1

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.142.1 (build ed4e152)

Framework Version

No response

Node.js Version

v18.19.0

OS

Mac 15.3.1

Language

TypeScript

Language Version

Typescript 5.6.3

Other information

No response

@jacobrasmuson jacobrasmuson added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Feb 25, 2025
@github-actions github-actions bot added @aws-cdk/aws-iam Related to AWS Identity and Access Management potential-regression Marking this issue as a potential regression to be checked by team member labels Feb 25, 2025
@pahud pahud self-assigned this Feb 25, 2025
@pahud
Copy link
Contributor

pahud commented Feb 25, 2025

Looking into it.

@pahud
Copy link
Contributor

pahud commented Feb 25, 2025

Hi @jacobrasmuson

    const user = iam.User.fromUserName(this,'user','SandboxCaminoReadWrite')

Is the IAM User from the same account of the stack?

@pahud
Copy link
Contributor

pahud commented Feb 25, 2025

This is related to #30023 by changing how the principalAccount property is set in the User.fromUserAttributes method:

Before

public readonly principalAccount = Aws.ACCOUNT_ID;

After

public readonly principalAccount = Stack.of(scope).splitArn(attrs.userArn, ArnFormat.SLASH_RESOURCE_NAME).account;

This change ensures that the principalAccount property is correctly set to the account ID extracted from the user's ARN, rather than always using the stack's account ID. This allows the CDK to correctly determine whether the user is in the same account as the stack or not, and create the appropriate policies.

The fix was implemented in CDK version 2.142.1, but it seems there might be a regression in how it's applied to SQS permissions specifically. Users experiencing this issue should update to the latest CDK version, and if the issue persists, they may need to explicitly specify the account ID when importing the user.

This issue highlights the importance of correctly handling cross-account permissions in CDK constructs, especially when using imported resources from other accounts.

What's happening:

  1. In CDK 2.141.0 (before the fix):
  • When you used User.fromUserArn(), the principalAccount was incorrectly set to the stack's account ID (Aws.ACCOUNT_ID)
  • The CDK thought the user was in the same account as the stack
  • It created both:
    • An identity policy for the user (which would fail during deployment)
    • A resource policy for the SQS queue (the AWS::SQS::QueuePolicy)
  1. In CDK 2.142.1 (after the fix):
  • The principalAccount is now correctly set to the account ID from the user's ARN
  • The CDK correctly identifies that the user is in a different account
  • But instead of just skipping the identity policy creation, it's also removing the resource policy for the SQS queue

The root cause:

The issue appears to be in the Grant class implementation, specifically in the addToPrincipalOrResource() method. When determining whether to add permissions to the principal (identity policy) or the resource (resource policy), the CDK is making an incorrect decision for cross-account users.

In the Grant class, when it detects that the principal is from a different account, it should:

  1. Skip adding permissions to the principal (since you can't modify a principal in another account)
  2. Add permissions to the resource via a resource policy

However, it seems that after the fix to correctly identify cross-account principals, the logic for adding permissions to the resource is not working correctly for SQS queues, resulting in the removal of the queue policy.

This is why you're seeing:

[-] AWS::SQS::QueuePolicy TestQueue/Policy TestQueuePolicyA65327BC destroy

To properly fix this, the CDK would need to ensure that when a principal is identified as being from a different account:

  1. It correctly skips creating an identity policy
  2. It still creates the appropriate resource policy for the SQS queue

This appears to be a regression that was introduced when fixing the principalAccount property, and would require another fix to ensure that cross-account permissions are handled correctly for SQS queues.

@pahud pahud added p0 and removed needs-triage This issue or PR still needs to be triaged. labels Feb 25, 2025
@pahud pahud removed their assignment Feb 25, 2025
@pahud pahud added the effort/medium Medium work item – several days of effort label Feb 25, 2025
@jacobrasmuson
Copy link
Author

It's not using cross-account for deployment. The user I'm using is in the same account as the SQS queue.

I checked again with command line aws sts get-caller-identity --query Account --output text comparing with the CfnOutput, this.account and they do match.

@pahud
Copy link
Contributor

pahud commented Feb 25, 2025

OK after further investigation. I think this is an expected behavior.

In 2.141.0 before #30023

public readonly principalAccount = Aws.ACCOUNT_ID;

This won't be available in cdk synth time as this is pseudo parameter reference, which will only be resolved in cloudformation deployment time.

Starting 2.142.0

public readonly principalAccount = Stack.of(scope).splitArn(attrs.userArn, ArnFormat.SLASH_RESOURCE_NAME).account;

This ensures the principalAccount can be correct resolved in cdk synth time.

Now, when grantConsumeMessages() is executed, it's essentially running addToPrincipalOrResource() which will first add to your principal policy on your IAM user and then conditionally add the resource policy from here

if (result.success && sameAccount) {
return result;
}

Now, given the principal policy is successfully added and the iam.User and sqs.Queue are actually from the "same account", it won't add resource policy anymore as only principal policy is required.

This explains why you are seeing the removal of resource-based policy starting 2.142.0.

So this is expected. Not a regression. You should still have required permissions to access this queue with the iam.User.

Let me know if you still have any issue.

@pahud pahud added p3 response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. and removed p0 potential-regression Marking this issue as a potential regression to be checked by team member labels Feb 25, 2025
@jacobrasmuson
Copy link
Author

Thanks I do see the user policy now.

I'm fine closing this ticket. Thanks!

Copy link

Comments on closed issues and PRs are hard for our team to see.
If you need help, please open a new issue that references this one.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 26, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
@aws-cdk/aws-iam Related to AWS Identity and Access Management bug This issue is a bug. effort/medium Medium work item – several days of effort p3 response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days.
Projects
None yet
Development

No branches or pull requests

2 participants