Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Infrastructure as Code By James Joyner IV · · 9 min read

AWS CDK Error: 'is not authorized to perform: cloudformation:CreateChangeSet' — Cause, Fix, and Troubleshooting Guide

Quick answer

Fix the CDK deploy error 'is not authorized to perform: cloudformation:CreateChangeSet' by fixing deploy-role trust, IAM policies, and bootstrap permissions.

  • #iac
  • #infrastructure-as-code
  • #cdk
  • #troubleshooting
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

This error appears during cdk deploy when the identity CDK is using does not have permission to call cloudformation:CreateChangeSet. Modern CDK does not apply templates directly with UpdateStack; it creates a change set, waits for it, then executes it. If the caller (or the bootstrap deploy role it assumes) lacks CreateChangeSet, the deploy fails before any resource is touched.

You will see this during cdk deploy:

❌  MyAppStack failed: User: arn:aws:iam::123456789012:user/deployer is not authorized to perform:
cloudformation:CreateChangeSet on resource:
arn:aws:cloudformation:us-east-1:123456789012:stack/MyAppStack/* because no identity-based policy
allows the cloudformation:CreateChangeSet action
(Service: AmazonCloudFormation; Status Code: 403; Error Code: AccessDenied)

The tricky part with modern CDK bootstrap (hnb659fds qualifier) is that the user running cdk deploy usually only needs permission to sts:AssumeRole the four bootstrap roles. The heavy CloudFormation permissions live on cdk-hnb659fds-deploy-role-*. So this error can mean either “your user policy is missing the action” or “you never assumed the deploy role and CDK fell back to your raw user credentials.”

Symptoms

  • cdk deploy fails immediately with AccessDenied and cloudformation:CreateChangeSet.
  • The ARN in the message is a user/ or assumed-role/ that is NOT the cdk-hnb659fds-deploy-role.
  • cdk diff works (read-only) but cdk deploy fails.
  • CI pipelines fail here after switching accounts, roles, or rotating credentials.
cdk deploy MyAppStack
Do you wish to deploy these changes (y/n)? y
MyAppStack: creating CloudFormation changeset...
❌  MyAppStack failed: User: arn:aws:iam::123456789012:user/deployer is not authorized to perform:
cloudformation:CreateChangeSet

Common Root Causes

1. CDK is using raw user credentials instead of the bootstrap deploy role

If credential assumption fails silently, CDK proceeds with your caller identity, which typically lacks broad CloudFormation rights. Notice the ARN is a plain user, not a cdk-hnb659fds-deploy-role.

current credentials could not be used to assume
'arn:aws:iam::123456789012:role/cdk-hnb659fds-deploy-role-123456789012-us-east-1',
but are for the right account. Proceeding anyway.

2. The IAM user/role policy simply omits the action

A least-privilege policy that lists CreateStack/UpdateStack but forgets CreateChangeSet, ExecuteChangeSet, and DescribeChangeSet.

Missing: cloudformation:CreateChangeSet, ExecuteChangeSet, DeleteChangeSet, DescribeChangeSet

3. A permissions boundary or SCP denies the action

An explicit Deny in an Organizations SCP or a permissions boundary overrides any Allow, so even an admin-looking policy fails.

aws organizations describe-policy --policy-id p-examplepolicy

4. Resource-scoped policy that does not match the stack ARN

A policy scoped to stack/prod-* will deny a stack named MyAppStack. The Resource ARN pattern must cover the stack, including the /* suffix change sets use.

5. Wrong account/role in the active profile

The credentials in scope belong to a sandbox account while the stack targets production, so the identity genuinely has no rights there.

aws sts get-caller-identity

How to Diagnose

Confirm who CDK actually is

aws sts get-caller-identity

Compare the returned ARN to the ARN in the error. If they match your human/CI user rather than cdk-hnb659fds-deploy-role, role assumption is the problem, not the policy.

Check whether the deploy role exists and is assumable

aws iam get-role --role-name cdk-hnb659fds-deploy-role-123456789012-us-east-1
aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/cdk-hnb659fds-deploy-role-123456789012-us-east-1 \
  --role-session-name diag

Simulate the exact action

aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:user/deployer \
  --action-names cloudformation:CreateChangeSet \
  --resource-arns "arn:aws:cloudformation:us-east-1:123456789012:stack/MyAppStack/*"

Look for EvalDecision: allowed vs explicitDeny (SCP/boundary) vs implicitDeny (missing grant).

Run deploy with verbose credential logging

cdk deploy MyAppStack --verbose

Search the output for could not be used to assume — that line is the smoking gun for silent fallback.

Fixes

Fix A (preferred): let CDK assume the bootstrap deploy role

Grant your CI/user identity permission to assume the CDK roles, then keep CloudFormation permissions on the deploy role where bootstrap already put them.

{
  "Effect": "Allow",
  "Action": "sts:AssumeRole",
  "Resource": "arn:aws:iam::123456789012:role/cdk-*"
}

Re-bootstrap if the roles are missing or old:

cdk bootstrap aws://123456789012/us-east-1

Fix B: grant the CloudFormation actions directly

If you deliberately deploy with raw credentials (--no-role style setups), add the full change-set action set.

{
  "Effect": "Allow",
  "Action": [
    "cloudformation:CreateChangeSet",
    "cloudformation:ExecuteChangeSet",
    "cloudformation:DescribeChangeSet",
    "cloudformation:DeleteChangeSet",
    "cloudformation:DescribeStacks",
    "cloudformation:DescribeStackEvents",
    "cloudformation:GetTemplate"
  ],
  "Resource": "arn:aws:cloudformation:us-east-1:123456789012:stack/MyAppStack/*"
}

Fix C: widen the resource scope

Change set operations reference stack/<name>/*. Ensure your policy Resource matches the real stack name, not a stale prefix.

Fix D: clear an SCP / boundary deny

Explicit denies win. Update the SCP or permissions boundary to stop denying cloudformation:CreateChangeSet, or deploy from an account/role the org policy permits.

What to Watch Out For

  • Do not “fix” this by attaching AdministratorAccess to a CI user. Prefer the assume-role model so the powerful policy stays on the bootstrap role.
  • CreateChangeSet alone is not enough — you also need ExecuteChangeSet or the deploy stalls right after creating the change set.
  • After cdk bootstrap upgrades, the deploy role’s inline policy can change; re-bootstrap all target regions, not just one.
  • The Proceeding anyway warning is not benign; treat it as a hard failure signal in CI by checking exit codes.
  • Custom bootstrap qualifiers change the role names — a hard-coded hnb659fds in your IAM policy will not match a custom-qualified bootstrap.
Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.