
Amazon ECS の新機能 「ECS Gateway」 を試してみた
はじめに
2026年10月20日、Amazon ECS Gateway が発表されました。
ECS Gateway は、ECS サービスの入口となる ALB と関連リソースを ECS が管理する機能で、1台の ALB を最大25のサービスで共有できます。
今回は、東京リージョンの同じクラスターにパブリック用とプライベート用のゲートウェイを用意し、それぞれにサービスを関連付けて FQDN を調べました。
検証環境
| 項目 | 構成 |
|---|---|
| リージョン | ap-northeast-1(東京) |
| ネットワーク | デフォルト VPC。1a、1c、1d のパブリックサブネットを使用 |
| ゲートウェイ | パブリック(gw-public)とプライベート(gw-private)を1つずつ作成。IP アドレスタイプは IPv4 |
| ECS サービス | nginx を Fargate で実行し、gw-public と gw-private に接続 |
| タスク | 各サービスに1個。0.25 vCPU / 0.5 GB、パブリック IP あり |
| 実行ツール | AWS CLI 2.39.3 |
ゲートウェイの作成とサービスの接続
パブリックとプライベートのゲートウェイ
ゲートウェイには、ECS が ALB などを作るためのインフラストラクチャロールを渡します。信頼ポリシーを trust-ecs.json として保存し、ロールを作ってマネージドポリシーを付けます。
インフラストラクチャロールの作成
trust-ecs.json:
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ecs.amazonaws.com"},"Action":"sts:AssumeRole"}]}
aws iam create-role --role-name gwv-gateway-infra --assume-role-policy-document file://trust-ecs.json
aws iam attach-role-policy --role-name gwv-gateway-infra --policy-arn arn:aws:iam::aws:policy/AmazonECSInfrastructureRoleForGatewayHostSharedALB
次のコマンドでプライベートのゲートウェイを作り、クラスターに関連付けました。パブリックのゲートウェイは、--name を gw-public に、scheme を internet-facing に変えて同じように作り、gw-verify に関連付けました。コンソールでは、次の画面で同じ設定を指定できます。

aws ecs create-gateway \
--name gw-private \
--infrastructure-role-arn arn:aws:iam::<ACCOUNT_ID>:role/gwv-gateway-infra \
--configuration '{"hostSharedAlb":{"scheme":"internal","networkConfiguration":{"subnets":["<subnet-id-1a>","<subnet-id-1c>","<subnet-id-1d>"],"ipAddressType":"ipv4"}}}'
aws ecs associate-gateway-with-cluster --gateway gw-private --cluster gw-verify
scheme の既定は internet-facing です。ipAddressType は networkConfiguration の中に書きます。既定は dualstack で、今回は ipv4 を指定しました。
作成直後に gw-private を describe-gateway で取得した応答です(gatewayArn と infrastructureRoleArn の2行は省いています)。
{
"gateway": {
"name": "gw-private",
"status": "ACTIVE",
"deletionProtection": true,
"configuration": {
"hostSharedAlb": {
"networkConfiguration": {
"subnets": [
"subnet-xxxxxxxxxxxxxxxxx",
"subnet-xxxxxxxxxxxxxxxxx",
"subnet-xxxxxxxxxxxxxxxxx"
],
"ipAddressType": "ipv4"
},
"scheme": "internal",
"port": 443,
"protocol": "HTTPS",
"maxAlbCount": 10,
"currentAlbCount": 0,
"httpDesync": "defensive"
}
},
"accessType": "PRIVATE",
"propagateTags": "GATEWAY",
"tags": [],
"createdAt": "2026-10-31T22:16:22.076000+09:00",
"updatedAt": "2026-10-31T22:16:22.076000+09:00"
}
}
currentAlbCount は0で、ゲートウェイを作っただけでは ALB は作られません。deletionProtection は指定しなくても true になりました。リスナーは HTTPS 443 だけで、ポートやプロトコルは変えられません。作成後、gw-public の accessType は PUBLIC、gw-private は PRIVATE になりました。
サービスの接続先
サービスをゲートウェイに接続するコネクタは、タスク定義の名前付きポートを portName で参照します。タスク定義の portMappings に name を付けておきます。
名前付きポートを持つタスク定義
taskdef.json として保存して登録します。タスク実行ロール gwv-task-exec は、AmazonECSTaskExecutionRolePolicy を付けた通常のロールです。
{
"family": "gwv-web",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"executionRoleArn": "arn:aws:iam::<ACCOUNT_ID>:role/gwv-task-exec",
"containerDefinitions": [
{
"name": "web",
"image": "public.ecr.aws/docker/library/nginx:stable",
"essential": true,
"portMappings": [
{"name": "web", "containerPort": 80, "protocol": "tcp", "appProtocol": "http"}
]
}
]
}
aws ecs register-task-definition --cli-input-json file://taskdef.json
サービスの作成時に --gateway-connectors を付け、接続先を filters.accessTypes で選びます。PRIVATE を指定したサービスはプライベートのゲートウェイだけに、PUBLIC を指定したサービスはパブリックのゲートウェイだけに接続されました。コンソールでは、サービス作成画面で接続先のゲートウェイを指定します。

