Skip to content

(hotswap): The bootstrap roles don't contain necessary permissions for hotswapping #867

@ajhool

Description

@ajhool

Describe the bug

When we tried to add the --hotswap flag to our deployment command in CICD development environments, the deployment failed:

❌ Deployment failed: AccessDenied: User: arn:aws:sts::***:assumed-role/github-actions-oidc-deployment-role/cicd is not authorized to perform: cloudformation:DescribeStacks on resource: arn:aws:cloudformation:us-east-1:***:stack/***/2765aac0-eb87-11ed-8a91-0ad92641443b because no identity-based policy allows the cloudformation:DescribeStacks action

The hotswap developer comments that the standard CDK bootstrap roles don't contain permissions to update Lambda functions directly (and presumably all of the other necessary hotswappable resource types), so they use some other credentials for the SDK:

https://github.com/aws/aws-cdk/blob/a65cddf77379087e7cecf772ea75299459c13244/packages/aws-cdk/lib/api/hotswap-deployments.ts#L54

Expected Behavior

We should be able to add the hotswap flag while using the CDK deployed bootstrap roles:

cdk bootstrap
cdk deploy
# No action needed related to IAM, the following should just work
cdk deploy --hotswap

Current Behavior

cdk bootstrap

Using an IAM user with these permssions that just allow the IAM user to assume the CDK bootstrap roles:

    /**
     * DeploymentRole that is assumed by GithubAction using OIDC. This role enables
     * GitHub action to interact with AWS resources.
     */
    this.deploymentRole = new Role(this, `deployment-role`, {
      roleName: `github-actions-oidc-deployment-role`,
      assumedBy: new FederatedPrincipal(
        this.oidcProvider.openIdConnectProviderArn,
        oidcConditions,
        "sts:AssumeRoleWithWebIdentity",
      ),
    });

    /**
     * This policy is able to assume cross-account roles using the
     * roles created by the CDK Bootstrap command. The `cdk` commands will
     * choose the appropriate role for the `cdk` subcommand.
     */
    this.assumeCdkPolicy = new Policy(this, "policy", {
      statements: [
        new PolicyStatement({
          effect: Effect.ALLOW,
          actions: ["sts:AssumeRole"],
          resources: ["arn:aws:iam::*:role/cdk-*"],
        }),
      ],
      roles: [this.deploymentRole],
    });
cdk deploy // This works
cdk deploy --hotswap // This fails due to the stack error from before

Reproduction Steps

cdk bootsrap

// Initially any CDK app
cdk init app --language typescript

// Add a NodejsFunction to the CDK sample stack because that is hotswappable

// Create IAM user with the "AssumeRole" "arn:aws:iam::*:role/cdk-*" policy above
// Using the IAM user created above...

cdk deploy; // No problems

// Make a change to the lambda to trigger hotswapping

cdk deploy --hotswap

// Expect error related to DescribeStacks

Possible Solution

The bootstrap command should create a more permissive hotswap deployment role. An "enable-hotswap-role" or "disable-hotswap-role" flag could be used to toggle the creation of that role -- I'm not sure which is a more sensible default.

As a short-term alternative, documentation of the required permissions on the CLI role would be helpful.

CDK CLI Version

2.86.0

Maintainer notes

Similarly this is also confusing for cross-account deployments: #876

Needs to be considered if we are addressing this.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions