Module 21B of 30+
Cloud Provider
Integration

One Claude model, four on-ramps. The same doctor sees you at four hospitals — direct API, AWS Bedrock, Google Vertex AI, and Microsoft Azure. Six concepts on what actually changes: the gateway, the auth, and the bill — not the model.

Track 7: Production ⏱ ~19 min read 21B / 30+
Concept 1 of 6

Same model, four different front doors

Claude always runs on Anthropic's own infrastructure. Whether you call it directly or through AWS Bedrock, Google Vertex AI, or Microsoft Azure AI, the same model does the work. What changes is only the gateway, authentication, and billing your request passes through on the way in.

Your request hits the cloud provider's endpoint first, its identity system checks your credentials, and it forwards the payload to Anthropic's fleet. In code, three of the four paths are a one-line constructor swap; the fourth (Azure) uses a different SDK and response shape. Picking a provider is picking who handles the paperwork — not which model you get.

Concept 1 of 6

One specialist, four hospital networks

BEFORE: Dr. Claude is a specialist you can see at four networks: her own private clinic (direct API), General Hospital (AWS), City Medical (GCP), and Metro Health (Azure). Same doctor, same expertise, same consultation quality at every one.

PAIN: Your company's insurance only covered one network. Seeing Dr. Claude anywhere else meant out-of-network paperwork, a special exception, and legal reviewing every single appointment — a months-long tax before you could even book.

MAPPING: Now she operates in all four. If your existing cloud contract already covers a network, you book through it — no new vendor, no new legal review, the bill goes to the account you already have. Choosing your provider is choosing which network handles billing and paperwork, not which doctor you see.

Concept 1 of 6

What actually differs between the paths

  1. The SDK classDirect uses Anthropic(); Bedrock AnthropicBedrock(); Vertex AnthropicVertex(); Azure a separate chat-completions client.
  2. The authDirect uses an API key; Bedrock uses AWS IAM; Vertex uses Google ADC; Azure uses a key or Entra ID.
  3. The model ID + billEach path names the model differently and routes the charge to that cloud's invoice — per-token pricing stays the same.
  4. New-model lagDirect gets new models day 0; the clouds follow days to weeks later. Data residency shifts to your own cloud account.
Direct APIClaude
Bedrock(one model
Vertexon Anthropic
Azureinfra)
Concept 1 of 6

Which door do I walk through?

# Question: how should I reach Claude?

IF you need the newest model on day 0
   OR you're just prototyping:
  USE the direct API   # one key, no cloud setup

ELIF procurement already signed a
      cloud contract (AWS/GCP/Azure):
  USE that cloud's gateway
  # no new vendor, bill on existing account

ELSE:
  START direct, wrap it (Concept 5)
  # migrate later with one env var

The token price is identical everywhere. The real difference is organizational velocity, not cost per token.

Concept 1 of 6

Misconceptions

"Claude on a cloud provider is a different, weaker model."
It's the identical model on Anthropic's infrastructure. Only the gateway, auth, and billing change — the quality and behavior do not.
"Going through a cloud provider is cheaper per token."
Per-token pricing is the same. What you save is a new vendor review and a separate invoice — velocity, not unit cost.

Picking a provider is picking the plumbing, not the model. Gateway, auth, and bill differ; Claude is the same everywhere.

Choose the path that matches contracts you already have — or start direct and stay portable.

Concept 2 of 6

A managed inference gateway inside AWS

AWS Bedrock is not a place to run your agent code — it's a managed gateway that sits in front of Claude. Your app runs wherever you put it and sends calls to Bedrock's regional endpoint. Bedrock validates your IAM credentials, logs to CloudTrail, applies any Guardrails, forwards to Claude, and streams the answer back.

Think of it as "API Gateway for AI." You inherit AWS's regions, compliance certifications (SOC 2, HIPAA BAA, FedRAMP), and the ability to keep data in one region — without running any new servers. Two things change vs. direct: auth is AWS IAM, and the model ID has a special format.

Concept 2 of 6

The corporate mailroom that stamps every package

BEFORE: In a big company, you don't hand parcels straight to the courier. You drop them at the mailroom, which weighs, logs, and stamps each one before it leaves the building.

PAIN: Skip the mailroom and nobody can prove what left, who sent it, or whether it broke policy. For a regulated company, an unlogged package leaving the building is an audit failure waiting to happen.

MAPPING: Bedrock is that mailroom for Claude calls. Every request is checked against your IAM badge, stamped into CloudTrail, and optionally screened by Guardrails before it reaches the model — all under the AWS contract you already signed. You get the courier (Claude) plus a full paper trail.

Concept 2 of 6

