fix(scp): carve out Bedrock InvokeModel/Converse to us-east-2 for cross-region inference

Add bedrock:InvokeModel, bedrock:InvokeModelWithResponseStream,
bedrock:Converse, and bedrock:ConverseStream to the existing
DenyRegionsOutsideApproved NotAction list so the us-east-1/us-west-2
region condition no longer denies them. Add a companion
DenyBedrockInvokeOutsideInference statement that re-denies those same
four actions outside {us-east-1, us-west-2, us-east-2}, bounding the
carve-out to us-east-2 only.

Without this, Anthropic cross-region inference profiles (us.anthropic.*)
that route InvokeModel to us-east-2 are denied, blocking all Claude
generation in workload accounts.

Refs: #53
This commit is contained in:
amoussa1229 2026-07-15 22:11:59 +00:00
parent ed26ff937d
commit 274b25d9e8

View file

@ -56,9 +56,13 @@ const scpContent = (name: string): Record<string, unknown> =>
* decision as the external-dev guardrails): it is the only generic
* cross-account expression for CDK exec roles; member baselines protect
* those roles from takeover (ProtectPrivilegedRoles pattern).
* - Region-lock NotAction list deliberately matches battle-tested
* p-i59g24mz; regional services (s3, kms, logs, ssm...) stay region-locked
* BY DESIGN — do not add them to NotAction (that would exempt them).
* - Region-lock NotAction list extends battle-tested p-i59g24mz with
* bedrock:InvokeModel/InvokeModelWithResponseStream/Converse/ConverseStream
* to allow cross-region inference profiles (us.anthropic.*) that route to
* us-east-2; a companion DenyBedrockInvokeOutsideInference statement
* re-denies those actions outside {us-east-1, us-west-2, us-east-2}.
* Regional services (s3, kms, logs, ssm...) stay region-locked BY DESIGN
* — do not add them to NotAction (that would exempt them).
*/
export class OrgGovernanceStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
@ -116,7 +120,10 @@ export class OrgGovernanceStack extends cdk.Stack {
// Region lock for workload accounts: us-east-1 (primary) + us-west-2
// (offsite backup/DR). Global services exempted via NotAction — the same
// list proven on the external-dev region lock.
// list proven on the external-dev region lock. Bedrock Invoke/Converse
// are carved out of the general deny and re-denied only outside
// {us-east-1, us-west-2, us-east-2} so cross-region inference profiles
// (us.anthropic.*) that route to us-east-2 are not blocked.
const workloadsRegionLock = new organizations.CfnPolicy(this, "WorkloadsRegionLock", {
name: "workloads-region-lock",
type: "SERVICE_CONTROL_POLICY",
@ -135,6 +142,8 @@ export class OrgGovernanceStack extends cdk.Stack {
"globalaccelerator:*", "budgets:*", "ce:*", "cur:*", "health:*",
"support:*", "supportplans:*", "trustedadvisor:*", "artifact:*",
"aws-portal:*",
"bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream",
"bedrock:Converse", "bedrock:ConverseStream",
],
Resource: "*",
Condition: {
@ -143,6 +152,20 @@ export class OrgGovernanceStack extends cdk.Stack {
},
},
},
{
Sid: "DenyBedrockInvokeOutsideInference",
Effect: "Deny",
Action: [
"bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream",
"bedrock:Converse", "bedrock:ConverseStream",
],
Resource: "*",
Condition: {
StringNotEquals: {
"aws:RequestedRegion": ["us-east-1", "us-west-2", "us-east-2"],
},
},
},
],
},
});