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

Deploy Claude apps gateway trên AWS

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.

Ví dụ này cấp phát Claude apps gateway trên AWS với Amazon Bedrock làm model upstream, dùng Amazon ECS trên AWS Fargate hoặc Amazon EKS cho compute. Okta là IdP mẫu, nhưng bất kỳ IdP tương thích OIDC nào cũng dùng được.

Gateway chạy như một HTTPS endpoint private trên mạng của bạn mà developer đăng nhập qua IdP. Session Claude Code của họ tiếp cận model Claude trên Amazon Bedrock qua IAM role của gateway, nên không credential model nào nằm trên máy developer. Cấu hình tham chiếu cấp phát:

  • Amazon ECS trên Fargate hoặc Amazon EKS chạy container gateway
  • Amazon ECR repository cho image gateway
  • Amazon RDS for PostgreSQL trong private subnet, không public, cho store của gateway
  • AWS Secrets Manager secret cho JWT signing key, OIDC client secret, và Postgres URL
  • IAM role với bedrock:InvokeModelbedrock:InvokeModelWithResponseStream, gắn làm ECS task role hoặc qua IRSA trên EKS
  • Internal Application Load Balancer cho HTTPS
  • Tài khoản AWS có quyền tạo các resource trên, AWS CLI v2 đã authenticate, Docker cài local
  • Một VPC với ít nhất hai private subnet ở AZ khác nhau, có NAT gateway cho outbound
  • Okta OIDC web application với redirect URI https://<gateway-host>/oauth/callback
  • Một hostname TLS cho gateway (thường là DNS name nội bộ trong Route 53 private hosted zone), kèm ACM certificate

Mọi lệnh trên trang này đọc bốn giá trị từ shell: AWS_REGION, ACCOUNT_ID, VPC_ID, PRIVATE_SUBNETS.

Terminal window
export AWS_REGION=us-east-1
export ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
export VPC_ID=<your-vpc-id>
export PRIVATE_SUBNETS="<subnet-id-a> <subnet-id-b>"

Chọn region US mà Bedrock serve model Claude bạn cần - ví dụ dựa trên catalog built-in resolve ra us.anthropic.* inference profile. Ở region ngoài US, thêm block models: với inference-profile ID phù hợp và đổi ARN prefix trong IAM policy.

  1. Tạo security group: ba group chain traffic - mạng công ty → load balancer (443), load balancer → gateway (8080), gateway → Postgres (5432).

  2. Tạo IAM role và nộp use case form: gateway chạy với task role chỉ có quyền invoke model Bedrock, cover cả ARN inference-profile lẫn foundation-model:

Terminal window
cat > bedrock-invoke.json <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"],
"Resource": [
"arn:aws:bedrock:${AWS_REGION}:${ACCOUNT_ID}:inference-profile/us.anthropic.*",
"arn:aws:bedrock:*::foundation-model/anthropic.*"
]
}]
}
EOF

Sau đó aws iam create-role cho task role (trust ecs-tasks.amazonaws.com) và execution role (thêm AmazonECSTaskExecutionRolePolicy cộng quyền đọc ba secret ở Secrets Manager). IAM policy cấp quyền gọi Bedrock; nếu chưa tài khoản nào trong account nộp use case form một lần của Anthropic, hãy mở Bedrock console, chọn model Anthropic từ Model catalog, và hoàn tất form.

  1. Cấp Amazon RDS for PostgreSQL: chạy trong private subnet, không public address, storage encryption bật, engine pin ở Postgres 16, parameter group set rds.force_ssl=1 để server từ chối kết nối plaintext:
Terminal window
PGPASS="$(openssl rand -hex 24)"
aws rds create-db-instance --db-instance-identifier claude-gateway-db \
--engine postgres --engine-version 16 \
--db-instance-class db.t4g.micro \
--allocated-storage 20 --db-name claude_gateway \
--master-username gateway --master-user-password "$PGPASS" \
--db-subnet-group-name claude-gateway-db \
--vpc-security-group-ids "$DB_SG" \
--no-publicly-accessible --storage-encrypted

Connection string dùng sslmode=verify-full, với trust anchor là AWS RDS certificate bundle được copy vào image tại /etc/claude/rds-global-bundle.pem và trust qua NODE_EXTRA_CA_CERTS.

  1. Viết gateway.yaml: block upstreams trỏ vào Bedrock với auth: {} để gateway xác thực qua AWS default credential chain. Set listen.public_url (bắt buộc sau load balancer) và listen.trusted_proxies thành CIDR subnet của ALB:
