CDK stack (AgentCoreStack)

AgentCoreStack is the only CDK stack, defined in cdk/lib/stacks/agentcore-stack.ts and instantiated in cdk/bin/cdk.ts. It deploys the AgentCore runtime and nothing else.

Never split this into a second stack, and never import an external role with iam.Role.fromRoleArn(). CDK owns every IAM identity it uses. Both rules are in AGENTS.md and both exist because the runtime’s permissions are its security boundary — an imported role is one whose policy is not reviewable in this repository.

Stack props

cdk/bin/cdk.ts passes:

new AgentCoreStack(app, 'AgentCoreStack', {
  appName: 'agentcore',
  logRetentionDays: logs.RetentionDays.ONE_MONTH,
  secretArn: 'arn:aws:secretsmanager:{aws-region}:{aws-account}:secret:agentcore-secrets-BHnvz6',
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});

AgentCoreStackProps in cdk/lib/types.ts defaults dockerPlatform to LINUX_ARM64, networkMode to PUBLIC, and logRetentionDays to ONE_MONTH. The dockerPlatform and networkMode overrides are present in bin/cdk.ts but commented out.

The account and region come from the CDK environment rather than being hardcoded, so CDK_DEFAULT_REGION must resolve to us-east-1 — Bedrock cross-region inference profiles for the us. models depend on it.

secretArn here points at agentcore-secrets-BHnvz6, which is not the agentcore-configs secret the Lambdas use. The two halves of the platform read different secrets. See Secrets Manager.

Constructs

Construct Id Purpose

ecr_assets.DockerImageAsset

agentcore-Image

Builds and pushes the runtime container

logs.LogGroup

agentcore-AgentLogs

Application logs for the agent

iam.Role

MemoryExecutionRole

Assumed by AgentCore Memory to invoke Bedrock

iam.Role

agentcore-RuntimeRole

The runtime’s execution identity

bedrockagentcore.CfnMemory

AgentMemory

Long-term memory with three extraction strategies

bedrockagentcore.CfnRuntime

agentcore-Runtime

The runtime itself

Two CfnRuntimeEndpoint constructs — agentcore-ProdEndpoint and agentcore-DevEndpoint — are written but commented out. The runtime is invoked through its ARN directly; see Invocation contract.

Container image

new ecr_assets.DockerImageAsset(this, `${props.appName}-Image`, {
  directory: path.join(__dirname, '../../../agentcore'),
  platform: dockerPlatform,   // LINUX_ARM64
});

CDK builds the image locally, pushes it to the CDK-managed ECR repository, and passes the resulting URI to the runtime. There is no separate docker push step and no ECR repository declared in the stack.

Property Value

Build context

agentcore/

Dockerfile

agentcore/Dockerfile (the default)

Platform

linux/arm64

Base image

python:3.12-slim

Working directory

/app

Dependencies

uv sync --frozen --no-dev

PYTHONPATH

/app

Exposed ports

9000, 8000, 8080

Command

["python", "-m", "main"]

uv sync --frozen fails rather than resolving if uv.lock disagrees with pyproject.toml, so a lockfile that was not committed alongside a dependency change breaks the build instead of producing a differently-resolved image.

Building an arm64 image on an x86_64 machine requires emulation, so the first build is slow. The commented LINUX_AMD64 line in bin/cdk.ts exists for that reason — but switching it changes the deployed architecture, not just the build.

AgentCore Memory

Property Value

name

agentCoreMemory

eventExpiryDuration

90 days

memoryExecutionRoleArn

MemoryExecutionRole

Three strategies, each writing into its own namespace:

Strategy Name Namespace

semanticMemoryStrategy

FactExtractor

/facts/{actorId}/

userPreferenceMemoryStrategy

ContactDetailsInteractions

/contactDetails/{actorId}/

summaryMemoryStrategy

SessionSummarizer

/summaries/{actorId}/{sessionId}/

The namespace templates decide the retrieval scope. Facts and contact details are keyed by actor alone, so they persist across every session for that prospect; summaries are keyed by actor and session, so each conversation gets its own. Ninety-day expiry then bounds how far back any of it reaches. Retrieval behaviour is described in AgentCore Memory.

