Skip to content

refactor(cdk): bedrockGeoRegion context key (default us; template-identical) #746

Description

@scottschreckengaust

Child 5 of 6 — parent #740/#741. Deploys safely. Pure refactor — synthesized template must be byte-identical.

Makes the Bedrock geo configurable without changing it. Prerequisite for child 6.

Problem

Both grant sites hardcode the US geo, so no non-US or global deployment is possible without editing constructs:

  • cdk/src/stacks/agent.ts:549geoRegion: bedrock.CrossRegionInferenceProfileRegion.US
  • cdk/src/constructs/ecs-agent-cluster.ts:585 — string-concatenates `us.${modelId}` into the profile ARN

Scope

1. New context key bedrockGeoRegion, defaulting to us. Resolve in cdk/src/constructs/bedrock-models.ts alongside resolveBedrockModelIds, following its established shape: read via node.tryGetContext, fall back to a documented constant, and throw at synth on an unknown value so a typo fails loudly rather than granting an invalid ARN.

Accept the geos @aws-cdk/aws-bedrock-alpha actually models — CrossRegionInferenceProfileRegion is an enum of global, us, eu, apac, jp, au, us-gov. Map the string to the enum in agent.ts; use it in place of the us. literal in ecs-agent-cluster.ts.

2. Thread it into both grant sites. CrossRegionInferenceProfile.fromConfig builds inferenceProfileId as `${geoRegion}.${model.modelId}`, so this is a prefix substitution, not an ARN-shape change. Confirmed empirically — us. and global. profile ARNs are identical in shape (both regional + account-qualified).

Note the foundation-model half of the grant is already geo-agnostic: grantInvoke on a cross-region profile calls grantInvokeAllRegions, which emits region: '*'. Only the profile half is US-pinned. Verified: the global profile's members are arn:aws:bedrock:::foundation-model/anthropic.claude-opus-5 (empty region = all Regions) plus the regional form — both already covered by the region: '*' grant.

3. Derive ANTHROPIC_DEFAULT_HAIKU_MODEL from the same key. Currently hardcoded us.-prefixed at cdk/src/stacks/agent.ts:393. If the deployment moves geo and this doesn't, the main and auxiliary models route differently. Verified the global counterpart exists and is invocable: global.anthropic.claude-haiku-4-5-20251001-v1:0 (ACTIVE), and a smoke test with it set alongside global Opus 5 passed. Derive the prefix; do not leave a second hardcode.

4. Generalize the drift guard. cdk/test/constructs/bedrock-models.test.ts:83 asserts the agent default matches /^us\./ and strips only a us. prefix. Widen to the enum's geos — e.g. /^(global|us|eu|apac|jp|au|us-gov)\./ — and strip whichever matched. Do not weaken to .*: the assertion's purpose is catching a bare ID where a profile ID is required, and a bare ID is genuinely un-invokable (ValidationException: on-demand throughput isn't supported). Keep that teeth.

5. Fix the latent prefix-guard hole. resolveBedrockModelIds rejects us|eu|apac-prefixed entries (bedrock-models.ts:84) but not global., us-gov., jp., or au.. So -c bedrockModels='[\"global.anthropic.claude-opus-5\"]' silently produces an invalid us.global.anthropic.claude-opus-5 ARN instead of failing at synth. Add the missing geos. Keep the contract clear in the error message: bedrockModels is bare-IDs-only; geo comes from bedrockGeoRegion.

Why this is safe to deploy alone

With the default us, the synthesized template is unchanged. Assert exactly that in a test — synth with no context override and confirm the Bedrock IAM resources match the pre-change template. That assertion is the safety proof, not a nicety.

Acceptance criteria

  • bedrockGeoRegion resolved in bedrock-models.ts, defaults to us, throws at synth on an unknown geo
  • Threaded into both stacks/agent.ts and constructs/ecs-agent-cluster.ts; no us. literal remains in either grant path
  • ANTHROPIC_DEFAULT_HAIKU_MODEL prefix derived from the key
  • Drift guard regex generalized to the enum's geos, still rejecting bare IDs
  • resolveBedrockModelIds rejects global./us-gov./jp./au. prefixes
  • Template-identity test: default-context synth produces the same Bedrock IAM resources as before this change
  • Parameterized test: -c bedrockGeoRegion=global yields inference-profile/global.anthropic.… ARNs and a global.-prefixed haiku env var
  • cdk/test/stacks/agent.test.ts:150 haiku assertion updated to derive its expectation rather than hardcode us.
  • mise //cdk:eslint + mise run build green
  • cdk diff on default context shows no changes

Notes

Blocks #746. Independent of #742/#743/#744/#745 — touches plumbing, not model values.

Metadata

Metadata

Labels

P1medium priorityapprovedWhen an issue has been approved and readyenhancementNew feature or requestinfra-cdkCDK stacks/constructs, bootstrap, deploy topology, tags, IAM wiring, teardown

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions