AWS に Claude apps gateway をデプロイする
AWS で Claude apps gateway を実行する実装例:ECS Fargate または EKS、Amazon RDS for PostgreSQL、AWS Secrets Manager、および Amazon Bedrock への IAM ロール認証。
このページは、AWS で Claude apps gateway を実行する 1 つの方法を説明しています。この設定は、サポートされている本番環境デプロイメントではなく、カスタマー管理インフラストラクチャの実装例です。各部分がどのように組み合わさるかを確認してから、自分の環境に適応させてください。プラットフォーム非依存の要件については、デプロイメントガイドを参照してください。
この例では、Amazon Bedrock をモデルアップストリームとして使用し、Amazon ECS を AWS Fargate で実行するか、Amazon EKS をコンピュートに使用して、AWS に Claude apps gateway をプロビジョニングします。Okta は例の ID プロバイダー(IdP)ですが、OpenID Connect(OIDC)準拠の任意の IdP が機能します。IdP ごとの詳細については、ID プロバイダーのセットアップを参照してください。
Bedrock は AWS 上の唯一の Claude アップストリームではありません。ゲートウェイは、Bedrock の代わりに、または Bedrock と並行して、AWS 認証と AWS Marketplace 課金を備えた Anthropic 運営の Claude API である Claude Platform on AWS もサポートしています。そのアップストリームエントリ、認証情報、および IAM 権限は、このページの Bedrock スコープのものとは異なります。Claude Platform on AWS アップストリームリファレンスは何が変わるかをカバーしており、このページの残りは変わらずに適用されます。
アーキテクチャ
ゲートウェイは、開発者が IdP を通じてサインインするネットワーク上のプライベート HTTPS エンドポイントとして実行されます。Claude Code セッションは、ゲートウェイの IAM ロールを通じて Amazon Bedrock 上の Claude モデルに到達するため、モデル認証情報は開発者マシンに到達しません。参照設定は以下をプロビジョニングします:
- Amazon ECS on AWS Fargate サービスまたは Amazon EKS デプロイメント(ゲートウェイコンテナを実行)
- Amazon ECR リポジトリ(ゲートウェイイメージ用)
- Amazon RDS for PostgreSQL インスタンス(プライベートサブネット内、公開アクセス不可、ゲートウェイのストア用)
- AWS Secrets Manager シークレット(JWT 署名キー、OIDC クライアントシークレット、Postgres URL 用)
- IAM ロール(
bedrock:InvokeModel、bedrock:InvokeModelWithResponseStream、bedrock:CountTokens権限付き、ECS タスクロールとしてアタッチされるか、EKS 上の IAM Roles for Service Accounts(IRSA)経由でバインドされる) - 内部アプリケーションロードバランサー(HTTPS 用)
前提条件
このウォークスルーではゲートウェイ独自のリソースを作成しますが、既に存在するネットワークおよびアイデンティティインフラストラクチャの上に構築されます。開始する前に、以下が必要です。
- 上記のリソースを作成する権限を持つ AWS アカウント
- AWS CLI v2 がインストールされ認証済みであること、および Docker がローカルにインストールされていること
- 異なるアベイラビリティゾーンに少なくとも 2 つのプライベートサブネットを持つ VPC。NAT ゲートウェイを通じたアウトバウンドインターネットアクセスがあること。内部ロードバランサーは 2 つの AZ のサブネットが必要であり、ゲートウェイは Bedrock および IdP へのエグレスが必要です
- リダイレクト URI が
https://<gateway-host>/oauth/callbackの Okta OIDC ウェブアプリケーション。ID プロバイダーのセットアップを参照してください - ゲートウェイ用の TLS ホスト名。通常は Route 53 プライベートホストゾーン内の内部 DNS 名でロードバランサーを指し、そのホスト名用の ACM 証明書があり、AWS Private CAによってインポートまたは発行されていること
環境変数を設定する
このページのすべてのコマンドはシェルから 4 つの値を読み込みます。AWS_REGION、ACCOUNT_ID、VPC_ID、および PRIVATE_SUBNETS です。
必要な Claude モデルを Bedrock が提供する US リージョンを選択してください。このウォークスルーはゲートウェイの組み込みモデルカタログに依存しており、これは us.anthropic.* 推論プロファイルに解決され、IAM ポリシーはそれらの ARN を許可します。US 以外のリージョンでは、そのジオの推論プロファイル ID を含む models: ブロックを追加し、IAM ポリシーの ARN プレフィックスを変更して一致させてください。
VPC ID が手元にない場合は、aws ec2 describe-vpcs で VPC をリストアップし、その VPC のサブネットをリストアップして、異なるアベイラビリティゾーンにある 2 つのプライベートサブネットを見つけてください。
aws ec2 describe-subnets --filters "Name=vpc-id,Values=<your-vpc-id>" \
--query 'Subnets[].{ID:SubnetId,AZ:AvailabilityZone,CIDR:CidrBlock}' --output table
続行する前に、4 つすべてをエクスポートしてください。
export AWS_REGION=us-east-1 # a US region where Bedrock serves the Claude models you need
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>"
ゲートウェイをデプロイする
以下の手順は、aws コマンドを使用して完全なデプロイをプロビジョニングします。
セキュリティグループを作成する
3 つのセキュリティグループがトラフィックパスをチェーンします。企業ネットワークはロードバランサーに 443 で到達し、ロードバランサーはゲートウェイに 8080 で到達し、ゲートウェイは Postgres に 5432 で到達します。それ以外は到達不可能です。それらをアタッチする方法は、コンピュートトラックによって異なります。
- ECS Fargate では、デプロイステップが
$ALB_SGをロードバランサーにアタッチし、$GW_SGをサービスにアタッチします。 - EKS では、AWS Load Balancer Controller が ALB 用に独自のフロントエンドセキュリティグループを作成するため、
$ALB_SGと$GW_SGは使用されません。デプロイステップのinbound-cidrsアノテーションがリスナーを企業ネットワークに制限し、データベースセキュリティグループはクラスタのセキュリティグループを$GW_SGの代わりに許可します。
ALB_SG="$(aws ec2 create-security-group --group-name claude-gateway-alb \
--description "Claude gateway ALB" --vpc-id "$VPC_ID" \
--query GroupId --output text)"
GW_SG="$(aws ec2 create-security-group --group-name claude-gateway-svc \
--description "Claude gateway service" --vpc-id "$VPC_ID" \
--query GroupId --output text)"
DB_SG="$(aws ec2 create-security-group --group-name claude-gateway-db \
--description "Claude gateway Postgres" --vpc-id "$VPC_ID" \
--query GroupId --output text)"
aws ec2 authorize-security-group-ingress --group-id "$ALB_SG" \
--protocol tcp --port 443 --cidr <your-corporate-cidr>
aws ec2 authorize-security-group-ingress --group-id "$GW_SG" \
--protocol tcp --port 8080 --source-group "$ALB_SG"
aws ec2 authorize-security-group-ingress --group-id "$DB_SG" \
--protocol tcp --port 5432 --source-group "$GW_SG"
IAM ロールを作成して使用例フォームを送信する
ゲートウェイは、Bedrock で Claude モデルを呼び出す唯一の権限を持つ専用タスクロールで実行されます。Bedrock アップストリームリファレンスに従い、ポリシーはクロスリージョン推論プロファイル ARN と基盤となるファウンデーションモデル ARN の両方をカバーする必要があります。
cat > bedrock-invoke.json <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream", "bedrock:CountTokens"],
"Resource": [
"arn:aws:bedrock:${AWS_REGION}:${ACCOUNT_ID}:inference-profile/us.anthropic.*",
"arn:aws:bedrock:*::foundation-model/anthropic.*"
]
}]
}
EOF
cat > ecs-trust.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "ecs-tasks.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}
EOF
aws iam create-role --role-name claude-gateway-task \
--assume-role-policy-document file://ecs-trust.json
aws iam put-role-policy --role-name claude-gateway-task \
--policy-name bedrock-invoke --policy-document file://bedrock-invoke.json
ECS には実行ロールも必要です。これは ECS エージェント自体が ECR からイメージをプルし、後で作成される Secrets Manager 値を注入するために使用します。これはゲートウェイの AWS SDK が実行時に使用するタスクロールとは別です。
aws iam create-role --role-name claude-gateway-execution \
--assume-role-policy-document file://ecs-trust.json
aws iam attach-role-policy --role-name claude-gateway-execution \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
cat > secrets-read.json <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret"],
"Resource": [
"arn:aws:secretsmanager:${AWS_REGION}:${ACCOUNT_ID}:secret:gateway-jwt-secret-??????",
"arn:aws:secretsmanager:${AWS_REGION}:${ACCOUNT_ID}:secret:gateway-oidc-client-secret-??????",
"arn:aws:secretsmanager:${AWS_REGION}:${ACCOUNT_ID}:secret:gateway-postgres-url-??????"
]
}]
}
EOF
aws iam put-role-policy --role-name claude-gateway-execution \
--policy-name read-gateway-secrets --policy-document file://secrets-read.json
ポリシーは、ベアの gateway-* ワイルドカードではなく、シークレットごとに 1 つの ARN を指定します。共有アカウントでは、ベアのワイルドカードは無関係なシークレットにも一致します。末尾の -?????? は、Secrets Manager がすべてのシークレットの ARN に追加する 6 文字のランダムサフィックスと正確に一致します。末尾の -* はプレーンプレフィックスグロブであり、gateway-postgres-url-prod などのより長い名前にも一致します。
IAM ポリシーはゲートウェイに Bedrock を呼び出す権限を付与し、Bedrock は商用リージョンでデフォルトでモデルアクセスを有効にします。残りのアカウントレベルのゲートは Anthropic の 1 回限りの使用例フォームです。アカウント内の誰もそれを送信していない場合は、Amazon Bedrock コンソールを開き、モデルカタログから Anthropic モデルを選択して、フォームを完成させます。アクセスは送信直後に付与されます。Claude Code on Amazon Bedrockで AWS Organizations フォームと送信者が必要な IAM 権限を参照してください。
EKS トラックは、2 つの ECS ロールの代わりに IRSA ロール上で両方のポリシードキュメントを再利用します。デプロイステップを参照してください。
Amazon RDS for PostgreSQL をプロビジョニングする
インスタンスはプライベートサブネットで実行され、パブリックアドレスがなく、ストレージ暗号化がオンです。エンジンバージョンは Postgres 16 に固定されており、ゲートウェイがサポートする PostgreSQL 14 の下限を満たし、以下のパラメータグループファミリーがインスタンスが実行するエンジンと一致することを保証します。
まず、プライベートサブネットにデータベースを配置するサブネットグループと、rds.force_ssl=1 を使用してサーバーがプレーンテキスト接続を拒否するパラメータグループを作成します。エンジンバージョンは 1 回固定されます。パラメータグループのファミリーはインスタンスが実行するエンジンのメジャーバージョンと一致する必要があるためです。
aws rds create-db-subnet-group --db-subnet-group-name claude-gateway-db \
--db-subnet-group-description "Claude gateway" --subnet-ids $PRIVATE_SUBNETS
PG_VERSION=16
PG_FAMILY="postgres${PG_VERSION}"
aws rds create-db-parameter-group --db-parameter-group-name claude-gateway-db \
--db-parameter-group-family "$PG_FAMILY" \
--description "Claude gateway - require TLS on every connection"
aws rds modify-db-parameter-group --db-parameter-group-name claude-gateway-db \
--parameters "ParameterName=rds.force_ssl,ParameterValue=1,ApplyMethod=immediate"
次に、生成されたマスターパスワードでインスタンスを作成します。
PGPASS="$(openssl rand -hex 24)"
aws rds create-db-instance --db-instance-identifier claude-gateway-db \
--engine postgres --engine-version "$PG_VERSION" \
--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 \
--db-parameter-group-name claude-gateway-db \
--vpc-security-group-ids "$DB_SG" \
--no-publicly-accessible --storage-encrypted
リテラル --master-user-password 引数は、コマンド実行中のプロセステーブルおよび監査/EDR ログに表示されます。これは、シークレットステップのメモがカバーする同じ露出です。共有またはモニタリングされたホストでは、代わりに 0600 ファイルを介して --cli-input-json でパスワードを渡してください。バンドルの setup.sh は、0600 一時ファイルを --cli-input-json に渡すことで、同じ方法でシークレット値をプロセス argv から保ちます。
インスタンスが起動するのを待ちます。これには数分かかる場合があります。その後、プライベートエンドポイントを読み取り、ゲートウェイが使用する接続文字列を組み立てます。
aws rds wait db-instance-available --db-instance-identifier claude-gateway-db
DB_HOST="$(aws rds describe-db-instances --db-instance-identifier claude-gateway-db \
--query 'DBInstances[0].Endpoint.Address' --output text)"
GATEWAY_POSTGRES_URL="postgres://gateway:${PGPASS}@${DB_HOST}:5432/claude_gateway?sslmode=verify-full"
sslmode=verify-full は、ゲートウェイが RDS サーバー証明書のチェーンとホスト名を検証し、暗号化するだけでなく検証することを確認します。トラストアンカーは AWS RDS 証明書バンドルです。これは、以下のイメージビルドステップで /etc/claude/rds-global-bundle.pem にコピーされ、NODE_EXTRA_CA_CERTS を介して信頼されます。libpq スタイルの sslrootcert= パラメータを URL に追加しないでください。ゲートウェイのドライバーはクエリ文字列から sslmode のみを読み取り、sslrootcert を Postgres スタートアップパラメータとして転送します。サーバーはこれを拒否します。
ECS サービスまたは EKS ポッドはこの VPC で実行され、インスタンスのプライベートエンドポイントに到達でき、claude-gateway-db セキュリティグループはゲートウェイのセキュリティグループのみを許可します。
gateway.yaml を書き込む
upstreams ブロックは auth: {} で Bedrock を指します。ゲートウェイは ECS のタスクロールまたは EKS の IRSA ロールから AWS デフォルト認証情報チェーンを介して認証します。すべてのフィールドについては、設定リファレンスを参照してください。
2 つの listen フィールドは、ゲートウェイの前にあるものに依存します。
public_url:外部https://オリジン。ロードバランサーの背後で必須です。listenリファレンスを参照してください。ゲートウェイは IdPredirect_uriと検出ドキュメントをこの値からのみ構築し、X-Forwarded-*ヘッダーからは構築しません。trusted_proxies:フロントエンドのソース範囲。ゲートウェイは TCP ピアがこのリストにある場合にのみX-Forwarded-Forを尊重し、信頼できるホップを過ぎてチェーンをウォークします。IP ごとのサインイン率制限と監査イベントは、ロードバランサーの代わりに開発者 IP を記録します。
両方のトラックでフロントエンドは内部 ALB です。直接作成されるか、AWS Load Balancer Controller によって作成されるかは関係ありません。ALB のノードはアタッチされたサブネットからアドレスを取得するため、trusted_proxies をそれらのサブネットの CIDR に設定します。これはそれらのサブネット内のすべてのホストをプロキシとして信頼します。ALB のイングレスソース(企業 CIDR)がそれらと重複しないようにし、X-Forwarded-For を介してクライアント IP をスプーフできる信頼できないワークロードとサブネットを共有しないでください。
ALB のクライアントポート保存属性 routing.http.xff_client_port.enabled は、どちらの設定でも保つことができます。オンの場合、ALB はクライアントを 203.0.113.7:54321 または [2001:db8::1]:54321 として書き込み、ゲートウェイはポートをドロップして両方を読み取ります。
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} # EKS: ${file:/secrets/oidc-client-secret}
allowed_email_domains: [example.com]
# Okta org 認可サーバーは、メールとグループを省略した薄い id_token を返します。
# ゲートウェイは /userinfo からそれらを入力します。
userinfo_fallback: true
# Okta は、`groups` スコープがリクエストされ、アプリのグループクレーム
# フィルターがそれらを許可する場合にのみグループを発行します。
scopes: [openid, profile, email, offline_access, groups]
session:
jwt_secret: ${GATEWAY_JWT_SECRET} # EKS: ${file:/secrets/jwt-secret}
ttl_hours: 8 # デプロビジョニングレイテンシーを制限します。より厳密な
# 取り消しのために 1 に向かって下げます
store:
postgres_url: ${GATEWAY_POSTGRES_URL} # EKS: ${file:/secrets/postgres-url}
upstreams:
- provider: bedrock
region: <your-region> # IAM ポリシーの ARN がそれをカバーするように $AWS_REGION と一致させます
auth: {} # AWS デフォルト認証情報チェーン:
# ECS タスクロール、または EKS の IRSA
oidc ブロックのみが Okta 固有です。Microsoft Entra ID を代わりに使用するには、issuer を https://login.microsoftonline.com/<tenant-id>/v2.0 に設定し、userinfo_fallback と groups スコープをドロップし、Entra がグループ名ではなくグループ Object ID を発行することに注意してください。managed.policiesは GUID で一致するか、oidc.groups_claim: roles を使用した App Roles で一致する必要があります。ID プロバイダーセットアップを参照してください。
AWS Secrets Manager にシークレットを保存する
3 つのシークレットを作成します。IAM ステップからの実行ロールはすでにそれらを読み取ることができます。
aws secretsmanager create-secret --name gateway-jwt-secret \
--secret-string "$(openssl rand -base64 32)"
aws secretsmanager create-secret --name gateway-oidc-client-secret \
--secret-string '<your-okta-client-secret>'
aws secretsmanager create-secret --name gateway-postgres-url \
--secret-string "$GATEWAY_POSTGRES_URL"
各呼び出しが出力する ARN に注意してください。ECS タスク定義は ARN でシークレットを参照します。
リテラル --secret-string 引数は、各コマンド実行中のプロセステーブルおよび監査/EDR ログに表示されます。共有またはモニタリングされたホストでは、値を 0600 ファイルに入れ、代わりに --secret-string file://<path> を渡してください。バンドルの setup.sh は、0600 一時ファイルを --cli-input-json に渡すことで、同じ方法でシークレット値をプロセス argv から保ちます。
シークレットとは異なり、gateway.yaml 自体にはシークレット値が含まれていません。すべての認証情報は ${VAR} または ${file:...} 展開を通じてブート時に解決されるためです。すべてがコンテナに到達する方法はトラックによって異なります。
- ECS では、次のステップのビルドが
gateway.yamlをイメージにコピーして/etc/claude/gateway.yamlに配置し、タスク定義は 3 つのシークレットを環境変数としてsecretsフィールドを介して注入するため、YAML は${GATEWAY_JWT_SECRET}、${OIDC_CLIENT_SECRET}、および${GATEWAY_POSTGRES_URL}を参照します。 - EKS では、
gateway.yamlを ConfigMap からマウントし、シークレットを/secretsのファイルとしてマウントし、${file:/secrets/...}として参照します。Kubernetes Secrets を External Secrets Operator または Secrets Store CSI ドライバーの AWS プロバイダーで Secrets Manager からソースするか、kubectlで直接作成します。
イメージを構築して Amazon ECR にプッシュする
コンテナイメージ要件に従ってイメージを構築し、linux-x64 glibc バイナリをビルドコンテキストの ./claude に配置します。これらの要件に従って独自の Dockerfile を作成するか、バンドルの Dockerfileから始めます。これは、前のステップから入力された gateway.yaml をイメージにコピーして /etc/claude/gateway.yaml に配置します。ECS では、その埋め込みコピーは設定がコンテナに到達する方法です。これが、ファイルが書き込まれた後にビルドが行われる理由です。EKS トラックは代わりにデプロイ時に ConfigMap から gateway.yaml をマウントするため、埋め込みコピーはそこで使用されません。
イメージは、接続文字列の sslmode=verify-full のトラストアンカーとして AWS RDS 証明書バンドルも搭載しているため、最初にビルドコンテキストにダウンロードします。AWS はバンドルをローテーションします(新しい地域の CA が追加されます)。ため、チェックサムをピンするか、コミットするのではなく、ビルドごとにダウンロードします。
curl -fL --proto '=https' -o rds-global-bundle.pem \
https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
コンテナイメージ要件はバンドルをカバーしていないため、独自の Dockerfile を作成する場合は、それをコピーして信頼する 2 行を追加してください。バンドルの Dockerfile にはすでに両方が含まれています。
COPY rds-global-bundle.pem /etc/claude/rds-global-bundle.pem
ENV NODE_EXTRA_CA_CERTS=/etc/claude/rds-global-bundle.pem
ECR リポジトリを作成し、Docker をそれにサインインします。イミュータブルタグは、デプロイステップがピンする <version> タグが後で別のイメージに静かに再ポイントされることはできないことを意味します。
aws ecr create-repository --repository-name claude-gateway \
--image-tag-mutability IMMUTABLE \
--image-scanning-configuration scanOnPush=true
aws ecr get-login-password --region "$AWS_REGION" \
| docker login --username AWS --password-stdin \
"${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
イメージを構築してプッシュします。以下のタスク定義は linux/amd64 を実行するため、プラットフォームはここで一致する必要があります。Fargate on ARM64(Graviton)の場合は、linux-arm64 バイナリで linux/arm64 を構築し、代わりに cpuArchitecture を ARM64 に設定します。
docker build --platform=linux/amd64 \
-t "${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/claude-gateway:<version>" .
docker push "${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/claude-gateway:<version>"
デプロイ
クラスターと、ゲートウェイの stderr 用のロググループを作成します。stderr は監査イベントと運用ログの両方を搭載しています。保持は別の呼び出しであり、保持がない場合、CloudWatch はログを永遠に保ちます。90 日を監査保持ポリシーと調整します。
aws ecs create-cluster --cluster-name claude-gateway
aws logs create-log-group --log-group-name /ecs/claude-gateway
aws logs put-retention-policy --log-group-name /ecs/claude-gateway \
--retention-in-days 90
タスク定義を書き込みます。タスクロールは Bedrock 権限を搭載し、実行ロールはシークレットを注入します。Secrets Manager ステップからシークレット ARN を使用します。
{
"family": "claude-gateway",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "1024",
"memory": "2048",
"runtimePlatform": { "cpuArchitecture": "X86_64", "operatingSystemFamily": "LINUX" },
"executionRoleArn": "arn:aws:iam::<account-id>:role/claude-gateway-execution",
"taskRoleArn": "arn:aws:iam::<account-id>:role/claude-gateway-task",
"containerDefinitions": [
{
"name": "gateway",
"image": "<account-id>.dkr.ecr.<region>.amazonaws.com/claude-gateway:<version>",
"portMappings": [{ "containerPort": 8080 }],
"secrets": [
{ "name": "GATEWAY_JWT_SECRET", "valueFrom": "<gateway-jwt-secret ARN>" },
{ "name": "OIDC_CLIENT_SECRET", "valueFrom": "<gateway-oidc-client-secret ARN>" },
{ "name": "GATEWAY_POSTGRES_URL", "valueFrom": "<gateway-postgres-url ARN>" }
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/claude-gateway",
"awslogs-region": "<region>",
"awslogs-stream-prefix": "gateway"
}
}
}
]
}
それを登録します。
aws ecs register-task-definition --cli-input-json file://claude-gateway-task.json
ゲートウェイをヘルスチェックするターゲットグループを持つ内部 ALB を前に配置します。--ip-address-type ipv4 は重要です。内部デュアルスタック ALB はパブリック範囲の AAAA レコードを公開し、/login プライベートネットワークチェックはそれらを拒否します。
ALB_ARN="$(aws elbv2 create-load-balancer --name claude-gateway \
--scheme internal --type application --ip-address-type ipv4 \
--subnets $PRIVATE_SUBNETS --security-groups "$ALB_SG" \
--query 'LoadBalancers[0].LoadBalancerArn' --output text)"
TG_ARN="$(aws elbv2 create-target-group --name claude-gateway \
--protocol HTTP --port 8080 --vpc-id "$VPC_ID" --target-type ip \
--health-check-path /readyz \
--query 'TargetGroups[0].TargetGroupArn' --output text)"
HTTPS リスナーを追加します。--ssl-policy は最新の TLS フロアをピンします。これを省略すると、レガシー ELBSecurityPolicy-2016-08 デフォルトにフォールバックします。これは TLS 1.0/1.1 をまだ受け入れます。
ALB はデフォルトで 60 秒間データがない接続を閉じます。ゲートウェイのキープアライブピングはストリームをそのデフォルト内に保つため、タイムアウトを上げるとピングケイデンスの上にマージンを追加します。トラブルシューティング行はドロップされたストリームのメカニズムと古いゲートウェイをカバーしています。以下のコマンドはリスナーを追加し、タイムアウトを上げます。
aws elbv2 create-listener --load-balancer-arn "$ALB_ARN" \
--protocol HTTPS --port 443 \
--ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06 \
--certificates CertificateArn=<your-acm-certificate-arn> \
--default-actions Type=forward,TargetGroupArn="$TG_ARN"
aws elbv2 modify-load-balancer-attributes --load-balancer-arn "$ALB_ARN" \
--attributes Key=idle_timeout.timeout_seconds,Value=3600
サービスを作成します。デプロイメント回路ブレーカーは、タスクが失敗し続けるデプロイメント(不正なイメージまたはブート不可能な設定から)を、失敗するタスクを永遠に再起動する代わりに、最後の安定した状態にロールバックします。
aws ecs create-service --cluster claude-gateway --service-name claude-gateway \
--task-definition claude-gateway --desired-count 1 --launch-type FARGATE \
--deployment-configuration "deploymentCircuitBreaker={enable=true,rollback=true}" \
--health-check-grace-period-seconds 60 \
--network-configuration "awsvpcConfiguration={subnets=[$(echo $PRIVATE_SUBNETS | tr ' ' ',')],securityGroups=[$GW_SG],assignPublicIp=DISABLED}" \
--load-balancers "targetGroupArn=$TG_ARN,containerName=gateway,containerPort=8080"
60 秒のグレースピリオドは、コールドタスクがイメージをプルし、ストアに接続し、ECS が失敗をデプロイメントに対してカウントし始める前に最初のヘルスチェックに答える時間を与えます。ターゲットグループの GET /readyz のヘルスチェックはストアが到達可能であることを検証するため、Postgres に到達できないタスクはローテーションに入りません。停止動作でトレードオフと /healthz 代替案を参照してください。
タスクはパブリック IP なしのプライベートサブネットで実行されるため、すべてのエグレス(Bedrock、IdP、Secrets Manager、ECR、CloudWatch Logs へ)は NAT ゲートウェイを通過します。Bedrock トラフィックをパブリックパスから保つには、bedrock-runtime インターフェース VPC エンドポイントを作成し、アップストリームの base_url をそれを指すように設定します。Bedrock アップストリームリファレンスに示されているように。IdP はまだインターネットエグレスが必要です。
開発者にプライベートに解決可能なホスト名を与えることで完了します。Route 53 プライベートホストゾーンで、ゲートウェイの内部 DNS 名を ALB にエイリアスし、listen.public_url をそのホスト名に設定します。ALB 自体の *.elb.amazonaws.com 名は内部 ALB のプライベートアドレスに解決されますが、ACM 証明書を搭載できないため、独自の名前を使用します。
最初のサインイン前に OAuth クライアントの認可リダイレクト URI を <public_url>/oauth/callback に更新します。public_url を変更した後、新しいタグの下でイメージを再構築してプッシュし、新しいタスク定義リビジョンを登録し、再デプロイします。ECS では、設定はイメージの埋め込み gateway.yaml に存在し、ゲートウェイはその設定からのみパブリックオリジンを構築し、X-Forwarded-Host と X-Forwarded-Proto を無視します。X-Forwarded-For は、listen.trusted_proxies が設定されている場合にのみクライアント IP に対して尊重されます。
このトラックには、ローカルにインストールされた kubectl と eksctl が必要です。また、IAM OIDC プロバイダーと AWS Load Balancer Controller がインストールされた既存の EKS クラスターが必要です。クラスターは $VPC_ID 上にある必要があります。ポッドが RDS プライベートエンドポイントに到達でき、claude-gateway-db セキュリティグループは $GW_SG の代わりにクラスタのポッドまたはノードセキュリティグループを許可する必要があります。
EKS では、ゲートウェイは ECS ロールではなく IRSA を通じて Bedrock 認証情報を取得します。IAM ステップからの ecs-tasks.amazonaws.com トラストポリシーはここに適用されません。IRSA には、クラスタの OIDC プロバイダーにフェデレートするトラストポリシーを持つロールが必要です。system:serviceaccount:claude-gateway:gateway にスコープされます。eksctl create iamserviceaccount は、そのロールを作成し、ポリシーをアタッチし、Kubernetes サービスアカウントに 1 つのステップでロール ARN に注釈を付けます。IAM ステップからの 2 つのポリシードキュメントをマネージドポリシーに変換します。それはアタッチできます。
BEDROCK_POLICY_ARN="$(aws iam create-policy --policy-name claude-gateway-bedrock-invoke \
--policy-document file://bedrock-invoke.json --query Policy.Arn --output text)"
SECRETS_POLICY_ARN="$(aws iam create-policy --policy-name claude-gateway-secrets-read \
--policy-document file://secrets-read.json --query Policy.Arn --output text)"
kubectl create namespace claude-gateway
eksctl create iamserviceaccount --cluster <your-cluster> --region "$AWS_REGION" \
--namespace claude-gateway --name gateway --role-name claude-gateway \
--attach-policy-arn "$BEDROCK_POLICY_ARN" \
--attach-policy-arn "$SECRETS_POLICY_ARN" \
--approve
シークレットポリシーは、Secrets Store CSI ドライバーの AWS プロバイダーがマウントするポッドのサービスアカウントを使用して行うように、ポッドが Secrets Manager 自体を読み取る場合にのみ必要です。別の方法で Kubernetes Secrets を作成する場合はドロップします。プロバイダーはポリシーの両方のアクションが必要です。ローテーションされたシークレットを調整するときに DescribeSecret を呼び出すため、GetSecretValue のみの付与はマウントされますが、最初のデプロイでローテーションの取得を停止します。
Kubernetes デプロイメントで説明されているように、ゲートウェイを標準 Deployment、Service、および Ingress としてデプロイします。
serviceAccountName: gateway- ConfigMap からマウントされた
gateway.yamlと/secretsにマウントされたシークレット GET /readyzを指すレディネスプローブ
フロントエンドの場合、AWS Load Balancer Controller によって管理される Ingress は内部 ALB をプロビジョニングします。以下でアノテーションを付けます。
alb.ingress.kubernetes.io/scheme: internalとalb.ingress.kubernetes.io/target-type: ipalb.ingress.kubernetes.io/ip-address-type: ipv4。パブリック範囲の AAAA レコードが/loginプライベートネットワークチェックに公開されないようにするため。拒否しますalb.ingress.kubernetes.io/inbound-cidrs: <your-corporate-cidr>。コントローラー管理のフロントエンドセキュリティグループが0.0.0.0/0デフォルトの代わりに企業ネットワークのみを許可するようにしますalb.ingress.kubernetes.io/certificate-arnと ACM 証明書alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06。リスナーが TLS 1.0 と 1.1 を受け入れるレガシーデフォルトポリシーにフォールバックしないようにするためalb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=3600。ゲートウェイのストリーミングキープアライブの上のマージン。トラブルシューティングを参照してください
IRSA では、AWS SDK はプロジェクトされたサービスアカウントトークンを読み取り、AWS STS と交換するため、ポッドは EC2 インスタンスメタデータサービスを必要としません。エグレス NetworkPolicy は 169.254.169.254 をゲートウェイポッドに対してブロックする場合があります。以下のトラブルシューティングのノードホップリミット問題は、IRSA をスキップし、ノードインスタンスロールに依存するクラスターにのみ適用されます。
ゲートウェイ URL を開発者マシンにプッシュする
ゲートウェイは実行されていますが、開発者は /login からそれに到達できません。ゲートウェイ URL がマシンに存在するまで。MDM を介して各デバイスにデプロイするマネージド設定ファイルで forceLoginMethod と forceLoginGatewayUrl を設定します。ログインピッカーにはゲートウェイオプションがなく、開発者が手動で選択することはできません。
Terraform リファレンス
examples/gateway/aws の付属バンドルは、このページをコードとしてパッケージ化しています。
setup.shは、上記のプロビジョニング手順を ECS Fargate トラックで同じawsコマンドでスクリプト化しています。べき等性があります。既存のリソースは検出されてスキップされるため、再実行しても安全です。また、デフォルト値は環境変数で上書きできます。Okta OIDC クライアントシークレットと ACM 証明書は自分で作成する必要があります。それらがない場合、実行は ECS/ALB デプロイをスキップし、不足している入力を名前付けし、create-secretコマンドを出力します。両方を作成して再実行してください。Bedrock ユースケースフォームと Route 53 エイリアスは、自動的に実行されるのではなく、次のステップとして出力されます。クライアント MDM プッシュはこのページからの手動ステップのままです。gateway.yaml.exampleは gateway.yaml ステップの設定テンプレートで、オプションキーはコメントアウトされた状態で含まれています。これをgateway.yamlにコピーし、ビルド前にすべてのREPLACE_MEを置き換えてください。Dockerfileは、プリビルドされたlinux-x64バイナリからランタイムイメージをビルドし、入力済みのgateway.yamlを/etc/claude/gateway.yamlにコピーします。また、ストアのsslmode=verify-fullをアンカーする AWS RDS 証明書バンドルもコピーします。setup.shは、ビルドコンテキストにまだ存在しない場合にのみバンドルをダウンロードします。ファイルを削除して新しいタグで再ビルドすると、AWS CA ローテーションを取得できます。設定ファイルはシークレット値を保持しません。すべての認証情報はブート時に${VAR}展開を通じて解決されるためです。したがって、設定ファイルの編集は新しいタグでの再ビルドを意味します。setup.shはファイルのハッシュでイメージにタグを付けることでこれを自動化します。terraform/は、同じ ECS Fargate スコープを宣言的にプロビジョニングします。セキュリティグループ、IAM ロール、ECR リポジトリ、RDS インスタンス、Secrets Manager シークレット、および内部 ALB の背後にある ECS サービスです。VPC とプライベートサブネットは前提条件のままで、変数として渡されます。Terraform は ECR リポジトリを作成しますがイメージはビルドしません。サービス定義はイメージを参照するため、apply は 2 パスです。リポジトリの対象 apply、その後ビルドとプッシュ、その後フル apply です。バンドルのterraform/README.mdは変数、リモート状態、およびティアダウンについて説明しています。
このページと同様に、バンドルはサポートされている本番環境デプロイメントではなく、カスタマー管理インフラストラクチャの動作例です。それに依存する前に、自分の環境に合わせてレビューして適応させてください。
トラブルシューティング
ゲートウェイのブートおよびログインエラーについては、プラットフォーム非依存のトラブルシューティングテーブルを参照してください。以下のエントリは AWS に固有です。
| 症状 | 原因 | 修正 |
|---|---|---|
CLI /login: Gateway hosts must be on your organization's private network; <host> resolves to the public (or unrecognized) address <ip> |
ゲートウェイ名が少なくとも 1 つのパブリックアドレスに解決されます。デュアルスタック内部 ALB はパブリック範囲の AAAA レコードを公開し、プライベートネットワークチェックは解決されたすべてのアドレスがプライベートであることを要求します | ALB を --ip-address-type ipv4 で作成するか、パブリック AAAA レコードのない別の内部専用 DNS 名を提供してください |
すべての Bedrock リクエストが 502 を返す。ログに Could not load credentials from any providers が表示される |
タスクは ECS EC2 起動タイプでタスクロールなしで実行されるか、ポッドは IRSA なしで EKS ノードで実行されるため、認証情報はインスタンスメタデータから取得されます。IMDSv2 のデフォルトホップリミット 1 はコンテナ内で停止します。このページの両方のトラック(Fargate タスクロールと IRSA)はインスタンスメタデータを使用しません | タスクロールと IRSA を優先してください。インスタンス認証情報が避けられない場合は、aws ec2 modify-instance-metadata-options --instance-id <id> --http-put-response-hop-limit 2 でホップリミットを上げてください。プラットフォーム非依存テーブルはトレードオフをカバーしています |
Bedrock リクエストが 403 AccessDeniedException を返す |
アカウントが Anthropic のワンタイム使用ケースフォームを送信していない、アカウントの最初の呼び出しで開始される自動 AWS Marketplace サブスクリプションがまだ完了していない、またはタスクロールのポリシーに推論プロファイルまたは基盤モデル ARN が不足している | Bedrock コンソールのモデルカタログから使用ケースフォームを送信してください。フォームが送信されたばかりの場合、またはこれがアカウントの最初の呼び出しの場合は、数分後に再試行してください。bedrock:InvokeModel と bedrock:InvokeModelWithResponseStream を両方の ARN ファミリーに付与してください。 |
Bedrock がオンデマンドスループットがサポートされていないと言う ValidationException を返す |
カスタム models: エントリが、リージョンが推論プロファイルを通じてのみ提供する基盤モデル ID にマップされている |
モデルをクロスリージョン推論プロファイル ID(us.anthropic.*)にマップしてください。組み込みカタログはすでにこれを行っています |
ECS タスクがゲートウェイがログに何も出力する前に ResourceInitializationError で停止する |
実行ロールが Secrets Manager シークレットを読み取ることができない、またはプライベートサブネットが Secrets Manager または ECR へのパスを持たない | 実行ロールに 3 つの gateway- シークレット ARN に対する secretsmanager:GetSecretValue を付与し、NAT ゲートウェイ経由でエグレスを提供するか、NAT ゲートウェイなしで Secrets Manager、ECR、CloudWatch Logs のインターフェースエンドポイント(awslogs ドライバーが同じステージで必要とする)と S3 ゲートウェイエンドポイントを提供してください |
| ゲートウェイブートが Postgres 接続タイムアウトエラーで終了する | データベースセキュリティグループがゲートウェイのセキュリティグループを 5432 で許可していない、またはサービスがデータベースの VPC 外で実行されている。ストアは 5 秒後に待機を停止します | データベースのセキュリティグループでゲートウェイのセキュリティグループから 5432 を許可し、サービスを DB サブネットグループと同じ VPC で実行してください |
| ゲートウェイブートが Postgres TLS 証明書検証エラーで終了する | 接続文字列が sslmode=verify-full を設定しているが、イメージが RDS CA バンドルを信頼していない。バンドルがイメージにコピーされていない、または NODE_EXTRA_CA_CERTS がそれを指していない |
ビルドステップの 2 つの Dockerfile 行を追加してバンドルをコピーし、NODE_EXTRA_CA_CERTS を設定してから、リビルドして新しいタグで プッシュし、再デプロイしてください |
| ストリーミング応答が静止期間後にストリーム途中でドロップする | v2.1.229 より前のゲートウェイが Bedrock または AWS 上の Claude Platform 上流で、上流が静止している間(例えば、ストリーム出力のない拡張思考中)は何も送信しません。ALB はデフォルトで 60 秒間データがない場合に接続を閉じるため、そのギャップでストリームを切断します。v2.1.229 以降のゲートウェイはそのタイムアウト下で静止したストリームを保持します。これらの上流では、ゲートウェイはストリームデータがない状態で約 15 秒経過すると SSE ping イベントを 1 回発行し、Anthropic API 上流ではゲートウェイは API 自体のピングをリレーします |
ゲートウェイを v2.1.229 以降に更新するか、idle_timeout.timeout_seconds 属性を 3600 に設定してください。modify-load-balancer-attributes または EKS の load-balancer-attributes Ingress アノテーション経由で設定します |
テレメトリ
ゲートウェイは、マシンごとの OTEL 設定なしで開発者ごとの使用メトリクスを提供します。Claude Code は OpenTelemetry(OTLP)メトリクス、ログ、およびオプトインのトレースを発行します。使用状況の監視は CLI が報告するすべてをカバーしています。ゲートウェイセッションでは、CLI は各エクスポートに認証された IdP ID 属性 user.id、user.email、および user.groups でスタンプを付けるため、使用状況は OTEL_RESOURCE_ATTRIBUTES 配管なしで開発者ごとにロールアップされます。
ゲートウェイ自体は認証された OTLP リレーです。telemetry.forward_to を listen.public_url と一緒に設定し、OTEL エクスポーター設定をすべての接続されたクライアントにプッシュし、OTLP トラフィックを逐語的にリストするすべての宛先に転送します。各宛先はメトリクス、ログ、およびトレースを独立して選択し、デフォルトはメトリクスのみです。telemetry リファレンスを参照してください。シグナルごとのフィールドとそれらの感度トレードオフについて。ゲートウェイはバッファ、集約、またはテレメトリを保存しないため、データが到達する場所は完全にコレクターのエクスポーター設定です。
クライアントテレメトリはデフォルトでオフです。telemetry.forward_to を設定することは、接続された開発者のためにそれをオンにするものです。各インタラクティブクライアントは、設定リファレンスで説明されているように、プッシュされた設定の 1 回限りのセキュリティ承認ダイアログを表示します。AWS では、各シグナルは次のように宛先にマップされます。
クライアントメトリクス、ログ、およびトレース
telemetry.forward_to を OpenTelemetry コレクター(AWS Distro for OpenTelemetry(ADOT)コレクターなど)に指し、Amazon CloudWatch、Amazon Managed Service for Prometheus、または任意の OTLP バックエンドにエクスポートします。
https:// 経由で到達可能な独自の内部サービスとしてコレクターを実行します。ゲートウェイはループバック URL に対してのみプレーンテキスト http:// を受け入れ、その場合でも SSRF ガードはデフォルトで送信時にループバック接続をブロックします。http://localhost:4318 のサイドカーコレクターは設定検証を渡しますが、トラフィックを受け取りません。エクスポートは ECONNREFUSED_SSRF として失敗します。ゲートウェイログで、CLAUDE_GATEWAY_ALLOW_LOOPBACK=1 がゲートウェイの環境に設定されていない限り。その変数はすべてのオペレーター設定 URL のループバックブロックを緩和し、テレメトリのみではなく、ネットワークが他の方法でロックダウンされているタスクのサイドカープラスフラグセットアップを予約してください。内部サービスパターンを優先します。
ゲートウェイログ
ECS Fargate では、追加のセットアップはありません。awslogs ドライバーはゲートウェイの stderr を配信します。これは監査イベントと運用ログを運びます。/ecs/claude-gateway ロググループに上記で作成されました。EKS では、ポッドログはデフォルトで CloudWatch に到達しないため、監査証跡は失われます。ログ収集をインストールするまで:コンテナログキャプチャが有効な Amazon CloudWatch Observability アドオン、または Fluent Bit DaemonSet。どちらのトラックでも、CloudWatch Logs Insights でログをクエリし、メトリクスフィルターからアラームを駆動します。
コンテナメトリクス
aws ecs update-cluster-settings --cluster claude-gateway --settings name=containerInsights,value=enabled でクラスタで Container Insights を有効にして、タスクごとの CPU、メモリ、およびネットワーク。EKS では、Amazon CloudWatch Observability アドオンをインストールします。
支出
テレメトリは事後に使用状況を表示します。支出制限は、共有アップストリーム認証情報の上にゲートウェイのライブ開発者ごとのビューと実装です。
次のステップ
- 設定リファレンス:すべての
gateway.yamlオプション。managed.policiesとtelemetryを含む - デプロイメントと運用:IdP セットアップ、ヘルスチェック、JWT シークレットローテーション、アップグレード、およびセキュリティモデル
- Claude apps gateway 概要:クイックスタートと開発者の接続
- Claude apps gateway の AWS サンプル:顧客環境の範囲をカバーする AWS 保守デプロイメントサンプル