Technical Blueprint · Document 2 of 3

Private Claude Deployment on AWS Bedrock in ca-central-1

Audience: Infrastructure engineering, cloud platform, and security teams Region of record: AWS Canada (Central), ca-central-1 (Montreal) Companion documents: Executive Summary · Alternative Platform (OpenAI) Analysis
Reader's note on figures and product behavior.

The pricing rates, the ≈$110/month operating overhead, and the ≈$43,320 annual forecast are planning inputs for modeling; on-demand model inference is consumption-billed and therefore variable, so every total is an envelope to size against, not a contract. Configuration keys, file paths, and registry locations reflect the current Anthropic/AWS enterprise deployment mechanism as verified against vendor documentation. Model access and per-region pricing must be confirmed in the live AWS console for ca-central-1 before procurement.

1. Component summary (high level)

The deployment is five components, all provisioned in ca-central-1:

#ComponentPurposeAWS/vendor service
1Managed desktop clientNative Claude app in third-party inference mode, centrally locked downClaude Desktop (Anthropic)
2Model hostingRuns the Claude model inside our accountAWS Bedrock
3Private network pathInference over the AWS backbone, no public internetAWS PrivateLink (interface VPC endpoint)
4Envelope encryptionCustomer-managed keys for data and audit trailAWS KMS (CMK)
5Audit, identity & residency enforcementPer-user auth, logging, region lockIAM Identity Center, CloudWatch, S3, AWS Organizations SCP, Fargate/ALB for identity routing

The rest of this document specifies each, then the client and MDM configuration, the total-cost model, and the detailed risk and tampering analysis.

2. Core architectural requirements

Two properties define success: zero data transfer to Anthropic's or OpenAI's cloud, and a hard geographic perimeter fixed to ca-central-1. Every control exists to satisfy one or both.

2.1 Zero data transfer to the AI vendors

The objective is that no prompt content — message text, attached source code, retrieved internal context, or model output — ever reaches an Anthropic-operated or OpenAI-operated cloud environment. This rests on one architectural decision plus three network controls.

The decision is to run the desktop client in third-party inference mode against AWS Bedrock rather than its default first-party mode. In default mode the client authenticates to Anthropic's own service and inference happens on Anthropic infrastructure. In third-party mode the client is told, through managed configuration, that its inference provider is bedrock; it then signs and sends model-invocation requests directly to the AWS Bedrock runtime endpoint in our account and region. Anthropic supplies the model weights that AWS hosts inside Bedrock, but the request/response path runs between the corporate device and our own AWS region. Anthropic's cloud is not a hop on that path, and AWS Bedrock does not use prompts for training or share them with Anthropic.

Three reinforcing network controls ensure a request cannot silently leave that path:

  • Private-only egress via AWS PrivateLink. Inference is routed to an interface VPC endpoint for the Bedrock runtime, so the request resolves to a private IP inside the corporate VPC and traverses the AWS backbone rather than the public internet.
  • Egress allow-listing on the client sandbox. The desktop client's agent sandbox is constrained to an explicit host allow-list — the private Bedrock endpoint, the AWS identity endpoints, and the minimal launch hosts. Everything else is denied by default.
  • Perimeter firewall alignment. The corporate egress firewall permits only that same host set, so a misconfigured client physically cannot reach a public inference endpoint.
Honest exception for auditors.

To launch, the Claude desktop app fetches its workspace VM bundle and bundled Claude Code binary from downloads.claude.ai (an Anthropic host) at session start. This is application delivery — no prompt content flows over it. Organizations requiring a fully self-contained launch path use the offline installer variant, which packages both components and removes the host. Document this so downloads.claude.ai in firewall logs is not mistaken for data egress.

2.2 Geographic perimeter — Canadian data residency

All model processing and logging are pinned to ca-central-1, enforced at four layers so no single misconfiguration breaches the boundary:

  • Model access is granted only in ca-central-1. Bedrock model access is per region; enable the required models in Montreal and nowhere else in the production account.
  • The client is pinned to the region via inferenceBedrockRegion, and to the regional private endpoint via inferenceBedrockBaseUrl.
  • In-region invocation is mandated — not geographic cross-region inference. This is the most easily missed residency control. AWS Bedrock offers cross-region inference profiles (geography prefixes such as us. or eu.) that transparently distribute a request across multiple regions within a geography. For strict Canadian residency this is a defect: a request could be served outside Montreal. Invoke the model in-region, constrained to ca-central-1, and validate that any Canada-scoped profile is genuinely contained to ca-central-1. The identifier ca.anthropic.claude-3-5-sonnet-20241022-v2:0 must be verified in the console to confirm Canada-contained inference before it is trusted for residency; if it is not strictly contained, use the direct in-region model identifier instead.
  • Residency is enforced by policy, not convention. An AWS Organizations Service Control Policy (SCP) and IAM condition keys deny any bedrock:InvokeModel* call whose requested region is not ca-central-1.

Auditing and storage follow the same rule: CloudWatch log groups, the S3 audit bucket, the KMS key, and supporting resources are all created in ca-central-1.

3. The client in hybrid-cloud mode

The native Claude desktop client is not replaced or forked; a managed configuration flips it from first-party to third-party inference.

What changes. On launch, the client reads a managed configuration delivered by device-management tooling. Because it sets inferenceProvider to bedrock with a region and credential source, the client presents a "start in third-party deployment" path instead of an Anthropic (claude.ai) sign-in, and every model call is signed as an AWS Bedrock InvokeModel request against the configured ca-central-1 endpoint.

What does not change. The application UI, local agentic tooling, and on-device workspace continue to run locally. The client is "hybrid" precisely here: interface and orchestration are local; model inference is a private call into our AWS cloud. No prompt is brokered through an Anthropic SaaS tenant.

Authentication. For a 100-seat rollout needing per-user attribution in AWS CloudTrail, use in-app AWS sign-in through IAM Identity Center, federated to the corporate IdP (Microsoft Entra ID, Okta, or equivalent). Each user signs in once; the app exchanges that session for short-lived AWS credentials scoped to one account and permission set, making every request attributable to a named user. A shared bearer token is simpler but loses attribution and is appropriate only for a short proof-of-concept.

Feature reduction. Capabilities that broaden the client's data surface — user-added plugin marketplaces, arbitrary skill creation, and high-risk tools such as shell execution and "computer use" — are disabled via managed keys.

4. Implementation steps

4.1 AWS perimeter controls

A.1 — Enable model access in ca-central-1 only. In the AWS Bedrock console for Montreal, request access to the specific Claude model(s) to be used; confirm no equivalent access is enabled in out-of-country regions in the production account.

A.2 — Identity and permission boundary. In IAM Identity Center, create a permission set whose inline policy allows only Bedrock inference, region-scoped:

IAM permission set — inline policy (JSON)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"],
      "Resource": "*",
      "Condition": { "StringEquals": { "aws:RequestedRegion": "ca-central-1" } }
    }
  ]
}

Set the permission-set session duration to 8–12 hours.

A.3 — Customer-managed KMS key (envelope encryption). Create a customer-managed KMS key (CMK) in ca-central-1. CloudWatch log groups and the S3 audit bucket encrypt with this CMK, so the data keys protecting log and object payloads are wrapped by a key whose policy we control. Restrict the key policy to the specific log-delivery and application roles, enable automatic annual rotation, and enable CloudTrail on the key so every Encrypt/Decrypt/GenerateDataKey call is audited. Because the CMK is customer-managed, the organization — not Anthropic or AWS — holds the authority to revoke the ability to decrypt the audit trail.

A.4 — Route inference over AWS PrivateLink. Create an interface VPC endpoint for the Bedrock runtime (com.amazonaws.ca-central-1.bedrock-runtime) across private subnets, with a security group permitting HTTPS only from corporate device CIDRs and private DNS enabled. Attach a VPC endpoint policy allowing only bedrock:InvokeModel* and only when the requested region is ca-central-1. Inference then resolves to a private IP inside the VPC and traverses the AWS backbone. Point the client at this endpoint via inferenceBedrockBaseUrl.

A.5 — Lock the region with an SCP. At the AWS Organizations level, attach an SCP to the OU containing the production account:

AWS Organizations SCP — region lock (JSON)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyBedrockOutsideCanada",
      "Effect": "Deny",
      "Action": "bedrock:*",
      "Resource": "*",
      "Condition": { "StringNotEquals": { "aws:RequestedRegion": "ca-central-1" } }
    }
  ]
}

This makes residency provable: even a misconfigured client cannot invoke a model outside Montreal.

A.6 — Identity/routing tier. For the in-app AWS sign-in flow and operational tooling, run a small containerized tier on AWS Fargate behind an Application Load Balancer (ALB), in ca-central-1. It does not sit in the prompt data path — inference goes device-to-Bedrock over PrivateLink — but provides a controlled surface for identity brokering and connectivity testing. Its cost is the "Identity & Routing Container Compute" TCO layer.

4.2 Client endpoint configuration

The managed configuration is authored once in the client's built-in Configure Third-Party Inference window on an admin workstation, validated, then exported for fleet deployment. The JSON below expresses the configuration schema deployed.

Precision note (corrects a common misconception).

The file claude_desktop_config.json at ~/Library/Application Support/Claude/ (macOS) or %APPDATA%\Claude\ (Windows) is the client's MCP-server configuration file. The third-party inference managed profile below is delivered through the managed-policy channel (macOS Managed Preferences / Windows registry policy) and, on an authoring machine, staged under Claude-3p/configLibrary/. The keys are identical regardless of transport; only the delivery location differs. Both are shown so the distinction is unambiguous.

Managed third-party inference profile (schema — authored in-app, exported to MDM):

Managed third-party inference profile (JSON)
{
  "inferenceProvider": "bedrock",
  "inferenceBedrockRegion": "ca-central-1",
  "inferenceBedrockBaseUrl": "https://bedrock-runtime.ca-central-1.amazonaws.com",
  "inferenceBedrockSsoStartUrl": "https://d-xxxxxxxxxx.awsapps.com/start",
  "inferenceBedrockSsoRegion": "ca-central-1",
  "inferenceBedrockSsoAccountId": "123456789012",
  "inferenceBedrockSsoRoleName": "BedrockInference",
  "inferenceModels": [
    {
      "name": "ca.anthropic.claude-3-5-sonnet-20241022-v2:0",
      "labelOverride": "Claude 3.5 Sonnet (ca-central-1)",
      "anthropicFamilyTier": "sonnet",
      "isFamilyDefault": true
    }
  ],
  "disableDeploymentModeChooser": true,
  "userPluginMarketplacesEnabled": false,
  "userPluginUploadsEnabled": false,
  "skillCreationEnabled": false,
  "disableBundledSkills": true,
  "disabledBuiltinTools": ["Bash", "computer"],
  "coworkEgressAllowedHosts": [
    "bedrock-runtime.ca-central-1.amazonaws.com",
    "oidc.ca-central-1.amazonaws.com",
    "portal.sso.ca-central-1.amazonaws.com"
  ]
}

Key notes:

  • inferenceBedrockBaseUrl is the host-origin override pinning the client to the regional private (PrivateLink) endpoint. In production, set it to the private-DNS name of the interface VPC endpoint from A.4; the public regional hostname above is only the schema shape.
  • inferenceModels is an array of Bedrock inference-profile identifiers (optional labelOverride for a readable picker label), not a single scalar field.
  • The intent to disable the design/skills marketplace and computer-use maps to userPluginMarketplacesEnabled: false (plus skillCreationEnabled/disableBundledSkills) and disabledBuiltinTools: ["Bash", "computer"]. disableDeploymentModeChooser: true hides the claude.ai sign-in path so users can only start in the sanctioned Bedrock deployment.

Client MCP config file locations (reference — MCP servers, not inference):

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

4.3 MDM governance (Windows machine policy)

On Windows, the exported profile is delivered to the machine-policy registry hive so users cannot alter it. The app reads managed configuration from HKLM\SOFTWARE\Policies\Claude (highest precedence); when any value is present directly under that key, the app treats the configuration as organization-managed, ignores the per-user hive, and renders the in-app configuration window read-only. Two mechanical constraints must be honored or the push silently fails: values must sit directly under the key (never a nested subkey) and be written as REG_SZ (REG_DWORD accepted for booleans/integers). REG_EXPAND_SZ, REG_QWORD, REG_MULTI_SZ, and REG_BINARY are unreadable or harmful (a stray REG_EXPAND_SZ counts as "machine policy present" while supplying no value, disabling user policy without configuring anything).

Windows machine policy — Claude Desktop 3P (PowerShell)
# Machine-wide Claude Desktop 3P (Bedrock / ca-central-1) managed configuration
# Writes REG_SZ values directly under HKLM:\SOFTWARE\Policies\Claude
$Key = 'HKLM:\SOFTWARE\Policies\Claude'
New-Item -Path $Key -Force | Out-Null

# --- Inference provider + region pin ---
New-ItemProperty -Path $Key -Name 'inferenceProvider'        -Value 'bedrock'        -PropertyType String -Force | Out-Null
New-ItemProperty -Path $Key -Name 'inferenceBedrockRegion'   -Value 'ca-central-1'   -PropertyType String -Force | Out-Null
New-ItemProperty -Path $Key -Name 'inferenceBedrockBaseUrl'  -Value 'https://bedrock-runtime.ca-central-1.vpce.amazonaws.com' -PropertyType String -Force | Out-Null

