AI in European Software | AI in the EU series

    How to Enforce EU-Only Claude Routing with IAM and SCPs

    Use IAM policies and service control policies to restrict Claude on Amazon Bedrock to approved EU inference routes.

    Siva SadhuBy Siva SadhuFounder and Principal ConsultantLast checked 29 September 2026
    Policy gates protecting approved European AI routes

    An EU inference profile only keeps your data in the EU if nobody can call anything else. If a developer swaps one model ID for a global. profile, processing leaves the EU, and by default nothing in Bedrock stops them.

    The fix comes in two layers. IAM policies decide which profiles each role can call. Service control policies (SCPs) enforce the same rule across every account in your organisation. In this post I’ll walk through both, plus the mistake that most often breaks EU routing: blocking a Region the profile needs. It builds on Can You Use Claude Without Sending Prompts and Responses Outside the EU?

    How Bedrock checks a cross-Region call

    A single call to an EU profile gets authorised several times: once for the inference profile, once for the model in your source Region, and once for the model in each Region the request could be sent to (AWS: Geographic cross-Region inference). Every one of those checks has to pass, in IAM and in your SCPs.

    Give each application role access to specific EU profiles and nothing more. The policy below follows AWS’s documented pattern for geographic profiles, but treat it as illustrative until you have tested it in your own sandbox. The exact resources and conditions depend on the model, source Region and profile you approve.

    • Block one destination Region and the whole call fails. If an SCP denies Bedrock in any Region the profile can route to, the request fails, even if every other Region is allowed (AWS ML blog). In organisations with Region-deny SCPs, this is the most common reason people think EU routing “doesn’t work”.
    • The bedrock:InferenceProfileArn condition key is what makes this manageable. It’s set on the model checks, which carry the destination Regions, but not on the profile check. So you can allow model access only when it comes through an approved profile, and exempt that routing from a Region-deny SCP without opening those Regions to anything else (AWS: Geographic cross-Region inference).

    Layer 1: IAM allows only the approved EU profile

    Give each application role access to specific EU profiles and nothing more. The policy below lets a role call Claude Sonnet 5 through the EU profile from Frankfurt, and use the underlying model only when the request comes through that profile. It follows the pattern AWS documents for geographic profiles (AWS: Prerequisites for inference profiles).

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowApprovedEuProfile",
          "Effect": "Allow",
          "Action": ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"],
          "Resource": "arn:aws:bedrock:eu-central-1:111122223333:inference-profile/eu.anthropic.claude-sonnet-5"
        },
        {
          "Sid": "AllowModelOnlyThroughEuProfile",
          "Effect": "Allow",
          "Action": ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"],
          "Resource": "arn:aws:bedrock:*::foundation-model/anthropic.claude-sonnet-5",
          "Condition": {
            "StringEquals": {
              "bedrock:InferenceProfileArn": "arn:aws:bedrock:eu-central-1:111122223333:inference-profile/eu.anthropic.claude-sonnet-5"
            }
          }
        }
      ]
    }
    

    A few notes on using it:

    • Replace the account ID and source Region with your own. System-defined profile ARNs include your account ID.
    • The wildcard Region on the model is safe here. The condition only allows access through the EU profile, and that profile can only route to its fixed list of destinations. If your auditors would rather see explicit Regions, list the ones get-inference-profile returns.
    • Converse and ConverseStream are covered too, because Bedrock authorises them through bedrock:InvokeModel and bedrock:InvokeModelWithResponseStream.

    Repeat both statements for every model you approve, and keep that list short. Each approved model is one more thing to recheck when models change.

    Layer 2: SCPs enforce it across the organisation

    IAM protects the roles you write policies for. An SCP protects every role in every account under an organisational unit, including the ones someone creates next month. Two rules do the work.

    Deny Global routing outright. AWS documents denying requests where aws:RequestedRegion equals unspecified as the way to block Global profiles (AWS: Prerequisites for inference profiles). I’d also deny the global. profile ARNs directly, so anyone reading the policy can see what it’s for. Doing both costs nothing.

    Deny unapproved Regions, but let EU routing through. Many organisations allow only one or two EU Regions, while an EU profile routes across six or more. Exempting calls that come through an approved bedrock:InferenceProfileArn lets the profile reach its destinations without opening those Regions for anything else. The exemption doesn’t apply to the originating call, so requests still have to start in an allowed Region (AWS: Geographic cross-Region inference). A useful side effect: nobody can call the EU profile from London or Zurich.

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "DenyGlobalBedrockRouting",
          "Effect": "Deny",
          "Action": "bedrock:InvokeModel*",
          "Resource": "*",
          "Condition": {
            "StringEquals": { "aws:RequestedRegion": "unspecified" }
          }
        },
        {
          "Sid": "DenyGlobalBedrockProfiles",
          "Effect": "Deny",
          "Action": "bedrock:InvokeModel*",
          "Resource": "arn:aws:bedrock:*:*:inference-profile/global.*"
        },
        {
          "Sid": "DenyOutsideApprovedRegionsExceptEuProfiles",
          "Effect": "Deny",
          "Action": "*",
          "Resource": "*",
          "Condition": {
            "StringNotEquals": { "aws:RequestedRegion": ["eu-central-1", "eu-west-1"] },
            "ArnNotLike": { "bedrock:InferenceProfileArn": "arn:aws:bedrock:*:*:inference-profile/eu.*" }
          }
        }
      ]
    }
    

    Please don’t paste the third statement in as it is. Real Region-deny SCPs exempt global services such as IAM, Organizations and Support, usually with NotAction. Merge the ArnNotLike condition into the Region-deny SCP you already have, following AWS’s example (AWS ML blog). If you use AWS Control Tower, use its OU Region-deny control or Customizations for Control Tower rather than editing its SCPs, so you don’t cause drift.

    Don’t forget the second endpoint

    Everything above covers the bedrock-runtime endpoint. Newer Claude models are also served through bedrock-mantle, which uses a different IAM action: bedrock-mantle:CreateInference (Anthropic: Claude in Amazon Bedrock). A role with that permission isn’t affected by any of your bedrock:InvokeModel rules.

    It’s also where single-Region inference lives for models like Claude Sonnet 5. AWS says to use bedrock-mantle with the bare model ID when you need single-Region processing, and for Sonnet 5 that’s available in Stockholm and Ireland within the EU (AWS: Claude Sonnet 5 model card).

    If you use it, allow the action only in those Regions:

    {
      "Sid": "AllowMantleInRegionOnly",
      "Effect": "Allow",
      "Action": "bedrock-mantle:CreateInference",
      "Resource": "*",
      "Condition": {
        "StringEquals": { "aws:RequestedRegion": ["eu-west-1", "eu-north-1"] }
      }
    }
    

    Then narrow Resource down to your approved model ARNs. I haven’t confirmed how aws:RequestedRegion behaves for Global calls on bedrock-mantle, so test that a Global call fails before relying on this. If you don’t use bedrock-mantle at all, deny bedrock-mantle:* in your SCP and the question goes away.

    Test it

    A policy you haven’t tested is a guess. Run these calls with an application role and keep the results with the date. They’re your evidence that the controls work.

    CallExpected result
    eu. profile from FrankfurtSucceeds
    global. profile from FrankfurtAccessDenied
    us. profile from FrankfurtAccessDenied
    eu. profile from London (eu-west-2)AccessDenied (Region not allowed)
    Bare model ID on bedrock-mantle in IrelandSucceeds, if you approved it
    Global call on bedrock-mantleAccessDenied
    Unapproved model through an eu. profileAccessDenied

    For the calls that succeed, check the CloudTrail event as described in How to Verify Where Claude Processed Your Request with AWS CloudTrail. For the ones that fail, the error message says which type of policy blocked the call, so you can see the right layer is doing its job.

    What these policies don’t cover

    • Other services. Knowledge bases, agents, S3 and vector stores need their own Region controls.
    • New models. Each approved model needs its own statements, so recheck the profile’s destinations with get-inference-profile before adding one.
    • What goes into the prompt. IAM controls where a request can be processed, not what’s in it. Your data classification rules still decide what can be sent at all.

    Need a second pair of eyes on the controls?

    Wolkn Minds can design the IAM and SCP layer, test the allowed and denied paths in a sandbox, and turn the results into evidence your security team can keep.

    Sources

    Two distinct Claude deployment paths through AWSNext in the AI in the EU seriesClaude Platform on AWS vs Claude on Amazon Bedrock: What Actually ChangesCompare who operates inference, processes prompts and controls data location across two distinct Claude services on AWS.Read next

    Related reading

    Need an answer for your own residency requirement?

    Our EU AI Residency Assessment maps where your requests are processed, who operates the infrastructure and what evidence you can show afterwards.