Bỏ qua để đến nội dung

Deploy và vận hành Claude apps gateway

Bài viết được dịch tự động từ bài viết gốc, chưa được kiểm tra lại bởi con người. Chỉ những bài viết có dấu tick xanh cạnh tiêu đề là đã được kiểm tra.

Trang này bao gồm phần vận hành của Claude apps gateway: đăng ký OAuth client trong identity provider (IdP), deploy gateway dưới dạng container, và chạy nó hằng ngày. Với mọi option trong gateway.yaml, xem Configuration reference.

Một production deployment đi theo bốn bước: setup IdP, deploy gateway, setup operations, và review security posture. Nếu sign-in hoặc boot thất bại, xem thẳng phần Troubleshooting bên dưới.

Đăng ký một confidential OAuth/OIDC web application với một redirect URI duy nhất, https://<gateway>/oauth/callback, và gán cho user/group nên có quyền truy cập gateway.

Bất kỳ IdP tương thích OIDC nào cũng dùng được: Okta, Entra ID, Google Workspace, Keycloak, Dex, PingFederate… IdP cần đáp ứng ba điều kiện: serve /.well-known/openid-configuration (HTTPS ở production), hỗ trợ authorization-code flow (PKCE bật mặc định), và trả email - tùy chọn groups - trong id_token hoặc qua userinfo endpoint.