From setup to first call

  1. Request model accessIn the Bedrock console, enable Claude under Anthropic. Usually instant for Haiku and Sonnet.
  2. Grant IAM permissionYour role needs bedrock:InvokeModel. No key in code — the instance role provides credentials in production.
  3. Use the Bedrock model IDNot claude-sonnet-4-6 but a prefixed ID like us.anthropic.claude-...-v1:0 for cross-region routing.
  4. Call and signThe client signs the request with SigV4 automatically and returns the same response shape as the direct API.
Concept 2 of 6

Pseudocode

# AUTH: AWS IAM via the standard credential chain
#   env vars -> ~/.aws -> instance role
client = BEDROCK_CLIENT(region = "us-west-2")

# MODEL ID: cross-region profile, NOT direct ID
model = "us.anthropic.claude-sonnet-4-6-...-v1:0"

TRY:
  reply = client.CREATE MESSAGE(
    model      = model,
    max_tokens = 1024,        # REQUIRED on Bedrock
    messages   = [user("Explain Bedrock.")])
  PRINT reply.text
CATCH api_error AS e:
  # 403 = IAM missing InvokeModel
  # 404 = wrong model-ID format
  PRINT "Bedrock error", e.status
Concept 2 of 6

Misconceptions

"The direct model ID works on Bedrock."
No — claude-sonnet-4-6 becomes anthropic.claude-...-v1:0 (or a us.-prefixed cross-region profile). The direct ID returns a ValidationException.
"Bedrock hosts and runs my agent code."
Bedrock only serves inference. Your agent code still runs on EC2, Lambda, or your laptop — Bedrock is the gateway it calls.

Bedrock = AWS IAM auth + a prefixed model ID + a mandatory max_tokens. Everything else matches the direct API.

The payoff: Claude under your existing AWS contract, with CloudTrail logging and optional Guardrails outside your code.

Concept 3 of 6

Claude from the GCP Model Garden

On Google Cloud, Claude lives in the Vertex AI Model Garden — GCP's catalog of foundation models. Enable Claude once per project, and Google exposes it as a serverless endpoint that accepts Anthropic-format calls. Your code uses the AnthropicVertex client.

The signature move is auth: Vertex uses Application Default Credentials (ADC). The SDK discovers a short-lived token from your gcloud login locally, or from the metadata server on Cloud Run / GKE — the same code, no key file, in every environment. Model IDs are date-pinned, like claude-sonnet-4-6@20250514.

Concept 3 of 6

The building's keycard vs. carrying a key

BEFORE: To enter a locked office you could carry a physical key — copy it, hand it out, hope nobody loses it. That's an API key: a secret you have to manage, store, and rotate yourself.

PAIN: Physical keys get copied, dropped, and forgotten in code. A key committed to a repo is a breach; a key that expired at 2am is an outage. Someone has to babysit every copy of it.

MAPPING: ADC is the building's keycard system. Your identity (your gcloud login, or the machine's attached service account) is recognized automatically, and a short-lived badge is issued on the spot. No key travels with your code — the environment vouches for you, and the badge expires on its own.

Concept 3 of 6

Enable, authenticate, call

  1. Enable the API + accept termsTurn on the Vertex AI API and enable Claude in Model Garden — once per GCP project.
  2. Let ADC handle authLocally: gcloud auth application-default login. In production: attach a service account with aiplatform.user — no key file.
  3. Pin the model by dateUse a date-stamped ID like claude-sonnet-4-6@20250514 so behavior doesn't shift under you.
  4. Call in a supported regionClaude is only in specific regions (e.g. us-east5). System prompts pass as a separate system param, same as direct.
Concept 3 of 6

Pseudocode

# AUTH: ADC resolves a short-lived token
#   gcloud login  OR  metadata server
client = VERTEX_CLIENT(
  project = env("GCP_PROJECT"),
  region  = "us-east5")   # Claude-enabled region

# MODEL ID: pin the date in production
model = "claude-sonnet-4-6@20250514"

TRY:
  reply = client.CREATE MESSAGE(
    model      = model,
    max_tokens = 1024,
    system     = "You are concise.",
    messages   = [user("What is Vertex AI?")])
  PRINT reply.text
CATCH api_error AS e:
  # 403 = SA missing aiplatform.user
  # 404 = model not enabled in this region
  PRINT "Vertex error", e.status
Concept 3 of 6

Misconceptions

"Claude on Vertex uses Gemini pricing."
No — it's the same per-token Anthropic rate, rolled into your GCP bill. GCP committed-use discounts can even make it cheaper.
"Any GCP region works, and I can drop the date."
Claude is only in specific regions (e.g. us-east5), and you should pin the date-stamped ID so a model update can't silently change behavior.