# --- Per-user AWS sign-in (IAM Identity Center) ---
New-ItemProperty -Path $Key -Name 'inferenceBedrockSsoStartUrl' -Value 'https://d-xxxxxxxxxx.awsapps.com/start' -PropertyType String -Force | Out-Null
New-ItemProperty -Path $Key -Name 'inferenceBedrockSsoRegion'   -Value 'ca-central-1' -PropertyType String -Force | Out-Null
New-ItemProperty -Path $Key -Name 'inferenceBedrockSsoAccountId'-Value '123456789012' -PropertyType String -Force | Out-Null
New-ItemProperty -Path $Key -Name 'inferenceBedrockSsoRoleName' -Value 'BedrockInference' -PropertyType String -Force | Out-Null

# --- Model list (JSON array as a single REG_SZ string) ---
$models = '[{"name":"ca.anthropic.claude-3-5-sonnet-20241022-v2:0","labelOverride":"Claude 3.5 Sonnet (ca-central-1)","anthropicFamilyTier":"sonnet","isFamilyDefault":true}]'
New-ItemProperty -Path $Key -Name 'inferenceModels' -Value $models -PropertyType String -Force | Out-Null

# --- Feature lockdown (booleans as REG_SZ 'true'/'false') ---
New-ItemProperty -Path $Key -Name 'disableDeploymentModeChooser'   -Value 'true'  -PropertyType String -Force | Out-Null
New-ItemProperty -Path $Key -Name 'userPluginMarketplacesEnabled'  -Value 'false' -PropertyType String -Force | Out-Null
New-ItemProperty -Path $Key -Name 'userPluginUploadsEnabled'       -Value 'false' -PropertyType String -Force | Out-Null
New-ItemProperty -Path $Key -Name 'skillCreationEnabled'           -Value 'false' -PropertyType String -Force | Out-Null
New-ItemProperty -Path $Key -Name 'disableBundledSkills'           -Value 'true'  -PropertyType String -Force | Out-Null
New-ItemProperty -Path $Key -Name 'disabledBuiltinTools'           -Value '["Bash","computer"]' -PropertyType String -Force | Out-Null

Write-Host 'Claude Desktop machine policy applied. Restart the app to load managed configuration.'

On macOS the equivalent is a .mobileconfig profile landing at /Library/Managed Preferences/com.anthropic.claudefordesktop.plist, deployed via Jamf, Kandji, or Intune; the same keys apply. In both cases: deploy the configuration first, then the app, so a user's first launch lands directly in the managed Bedrock deployment with no window to sign in to a public account.

5. Total Cost of Ownership (100 users, 12 months)

5.1 Assumptions

Fixed AWS platform overhead ≈ $110 USD/month (≈ $1,320/year) covering Fargate compute for the identity/routing tier, the ALB, PrivateLink interface endpoints, CloudWatch ingestion, and the KMS key(s). Inference is modeled per user per month at the on-demand Bedrock rate for ca-central-1: Claude 3.5 Sonnet — input $3.00 / 1M tokens, output $15.00 / 1M tokens. The reference workload is ≈ 5.83M input and ≈ 1.17M output tokens per user per month (~5:1 read-to-generate ratio, after prompt caching), which at the Claude rate is ≈ $35.00 per user per month of inference.

5.2 Layer breakdown

#Operational layerWhat it coversAnnual (100 users)
1Identity & Routing Container ComputeFargate tasks + ALB hours and LCU processingportion of $1,320
2Networking Perimeter ProcessingPrivateLink endpoint hourly baseline (per-AZ) + per-GB transitportion of $1,320
3Auditing, Compliance & StorageKMS CMK, encrypted CloudWatch ingestion/retention + S3 audit bucket with lifecycle tieringportion of $1,320
Fixed platform subtotal (Layers 1–3)≈ $1,320
4Core Model Inference (consumption)On-demand Bedrock token billing, ≈$35/user/mo≈ $42,000
Total — Claude ecosystem≈ $43,320

The headline is dominated (~97%) by consumption-billed inference. Strategic implication: optimize token consumption, not infrastructure. A 20% reduction in effective input tokens (readily achievable via prompt caching) saves more than the entire Fargate/PrivateLink/CloudWatch/KMS stack costs in a year. Treat $43,320 as a budgeting envelope with a usage-driven variance band, and stand up a monthly CloudWatch/Cost Explorer review against per-user token dashboards.

6. Risk, failure-mode, and tampering analysis

This is the section a security reviewer will scrutinize. Each risk lists how it could cause a failed security check or arise from end-user tampering, and the mandatory control.