Vài provider xử lý claim khác nhau:

  • Okta: org authorization server (https://example.okta.com) trả id_token “thin” thiếu email/groups - set oidc.userinfo_fallback: true. Custom authorization server (.../oauth2/default) thì không cần. groups chỉ xuất hiện khi scope groups được yêu cầu.
  • Microsoft Entra ID: issuer = https://login.microsoftonline.com/<tenant-id>/v2.0. Entra emit group Object ID chứ không phải tên - dùng GUID trong managed.policies.match.groups, hoặc dùng App Roles cho tên đọc được. Nếu tenant emit roles dưới roles, set oidc.groups_claim: roles.
  • Google Workspace: issuer = https://accounts.google.com. id_token của Google không có groups - dùng oidc.google_groups để tra qua Admin SDK Directory API, hoặc dùng allowed_email_domains/match.email_domain. Google cũng bỏ qua scope offline_access chuẩn - để có refresh token, set scopes: [openid, profile, email]extra_auth_params: { access_type: offline, prompt: consent }.

Gateway là một binary Linux đơn lẻ, scale ngang được vì các replica stateless và Postgres là lớp điều phối chung. Chạy nó theo cách bạn chạy stateless service khác trong môi trường của mình.

Vài quyết định định hình deployment:

  • Chi phí: không có license hay phí per-seat riêng cho gateway - nó là một phần của binary claude. Bạn trả tiền inference theo commitment cloud/Anthropic hiện có, cộng compute cho container và telemetry collector.
  • Bypass: gateway không tự enforce rằng model chỉ được gọi qua nó - một developer có credential riêng vẫn gọi thẳng provider được, nên chặn đường đó là quyết định network policy (ví dụ block egress đến api.anthropic.com trừ từ gateway).
  • Nhiều gateway: mỗi gateway là một deployment riêng với config riêng. CLI lưu trust fingerprint và credential theo từng gateway hostname.
  • Serverless: Cloud Run dùng được (set min-instances: 1 để tránh cold OIDC discovery). Lambda/Cloud Functions không dùng được vì gateway là HTTP server chạy dài hạn.

Mọi topology production đều đặt một L7 proxy (Ingress, Cloud Run front end, ALB) trước các replica plain-HTTP. Set listen.trusted_proxies thành dải nguồn của proxy để gateway đọc client IP từ X-Forwarded-For.

Build image riêng quanh binary claude từ release chuẩn:

  1. Tải bản Linux cho kiến trúc image của bạn từ một release cố định phiên bản.
  2. Verify với manifest.json ký GPG của release.
  3. Copy vào build context.

Image cần thêm: base image glibc (musl cần build linux-x64-musl/linux-arm64-musl cộng package bổ sung), một state directory ghi được (set CLAUDE_CONFIG_DIR vào đường dẫn ghi được như /tmp/.claude), và container command claude gateway --config /etc/claude/gateway.yaml.

Chạy gateway như một Deployment stateless thông thường: mount config từ ConfigMap và secret từ Secret; terminate TLS ở Ingress và set listen.public_url thành hostname Ingress; trỏ readiness probe vào GET /readyz và liveness probe vào GET /healthz.

Ví dụ đầy đủ trên AWS (ECS Fargate/EKS, RDS, Secrets Manager): Deploy on AWS.

Giữ listen.port mặc định 8080 hoặc set port: ${PORT}; set public_url thành origin reachable từ bên ngoài (thường là hostname internal load balancer, vì /login từ chối địa chỉ public và URL *.run.app resolve ra public); mount config như secret volume; set min-instances: 1 để tránh cold OIDC discovery.

Ví dụ đầy đủ trên Google Cloud (Cloud Run/GKE, Cloud SQL, Secret Manager): Deploy on Google Cloud.

Khi gateway đã chạy, push forceLoginMethod, forceLoginGatewayUrl, và parentSettingsBehavior: "merge" đến từng máy developer qua managed settings (MDM hoặc ghi trực tiếp managed-settings.json). Không có bước này, /login chỉ hiện account picker chuẩn, không có option gateway.

Gateway ghi hai luồng ra stderr, đều thân thiện JSON:

  • Audit events: JSON một dòng cho mỗi sự kiện liên quan bảo mật - config.load, session.mint, session.refresh, device.authorize, device.verify, auth.denied, access.denied, inference, managed.serve, desktop_bootstrap.serve, desktop_bootstrap.denied, spend.blocked, admin.denied.
  • Operational logs: dòng dạng [gateway] dễ đọc cho boot, warning, lỗi upstream. Biến CLAUDE_GATEWAY_LOG_LEVEL (info/warn/error, default info) kiểm soát verbosity - không ảnh hưởng audit events, luôn được emit.

GET /healthz là liveness probe, GET /readyz là readiness probe (verify store reachable). Cả hai đều exempt khỏi access_control.allow_cidrs. Discovery document /.well-known/oauth-authorization-server cũng chỉ trả 200 sau khi config load, OIDC discovery, xây upstream client, và Postgres migration đều thành công - dùng như end-to-end boot check.

Nếu Postgres down: session hiện tại vẫn hoạt động (bearer token validate cục bộ bằng JWT secret); sign-in mới thất bại (device flow cần Postgres); spend-limit enforcement fail open theo mặc định (đổi sang fail closed bằng enforcement.fail_closed_on_error: true nếu muốn chặn thay vì chạy unmetered); /readyz báo not-ready - nếu orchestrator gate traffic theo readiness, toàn bộ replica bị rút khỏi rotation cùng lúc; trỏ readiness probe vào /healthz thay vào đó nếu muốn developer đã đăng nhập tiếp tục làm việc qua store outage.

Nếu IdP down: session hiện tại hoạt động đến khi hết ttl_hours, login và refresh mới thất bại.

  1. Tạo secret mới, thêm vào đầu mảng session.jwt_secret.
  2. Roll deployment - token mới ký bằng secret mới, token cũ vẫn verify được.
  3. Sau ttl_hours cộng thêm biên độ an toàn, gỡ secret cũ và roll lại.

Rotate cũng là cách duy nhất để ép session hết hạn sớm (không có revocation theo từng session). Thay hẳn secret mà không giữ cái cũ trong mảng sẽ vô hiệu hóa mọi session đang tồn tại ngay lập tức.

Gateway giữ 5 bảng, tạo bởi migration lúc boot:

BảngNội dungRetention
kvDevice grant (TTL 10 phút) và bộ đếm rate-limitTTL theo dòng
spendBộ đếm spend period-to-date theo principal, tính bằng centadmin.spend_retention_months, default 13
spend_limitsCap đã cấu hìnhĐến khi xóa qua API
admin_auditLịch sử mutation Admin APIadmin.audit_retention_days, default 365
principal_emailsEmail, tên hiển thị, IdP group last-seen của mỗi principal (có PII)admin.identity_retention_days, default 90

Với spend limits đang dùng, mất database nghĩa là mất cả spend tracking và cap, không chỉ mất login lại - hãy backup định kỳ.

Replica stateless nên rolling restart an toàn bất kỳ lúc nào. Gateway chạy schema migration lúc boot. Migration là append-only nên rollback về binary cũ hơn (biết ít migration hơn) an toàn - nó bỏ qua các dòng thừa. Rollback cũng validate lại YAML theo schema của binary cũ, nên một config dùng key mới từ release sau sẽ fail boot trên bản cũ - gỡ key mới trước khi rollback.

Dữ liệuĐường điGửi cho Anthropic bởi gateway
Inference (prompt, completion)CLI → gateway → upstream của bạnChỉ khi Anthropic API là upstream được cấu hình
Telemetry (OTLP metrics, logs/traces opt-in)CLI → gateway → collector của bạnKhông bao giờ
Identity (email, groups, sub)IdP → gateway → JWT → CLIKhông bao giờ
Managed settingsYAML gateway của bạn → CLIKhông bao giờ
Audit logstderr gateway → aggregator của bạnKhông bao giờ

Gateway nằm trong network perimeter của bạn, nhưng laptop developer riêng lẻ không được coi là trusted:

  • Developer giữ JWT ngắn hạn thay vì raw upstream key. CLI-to-gateway dùng RFC 8628 device grant, và authorization-code exchange của gateway với IdP chạy PKCE mặc định.
  • Trang device-verification enforce same-origin POST và rate-limit theo IP theo RFC 8628 §5.1.
  • Request đi ra ngoài qua một SSRF guard: resolve DNS, chặn địa chỉ link-local và cloud-metadata cộng loopback mặc định, và pin connection vào IP đã resolve. RFC 1918 private range được cho phép có chủ đích vì IdP và OTLP collector thường nằm trên private IP.

Hai loại nguy cơ nằm ngoài phạm vi vì thuộc hạ tầng của bạn tự bảo vệ: gateway host bị compromise (host giữ upstream credential và phân phối managed settings cho mọi developer kết nối, nên kiểm soát gateway tương đương kiểm soát MDM của bạn), và OIDC provider độc hại (provider ký id_token mà gateway tin, nên nó có thể giả bất kỳ danh tính nào - bảo mật IdP là trách nhiệm của bạn).

user_code mà developer gõ vào trang /device dài 8 ký tự từ bảng chữ 20 ký tự (≈2.56×10¹⁰ tổ hợp), hết hạn sau 10 phút. Gateway áp rate-limit theo IP trên các endpoint device-grant, cấu hình qua rate_limits.

  • Data residency: data plane của gateway không gửi gì cho Anthropic trừ khi Anthropic API là upstream được cấu hình.
  • Host-process traffic: host process là Claude Code CLI, vẫn có thể gửi startup analytics và update check đến Anthropic. Với deployment egress nghiêm ngặt, set CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 trong environment container gateway.
  • Client analytics: CLI tự tắt usage analytics khi đăng nhập gateway.
  • Client machine: CLI của developer vẫn gửi WebFetch hostname check và version check đến Anthropic trừ khi CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1skipWebFetchPreflight: true được set.
  • TLS: serve public_url qua HTTPS ở production, từ listener của gateway (listen.tls) hoặc từ ingress terminate TLS phía trước.
Triệu chứngNguyên nhânCách khắc phục
/login của developer hiện account picker chuẩn thay vì màn hình Cloud gatewayforceLoginMethod/forceLoginGatewayUrl chưa set trong managed settings trên máy đóDeploy managed settings file đến thiết bị
Claude Desktop báo không fetch được bootstrap config/user/bootstrap trả 404: policy khớp user không có key desktop, hoặc không có policy nào khớpThêm block desktop vào policy khớp, hoặc vào base match: {}
CLI /login: Gateway hosts must be on your organization's private networkHostname gateway resolve ra ít nhất một IP publicĐảm bảo hostname chỉ resolve ra địa chỉ private trên máy developer
CLI /login: Gateway login requires a direct connection and does not support connecting through an HTTP proxyHTTPS_PROXY/HTTP_PROXY áp dụng cho gateway host và proxy resolve ra địa chỉ publicThêm gateway host vào NO_PROXY
Boot exit với lỗi validate config nêu store.postgres_urlChưa cấu hình PostgresSet store.postgres_url
Boot exit: requires the native binaryĐang chạy dưới Node thay vì native binaryCài Claude Code bằng phương thức standalone
/oauth/callback báo “Sign-in could not be completed”Email domain bị từ chối, id_token validate fail, hoặc email_verifiedfalseKiểm tra allowed_email_domains và claim email_verified
Sign-in không tự renew sau khi set oidc.scopesoffline_access bị bỏ khỏi overrideThêm lại offline_access nếu IdP hỗ trợ
Login hoạt động local nhưng fail sau ALBpublic_url chưa set, IdP nhận origin http:// nội bộ làm redirect_uriSet listen.public_url thành origin https:// bên ngoài