aws ecs create-service --cluster gw-verify --service-name svc-private-01 \
--task-definition gwv-web --desired-count 1 --launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[<subnet-id-1a>,<subnet-id-1c>,<subnet-id-1d>],assignPublicIp=ENABLED}" \
--gateway-connectors '[{"portName":"web","filters":{"accessTypes":["PRIVATE"]}}]'
assignPublicIp=ENABLED は、タスクがコンテナイメージを取得できるよう、インターネットへの経路を持たせるために指定しました。接続するゲートウェイの種類は、この設定ではなく filters.accessTypes で決まります。
svc-public-01 と svc-private-01 の作成から約12秒後、パブリック側に internet-facing ALB、プライベート側に internal ALB が1台ずつ作られました。
filters を省略すると、同じ VPC にあり、サービスが使うすべての AZ をカバーするゲートウェイへ接続されます。後からパブリックのゲートウェイをクラスターに関連付けた場合も、次のデプロイで接続対象になります。意図しない公開を防ぐため、インターネットに公開しないサービスには PRIVATE を明示します。
FQDN と IP アドレス
FQDN の形
サービスリビジョンの ARN を describe-service-revisions に渡すと、serviceUrl を取得できます。
aws ecs describe-service-revisions --service-revision-arns <サービスリビジョンのARN> \
--query 'serviceRevisions[0].ecsManagedResources.gatewayConnections[].[accessType,status,serviceUrl]' --output text
パブリックとプライベートのサービスから取得した結果です。URL の ID はマスクしています。
| サービス | accessType | status | serviceUrl |
|---|---|---|---|
| svc-private-01 | PRIVATE | ACTIVE | https://sv-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.ecs.<リージョン>.on.aws |
| svc-public-01 | PUBLIC | ACTIVE | https://sv-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.ecs.<リージョン>.on.aws |
URL は https://sv-<32桁の16進数>.ecs.<リージョン>.on.aws の形でした。ID はランダムに生成されるため、同じ名前でサービスを作り直しても URL は変わります。
名前解決の結果
VPC の外にある PC(以下、手元の PC)から、各 FQDN の A レコードを取得しました。
svc-private-01: 172.31.x.a 172.31.x.b 172.31.x.c
svc-public-01: x.x.x.p x.x.x.q x.x.x.r
svc-private-01 には internal ALB のプライベート IP、svc-public-01 には internet-facing ALB のパブリック IP が返りました。
どちらの FQDN も CNAME を挟まず A レコードが直接返り、TTL は60秒でした。プライベートの FQDN も手元の PC から名前解決できましたが、返ったのは VPC 内のプライベート IP でした。
Express Mode との比較
共通の構成
別クラスター gw-verify-express に、Express Mode でパブリックのサービス svc-express-01 を1つ作りました。その ALB まわりのリソースを gw-public のものと比べました。次の点が同じでした。
- エンドポイントの形(
https://sv-<32桁の16進数>.ecs.<リージョン>.on.aws) - HTTPS 443 のリスナー(TLS ポリシー ELBSecurityPolicy-TLS13-1-2-Ext1-PQ-2025-09、デフォルトアクションは固定応答 404 Not Found)
- host-header 条件で転送するルール(優先度はどちらも 44990)
- ターゲットグループ(ターゲットタイプ ip、HTTP 80、ヘルスチェックのパス
/、間隔30秒、成功コード 200) - サービスごとの ACM 証明書(AMAZON_ISSUED、EC-prime256v1、DNS 検証)
- セキュリティグループの組み方(ALB 用は 80 と 443 を 0.0.0.0/0 から許可、サービス用はインバウンドで ALB 用のセキュリティグループから TCP 80 を許可)
- ALB、セキュリティグループ、ターゲットグループに付くタグ AmazonECSManaged=true
Express Mode と異なる点
ECS Gateway が作るのは、ALB、リスナー、ルール、ターゲットグループ、証明書、ホスト名、セキュリティグループなどの入口に関するリソースです。Express Mode とは異なり、タスク定義、ログ、オートスケーリングは自分で設定します。
Express Mode のサービスは ECS Gateway に接続できません。同じ VPC で併用しても、それぞれに別の ALB が作られます。
ゲートウェイの削除
サービスを削除し、ルートと ALB が消えた後、クラスターとの関連付けと削除保護を解除してゲートウェイを削除しました。
aws ecs disassociate-gateway-from-cluster \
--gateway gw-private \
--cluster gw-verify
aws ecs update-gateway \
--gateway gw-private \
--infrastructure-role-arn arn:aws:iam::<ACCOUNT_ID>:role/gwv-gateway-infra \
--no-deletion-protection \
--configuration '{"hostSharedAlb":{"maxAlbCount":10}}'
aws ecs delete-gateway --gateway gw-private
検証時の update-gateway では、削除保護だけを変更する場合も --infrastructure-role-arn と --configuration が必要でした。また、delete-gateway はステータスが UPDATE_COMPLETE になってから実行します。
まとめ
ECS Gateway を使うと、ALB、HTTPS リスナー、証明書、ホストベースのルーティング、セキュリティグループといった、サービスの入口に必要なリソースをまとめて作成・管理できます。1台の ALB を最大25のサービスで共有するため、サービスごとに ALB を立てる構成に比べて ALB の維持費を抑えられます。証明書は、AWS が管理するドメイン(on.aws)に対する ACM 証明書が追加料金なしで使え、HTTPS リスナーもゲートウェイが用意します。コンソールのサービス作成画面からは、CloudFront や WAF もあわせて設定できます。
基盤チームがパブリック用とプライベート用のゲートウェイを用意してネットワーク構成を管理し、アプリケーションチームは名前付きポートと accessType を指定して接続するだけ、という分担にできます。タスク定義やログ、オートスケーリングはアプリケーション側に残るため、入口の管理と役割を分けられます。








