Skip to content

agentcore deploy fails with "NoStack" when the account requires a permissions boundary #2292

Description

@DongZhaoXiong

Description

In an AWS account where the CDK CloudFormation execution role carries an organization
permissions boundary that denies iam:CreateRole unless the new role also carries a boundary,
agentcore deploy cannot succeed — and the failure gives the user nothing to act on.

Two distinct problems:

  1. No way to declare a boundary. There is no setting for the permissions boundary that the
    roles created by the project must carry, so the deploy is permanently blocked.

  2. The failure is unreadable. In non-interactive mode the whole output is
    NoStack: CloudFormationStack object does not hold a stack. The actual IAM denial never
    reaches the thrown error — recording the toolkit's ioHost message stream on a failing deploy
    shows the reason appears only on CDK_TOOLKIT_I5502 progress messages, and the thrown error
    has an empty cause. The reason is otherwise only visible via
    aws cloudformation describe-stack-events.

This is the exact configuration docs/PERMISSIONS.md recommends under "Hardening with
permission boundaries", and that section already flags it as not working:

Note: These deny statements require a corresponding update to the AgentCore CDK
constructs. The constructs do not currently attach a permissionsBoundary to the IAM roles
they create (runtime, memory, gateway, etc.), so CloudFormation will fail to create those
roles when ForceExecutionRoleBoundary is active.

Steps to Reproduce

The account-side setup is exactly steps 1 and 2 of docs/PERMISSIONS.md
"Hardening with permission boundaries", using the policy files shipped in this repo.

  1. Create the boundary policy:

    aws iam create-policy \
      --policy-name AgentCoreExecutionRoleBoundary \
      --policy-document file://docs/policies/iam-policy-boundary.json
    
  2. Attach the ForceExecutionRoleBoundary deny statement from
    docs/policies/iam-policy-cfn-execution.json to the CDK CloudFormation execution role
    (cdk-hnb659fds-cfn-exec-role-<account>-<region>). That statement denies iam:CreateRole
    unless the request carries iam:PermissionsBoundary equal to the boundary ARN.

  3. Create a minimal project with one agent and deploy it:

    agentcore create --name repro --no-agent
    cd repro
    agentcore add agent --name MyAgent --type template --framework Strands
    agentcore deploy --target default --yes
    
  4. Observe the deploy fail at "Deploy to AWS".

  5. To see the real reason, which the CLI never prints:

    aws cloudformation describe-stack-events --stack-name AgentCore-repro-default \
      --region <region> \
      --query 'StackEvents[?ResourceStatus==`CREATE_FAILED`].[LogicalResourceId,ResourceStatusReason]'
    

Expected Behavior

  1. A way to declare the permissions boundary that the project's IAM roles must carry, so the
    deploy succeeds in a boundary-enforcing account.

  2. When no boundary is declared and the account requires one, a failure message that names the
    boundary the account expects and how to configure it. The denial text already contains the
    required boundary ARN, so the remedy can be stated exactly.

Actual Behavior

agentcore deploy --target default --yes (CLI 0.29.0):

✓ Load deployment target
✓ Validate project
✓ Sync CDK dependencies
✓ Build CDK project
✓ Synthesize CloudFormation
✓ Check bootstrap status
✓ Check stack status
CDK deploy failed: ❌  AgentCore-repro-default failed: NoStack: CloudFormationStack object does not hold a stack

Nothing in the output, or in agentcore/.cli/logs/deploy/deploy-*.log, mentions IAM or a
permissions boundary. The stack is left in ROLLBACK_COMPLETE and must be deleted manually
before another attempt.

The real reason, from describe-stack-events:

Resource handler returned message: "Encountered a permissions error performing a tagging
operation, please add required tag permissions. See
https://repost.aws/knowledge-center/cloudformation-tagging-permission-error for how to
resolve. Resource handler returned message: "User:
arn:aws:sts::111122223333:assumed-role/cdk-hnb659fds-cfn-exec-role-111122223333-<region>/AWSCloudFormation
is not authorized to perform: iam:CreateRole on resource:
arn:aws:iam::111122223333:role/AgentCore-repro-default-ApplicationAgentMyAgentRu-xxxxxxxx
with an explicit deny in a permissions boundary:
arn:aws:iam::111122223333:policy/AgentCoreExecutionRoleBoundary
(Service: Iam, Status Code: 403)"" (HandlerErrorCode: UnauthorizedTaggingOperation)

Note the UnauthorizedTaggingOperation code is CloudFormation wrapping the denied CreateRole
call, which also carries tags. It sends you looking at tag permissions; the boundary is the
actual cause.

CLI Version

0.29.0

Operating System

Linux

Additional Context

The CDK constructs do not need to change

The note in docs/PERMISSIONS.md assumes @aws/agentcore-cdk has to expose a
permissionsBoundary prop. It does not. aws-cdk-lib reads the
@aws-cdk/core:permissionsBoundary context key and installs a stack-wide aspect over
AWS::IAM::Role / AWS::IAM::User, which reaches roles created inside the L3 constructs.
Confirmed by synthesizing a real vended project with that context set — the runtime execution
role picks up PermissionsBoundary with no construct changes. Verified against
@aws/agentcore-cdk@0.1.0-alpha.50 and aws-cdk-lib@2.261.0.

Acceptance criteria

  • A permissions boundary can be declared as a policy name or a policy ARN, with a bare name
    resolved against each deployment target's own partition and account.
  • It is applied to every IAM role the project creates (runtime execution role, memory,
    gateway, harness, payment, A/B test).
  • It is honoured consistently by synth, deploy, diff and destroy, so it does not read as
    stack drift.
  • With no boundary configured, the synthesized template is unchanged.
  • When the account requires a boundary and none is set, the deploy failure names the required
    boundary and the command to configure it, instead of NoStack.
  • Existing projects benefit after a CLI upgrade, without re-vending agentcore/cdk/.

Where the setting belongs

A boundary is a property of the account you deploy into, not of the project. Committing it to
agentcore.json breaks a teammate whose account has no such policy, and has to be repeated per
project. ~/.agentcore/config.json already holds this class of corporate-environment setting
(uvIndex, disableDependencyManagement), so it seems like the right primary home, with a
project-level field for teams that all deploy into the same enforcing account.

An interactive prompt seems wrong here: at agentcore create the user does not yet know which
account they will deploy into, and the boundary is chosen by whoever set that account up. Like
CDK bootstrap, it is an account-level prerequisite best surfaced when it blocks a deploy.

Possible follow-ups, better handled separately

  • agentcore config has no way to unset a key (affects every key, not just this one).
  • A --permissions-boundary deploy flag for one-off overrides.
  • Per-target boundaries in aws-targets.json for multi-account setups.

Environment

Amazon Linux 2023, kernel 6.1.166-197.305.amzn2023.x86_64, Node 24.14.1, ap-northeast-2.

I have a working fix and will open a PR referencing this issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions