From a034b6455bd8045b3310a7c36612a6906641ecca Mon Sep 17 00:00:00 2001 From: Fahad Farrukh Date: Sat, 13 Jun 2026 01:07:06 -0400 Subject: [PATCH 1/2] docs(payments): correct T02 description of the runtime execution role MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Key Concepts" section called the execution role `ProcessPaymentRole` and described it as having "explicit denies on CreatePaymentSession, CreatePaymentInstrument, and all control-plane operations." Two factual errors in one sentence: 1. The deployed runtime is not bound to AgentCorePaymentsProcessPaymentRole. `deploy_payment_agent.py` runs `agentcore deploy -y` and the CLI's CDK construct creates a fresh execution role itself. The script then attaches a narrow inline policy to whichever auto-created role it finds. The runtime's roleArn returned by GetAgentRuntime is that auto-created role, not the role utils.py creates. 2. Per the official IAM roles guide for AgentCore payments, the `Deny ProcessPayment` statement lives on **ManagementRole**, not on ProcessPaymentRole. ProcessPaymentRole's design is narrow scope (Allow only ProcessPayment + read APIs); the absence of CreateSession and CreateInstrument is what enforces separation, not a Deny. Update the section to describe what actually happens — the auto-created execution role plus the inline PaymentDataPlaneAccess policy. Cross-link to the AWS IAM roles guide so users see the canonical separation pattern. Add a code comment near the IAM attach in deploy_payment_agent.py explaining that the CLI's `agentcore.json` schema (`AgentEnvSpec`) does not currently expose `executionRoleArn`, so binding the runtime to a caller-managed role is not possible today. The narrow inline policy is the workaround. Verified: - AWS Knowledge MCP confirmed the canonical IAM separation pattern (Deny on ManagementRole, narrow scope on ProcessPaymentRole) - Live deploy on us-west-2: runtime roleArn was the auto-CDK role (AgentCore-PaymentAgent-de-ApplicationAgentPaymentAg-...), inline policy was Allow-only as written by the script. Stack torn down. --- .../02-deploy-to-agentcore-runtime/README.md | 2 +- .../deploy_payment_agent.py | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/README.md b/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/README.md index 2f65409e9..d64e65216 100644 --- a/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/README.md +++ b/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/README.md @@ -124,7 +124,7 @@ python payment_agent.py **Stateless agent** — `payment_agent.py` reads all payment context from the invocation payload, not from environment variables. This means the same agent binary can serve different users with different budgets — the app backend controls what each user can spend by creating a session with the appropriate budget before invoking. -**ProcessPaymentRole** — The execution role the agent runs under. It has `ProcessPayment` permission and explicit denies on `CreatePaymentSession`, `CreatePaymentInstrument`, and all control-plane operations. The agent cannot create sessions, override budgets, or provision wallets. +**Runtime execution role** — The agentcore CLI auto-creates an execution role when it scaffolds the project. `deploy_payment_agent.py` then attaches a narrow inline policy (`PaymentDataPlaneAccess`) that grants only `ProcessPayment` and the read-only payment APIs (`GetPaymentInstrument`, `GetPaymentInstrumentBalance`, `GetPaymentSession`, `ListPaymentInstruments`, `GetResourcePaymentToken`). The agent cannot create sessions, override budgets, or provision wallets because those actions are not on the allow list. This matches the [IAM roles guide](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-iam-roles.html), which separates payment management from payment execution by **narrow scope** on the execution role and an **explicit `Deny ProcessPayment`** on the management role used by the app backend. **Payload-driven sessions** — The app backend creates a fresh session with a budget before every invocation, then passes the `payment_session_id` in the payload. The agent cannot reuse sessions from previous invocations or extend their expiry. diff --git a/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/deploy_payment_agent.py b/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/deploy_payment_agent.py index 5ac498534..b00527299 100644 --- a/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/deploy_payment_agent.py +++ b/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/deploy_payment_agent.py @@ -157,7 +157,15 @@ result = subprocess.run(["agentcore", "status"], cwd=project_dir, capture_output=True, text=True) print(result.stdout) -# Add payment permissions to the auto-created execution role +# Add payment permissions to the auto-created execution role. +# The agentcore CLI creates the execution role itself from the CDK construct; +# `agentcore.json` (AgentEnvSpec) does not currently expose `executionRoleArn`, +# so we cannot bind the runtime to the AgentCorePaymentsProcessPaymentRole that +# Tutorial 00 created. Instead, we attach a narrow inline policy here. Allow +# only on ProcessPayment + the read APIs is what enforces separation — the +# absence of CreatePaymentSession / CreatePaymentInstrument on the role keeps +# the agent from creating its own budgets or wallets. See +# https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-iam-roles.html. print("Adding payment permissions to execution role...") iam = boto3.client("iam") roles = iam.list_roles(MaxItems=200)["Roles"] From 1b4be53e18bb147f3a8cd8eb5dea74a80d9ff820 Mon Sep 17 00:00:00 2001 From: Fahad Farrukh Date: Sat, 13 Jun 2026 01:08:39 -0400 Subject: [PATCH 2/2] docs(payments): tighten T02 runtime execution role paragraph Replace the API-name list and the slightly defensive 'this matches' phrasing with a tighter contrast: narrow scope is what enforces the boundary on the execution role; the explicit Deny lives on the management role. --- .../00-getting-started/02-deploy-to-agentcore-runtime/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/README.md b/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/README.md index d64e65216..3ac799881 100644 --- a/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/README.md +++ b/01-features/08-agents-that-transact/00-getting-started/02-deploy-to-agentcore-runtime/README.md @@ -124,7 +124,7 @@ python payment_agent.py **Stateless agent** — `payment_agent.py` reads all payment context from the invocation payload, not from environment variables. This means the same agent binary can serve different users with different budgets — the app backend controls what each user can spend by creating a session with the appropriate budget before invoking. -**Runtime execution role** — The agentcore CLI auto-creates an execution role when it scaffolds the project. `deploy_payment_agent.py` then attaches a narrow inline policy (`PaymentDataPlaneAccess`) that grants only `ProcessPayment` and the read-only payment APIs (`GetPaymentInstrument`, `GetPaymentInstrumentBalance`, `GetPaymentSession`, `ListPaymentInstruments`, `GetResourcePaymentToken`). The agent cannot create sessions, override budgets, or provision wallets because those actions are not on the allow list. This matches the [IAM roles guide](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-iam-roles.html), which separates payment management from payment execution by **narrow scope** on the execution role and an **explicit `Deny ProcessPayment`** on the management role used by the app backend. +**Runtime execution role** — The agentcore CLI auto-creates an execution role when it scaffolds the project. `deploy_payment_agent.py` then attaches a narrow inline policy (`PaymentDataPlaneAccess`) that grants only `ProcessPayment` and the read-only payment APIs. The agent cannot create sessions, override budgets, or provision wallets because those actions are not on the allow list — narrow scope is what enforces the boundary. The [IAM roles guide](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-iam-roles.html) puts the explicit `Deny ProcessPayment` on the management role (used by the app backend to create sessions), not on the execution role. **Payload-driven sessions** — The app backend creates a fresh session with a budget before every invocation, then passes the `payment_session_id` in the payload. The agent cannot reuse sessions from previous invocations or extend their expiry.