Deploying AWS Bedrock AgentCore with CDK: a quickstart
A CDK guide for deploying a minimal Strands agent on AgentCore Runtime — parameterized stack, arm64 build, deploy and invoke, and the IAM and Marketplace prerequisites you need before the first call.
The setup
A companion post walks through what AgentCore Runtime is at the architecture level: container, identity, memory, gateway. This post picks up where that ends and asks the deployment question: AgentCore is now reachable from CDK through @aws-cdk/aws-bedrock-agentcore-alpha, so what does a working trial look like end-to-end? In practice the code is short and the alpha L2 carries most of the weight, but a few IAM and Marketplace prerequisites need to land before the first invoke returns.
What we are building
A single CDK stack that deploys a minimal Strands agent on AgentCore Runtime in eu-central-1, plus the build script and the boto3 invoke helper. The full layout:
Roughly 150 lines of TypeScript and Python total. Region, model, and runtime config sit in cdk.json so the Stack class itself stays parameter-driven and one configuration change moves you across regions or models. The interesting part is not the volume; it is which lines you write and which the alpha L2 writes for you. Full source: github.com/ayhansipahi/agent-core-cdk.
App entry and config
cdk.json carries the runtime parameters as CDK context, so the Stack class stays a pure construct and the values change without code edits:
bin/app.ts reads, validates, and passes them into the stack:
The throw is a deploy-time guard — synth fails fast if any key is missing instead of producing a stack with undefined ARNs. To switch regions or models, edit cdk.json and re-deploy; the Stack class itself never holds a string literal for any of these.
The CDK stack
lib/agent-runtime-stack.ts takes the four config props and produces the whole infrastructure surface — two manual PolicyStatement blocks, one Runtime construct, one CfnOutput, two stack-level tags:
Three details worth pausing on. The Bedrock invoke statement lists three ARNs, not one: the regional foundation model, a wildcard region, and the inference profile (constructed at runtime from props.inferenceProfilePrefix + props.modelId). EU cross-region inference uses the eu. prefixed profile, and the wildcard region is required because the inference profile fans out to other regions internally. The Marketplace statement scopes resources to * because Marketplace API actions do not support resource-level IAM. And the runtime name has to be camelCase because the alpha L2 inherits CFN naming constraints — hyphens fail at deploy-time, not synth-time.
The agent code
agent/main.py reads the model ID and region from environment. AWS_REGION mirrors cdk.json; MODEL_ID defaults to the eu.-prefixed inference profile because the agent calls Bedrock directly and needs the prefixed ID, while the stack constructs the same value at synth time from inferenceProfilePrefix + modelId. The same file runs locally with agentcore dev and in the deployed runtime:
BedrockAgentCoreApp is the runtime contract; it spins up the HTTP server on port 8080 inside the AgentCore container and routes every invoke_agent_runtime call to the function decorated with @app.entrypoint. The default MODEL_ID carries the eu. regional prefix because the runtime executes in eu-central-1 and Bedrock requires the prefixed profile for cross-region inference. AgentCore injects AWS_REGION automatically; MODEL_ID can be overridden through the Runtime construct's environmentVariables prop if you ever want it different from the cdk.json value.
The arm64 build hop
AgentCore Runtime executes only on arm64. A macOS or x86_64 host that runs pip install -r requirements.txt --target=dist will produce x86_64 wheels and the container will fail with an exec format error on first invoke. The build script forces the right platform:
--only-binary=:all: is the safety net. If a dependency has no arm64 wheel and pip falls back to building from source, the source build runs on the host arch and the resulting .so files break in the container. :all: makes pip fail loudly instead. uv in place of pip is a ~4-6 second versus ~30 second difference on this dependency set, but plain pip --platform works too. Output goes to agent/dist/, which is what AgentRuntimeArtifact.fromCodeAsset zips and uploads.
First deploy: 66 seconds
cdk deploy from a clean slate took 66.13s in this trial: CFN bootstrap reuse, Runtime resource creation, IAM role creation, and the S3 asset upload through the CDK staging bucket. Subsequent deploys are faster because the Runtime resource is already there: an IAM-only update came in at 30.48s, a description bump that forced a new Runtime version landed at 24.9s, and an idempotent re-deploy with no diff at 21.25s.
That was the easy half. Three IAM/billing prerequisites stand between this and the first successful invoke.
Prerequisites you may not see in the docs
Three layers gate the first invoke. The CDK stack above already covers the first two; the third is account-level and worth checking before the first deploy.
1. Bedrock model invoke (in the stack). The runtime role needs bedrock:InvokeModel against the foundation model and the inference profile. Without it, the invoke returns:
The first PolicyStatement in the stack covers this — three ARN forms (regional, wildcard, inference profile).
2. Marketplace subscription validation (in the stack). Newer Anthropic models on Bedrock validate an AWS Marketplace subscription on each ConverseStream call (the Sonnet 4.5 model card lists a Marketplace product ID: prod-mxcfnwvpd6kb4). Without aws-marketplace:Subscribe, Unsubscribe, and ViewSubscriptions on the runtime role, the invoke returns:
The minimal IAM example in the AWS AgentCore docs assumes an Anthropic model but does not include these actions; the second PolicyStatement in the stack covers them.
3. Account payment instrument (account-level, not IaC). With both IAM blocks correct, the Marketplace subscription itself can still fail at the billing layer:
Fix in the AWS Billing console (not the Marketplace one): Account → Payment preferences → Add card. Roughly two minutes for propagation, no redeploy.
The L2 alpha bonus
Inspecting the runtime role after deploy with aws iam get-role-policy revealed seven policy statements that the L2 construct attached on its own. None of these are in the stack code; they are what agentcore.Runtime writes for you:
Plus the two manual statements above (Bedrock invoke + Marketplace), the runtime role ends up with nine statements total. Written by hand on top of the L1 CfnRuntime, this is roughly 80 lines of JSON you do not maintain. That is the case for staying on the alpha L2 even with the version-pin caveat.
The numbers
All measurements from the same POC session in eu-central-1, fresh runtimeSessionId per invoke:
Client-side overhead sits around 3.5-4 seconds across all three invokes: boto3 import, archive resolve, AgentCore session create, network round-trip. For SLO measurement, take the server-side timing; the client-side number is dominated by Python and SDK startup.
Closing
AgentCore-on-CDK is a small surface — about 150 lines of TypeScript and Python with cdk.json on the side. The two things to bring with you that the AWS docs minimal example does not flag: the Marketplace IAM block on the runtime role for newer Anthropic models, and a payment method on the account before the first invoke. The recommendation: stay on the alpha L2 (@aws-cdk/aws-bedrock-agentcore-alpha) because it injects seven policy statements you would otherwise hand-roll on top of the L1 CfnRuntime, and pin the version because alpha qualifiers are not semver-stable; the trial here ran on 2.252.0-alpha.0. Drop to L1 only if an alpha qualifier is a hard compliance blocker.
The natural next step from this stack is the AgentCore Memory and Gateway constructs, which the same alpha module exposes; both layer onto the same Runtime role this trial set up.
References
- @aws-cdk/aws-bedrock-agentcore-alpha L2 reference -
Runtime,AgentRuntimeArtifact.fromCodeAsset,AgentCoreRuntime.PYTHON_3_13API surface. - AgentCore Runtime get-started: deploy via direct code - the minimal IAM example that misses the Marketplace block for Anthropic models.
- AgentCore Runtime get-started: Python entrypoint -
BedrockAgentCoreAppand@app.entrypointcontract. - AgentCore region availability - eu-central-1 support and the
eu.inference profile prefix rule. - AWS::BedrockAgentCore CFN reference - L1 surface that the alpha L2 renders to underneath.
- Anthropic Claude Sonnet 4.5 model card on Bedrock - model ID and regional availability.
- Strands Agents documentation -
BedrockModelandAgentAPI used inagent/main.py. - bedrock-agentcore SDK Python (GitHub) -
BedrockAgentCoreAppsource and the runtime contract. - agentcore-samples (GitHub, awslabs) - community samples covering Marketplace IAM patterns.
- agent-core-cdk (GitHub, this trial's source) - the CDK stack, Strands agent, build script, and invoke helper as deployed in this trial.
- AWS CDK assets bucket convention - the
cdk-hnb659fds-assets-<account>-<region>staging bucket thatS3AssetReadtargets.