Vertex = ADC auth + date-pinned model IDs + a Claude-enabled region. The call shape matches the direct API exactly.

ADC means the same code runs on your laptop and on Cloud Run with zero key files to manage.

Concept 4 of 6

The one that uses a different SDK

Azure AI Foundry is Microsoft's unified AI platform. You deploy Claude from its model catalog as a serverless deployment, get an endpoint URL and key, and call it. But unlike Bedrock and Vertex, Azure does not use the Anthropic SDK.

Instead you use Microsoft's azure-ai-inference package, which speaks the chat-completions format (the OpenAI-style shape). You call complete() instead of messages.create(), and the answer comes back at choices[0].message.content — not content[0].text. Same model, genuinely different client and response shape.

Concept 4 of 6

Same power, different wall socket

BEFORE: Your laptop charger delivers the same electricity in any country. Plug it into the wall and it just works — at home.

PAIN: Fly abroad and the wall socket has a different shape. The electricity behind it is identical, but your plug physically won't fit. You need an adapter, or nothing charges — and the adapter's prongs sit in a different arrangement than you're used to.

MAPPING: Azure is that foreign socket. The power (Claude) is the same, but the plug shape (the SDK and JSON format) differs. You reach for the azure-ai-inference adapter, call complete(), and read the answer from a differently-named field. Once the adapter's in, it charges exactly the same.

Concept 4 of 6

Deploy, then call the Azure way

  1. Create + deployMake an Azure AI Foundry resource, deploy Claude as a "Serverless API," and name the deployment.
  2. Grab endpoint + keyCopy the endpoint URL and key into env vars — or use Entra Managed Identity in production (no key at all).
  3. Use the Azure clientBuild a ChatCompletionsClient and call complete() — the model name is your deployment name, not the Anthropic ID.
  4. Read the OpenAI shapeThe answer is at choices[0].message.content. Native Anthropic tool-use isn't available here.
Concept 4 of 6

Pseudocode

# AUTH: API key (dev) or Managed Identity (prod)
client = CHAT_COMPLETIONS_CLIENT(
  endpoint   = env("AZURE_AI_ENDPOINT"),
  credential = key(env("AZURE_AI_KEY")))

# NOTE: different method + message shape
TRY:
  reply = client.COMPLETE(
    model    = "my-claude-deployment",  # deployment name
    messages = [ system("Be concise."),
                 user("What is Azure AI?") ],
    max_tokens = 512)
  # response is OpenAI-shaped:
  PRINT reply.choices[0].message.content
CATCH http_error AS e:
  # 401 = bad key   404 = wrong deployment name
  PRINT "Azure error", e.status
Concept 4 of 6

Misconceptions

"Azure works just like Bedrock and Vertex."
It uses a different SDK (azure-ai-inference), a different method (complete()), and returns the OpenAI shape (choices[0].message.content).
"The model field takes the Anthropic model ID."
On Azure the model field is the deployment name you chose when deploying — not claude-sonnet-4-6. A mismatch returns a 404.

Azure is the odd one out: different SDK, complete() not messages.create(), and a chat-completions response shape.

In production, Entra Managed Identity removes API keys entirely — the runtime vouches for your app.

Concept 5 of 6

Hide all four behind one method

You've seen four clients with three auth systems and two response shapes. If your agent code calls those clients directly, it's welded to one cloud forever. The fix is the adapter pattern: one wrapper class whose chat() method always returns a plain string.

Internally the wrapper reads an environment variable (CLAUDE_PROVIDER), builds the right backend client, and normalizes the response — including Azure's different field path. Every other file in your codebase just calls client.chat(message). Switching clouds becomes a one-line config change, not a rewrite.

Concept 5 of 6

The universal travel adapter

BEFORE: Every country has its own socket shape. Without help you'd pack four different plugs and swap them at each border, hoping you grabbed the right one.

PAIN: Wiring four plug types into every device is brittle. Change destination and you're rewiring gear — and if you hardcode one country's plug, that device simply won't work anywhere else.

MAPPING: The wrapper is a universal travel adapter with one face your device plugs into. Flip a switch on the back (the env var) and it reshapes to whatever the wall needs. Your device (agent code) only ever sees the one familiar socket; the adapter absorbs every country's quirks.

Concept 5 of 6

One class, four backends

  1. Read the providerThe constructor reads CLAUDE_PROVIDER (direct / bedrock / vertex / azure), defaulting to direct.
  2. Build the right clientA switch picks the matching backend and its auth — the only place in the codebase that knows the clouds exist.
  3. Resolve the model IDEach provider maps to its own model-ID format via env vars, so the caller never sees the difference.
  4. Normalize the responsechat() returns a plain string — converting Azure's choices[0]... path so every path looks identical.
