Download examples/gateway/aws/gateway.yaml.example from SaylorTwift/claude-code: direct link, hf CLI and curl.
- Browser
- Download file 10.7 kB
-
https://huggingface.co/SaylorTwift/claude-code/resolve/main/examples/gateway/aws/gateway.yaml.example
- Command line
-
hf download hf://SaylorTwift/claude-code/examples/gateway/aws/gateway.yaml.example
-
curl -L -o gateway.yaml.example https://huggingface.co/SaylorTwift/claude-code/resolve/main/examples/gateway/aws/gateway.yaml.example
10.7 kB
| # gateway.yaml.example β Claude apps gateway config template, AWS-shaped (walkthrough Β§4). | |
| # | |
| # Okta IdP + Bedrock upstream, following the walkthrough at | |
| # https://code.claude.com/docs/en/claude-apps-gateway-on-aws. The active sections | |
| # below are a strict subset of the full configuration reference at | |
| # https://code.claude.com/docs/en/claude-apps-gateway-config; optional keys are | |
| # included commented-out. | |
| # | |
| # USAGE β this is the shippable TEMPLATE. Copy it to gateway.yaml and fill it in: | |
| # cp gateway.yaml.example gateway.yaml | |
| # setup.sh and terraform/ read gateway.yaml (your filled-in copy, which is | |
| # gitignored). Unlike the GCP example it is NOT published to a secret store: | |
| # the Dockerfile bakes it into the image at /etc/claude/gateway.yaml β the | |
| # container ENTRYPOINT runs `claude gateway --config /etc/claude/gateway.yaml`. | |
| # It holds no secret values; a config edit means an image rebuild (setup.sh | |
| # tags images with a hash of this file, so a re-run rebuilds automatically). | |
| # | |
| # Secret expansion: ${ENV_VAR} reads an env var; ${file:/path} reads a mounted file. | |
| # On ECS, the task definition injects the JWT / OIDC / Postgres secrets as ENV | |
| # VARS via its `secrets` field (valueFrom -> Secrets Manager ARN). On EKS you | |
| # may mount them as files instead and use ${file:/secrets/...}. | |
| # | |
| # BEFORE BUILD β replace every REPLACE_ME placeholder below (setup.sh refuses to | |
| # build the image while any remain β the config is baked in, so a half-filled | |
| # config would ship), and create the referenced secrets: | |
| # gateway-jwt-secret (setup.sh generates this) | |
| # gateway-oidc-client-secret (from the Okta admin console OIDC web app) | |
| # gateway-postgres-url (setup.sh generates this) | |
| # ββ Listener βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| listen: | |
| host: 0.0.0.0 | |
| port: 8080 # the target group forwards ALB :443 -> :8080 | |
| # Required. Fixes the IdP redirect_uri, the OIDC discovery doc, and the | |
| # gateway-token issuer so none are derived from the client-controlled Host | |
| # header (X-Forwarded-Host/-Proto are likewise never trusted). Set it to the | |
| # internal hostname you picked in the prerequisites β the Route 53 private | |
| # zone name your ACM certificate covers (e.g. | |
| # https://claude-gateway.internal.example.com). Unlike Cloud Run there is no | |
| # first-deploy placeholder dance: you choose the hostname up front, alias it | |
| # to the internal ALB after the deploy, and register the same host's | |
| # /oauth/callback on the Okta app. | |
| public_url: REPLACE_ME | |
| # Register this exact redirect URI on the Okta OIDC web application: | |
| # https://<public_url host>/oauth/callback | |
| # | |
| # Behind the internal ALB every request arrives via the load balancer, so the | |
| # gateway sees ALB-node peer IPs for all developers β set trusted_proxies so | |
| # X-Forwarded-For from those proxies is trusted and per-IP rate limiting / | |
| # audit IPs record the real client. ALB nodes take addresses from the subnets | |
| # the ALB is attached to, so list those subnets' CIDRs (the private subnets | |
| # from the prerequisites). | |
| # | |
| # NOTE: listing the ALB subnets' CIDRs trusts every host in those subnets as a | |
| # proxy β any co-located workload that can reach the ALB can then spoof the | |
| # client IP via X-Forwarded-For (audit logs, per-IP rate limits, IP | |
| # allowlists). Keep the ALB :443 ingress source (CORP_CIDR / corporate_cidr) | |
| # from overlapping these subnets, and don't share the subnets with untrusted | |
| # workloads. | |
| trusted_proxies: [REPLACE_ME] # e.g. [10.0.1.0/24, 10.0.2.0/24] | |
| # | |
| # Alternative β terminate TLS in the gateway itself instead of at the ALB: | |
| # tls: | |
| # cert: /certs/gateway.crt | |
| # key: /certs/gateway.key | |
| # ββ Identity provider β Okta βββββββββββββββββββββββββββββββββββββββββββββββββ | |
| oidc: | |
| issuer: REPLACE_ME # e.g. https://example.okta.com (or your custom auth server URL) | |
| client_id: REPLACE_ME # Okta OIDC web app client ID (not secret) | |
| client_secret: ${OIDC_CLIENT_SECRET} # EKS file mounts: ${file:/secrets/oidc-client-secret} | |
| allowed_email_domains: [REPLACE_ME] # e.g. [example.com] β reject id_tokens outside your org | |
| # The Okta org authorization server returns a thin id_token that omits email | |
| # and groups; the gateway fills them from /userinfo. | |
| userinfo_fallback: true | |
| # offline_access yields refresh tokens (silent renewal + the deprovision | |
| # leash); Okta emits groups only when the `groups` scope is requested AND the | |
| # app's groups claim filter allows them (Okta admin console -> the app's | |
| # Sign On tab -> OpenID Connect ID Token -> Groups claim filter). | |
| scopes: [openid, profile, email, offline_access, groups] | |
| # groups_claim: groups # Okta default. Entra app roles=roles; see the config reference | |
| # ca_cert_pem: ${file:/secrets/idp-ca.pem} # only for an IdP behind a private CA | |
| # ββ Sessions βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| session: | |
| jwt_secret: ${GATEWAY_JWT_SECRET} # >= 32 bytes; openssl rand -base64 32 | |
| # Okta issues refresh tokens (offline_access above), so sessions renew | |
| # silently and this mainly bounds deprovision latency. 8 is a sane default; | |
| # lower toward 1 for tighter revocation. Array form rotates keys: | |
| # [new, old] (index 0 signs, all verify). | |
| ttl_hours: 8 | |
| # ββ Store (REQUIRED β the gateway refuses to boot without it) βββββββββββββββββ | |
| store: | |
| postgres_url: ${GATEWAY_POSTGRES_URL} # private-subnet RDS; built with ?sslmode=verify-full by setup.sh | |
| # (the image trusts the RDS CA bundle via NODE_EXTRA_CA_CERTS β see Dockerfile) | |
| # ββ Upstreams β Amazon Bedrock βββββββββββββββββββββββββββββββββββββββββββββββ | |
| upstreams: | |
| - provider: bedrock | |
| # Must equal the region you provision in (setup.sh's AWS_REGION / | |
| # terraform's region): the IAM policy's inference-profile ARNs are scoped | |
| # to that region, and Bedrock model access is enabled there (cross-region | |
| # us.anthropic.* profiles need access in every spanned region). NOTE: the | |
| # walkthrough is scoped to US regions β the built-in model catalog maps to | |
| # us.anthropic.* (US-geo) profiles; a non-US region also needs a models: | |
| # list below (see the model catalog section). | |
| region: REPLACE_ME # e.g. us-east-1 | |
| auth: {} # AWS default credential chain: ECS task role / IRSA on EKS (preferred β no static keys) | |
| # base_url: https://bedrock-runtime.us-east-1.amazonaws.com # bedrock-runtime interface VPC endpoint, to keep model traffic off the public path | |
| # Add more upstreams for failover (tried topβbottom on 5xx/timeout/501): a | |
| # second region, or an anthropic/vertex fallback. See | |
| # https://code.claude.com/docs/en/claude-apps-gateway. | |
| # ββ Telemetry fan-out (OPTIONAL) βββββββββββββββββββββββββββββββββββββββββββββ | |
| # The CLI sends OTLP/HTTP to the gateway; the gateway fans out, stamping | |
| # user.id/user.email/user.groups server-side. On AWS, point at an OpenTelemetry | |
| # Collector (e.g. the AWS Distro for OpenTelemetry -> CloudWatch / Managed | |
| # Prometheus). When forward_to and public_url are both configured the gateway | |
| # pushes CLAUDE_CODE_ENABLE_TELEMETRY and the OTEL exporter selectors to every | |
| # client automatically β no per-developer config needed. | |
| # telemetry: | |
| # forward_to: | |
| # - url: https://otel-collector.internal.example.com:4318 | |
| # headers: | |
| # Authorization: ${file:/secrets/otlp-token} | |
| # metrics: true # safe aggregate counters (default) | |
| # logs: false # carries bash commands / tool inputs β opt in deliberately | |
| # traces: false | |
| # ββ RBAC + managed settings (OPTIONAL; first-match-wins, top -> bottom) βββββββ | |
| # With Okta as IdP, match on the group names the `groups` scope emits (subject | |
| # to the app's groups claim filter), or on email_domain. | |
| # managed: | |
| # policies: | |
| # - match: { groups: [engineering] } | |
| # cli: | |
| # availableModels: [claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5] | |
| # permissions: { deny: ["Read(./.env)", "Read(./secrets/**)"] } | |
| # - match: {} # catch-all floor β keep LAST | |
| # cli: | |
| # availableModels: [claude-sonnet-4-6, claude-haiku-4-5] | |
| # ββ Admin API (OPTIONAL β enables db-mode runtime config + spend caps) βββββββ | |
| # admin_groups needs a groups claim β Okta provides one via the `groups` scope | |
| # above β or use the bootstrap keys below instead. Named keys for attribution | |
| # in the audit log; 32-char minimum on key values. On ECS add these to the task | |
| # definition's `secrets` field (valueFrom -> a Secrets Manager ARN), same as the | |
| # JWT/OIDC/Postgres secrets above; on EKS you may use ${file:...}. | |
| # admin: | |
| # write_keys: | |
| # - id: terraform | |
| # key: ${GATEWAY_ADMIN_WRITE_KEY} | |
| # read_keys: | |
| # - id: reporting | |
| # key: ${GATEWAY_ADMIN_READ_KEY} | |
| # # admin_groups: [platform-finops] # Okta group names via the groups scope | |
| # ββ Model catalog (OPTIONAL for US regions) ββββββββββββββββββββββββββββββββββ | |
| # Default true: every built-in Claude model is exposed and auto-translated per | |
| # upstream (the built-in table already maps to us.anthropic.* cross-region | |
| # inference profiles). Set false + a models: list to pin IDs (e.g. an | |
| # application or provisioned-throughput inference-profile ARN). | |
| # NON-US REGIONS: the built-in us.anthropic.* mappings do not exist outside | |
| # the US geo β set auto_include_builtin_models: false and list your region's | |
| # inference profiles (eu.anthropic.*, apac.anthropic.*, ...) here, and widen | |
| # the geo prefix in the deploy's bedrock-invoke IAM policy to match. See the | |
| # models: guidance in the config reference: | |
| # https://code.claude.com/docs/en/claude-apps-gateway-config | |
| # auto_include_builtin_models: true | |
| # models: | |
| # - id: claude-opus-4-8 | |
| # label: Claude Opus 4.8 | |
| # upstream_model: { bedrock: us.anthropic.claude-opus-4-8 } | |