6.1 Cross-region data leakage (residency failure). How it fails: a geographic cross-region inference profile (e.g. us./eu. prefixes) serves a request outside Canada, or a failover routes cross-border. Control: mandate in-region invocation; account-wide SCP + IAM aws:RequestedRegion conditions + a VPC-endpoint policy hard-deny any Bedrock call outside ca-central-1; explicitly do not configure geographic cross-region inference; alarm on any denied out-of-region call.

6.2 End-user tampering with local configuration. How it fails: a user edits local settings to change the provider, add a public endpoint, or re-enable a disabled tool. Control: deploy configuration as machine policy (HKLM\SOFTWARE\Policies\Claude / macOS Managed Preferences), which makes the in-app configuration window read-only and ignores user-hive overrides; disableDeploymentModeChooser: true removes the public sign-in path. Residual: a local admin on an unmanaged device could still alter the registry — so this control depends on users not having local admin and on MDM enrollment being enforced. Non-enrolled or local-admin devices are the primary tampering exposure and must be blocked from the deployment.

6.3 Shadow AI / bypass. How it fails: a frustrated user pastes sensitive data into public ChatGPT or claude.ai in a browser, defeating the whole control set. Control: make the sanctioned tool genuinely capable (this is why feature reduction must be surgical, not blanket), pair with corporate egress controls/CASB that block or log public AI endpoints, and monitor adoption. This is a people-and-adoption risk as much as a technical one and is often the real point of failure.

6.4 Data exfiltration via plugins, extensions, or tools. How it fails: a user-added MCP server, plugin, or a high-risk built-in tool (shell, computer-use) moves data to an unapproved destination. Control: userPluginUploadsEnabled: false, userPluginMarketplacesEnabled: false, skillCreationEnabled: false, signed-extensions enforcement, disabledBuiltinTools: ["Bash","computer"], and a sandbox egress allow-list limited to our endpoints.

6.5 Endpoint compromise. How it fails: this architecture protects the inference path, not the laptop. Call transcripts and data live on the endpoint before and after inference; a compromised device exposes them regardless of Bedrock controls. Control: full-disk encryption, EDR, MDM enrollment, and DLP remain prerequisites, not replaced by this design. State plainly to reviewers that endpoint security is in scope and assumed.

6.6 Credential and key mismanagement. How it fails: a shared bearer token gives unattributable access; an over-broad KMS key policy lets the wrong role decrypt logs. Control: per-user IAM Identity Center sign-in (not a shared token) in production; inference-only permission set; least-privilege KMS key policy with rotation and CloudTrail on key usage.

6.7 Audit logs containing sensitive prompt content. How it fails: CloudWatch/S3 logs capture full prompt text (including customer data), creating a secondary data store to protect and retain. Control: decide deliberately what is logged (prefer request metadata over full prompt/response bodies where the use case allows), encrypt all tiers under the CMK, keep them in ca-central-1, and apply the retention lifecycle in §7.

6.8 Vendor launch dependency. How it fails: reliance on downloads.claude.ai at launch is flagged as vendor egress. Control: document it as app-code-only, or adopt the offline installer to remove it.

6.9 Model/region availability drift. How it fails: a model is deprecated, or availability/pricing in ca-central-1 changes, breaking the deployment or the residency assumption. Control: validate model availability and pricing in the live console before rollout; monitor AWS change notices; keep an in-region fallback model identified.

7. Optimization directives (mandatory)

7.1 Prompt caching (up to ~90% input savings). The single largest cost lever. Design prompts so the large, stable prefix (system instructions, tool/schema definitions, retrieved reference context) is cache-anchored and only the volatile user turn varies; monitor cache-hit rates in CloudWatch and treat a falling rate as a budget incident. The TCO model assumes this discipline is in place.

7.2 Log-retention lifecycle. Keep hot, queryable logs in CloudWatch for a defined window (e.g. 30–90 days), export to the S3 audit bucket for the compliance retention period, and transition aged objects to infrequent-access then Glacier before expiry. All tiers stay encrypted under the CMK and stay in ca-central-1.

7.3 Regional routing lock. The SCP, IAM conditions, VPC-endpoint policy, and in-region-invocation mandate together prevent any request being served outside ca-central-1 — a compliance control (no data leaves Canada) and a cost control (no cross-region transfer/failover charges) at once.

7.4 Continuous residency proof. Schedule a control test that attempts an out-of-region Bedrock call and confirms the SCP denies it, plus a CloudTrail query confirming 100% of production InvokeModel events carry awsRegion = ca-central-1. Residency asserted but never re-tested will eventually drift.

7.5 Least privilege and attribution. Per-user sign-in, inference-only permission sets, and a tightly scoped KMS key policy turn the audit trail from a log file into evidence.