Concept 5 of 6

Pseudocode

CLASS ClaudeClient:
  INIT(provider = env("CLAUDE_PROVIDER", "direct")):
    self.backend = BUILD_BACKEND(provider)

  FUNCTION chat(message, system?):
    model = MODEL_ID_FOR(self.provider)

    IF provider == "azure":
      r = backend.complete(model, msgs)
      RETURN r.choices[0].message.content
    ELSE:  # direct / bedrock / vertex
      r = backend.create_message(model, msgs)
      RETURN r.content[0].text

# every other file just does:
answer = ClaudeClient().chat("Hello!")
Concept 5 of 6

Misconceptions

"A wrapper just adds pointless indirection."
It's the one seam that keeps a whole codebase portable. Without it, a procurement-driven move to Bedrock means editing every call site.
"The wrapper can ignore Azure's response difference."
It can't — Azure returns choices[0].message.content while the others use content[0].text. The adapter must normalize both to a string.

One env var, CLAUDE_PROVIDER, swaps the entire cloud with zero code changes. The wrapper is the only file that knows which cloud you're on.

Start direct for speed, wrap from day one, and migrate to a cloud later as a config change — not a rewrite.

Concept 6 of 6

Pick the cloud you're already standing in

Because Claude is identical everywhere, the choice isn't about the model — it's about your existing contracts, identity system, and data-residency rules. The right provider is almost always the one your organization is already committed to.

Need the newest model on day 0, or just prototyping? Direct API. Already deep in AWS, GCP, or Azure? Use that cloud so there's no new vendor review and the bill lands on an account you already have. Not sure yet? Start direct behind the wrapper and let the decision come later — painlessly.

Concept 6 of 6

Which bank branch to open an account at

BEFORE: The money (Claude) is the same currency at every branch. What differs is which bank you already have a relationship with, where your paychecks land, and which ATMs are free for you.

PAIN: Open an account at a brand-new bank and you re-do every check: identity verification, new paperwork, new logins, reconnecting your direct deposits. All that friction for the exact same dollars.

MAPPING: If your salary already deposits at one bank, you bank there — the accounts, the trust, and the compliance are already in place. Choosing a cloud provider works the same way: go where your contracts, identity, and data already live, and the same Claude costs you far less friction.

Concept 6 of 6

The migration path most teams take

  1. Stage 1 — prototypeDirect API. One key, zero cloud setup, fastest to ship.
  2. Stage 2 — scalingDirect API behind the provider-agnostic wrapper. Same speed, but portable.
  3. Stage 3 — enterpriseMove to Bedrock / Vertex / Azure when procurement or data residency requires it — a one-line switch.
  4. Match your stackAWS-native → Bedrock; GCP → Vertex; Microsoft-heavy → Azure; none → direct.
Concept 6 of 6

Which provider, in one glance

# Which cloud should host my Claude calls?

IF need newest model day-0 OR prototyping:
  → Direct API      # fastest, day-0 models

IF AWS-native (EA/BAA, S3, EC2):
  → AWS Bedrock     # + Guardrails, Knowledge Bases

IF on GCP (BigQuery, Cloud Run, GKE):
  → Vertex AI       # ADC auth, CUD discounts

IF Microsoft-heavy (Entra, M365, Azure):
  → Azure AI        # Managed Identity, no keys

ELSE:
  → Direct + wrapper  # migrate later, 1 env var
Concept 6 of 6

Misconceptions

"Pick the 'best' provider by benchmarking the model."
The model is identical on all four. Benchmarking them against each other measures noise — decide on contracts, identity, and data residency instead.
"Choosing a cloud early locks me in forever."
Not if you built the wrapper. Migration between providers is a one-line env-var change, so you can start direct and move when the business reason appears.

Choose the cloud you already live in. Existing contracts, identity, and data residency decide it — not model quality, which is the same everywhere.

Start direct behind the wrapper; graduate to Bedrock, Vertex, or Azure as a config change when procurement unlocks.

Test the core insight

One question per concept. Tap to reveal the answer.

Open the full module on desktop

The desktop version is the full build — complete Python and Node clients for Bedrock, Vertex, and Azure with real auth and error handling, Bedrock Guardrails and Knowledge Bases, Entra Managed Identity, the full provider-agnostic wrapper class, and a hands-on lab that calls Claude across all four providers.

Open M21B on Desktop → Full cloud build · Bedrock + Vertex + Azure + wrapper · ~75 min

⌂ All modules · Course index

Module 21B of 30+ · Track 7: Production Deployment