Runtime

Property Value

agentRuntimeName

agentcore

agentRuntimeArtifact

containerConfiguration.containerUri from the image asset

protocolConfiguration

HTTP

networkConfiguration

networkMode: PUBLIC

roleArn

agentcore-RuntimeRole

Environment variables injected by CDK:

Variable Value

AWS_REGION

The stack region

LOG_GROUP_NAME

/aws/bedrock-agentcore/agents/agentcore

MEMORY_ID

memory.attrMemoryId

SECRET_ARN

props.secretArn, only when set

That is the complete list, and it is deliberately short. Model ids, system prompts, provider selection, and workflow registration are not here — they live in runtime code under agentcore/. Infrastructure supplies coordinates (where to log, which memory, which secret); behaviour is code. See Configuration.

Log group

/aws/bedrock-agentcore/agents/agentcore, retention ONE_MONTH, removalPolicy: DESTROY.

The destroy policy means tearing down the stack deletes the logs with it. Separately, the AgentCore platform writes system-level logs to /aws/bedrock-agentcore/runtimes/*, which the stack does not create but does grant write access to.

Outputs

Output Value

ImageUri

ECR URI of the pushed image

LogGroupName

The agent log group

AgentRuntimeId

Runtime id

AgentRuntimeArn

Runtime ARN — the invoke target

RuntimeRoleArn

Execution role ARN

SecretArn

Emitted only when secretArn was supplied

AgentRuntimeArn and RuntimeRoleArn are the two that matter operationally: both are copied into agentcore/.bedrock_agentcore.yaml so the AgentCore CLI can invoke the deployed runtime. That file holds a previous deploy’s values until someone updates it, which is the usual reason a CLI invocation targets the wrong runtime after a stack recreate.

Modifying the stack

Four changes that come up repeatedly. All are in cdk/lib/stacks/agentcore-stack.ts unless noted.

Add a runtime environment variable

environmentVariables: {
  AWS_REGION: this.region,
  LOG_GROUP_NAME: this.logGroup.logGroupName,
  MEMORY_ID: memory.attrMemoryId,
  MY_NEW_SETTING: 'value',
}

Only for infrastructure coordinates. A model id, prompt, or provider choice belongs in runtime code, and a credential belongs in the secret.

Add an IAM permission

runtimeRole.addToPolicy(new iam.PolicyStatement({
  sid: 'DescriptiveSid',
  actions: ['service:Action'],
  resources: [specificArn],
}));

Name a resource ARN. If the action supports no resource-level scoping, add a conditions block rather than accepting a bare * — CloudWatchMetrics in IAM is the pattern to copy.

Change log retention

// cdk/bin/cdk.ts
new AgentCoreStack(app, 'AgentCoreStack', {
  logRetentionDays: logs.RetentionDays.THREE_MONTHS,
});

Move the runtime into a VPC

// cdk/bin/cdk.ts
new AgentCoreStack(app, 'AgentCoreStack', {
  networkMode: 'VPC',
});

The prop is already threaded through AgentCoreStackProps and is commented out in bin/cdk.ts. Switching it also requires subnets, security groups, and VPC endpoints for ECR, Secrets Manager, CloudWatch Logs, and Bedrock — none of which the stack declares today. Expect this to be more than a one-line change.

Commands

Command Effect

make deploy-cdk

npx cdk bootstrap then cdk deploy --all

make deploy-dev

cdk deploy --all, no bootstrap

make deploy-prod

cdk deploy --all --require-approval never

Underlying CDK CLI, run from cdk/:

Command Effect

npx cdk diff

Show pending changes, including an IAM summary

npx cdk synth

Emit the CloudFormation template without deploying

npx cdk deploy

Deploy or update

npx cdk destroy

Tear down — takes the log group with it (removalPolicy: DESTROY)

cdk diff before any deploy that touched a policy: it is the only IAM review in the path. --require-approval never skips the confirmation prompt, so use it in automation only.

Dependencies in cdk/ are managed with pnpm. Never run npm install there.