listen:
host: 0.0.0.0
port: 8080
public_url: https://claude-gateway.internal.example.com
trusted_proxies: [<your-alb-subnet-cidrs>]
oidc:
issuer: https://example.okta.com
client_id: 0oa1example2
client_secret: ${OIDC_CLIENT_SECRET}
allowed_email_domains: [example.com]
userinfo_fallback: true
scopes: [openid, profile, email, offline_access, groups]
session:
jwt_secret: ${GATEWAY_JWT_SECRET}
ttl_hours: 8
store:
postgres_url: ${GATEWAY_POSTGRES_URL}
upstreams:
- provider: bedrock
region: <your-region>
auth: {}
  1. Lưu secret vào AWS Secrets Manager: ba secret - gateway-jwt-secret, gateway-oidc-client-secret, gateway-postgres-url. Trên ECS, task definition inject qua field secrets; trên EKS, mount qua file tại /secrets, tham chiếu bằng ${file:/secrets/...}.

  2. Build và push image lên Amazon ECR: build theo yêu cầu container image, đặt binary glibc linux-x64 tại ./claude trong build context, kèm bundle RDS cert. Tạo repo với --image-tag-mutability IMMUTABLE.

  3. Deploy:

    • ECS Fargate: tạo cluster, log group CloudWatch, task definition tham chiếu task role/execution role/secrets, internal ALB với --ip-address-type ipv4 (quan trọng - ALB dual-stack sẽ publish AAAA record public khiến private-network check của /login từ chối), listener HTTPS với --ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06, idle timeout 3600s cho streaming, và service với deployment circuit breaker.
    • EKS: dùng eksctl create iamserviceaccount cho IRSA thay vì ECS role, Ingress qua AWS Load Balancer Controller với các annotation scheme: internal, ip-address-type: ipv4, inbound-cidrs, certificate-arn, ssl-policy, load-balancer-attributes: idle_timeout.timeout_seconds=3600.
  4. Push gateway URL đến máy developer: set forceLoginMethodforceLoginGatewayUrl trong managed settings deploy qua MDM.

Bundle mẫu tại examples/gateway/aws đóng gói trang này thành code: setup.sh (script hóa toàn bộ walkthrough trên track ECS Fargate, idempotent), gateway.yaml.example, Dockerfile, và terraform/ (provision cùng scope ECS Fargate khai báo).

Triệu chứngNguyên nhânCách khắc phục
/login: hostname resolve ra địa chỉ publicALB dual-stack publish AAAA record publicTạo ALB với --ip-address-type ipv4
Mọi request Bedrock trả 502, log Could not load credentials from any providersTask chạy ECS EC2 launch type không có task role, hoặc pod EKS không có IRSA - IMDSv2 hop limit mặc định 1 chặn request bên trong containerƯu tiên task role và IRSA; nếu không tránh được, nâng hop limit lên 2
Bedrock trả 403 AccessDeniedExceptionChưa nộp use case form, subscription AWS Marketplace chưa xong, hoặc policy thiếu ARNNộp use case form, retry sau vài phút, cấp đủ hai action trên cả hai họ ARN
ECS task dừng với ResourceInitializationErrorExecution role không đọc được Secrets Manager, hoặc subnet không có đường ra Secrets Manager/ECRCấp secretsmanager:GetSecretValue, thêm NAT gateway hoặc interface endpoint
Gateway boot exit lỗi timeout kết nối PostgresSecurity group database không cho phép security group gateway trên 5432Mở port 5432 từ security group gateway
Gateway boot exit lỗi verify TLS certificate PostgresImage không trust RDS CA bundleThêm bước Dockerfile copy bundle và set NODE_EXTRA_CA_CERTS
Streaming response ngắt giữa chừng sau khoảng lặngALB idle timeout 60s mặc địnhSet idle_timeout.timeout_seconds thành 3600

Set telemetry.forward_to cùng listen.public_url, gateway push cấu hình OTEL exporter đến mọi client kết nối và forward nguyên trạng OTLP traffic đến từng destination. Trên AWS, chạy collector như AWS Distro for OpenTelemetry (ADOT) và export sang CloudWatch, Amazon Managed Service for Prometheus, hoặc backend OTLP bất kỳ. Trên ECS, driver awslogs tự đưa stderr của gateway vào CloudWatch log group; trên EKS cần cài thêm Container Insights hoặc Fluent Bit DaemonSet.