Amazon EventBridge × VPC Lattice × Fargate — イベント駆動サービス間通信ハンズオン

目次

Amazon EventBridge × VPC Lattice × Fargate — イベント駆動サービス間通信ハンズオン

マイクロサービスアーキテクチャが普及するにつれて、「サービスAのイベントをトリガーに、VPC内のプライベートなサービスBを呼び出したい」というユースケースが増えています。従来はこのパターンを実現するためにALBをインターネット側に公開するか、Lambdaをプロキシに挟む構成が一般的でした。

2024年11月、Amazon EventBridgeはプライベート接続機能を追加しました。EventBridge ConnectionにVPC Lattice Resource Configuration ARNを指定することで、EventBridgeからVPC内のプライベートAPIをインターネットを経由せずに直接呼び出せるようになっています。本記事ではこの新機能とVPC Lattice・ECS Fargateを組み合わせた、セキュアなイベント駆動アーキテクチャの構築手順をコンソール操作とTerraformの両方で解説します。

この記事で学ぶこと

– EventBridgeのAPI DestinationとVPC Lattice Resource Gatewayを連携させる方法
– ECS FargateサービスをVPC LatticeのTarget Groupに自動登録する仕組み
– S3イベントをトリガーにFargate上のプライベートAPIを呼び出す構成
– コンソール手順とTerraform両方での構築方法


アーキテクチャ概要

全体フロー

このハンズオンで構築するシステムは、S3バケットへのファイルアップロードをトリガーに、VPC内のECS Fargateコンテナで動くプライベートAPIを安全に呼び出すイベント駆動アーキテクチャです。

EventBridge Rule
  → API Destination (HTTPS)
 → Connection (Resource Configuration ARN)
→ VPC Lattice Resource Gateway (in VPC)
  → VPC Lattice Service (FQDN)
 → Listener (HTTP:80)
→ Target Group (IP type)
  → ECS Fargate Tasks (HTTP API)

各区間の通信プロトコルと役割:

区間プロトコル説明
Rule → API DestinationHTTPSEventBridgeがAPI Destinationに対してHTTPS呼び出しを行う
API Destination ↔ ConnectionConnectionがAPI Destinationに認証情報・プライベート接続設定を提供
Connection → Resource GatewayHTTPS / TCPResource Configuration ARNを経由してVPC内Resource Gatewayに到達
Resource Gateway → VPC Lattice ServiceHTTPVPC内でHTTPルーティング(Resource Gatewayが終端)
Listener → Target GroupHTTP:80FargateタスクのIPへ転送

アーキテクチャ図


各コンポーネントの役割

Amazon EventBridge

EventBridge Event Bus

S3からのイベントを受信するイベントバスです。S3バケットに対して「EventBridgeへの通知」を有効化すると、PutObject等のイベントがJSONペイロードとして送られてきます。カスタムイベントバスを使用することも、デフォルトイベントバスをそのまま使うこともできます。

EventBridge Rule

イベントパターンに一致するイベントをフィルタリングし、API Destinationに転送します。本ハンズオンでは以下のパターンで特定のS3バケットへのオブジェクト作成イベントのみをキャッチします。

{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
 "bucket": {"name": ["demo-event-bucket"]}
  }
}

EventBridge Connection

API Destinationに対する認証情報とプライベート接続設定を保持します。invocation_connectivity_parametersresource_configuration_arnを指定することで、EventBridgeがResource Gateway経由でVPC内のAPIを呼び出せるようになります。認証方式はAPI_KEY / BASIC / OAUTHのいずれかを選択します(本ハンズオンではAPI_KEY)。

EventBridge API Destination

VPC Lattice Service FQDNをエンドポイントとして定義します。connection_arnにConnectionを紐付け、HTTPメソッド(POST)・呼び出しレート制限(10 req/sec)を設定します。


VPC Lattice

Service Network

サービスとVPCを論理的にグループ化するネットワーク基盤です。VPCをService Networkに関連付けることで、そのVPC内のリソースからService Network内のサービスにアクセスできるようになります。1つのService Networkに最大500のサービスを登録可能です。

Service

Fargate APIへのルーティングを提供するサービスエンティティです。作成時に一意のFQDN({service-id}.{region}.vpc-lattice-svcs.{region}.on.aws形式)が自動生成されます。このFQDNをEventBridge API Destinationのエンドポイントとして使用します。

Listener

HTTP:80でインバウンドリクエストを受け付け、Target Groupに転送するルールを定義します。デフォルトアクションとして「Target Groupへ転送」を設定します。

Target Group (IP type)

ECS Fargateタスクのプライベートサブネット内IPアドレスをターゲットとして管理します。type: IPを指定し、ポート80・プロトコルHTTP・VPC IDを設定します。ECS Serviceのvpc_lattice_configurationsを設定することで、タスクの起動・終了に合わせて自動的に登録・解除が行われます。

Resource Gateway

VPC内に配置されるネットワークエントリーポイントです。EventBridgeからResource Configuration経由で送られてくる通信を受け入れ、VPC内のリソースに転送します。プライベートサブネットに配置し、セキュリティグループでポート443(EventBridgeからの接続用)のインバウンドを許可します。

Resource Configuration

リソースの識別情報(ドメイン名またはIP)と接続方法(プロトコル・ポート)を定義します。EventBridge ConnectionからARNで参照されることで、EventBridgeがどのリソースに接続するかを指定します。type: SINGLEprotocol: TCPport_ranges: [80]が基本設定です。


ECS Fargate

本ハンズオンでは、/processエンドポイントでHTTP POSTリクエストを受け付け、リクエストボディをCloudWatch Logsに出力するシンプルなFlask(またはNode.js Express)APIをFargateで動かします。

ECS Serviceにvpc_lattice_configurationsを設定すると、ECS Infrastructure Role経由でVPC Lattice Target Groupへの自動登録が行われます。この設定により、以下が自動化されます。

  • タスク起動時: タスクのプライベートIPがTarget Groupに登録される
  • タスク終了時: ターゲット登録が自動解除される
  • スケールアウト時: 追加されたタスク分のIPが追加登録される

このアーキテクチャが解決すること

3つの課題を解決するアーキテクチャ

1. プライベートVPC内APIをインターネット公開せずEventBridgeから呼び出せる
Resource Gateway経由のプライベート接続により、FargateのAPIをインターネットに公開する必要がなくなります。パブリックIPもALBも不要です。セキュリティグループで通信経路を厳格に制御できます。

2. ECSタスクのスケールイン/アウトに応じてTarget Groupが自動更新
vpc_lattice_configurationsにより、Fargateタスクの起動・終了と連動してTarget Groupのメンバーシップが自動管理されます。手動でのターゲット登録・解除が不要です。

3. VPC Latticeでサービス間通信を一元管理
Service NetworkにVPCとサービスを関連付けることで、サービスメッシュとして機能します。クロスアカウント・クロスVPCのサービス間通信も同一インターフェースで管理可能です。


前提条件

このハンズオンを始める前に以下を確認してください

AWSアカウント: ECS / VPC Lattice / EventBridge / S3 / IAMの操作権限が必要です
AWS CLI v2: インストール・設定済み(aws configureでリージョン・認証情報設定済み)
Docker: ローカル環境にインストール済み(Fargateコンテナイメージのビルド・ECR push用)
Terraform >= 1.3: Terraformセクションを使用する場合に必要
対象リージョン: ap-northeast-1(東京)

VPC Lattice Resource Gatewayはap-northeast-1を含む主要リージョンで利用可能です。EventBridgeとのプライベート接続機能は2024年11月リリース。使用前にリージョンのサービス提供状況を確認してください。


構築するリソース一覧

このハンズオンで作成するAWSリソースの全体像です。手順を始める前に全体像を把握しておくと、各ステップの目的が理解しやすくなります。

リソースサービス役割
ECSクラスター / タスク定義 / サービスAmazon ECSHTTP APIホスト(Fargate)
VPC Lattice Target Group (IP)VPC LatticeECSタスク自動登録先
VPC Lattice Listener / ServiceVPC LatticeAPIへのルーティング
VPC Lattice Service NetworkVPC Latticeサービスメッシュ基盤・VPC関連付け
VPC Lattice Resource GatewayVPC LatticeEventBridgeからのプライベート接続入口
VPC Lattice Resource ConfigurationVPC Latticeリソース接続定義(ポート/プロトコル)
EventBridge ConnectionEventBridgeResource Configuration経由のプライベート接続設定
EventBridge API DestinationEventBridgeFargate APIのHTTPSエンドポイント定義
EventBridge Rule + TargetEventBridgeS3イベント → API Destinationへのルーティング
S3バケットS3イベントソース(PutObjectでEventBridge発火)
VPC / サブネット / NAT GatewayVPCネットワーク基盤(プライベート × 2、パブリック × 2)
IAMロール(4種)IAMECS実行・タスク・VPC Lattice統合・EventBridge呼び出し

概算コスト

ハンズオン規模でのコスト目安

| サービス | 課金項目 | 単価 |
|———|———|—–|
| VPC Lattice | データ処理料金 | $0.025/GB |
| VPC Lattice | リクエスト料金 | $0.10/100万リクエスト |
| Resource Gateway | 時間課金 + データ処理課金 | PrivateLink料金に準ずる($0.01/時間程度) |
| EventBridge | API Destination呼び出し | $1.00/100万回 |
| Fargate | vCPU時間 | $0.04048/vCPU時間 |
| Fargate | メモリ時間 | $0.004445/GB時間 |

ハンズオン規模(数時間・数十リクエスト)であれば無料枠内または数十円程度の見込みです。

ただし、Resource GatewayはPrivateLinkに準ずる時間課金が発生するため、使用後は必ずクリーンアップを実施してください。Terraform使用時はterraform destroyで一括削除できます。


アーキテクチャ構成図


図1: EventBridge × VPC Lattice × Fargate 全体アーキテクチャ


図2: VPCネットワーク詳細構成


図3: EventBridgeイベント駆動フロー


コンソールハンズオン Phase 1: VPC・ネットワーク基盤の準備

ECS Fargateのコンテナと、VPC Lattice Resource Gatewayを配置するためのVPCネットワークを構築します。プライベートサブネットにアプリケーションを配置し、NAT Gatewayを経由してECRからコンテナイメージをpullできる構成にします。

1-1. VPCの作成

  1. AWSマネジメントコンソールにログインし、VPC サービスを開きます
  2. 左メニューから 「Your VPCs」「Create VPC」 をクリック
  3. 以下の設定を入力します
項目
Name tageventbridge-lattice-vpc
IPv4 CIDR block10.0.0.0/16
IPv6 CIDR blockNo IPv6 CIDR block
TenancyDefault
  1. 「Create VPC」 をクリックして作成

1-2. サブネットの作成

プライベートサブネット(×2、異なるAZ)

  1. 左メニューから 「Subnets」「Create subnet」 をクリック
  2. VPC ID に先ほど作成した eventbridge-lattice-vpc を選択
  3. 以下の2つのサブネットを同じ画面で追加します(「Add new subnet」で追加)
NameAZIPv4 CIDR
private-subnet-aap-northeast-1a10.0.1.0/24
private-subnet-cap-northeast-1c10.0.2.0/24
  • 「Auto-assign public IPv4 address」無効(デフォルト) のままにします

  • 「Create subnet」 をクリック

パブリックサブネット(×2、NAT Gateway配置用)

同様の手順で以下のサブネットを作成します。

NameAZIPv4 CIDR
public-subnet-aap-northeast-1a10.0.101.0/24
public-subnet-cap-northeast-1c10.0.102.0/24
  • 「Auto-assign public IPv4 address」「Enable」 にチェックを入れます

1-3. Internet Gatewayの作成・VPCへのアタッチ

  1. 左メニューから 「Internet Gateways」「Create internet gateway」 をクリック
  2. Name tag: eventbridge-lattice-igw と入力して 「Create internet gateway」
  3. 作成後、「Actions」「Attach to VPC」 をクリック
  4. eventbridge-lattice-vpc を選択して 「Attach internet gateway」

1-4. NAT Gatewayの作成

NAT GatewayはプライベートサブネットのFargateタスクがECRからイメージをpullするために必要です。

  1. 左メニューから 「NAT Gateways」「Create NAT gateway」 をクリック
  2. 以下の設定を入力します
項目
Nameeventbridge-lattice-nat-a
Subnetpublic-subnet-a
Connectivity typePublic
Elastic IP allocation ID「Allocate Elastic IP」 をクリックして新規取得
  1. 「Create NAT gateway」 をクリック
NAT Gateway の課金に注意
NAT GatewayはEIPの確保時点から時間課金(約$0.062/時間)が発生します。ハンズオン終了後はNAT Gatewayを削除し、EIPも解放してください。

1-5. ルートテーブルの設定

パブリックサブネット用ルートテーブル

  1. 左メニューから 「Route Tables」「Create route table」
  2. Name: public-rtb、VPC: eventbridge-lattice-vpc を選択して作成
  3. 作成したルートテーブルを選択 → 「Routes」 タブ → 「Edit routes」
  4. 「Add route」 をクリックし以下を追加
DestinationTarget
0.0.0.0/0Internet Gateway (eventbridge-lattice-igw)
  1. 「Save changes」「Subnet associations」 タブ → 「Edit subnet associations」
  2. public-subnet-apublic-subnet-c を選択して 「Save associations」

プライベートサブネット用ルートテーブル

  1. 同様に 「Create route table」 でルートテーブルを作成
  2. Name: private-rtb、VPC: eventbridge-lattice-vpc
  3. 「Routes」「Edit routes」「Add route」
DestinationTarget
0.0.0.0/0NAT Gateway (eventbridge-lattice-nat-a)
  1. 「Subnet associations」private-subnet-aprivate-subnet-c を関連付け

1-6. セキュリティグループの作成

ECS Fargateコンテナと、VPC Lattice Resource Gatewayのそれぞれに専用のセキュリティグループを作成します。

sg-fargate(ECS Fargateコンテナ用)

  1. 左メニューから 「Security Groups」「Create security group」
  2. 以下の設定を入力します
項目
Security group namesg-fargate
DescriptionECS Fargate container SG
VPCeventbridge-lattice-vpc
  1. Inbound rules に以下を追加
TypeProtocolPort rangeSource
Custom TCPTCP80Custom — sg-lattice-rg のSG ID(後で設定)
  1. Outbound rules はデフォルト(全トラフィック許可)のまま
  2. 「Create security group」

sg-lattice-rg(VPC Lattice Resource Gateway用)

  1. 同様に 「Create security group」
項目
Security group namesg-lattice-rg
DescriptionVPC Lattice Resource Gateway SG
VPCeventbridge-lattice-vpc
  1. Inbound rules
TypeProtocolPort rangeSource
HTTPSTCP443Anywhere-IPv4 (0.0.0.0/0)
  1. Outbound rules
TypeProtocolPort rangeDestination
Custom TCPTCP80Custom — sg-fargate のSG ID
  1. 「Create security group」

作成後、sg-fargate のインバウンドルールに戻り、ソースを sg-lattice-rg のSG IDに更新してください(「Edit inbound rules」 → ソースにSG IDを入力)。

セキュリティグループの相互参照
sg-fargate のインバウンドは sg-lattice-rg からのTCP:80のみ許可します。これにより、Resource Gateway経由でのみFargateコンテナへのアクセスを許可し、直接アクセスを防ぎます。
💡 推奨: vpc-lattice マネージドプレフィックスリストの追加
AWS公式ドキュメントでは、VPC Latticeのヘルスチェックが正常に動作するよう、
Fargate SGのインバウンドに com.amazonaws.ap-northeast-1.vpc-lattice
マネージドプレフィックスリストも追加することが推奨されています。
「Edit inbound rules」→ 「Add rule」→ Type: Custom TCP, Port: 80,
Source: Prefix listvpc-lattice を検索して選択してください。

コンソールハンズオン Phase 2: Fargate用APIコンテナの準備とECS構築

2-1. サンプルAPIアプリケーションの準備

EventBridgeからのイベントを受け取るシンプルなFlask APIを作成します。以下のファイルをローカル環境に用意してください。

# app.py
from flask import Flask, request, jsonify
import logging, json

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)

@app.route('/process', methods=['POST'])
def process():
 body = request.get_json(silent=True) or {}
 app.logger.info(f"Received event: {json.dumps(body)}")
 return jsonify({"status": "ok", "received": body}), 200

@app.route('/health', methods=['GET'])
def health():
 return jsonify({"status": "healthy"}), 200

if __name__ == '__main__':
 app.run(host='0.0.0.0', port=80)
# Dockerfile
FROM python:3.12-slim
WORKDIR /app
RUN pip install flask gunicorn
COPY app.py .
EXPOSE 80
CMD ["gunicorn", "-b", "0.0.0.0:80", "app:app"]

ECRリポジトリの作成とDockerイメージのpush

  1. AWSマネジメントコンソールで 「Elastic Container Registry」 を開く
  2. 「Create repository」 をクリック
  3. Repository name: eventbridge-lattice-api、Visibility: Private で作成

コンテナイメージのビルドとpushはCLIで実行します。

# ECRリポジトリ作成(CLIで行う場合)
aws ecr create-repository --repository-name eventbridge-lattice-api --region ap-northeast-1

# Docker ログイン
aws ecr get-login-password --region ap-northeast-1 | \
  docker login --username AWS --password-stdin <ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com

# ビルド & プッシュ
docker build -t eventbridge-lattice-api .
docker tag eventbridge-lattice-api:latest \
  <ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/eventbridge-lattice-api:latest
docker push <ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/eventbridge-lattice-api:latest

<ACCOUNT_ID> は自身のAWSアカウントIDに置き換えてください。ECRコンソールの 「View push commands」 ボタンからも同様のコマンドが確認できます。

2-2. ECSタスク実行ロールの作成

ECSがECRからイメージをpullし、CloudWatch Logsにログを書き込むためのIAMロールを作成します。

  1. AWSマネジメントコンソールで 「IAM」「Roles」「Create role」 をクリック
  2. 「Trusted entity type」: AWS service → 「Elastic Container Service」
  3. 「Use case」: 「Elastic Container Service Task」 を選択 → 「Next」
  4. Permissions policies で以下を検索して追加
ポリシー名
AmazonECSTaskExecutionRolePolicy
  1. Role name: ecsTaskExecutionRole「Create role」

2-3. ECSクラスターの作成

  1. AWSマネジメントコンソールで 「Elastic Container Service」 を開く
  2. 左メニューから 「Clusters」「Create cluster」
  3. 以下の設定を入力
項目
Cluster nameeventbridge-lattice-cluster
InfrastructureAWS Fargate (serverless)
  1. 「Create」 をクリック

2-4. ECSタスク定義の作成

  1. 左メニューから 「Task definitions」「Create new task definition」
  2. Task definition family: eventbridge-lattice-api
  3. Launch type: FARGATE
  4. Operating system/Architecture: Linux/X86_64
  5. CPU: 0.25 vCPU(256)、Memory: 0.5 GB(512)
  6. Task execution role: ecsTaskExecutionRole

コンテナの設定

「Add container」 で以下を設定します。

項目
Nameapi
Image URI<ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/eventbridge-lattice-api:latest
Container port80 / Protocol: TCP
Port nameapi-port

Log collection セクション:
「Use log collection」 を有効化
– Log driver: awslogs
– Log group: /ecs/eventbridge-lattice-api(自動作成される)
– Region: ap-northeast-1
– Stream prefix: ecs

  1. 「Create」 をクリック

2-5. ECSサービスの作成(初回・VPC Lattice設定前)

この時点ではVPC Lattice統合なしでECSサービスを作成します。VPC Lattice連携(vpc_lattice_configurationsの設定)はPhase 3で行います。

  1. 「Clusters」eventbridge-lattice-cluster を選択 → 「Services」 タブ → 「Create」
  2. 以下の設定を入力します
項目
Launch typeFARGATE
Task definitioneventbridge-lattice-api(最新リビジョン)
Service nameeventbridge-lattice-api-svc
Desired tasks2
  1. 「Networking」 セクション
項目
VPCeventbridge-lattice-vpc
Subnetsprivate-subnet-aprivate-subnet-c を選択
Security groupssg-fargate を選択(デフォルトは削除)
Public IPTURNED OFF(プライベートサブネットのため)
  1. Load balancing は 「None」 のまま(ALBは使用しない)
  2. 「Create」 をクリック
ECS「VPC Lattice統合」はサービス作成後でも更新可能
ECSサービスの「VPC Lattice configurations」はサービス作成後に更新で追加できます。Phase 3でVPC LatticeのTarget Groupを作成してから、ECSサービスを更新して統合を設定します。今の時点では省略してOKです。

しばらく待つと、ECSサービスが 2/2 tasks running の状態になります。このタスクはプライベートサブネット内で起動しており、NAT Gateway経由でECRからイメージをpullしています。ALBがないためこの時点では外部からの疎通確認はできません。動作確認はPhase 6で、VPC Lattice経由で実施します。

コンソールハンズオン Phase 3: VPC Lattice 構成

このPhaseでは、ECS Fargateサービスへのトラフィックをルーティングする VPC Lattice のコンポーネント(Target Group・Service・Listener・Service Network)を作成し、ECSサービスと統合します。完了後、VPC Lattice Service の一意なFQDNが払い出され、EventBridgeからの呼び出しが可能になる準備が整います。

ステップ内容
3-1VPC Lattice Service 作成(FQDN払い出し)
3-2VPC Lattice Service Network 作成
3-3Service Network ↔ Service 関連付け
3-4Service Network ↔ VPC 関連付け
3-5ECSサービス更新: VPC Lattice有効化 → Target Group自動作成
3-6VPC Lattice Listener 作成(HTTP:80)
3-7Target Group のターゲット登録確認

3-1. VPC Lattice Service 作成

VPC Lattice Service は、ルーティングのエントリーポイントとなるコンポーネントです。作成時に一意のFQDNが自動生成され、EventBridgeのAPI Destinationの呼び出し先として使用します。

AWSコンソール → VPC → 左ペイン「VPC Lattice」→「Services」→「Create service

基本設定

項目設定値
Nameeventbridge-lattice-service
Auth typeNone(デモ用。本番環境ではAWS IAMを推奨)

Custom domain name: 設定しない(デフォルトのまま)

Monitoring: デフォルトのまま(CloudWatch メトリクスは自動有効化)

Next」→ Listener 設定画面はスキップし(3-6で別途追加)、「Create service」をクリック。

作成完了後、サービス詳細画面の「Summary」タブで FQDN を確認・コピーしてください。

形式: {service-id}.{hash}.vpc-lattice-svcs.ap-northeast-1.on.aws
例:  svc-01abc23def456789.abc123def456.vpc-lattice-svcs.ap-northeast-1.on.aws
ポイント: FQDNを必ず記録する
この FQDN は後続の Phase 4(Resource Configuration)および Phase 5(EventBridge API Destination)で使用します。メモ帳やターミナルに貼り付けておいてください。

3-2. VPC Lattice Service Network 作成

Service Network は、複数のサービスとVPCを論理的にグループ化する仮想ネットワークです。Service Network にサービスとVPCを関連付けることで、そのVPC内のリソース(ECSタスク、Lambda等)からサービスへのアクセスが可能になります。

AWSコンソール → VPC → 左ペイン「VPC Lattice」→「Service networks」→「Create service network

項目設定値
Nameeventbridge-lattice-sn
Auth policyNone(デモ用。本番環境ではAWS IAMを推奨)

Create service network」をクリック。


3-3. Service Network ↔ Service 関連付け

作成した Service Network に、3-1で作成したサービスを関連付けます。

VPC Lattice コンソール → 「Service networks」→「eventbridge-lattice-sn」をクリック → 「Services」タブ → 「Associate services

項目設定値
Serviceeventbridge-lattice-service(リストから選択)

Associate」をクリック。

ステータスが「Active」になるまで数秒〜1分ほど待ちます。


3-4. Service Network ↔ VPC 関連付け

VPC を Service Network に関連付けることで、VPC 内のリソースから VPC Lattice サービスへのアクセスが可能になります。セキュリティグループによりアクセス範囲を制御します。

VPC Lattice コンソール → 「Service networks」→「eventbridge-lattice-sn」→「VPC associations」タブ → 「Associate VPC

項目設定値
VPCPhase 1 で作成した VPC を選択
Security groupsPhase 1 で作成した sg-lattice-vpc-assoc(またはLattice用SG)を選択

Associate」をクリック。

⚠️ 注意: VPC関連付けのセキュリティグループ
VPC関連付けに指定するセキュリティグループは、VPC内からVPC Lattice Serviceへのアクセスを制御します。Resource Gateway からのトラフィックはVPC内経由で送られるため、ECSタスクやResource GatewayのSGからHTTP(ポート80)のインバウンドを適切に許可してください。

最小限の設定例:インバウンドでECS FargateのSGからポート80を許可、アウトバウンドはすべて許可。


3-5. ECSサービス更新: VPC Lattice有効化とTarget Group自動作成

ECSサービスに VPC Lattice Configurations を追加することで、タスク起動時にプライベートIPアドレスが自動的にTarget Groupに登録されます。この設定にはECS Infrastructure Role(専用IAMロール)が必要です。

事前準備: ECS Infrastructure Role の作成

AWSコンソール → IAM → 「ロール」→「ロールを作成

ステップ 1: 信頼されたエンティティの選択

項目設定値
信頼されたエンティティタイプAWS のサービス
サービスElastic Container Service
ユースケースElastic Container Service

次へ」をクリック。

ステップ 2: 許可ポリシーの追加

検索ボックスに「vpc-lattice」と入力→「インラインポリシーを作成」を選択し、以下のJSONを入力:

{
  "Version": "2012-10-17",
  "Statement": [
 {
"Effect": "Allow",
"Action": [
  "vpc-lattice:RegisterTargets",
  "vpc-lattice:DeregisterTargets",
  "vpc-lattice:GetTargetGroup"
],
"Resource": "*"
 }
  ]
}

ポリシー名: ECSVpcLatticeIntegrationPolicy

次へ」→ ロール名: ecsInfrastructureRole → 「ロールを作成

💡 ヒント: ecsInfrastructureRole の役割
このロールは ECS コントロールプレーンが使用します。ECSサービスのvpc_lattice_configurations設定により、タスクの起動・停止イベントに連動して VPC Lattice Target Group へのRegisterTargets/DeregisterTargets API を自動的に呼び出します。タスクロールやタスク実行ロールとは別物です。

ECSサービスの更新

AWSコンソール → Amazon ECS → 「クラスター」→ Phase 2 で作成したクラスター(例: eventbridge-lattice-cluster)→ 「Services」タブ → eventbridge-lattice-service → 「更新

VPC Lattice integration」セクションまでスクロールし、「Turn on VPC Lattice」を有効化してください。

項目設定値
Infrastructure roleecsInfrastructureRole(作成したロールを選択)
Target group nameeventbridge-lattice-tg(ECSが自動作成する名前を入力)
Port nameapi-port(タスク定義の portMappings.name と一致させる)
ProtocolHTTP
Port80

更新」をクリック → ECSが VPC Lattice Target Group eventbridge-lattice-tg を自動作成します。

⚠️ 重要: ECSコンソールはTarget Groupを「自動作成」します
VPC Latticeコンソールで事前にTarget Groupを独立作成しても、ECSコンソールの「VPC Lattice integration」画面では既存のTarget Groupを選択できません。ECSコンソールは新しいTarget Group名を入力してECSに自動作成させる仕様です。
Target group name に作成したいTG名を入力すると、ECSがVPC Lattice APIを使って自動的にIPタイプのTarget Groupを作成します。

ECSサービスの更新が完了すると、新しいタスクが起動し始めます。タスクが起動するまで数分かかります。

ヘルスチェック設定(path: /health, interval: 30秒)はTarget Group自動作成後にVPC Latticeコンソールで確認・調整してください。


3-6. VPC Lattice Listener 作成

Listener は、Service に到着したリクエストをどのTarget Groupに転送するかを定義します。HTTP:80 で受け付け、3-5でECSが自動作成した Target Group に転送するルールを設定します。

VPC Lattice コンソール → 「Services」→「eventbridge-lattice-service」をクリック → 「Listeners」タブ → 「Add listener

項目設定値
ProtocolHTTP
Port80
Default actionForward to target group
Target groupeventbridge-lattice-tg(ドロップダウンから選択)
Weight100(デフォルト)

Save changes」をクリック。


3-7. Target Group のターゲット登録確認

ECSタスクが起動した後、Target Group にタスクのプライベートIPが自動登録されていることを確認します。

VPC Lattice コンソール → 「Target groups」→「eventbridge-lattice-tg」→「Targets」タブ

確認項目期待値
ターゲット(IPアドレス)ECSタスクのプライベートIP(例: 10.0.x.x)が表示される
ポート80
ステータスHealthy
💡 ヒント: ヘルスチェックの待機時間
ECSタスクが起動してからTarget GroupのステータスがHealthyになるまで、ヘルスチェック設定(インターバル30秒 × Healthy threshold 3回)の関係で 最大1〜2分 かかります。しばらく待ってからページを更新してください。

もしUnhealthyが続く場合は、FargateタスクのSGがポート80のインバウンドを許可しているか、アプリが /health エンドポイントで200を返しているかを確認してください。

VPC Lattice Service FQDN の最終確認

VPC Lattice コンソール → 「Services」→「eventbridge-lattice-service」→「Summary」タブ → 「DNS name」の値をメモ

これで Phase 3 が完了です。ECS Fargate タスクが VPC Lattice 経由でアクセス可能な状態になりました。


コンソールハンズオン Phase 4: VPC Lattice Resource Gateway 構成

このPhaseでは、EventBridgeがプライベートVPC内のAPI(VPC Lattice Service)へアクセスするための入口となる Resource Gateway と Resource Configuration を作成します。

EventBridge Connection は Resource Configuration の ARN を参照することで、パブリックインターネットを経由せずに VPC Lattice Service FQDN を呼び出せるようになります。

ステップ内容
4-1Resource Gateway 作成(VPCへのエントリーポイント)
4-2Resource Configuration 作成(VPC Lattice Service FQDN を登録)

4-1. Resource Gateway 作成

Resource Gateway は VPC 内に配置されるネットワークエンドポイントで、EventBridge からの HTTPS トラフィックを受け入れます。プライベートサブネットに配置することで、インターネットから直接アクセスできない安全な構成になります。

AWSコンソール → VPC → 左ペイン「VPC Lattice」→「Resource gateways」→「Create resource gateway

項目設定値
Nameeventbridge-lattice-rg
VPCPhase 1 で作成した VPC を選択
Subnetsプライベートサブネット × 2(AZ-a, AZ-c)を選択
Security groupssg-lattice-rg(Phase 1 で作成したResource Gateway用SG)を選択
IP address typeIPv4

Create resource gateway」をクリック。

作成には数分かかります。ステータスが「Active」になるまで待ちます。

💡 ヒント: Resource Gateway の配置場所
Resource Gateway は VPC 内のプライベートサブネットに配置されます。
EventBridge は、Resource Configuration ARN を介してこの Resource Gateway に HTTPS(ポート443)でアクセスし、Resource Gateway が VPC 内の VPC Lattice Service FQDN(HTTP:80)にプロキシします。

セキュリティグループ sg-lattice-rg では、EventBridge(AWSサービス)からのポート443インバウンドと、VPC Lattice ServiceへのHTTP(ポート80)アウトバウンドを許可しておく必要があります。

sg-lattice-rg のインバウンドルール(最小構成)

タイププロトコルポートソース
HTTPSTCP4430.0.0.0/0(EventBridgeマネージドプレフィックスリストが理想)

sg-lattice-rg のアウトバウンドルール

タイププロトコルポート送信先
HTTPTCP80FargateのSG(sg-fargate)
⚠️ 注意: インバウンドポートについて
EventBridge → Resource Gateway の通信は HTTPS(ポート443)です。Resource Gateway はTLSを終端し、VPC Lattice Service へはHTTP(ポート80)で転送します。
そのため、Resource GatewayのSGのインバウンドはポート443、Fargate側SGのインバウンドはResource GatewayのSGからポート80を許可する設定が必要です。

4-2. Resource Configuration 作成

Resource Configuration は、Resource Gateway を通じてアクセスするリソース(本ハンズオンでは VPC Lattice Service FQDN)を定義します。作成後に払い出される Resource Configuration ARN は、Phase 5 の EventBridge Connection 設定で参照します。

AWSコンソール → VPC → 左ペイン「VPC Lattice」→「Resource configurations」→「Create resource configuration

基本設定

項目設定値
Nameeventbridge-lattice-rc
TypeSingle resource
ProtocolTCP

Resource gateway

項目設定値
Resource gatewayeventbridge-lattice-rg(4-1で作成したゲートウェイ)

ポートの設定

項目設定値
Port ranges80-80

リソースの設定

項目設定値
Domain name3-2で記録した VPC Lattice Service FQDN を入力

例:

svc-01abc23def456789.abc123def456.vpc-lattice-svcs.ap-northeast-1.on.aws

Create resource configuration」をクリック。

作成完了後、「Resource configurations」一覧または詳細画面で ARN を確認・コピーします。

形式: arn:aws:vpc-lattice:ap-northeast-1:{account-id}:resourceconfiguration/{rc-id}
ポイント: Resource Configuration ARN を必ず記録する
この ARN は Phase 5 の EventBridge Connection
invocation_connectivity_parametersresource_configuration_arn フィールドで参照されます。
Phase 5 に進む前に、この ARN をメモしておいてください。
⚠️ 警告: Resource Association の手動削除不可
EventBridge Connection を作成すると、内部的に VPC Lattice の Resource Association が自動作成されます。この Resource Association は手動で削除できません。

ハンズオン終了時のクリーンアップでは、EventBridge Connection を先に削除することで Resource Association も自動的に削除されます。Resource Configuration や Resource Gateway を先に削除しようとすると依存関係エラーが発生するため、必ず正しい順序(EventBridge側 → VPC Lattice側)でクリーンアップしてください。

クリーンアップ手順の詳細は Phase 7 を参照してください。


Phase 3-4 完了チェックリスト

Phase 5(EventBridge構成)に進む前に、以下を確認してください。

確認項目確認方法期待値
VPC Lattice Target GroupVPC Lattice > Target groups > Targets タブECSタスクIPがHealthy状態で登録されている
VPC Lattice Service FQDNVPC Lattice > Services > Summary タブFQDNが表示・コピー済み
VPC Lattice ListenerVPC Lattice > Services > Listeners タブHTTP:80 のリスナーが存在する
Service Network ↔ ServiceVPC Lattice > Service networks > Services タブActiveステータスで関連付けられている
Service Network ↔ VPCVPC Lattice > Service networks > VPC associations タブActiveステータスで関連付けられている
Resource GatewayVPC Lattice > Resource gatewaysActiveステータス
Resource Configuration ARNVPC Lattice > Resource configurationsARNをメモ済み

すべての項目を確認したら、Phase 5: EventBridge 構成に進んでください。

コンソールハンズオン Phase 5: EventBridge 構成

Phase 1〜4 でネットワーク基盤・ECS Fargate・VPC Lattice(Service Mesh + Resource Gateway)を構築しました。Phase 5 では EventBridge 側の設定を行い、S3 へのファイルアップロードを起点としてプライベート API を呼び出す経路を完成させます。

5-1. S3 バケット作成 + EventBridge 通知有効化

まず、イベントのトリガーとなる S3 バケットを作成します。

バケット作成手順:

  1. AWS マネジメントコンソールで S3 を開く
  2. バケットを作成」をクリック
  3. 以下を入力する:
  4. バケット名: eventbridge-demo-{ACCOUNT_ID}(グローバル一意。ACCOUNT_ID は 12 桁の AWS アカウント ID)
  5. AWS リージョン: アジアパシフィック (東京) ap-northeast-1
  6. その他の設定: デフォルトのまま(「パブリックアクセスをすべてブロック」は有効のまま)
  7. バケットを作成」をクリック

EventBridge 通知を有効化:

  1. 作成したバケットを開く
  2. プロパティ」タブを選択
  3. Amazon EventBridge」セクションまでスクロール
  4. 編集」をクリックし、「Amazon EventBridge へのイベントの送信」を オン に切り替える
  5. 変更の保存」をクリック
仕組み: S3 EventBridge 通知とは
S3 の「Amazon EventBridge 通知」を有効化すると、S3 バケットで発生するすべてのイベント(PutObject、DeleteObject 等)が自動的に EventBridge のデフォルトイベントバスに送信されます。従来の個別イベント通知設定(SNS / SQS / Lambda への通知)とは別の仕組みです。EventBridge を経由することで、より柔軟なルーティングとフィルタリングが可能になります。

5-2. EventBridge Connection 作成

EventBridge Connection は、API Destination が呼び出す先の認証情報と、プライベート接続設定(VPC Lattice Resource Configuration への参照)を保持するリソースです。

手順:

  1. EventBridge コンソールを開く
  2. 左メニューから「API destinations」→「Connections」を選択
  3. Create connection」をクリック
  4. 以下を入力する:
  5. Connection name: lattice-api-connection
  6. Authorization type: API Key(デモ用)
    • API key name: x-api-key
    • Value: demo-key-12345(任意の値)
  7. VPC connectivity」または「Invocation connectivity」セクションを展開し:
  8. Enable VPC connectivity: チェックを オン
  9. Resource configuration ARN: Phase 4 で作成した Resource Configuration の ARN を貼り付ける
  10. Create」をクリック
画面レイアウトについて
VPC connectivity(プライベート接続)の設定は、AWS マネジメントコンソールの画面更新によりセクション名や位置が変わることがあります。「Connectivity settings」「Invocation connectivity」「Additional settings」「Advanced」など、展開できるセクションがあれば確認してください。Resource Configuration ARN の入力欄が見つからない場合は、画面を下にスクロールするか、折りたたまれたセクションを展開してみてください。
Terraform での代替手段
aws_cloudwatch_event_connection リソースの invocation_connectivity_parameters ブロックは、Terraform AWS Provider v5.x 時点で対応状況が要確認です。Terraform 未対応の場合は AWS CLI で代替できます:

aws events create-connection \
  --name lattice-api-connection \
  --authorization-type API_KEY \
  --auth-parameters '{"ApiKeyAuthParameters":{"ApiKeyName":"x-api-key","ApiKeyValue":"demo-key-12345"}}' \
  --invocation-connectivity-parameters \
  '{"ResourceParameters":{"ResourceConfigurationArn":""}}'

5-3. EventBridge API Destination 作成

API Destination は、Connection を使って呼び出す HTTP エンドポイントを定義します。ここでは VPC Lattice Service の FQDN を指定します。

手順:

  1. EventBridge コンソール左メニューから「API destinations」を選択
  2. Create API destination」をクリック
  3. 以下を入力する:
  4. Name: lattice-api-destination
  5. API destination endpoint: https://{VPC Lattice Service FQDN}/process
    {VPC Lattice Service FQDN} は Phase 3-2 で記録した FQDN。/process パスを末尾に追加する)
  6. HTTP method: POST
  7. Invocation rate limit: 10(1 秒あたりの最大呼び出し数)
  8. Connection: lattice-api-connection(5-2 で作成)
  9. Create」をクリック
VPC Lattice Service FQDN の形式
VPC Lattice Service FQDN は {service-id}.{hash}.vpc-lattice-svcs.ap-northeast-1.on.aws 形式で自動生成されます。ポート 80 はデフォルト HTTP ポートのため URL に :80 は不要です。API Destination のエンドポイントは HTTPS で指定する必要があります(VPC Lattice Resource Gateway が TLS を終端します)。

5-4. EventBridge Rule 作成(S3 PutObject イベントパターン)

S3 へのファイルアップロードイベントを検知し、API Destination に転送するルールを作成します。

手順:

  1. EventBridge コンソール左メニューから「Rules」を選択
  2. Create rule」をクリック
  3. Rule detail」で以下を入力する:
  4. Name: s3-to-lattice-api
  5. Event bus: default
  6. Rule type: Rule with an event pattern
  7. Next」をクリック
  8. Build event pattern」で以下の JSON を入力する:
{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
 "bucket": {
"name": ["eventbridge-demo-{ACCOUNT_ID}"]
 }
  }
}
  1. Next」をクリック
  2. Target 1」で以下を選択・入力する:
  3. Target types: EventBridge API destination
  4. API destination: lattice-api-destination(5-3 で作成)
  5. Execution role: 「Create a new role for this specific resource」を選択
    AmazonEventBridgeInvokeApiDestinationRolePolicy が自動付与される)
  6. Configure input transformer: デモではデフォルト(変換なし)のまま省略可
  7. Next」→「Create rule」をクリック

以上で EventBridge 側の構成が完了しました。S3 バケットへのファイルアップロード → EventBridge Rule → API Destination → VPC Lattice Resource Gateway → ECS Fargate の経路が接続されました。


コンソールハンズオン Phase 6: 動作確認

構成が正しく機能しているか確認します。

6-1. S3 にファイルをアップロード

テスト用のファイルを S3 バケットにアップロードして、イベントを発生させます。

AWS CLI を使う場合:

# テスト用 JSON ファイルを作成
echo '{"test": "eventbridge-lattice-demo"}' > test-event.json

# S3 バケットにアップロード(ACCOUNT_ID を置き換えること)
aws s3 cp test-event.json s3://eventbridge-demo-{ACCOUNT_ID}/test-event.json

コンソールを使う場合:

  1. S3 コンソールで eventbridge-demo-{ACCOUNT_ID} バケットを開く
  2. アップロード」をクリック
  3. 任意のファイルを選択してアップロード

6-2. EventBridge Rule モニタリングで確認

アップロード後、EventBridge ルールが API Destination を呼び出したか確認します。

手順:

  1. EventBridge コンソール → 「Rules」→ s3-to-lattice-api を選択
  2. Monitoring」タブを開く
  3. 以下のメトリクスが増加していることを確認:
  4. Invocations(呼び出し回数): 1 以上
  5. FailedInvocations(失敗数): 0

FailedInvocations が増加している場合は、セキュリティグループの設定または Resource Configuration ARN を再確認してください。

6-3. ECS タスクの CloudWatch Logs で確認

Fargate タスクがリクエストを受信したか、ログで確認します。

手順:

  1. CloudWatch コンソールを開く
  2. 左メニューから「Log groups」を選択
  3. /ecs/eventbridge-lattice-api を開く
  4. 最新のログストリームをクリック
  5. 以下のようなログが出力されていることを確認:
INFO:app:Received event: {"version":"0","id":"...","source":"aws.s3","detail-type":"Object Created","detail":{"bucket":{"name":"eventbridge-demo-..."},...}}
動作確認のポイント
CloudWatch Logs にリクエスト内容が記録されていれば、EventBridge → VPC Lattice Resource Gateway → ECS Fargate の全経路が正常に機能している証拠です。このログ確認が今回のハンズオンで最も重要な検証ステップです。

6-4. VPC Lattice Target Group ヘルス確認

ECS タスクが VPC Lattice Target Group に正常に登録され、ヘルシーな状態であることを確認します。

手順:

  1. VPC Lattice コンソールを開く
  2. 左メニューから「Target groups」→ eventbridge-lattice-tg を選択
  3. Targets」タブを開く
  4. すべてのターゲット(ECS タスクの IP アドレス)が Healthy 状態であることを確認
ヘルスチェックが Unhealthy の場合の対処
ターゲットが Unhealthy になっている場合、以下の順番で確認してください:

  1. ECS タスクのセキュリティグループのインバウンドルールに「ポート 80 を VPC Lattice Resource Gateway のセキュリティグループから許可」が設定されているか確認する
  2. ECS タスクが /health エンドポイントをポート 80 で正常に応答しているか確認する(CloudWatch Logs でエラーが出ていないか確認)
  3. タスク定義のコンテナポートマッピングが 80 番ポートになっているか確認する

コンソールハンズオン Phase 7: クリーンアップ

ハンズオン終了後は、不要な料金発生を防ぐためにリソースを削除します。依存関係があるため、必ず以下の順番で削除してください。

削除順序を守ること
依存関係のあるリソースを先に削除すると、削除エラーが発生します。特に VPC Lattice の Service Network 関連付けは、Service / VPC の関連付けを先に解除してからでないと削除できません。また、EventBridge Connection が自動作成する Resource Association は手動削除が必要な場合があります。

削除順序(上から順に実行):

  1. EventBridge Rule 削除
  2. EventBridge コンソール → Rules → s3-to-lattice-api → Delete

  3. EventBridge API Destination 削除

  4. EventBridge コンソール → API destinations → lattice-api-destination → Delete

  5. EventBridge Connection 削除

  6. EventBridge コンソール → API destinations → Connections → lattice-api-connection → Delete
  7. ※ Connection 削除前に VPC Lattice コンソール → Resource associations で、この Connection が自動作成した関連付けを先に手動削除が必要な場合がある

  8. S3 バケット内のオブジェクト削除 → バケット削除

  9. S3 コンソール → eventbridge-demo-{ACCOUNT_ID} → 「空にする」→「削除」

  10. ECS サービス削除

  11. ECS コンソール → クラスター → サービス → Desired tasks を 0 に更新 → サービス削除

  12. ECS タスク定義 無効化

  13. ECS コンソール → Task definitions → 対象タスク定義 → 「Deregister」

  14. ECS クラスター削除

  15. ECS コンソール → クラスター → Delete cluster

  16. VPC Lattice Resource Configuration 削除

  17. VPC Lattice コンソール → Resource configurations → 削除

  18. VPC Lattice Resource Gateway 削除

  19. VPC Lattice コンソール → Resource gateways → 削除

  20. VPC Lattice Service Network ↔ VPC 関連付け解除

    • VPC Lattice コンソール → Service networks → 対象 → VPC associations → 削除
  21. VPC Lattice Service Network ↔ Service 関連付け解除

    • VPC Lattice コンソール → Service networks → 対象 → Service associations → 削除
  22. VPC Lattice Service 削除

    • VPC Lattice コンソール → Services → 削除
  23. VPC Lattice Target Group 削除

    • VPC Lattice コンソール → Target groups → 削除
  24. VPC Lattice Service Network 削除

    • VPC Lattice コンソール → Service networks → 削除
  25. NAT Gateway 削除 → Elastic IP 解放

    • VPC コンソール → NAT gateways → 削除(削除完了まで数分かかる)
    • Elastic IPs → 「Release Elastic IP address」
  26. VPC 削除(サブネット・Internet Gateway・ルートテーブルを含む)

    • VPC コンソール → VPCs → 対象 VPC → 「Delete VPC」(関連リソースが自動削除される)
  27. IAM ロール削除

    • IAM コンソール → Roles → 以下を削除:
    • ecsTaskExecutionRole
    • ecsInfrastructureRole(VPC Lattice 登録用)
    • EventBridge 実行ロール(AmazonEventBridgeInvokeApiDestinationRolePolicy がアタッチされたロール)
  28. ECR リポジトリ削除(イメージを含む)

    • ECR コンソール → Repositories → 対象リポジトリ → 「Delete」
NAT Gateway と Elastic IP の削除忘れに注意
NAT Gateway は起動しているだけで時間課金($0.045/時間)が発生します。また、Elastic IP は EC2 リソースに関連付けられていない場合に課金されます。ハンズオン終了後は必ず削除してください。削除順序は NAT Gateway を先に削除してから Elastic IP を解放します(順序が逆だと解放できません)。

Terraform を使用した場合:

Terraform でリソースを作成した場合は、以下のコマンドで一括削除できます:

terraform destroy

ただし、EventBridge Connection が自動作成した Resource Association は Terraform の管理外のため、terraform destroy 後に手動で確認・削除が必要な場合があります。

TerraformでEventBridge × VPC Lattice × Fargate構成を構築する

Section 3のコンソールハンズオンで構築した同等構成を、Terraformでコード化します。全22リソースを7つのファイルに整理し、terraform apply 一発で再現可能なIaCを実現します。

📋 この章の前提

コンソールハンズオン(Section 3)を先に読んでおくと、各リソースの役割を理解しやすくなります。Terraform 1.3以上・AWS CLI設定済み・必要なIAM権限(VPC/ECS/VPC Lattice/EventBridge/S3/IAM の作成・管理権限)が必要です。


5-1. ディレクトリ構成

プロジェクトディレクトリ eventbridge-lattice-fargate/ を作成し、以下の構成にします。

eventbridge-lattice-fargate/
├── main.tf # Provider設定
├── variables.tf  # 変数定義
├── outputs.tf # 出力定義
├── vpc.tf  # ネットワーク基盤(VPC/サブネット/NAT/SG)
├── iam.tf  # IAMロール×4
├── ecs.tf  # ECS Fargate(ECR/クラスター/タスク定義/サービス)
├── lattice.tf # VPC Lattice(Service/Target Group/Resource Gateway等)
└── eventbridge.tf# EventBridge(Connection/API Destination/Rule/Target)
mkdir eventbridge-lattice-fargate
cd eventbridge-lattice-fargate

5-2. variables.tf — 変数定義

variable "aws_region" {
  description = "AWSリージョン"
  default  = "ap-northeast-1"
}

variable "project_name" {
  description = "プロジェクト名(リソース名のプレフィックスに使用)"
  default  = "eventbridge-lattice"
}

variable "vpc_cidr" {
  description = "VPCのCIDRブロック"
  default  = "10.0.0.0/16"
}

variable "container_image" {
  description = "ECSタスクで使用するECRイメージURI"
  type  = string
}

variable "account_id" {
  description = "AWSアカウントID(S3バケット名のユニーク化に使用)"
  type  = string
}

5-3. main.tf — Provider設定

terraform {
  required_version = ">= 1.3"
  required_providers {
 aws = {
source  = "hashicorp/aws"
version = "~> 5.0"
 }
  }
}

provider "aws" {
  region = var.aws_region
}

# アベイラビリティゾーンの動的取得
data "aws_availability_zones" "available" {
  state = "available"
}

5-4. vpc.tf — ネットワーク基盤

VPC・サブネット(パブリック×2/プライベート×2)・NAT Gateway・セキュリティグループを定義します。

# ─────────────────────────────────────────
# VPC
# ─────────────────────────────────────────
resource "aws_vpc" "main" {
  cidr_block  = var.vpc_cidr
  enable_dns_hostnames = true
  enable_dns_support= true

  tags = {
 Name = "${var.project_name}-vpc"
  }
}

# ─────────────────────────────────────────
# プライベートサブネット × 2
# (ECS Fargate / Resource Gateway 配置用)
# ─────────────────────────────────────────
resource "aws_subnet" "private" {
  count = 2
  vpc_id= aws_vpc.main.id
  cidr_block  = cidrsubnet(var.vpc_cidr, 8, count.index)
  availability_zone = data.aws_availability_zones.available.names[count.index]

  map_public_ip_on_launch = false

  tags = {
 Name = "${var.project_name}-private-${count.index + 1}"
  }
}

# ─────────────────────────────────────────
# パブリックサブネット × 2
# (NAT Gateway 配置用。FargateのECRイメージpull等の外部通信に使用)
# ─────────────────────────────────────────
resource "aws_subnet" "public" {
  count = 2
  vpc_id= aws_vpc.main.id
  cidr_block  = cidrsubnet(var.vpc_cidr, 8, count.index + 10)
  availability_zone = data.aws_availability_zones.available.names[count.index]

  map_public_ip_on_launch = true

  tags = {
 Name = "${var.project_name}-public-${count.index + 1}"
  }
}

# ─────────────────────────────────────────
# Internet Gateway
# ─────────────────────────────────────────
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
 Name = "${var.project_name}-igw"
  }
}

# ─────────────────────────────────────────
# Elastic IP / NAT Gateway
# (プライベートサブネットからの外部通信用)
# ─────────────────────────────────────────
resource "aws_eip" "nat" {
  domain = "vpc"

  tags = {
 Name = "${var.project_name}-nat-eip"
  }
}

resource "aws_nat_gateway" "main" {
  allocation_id = aws_eip.nat.id
  subnet_id  = aws_subnet.public[0].id

  tags = {
 Name = "${var.project_name}-nat"
  }

  depends_on = [aws_internet_gateway.main]
}

# ─────────────────────────────────────────
# ルートテーブル — パブリック
# ─────────────────────────────────────────
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  route {
 cidr_block = "0.0.0.0/0"
 gateway_id = aws_internet_gateway.main.id
  }

  tags = {
 Name = "${var.project_name}-public-rt"
  }
}

resource "aws_route_table_association" "public" {
  count = 2
  subnet_id= aws_subnet.public[count.index].id
  route_table_id = aws_route_table.public.id
}

# ─────────────────────────────────────────
# ルートテーブル — プライベート
# ─────────────────────────────────────────
resource "aws_route_table" "private" {
  vpc_id = aws_vpc.main.id

  route {
 cidr_block  = "0.0.0.0/0"
 nat_gateway_id = aws_nat_gateway.main.id
  }

  tags = {
 Name = "${var.project_name}-private-rt"
  }
}

resource "aws_route_table_association" "private" {
  count = 2
  subnet_id= aws_subnet.private[count.index].id
  route_table_id = aws_route_table.private.id
}

data "aws_ec2_managed_prefix_list" "vpc_lattice" {
  name = "com.amazonaws.ap-northeast-1.vpc-lattice"
}

# ─────────────────────────────────────────
# セキュリティグループ — ECS Fargate
# ─────────────────────────────────────────
resource "aws_security_group" "fargate" {
  name  = "${var.project_name}-fargate-sg"
  description = "ECS Fargate: port 80 from VPC Lattice Resource Gateway SG"
  vpc_id= aws_vpc.main.id

  ingress {
 description  = "HTTP from VPC Lattice Resource Gateway"
 from_port = 80
 to_port= 80
 protocol  = "tcp"
 security_groups = [aws_security_group.lattice_rg.id]
  }

  # VPC Lattice ヘルスチェック用(推奨)
  ingress {
 from_port = 80
 to_port= 80
 protocol  = "tcp"
 prefix_list_ids = [data.aws_ec2_managed_prefix_list.vpc_lattice.id]
 description  = "Allow VPC Lattice health checks"
  }

  egress {
 from_port= 0
 to_port  = 0
 protocol = "-1"
 cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
 Name = "${var.project_name}-fargate-sg"
  }
}

# ─────────────────────────────────────────
# セキュリティグループ — VPC Lattice Resource Gateway
# ─────────────────────────────────────────
resource "aws_security_group" "lattice_rg" {
  name  = "${var.project_name}-lattice-rg-sg"
  description = "VPC Lattice Resource Gateway: port 443 inbound from EventBridge"
  vpc_id= aws_vpc.main.id

  # EventBridgeのIPは動的なため、CIDR全開放。
  # 本番環境ではAWS EventBridgeのIPプレフィックスリストを利用することを推奨。
  ingress {
 description = "HTTPS from EventBridge (dynamic IP)"
 from_port= 443
 to_port  = 443
 protocol = "tcp"
 cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
 description  = "HTTP to ECS Fargate"
 from_port = 80
 to_port= 80
 protocol  = "tcp"
 security_groups = [aws_security_group.fargate.id]
  }

  tags = {
 Name = "${var.project_name}-lattice-rg-sg"
  }
}
💡 セキュリティグループの循環参照について

fargate SGが lattice_rg SGを参照し、lattice_rg SGが fargate SGを参照しています。Terraformはこの双方向SGルールを正しく処理しますが、aws_security_group_rule リソースに分割して定義する方法もあります。


5-5. iam.tf — IAMロール(4種)

ECS・VPC Lattice・EventBridgeの各サービスに必要な4つのIAMロールを定義します。

# ─────────────────────────────────────────
# ECS Task Execution Role
# (ECRイメージpull・CloudWatch Logs書き込みに使用)
# ─────────────────────────────────────────
resource "aws_iam_role" "ecs_task_execution" {
  name = "${var.project_name}-ecs-task-execution-role"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "ecs-tasks.amazonaws.com" }
Action = "sts:AssumeRole"
 }]
  })

  tags = {
 Name = "${var.project_name}-ecs-task-execution-role"
  }
}

resource "aws_iam_role_policy_attachment" "ecs_task_execution" {
  role = aws_iam_role.ecs_task_execution.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

# ─────────────────────────────────────────
# ECS Task Role
# (コンテナアプリケーション固有の権限。デモでは最小限)
# ─────────────────────────────────────────
resource "aws_iam_role" "ecs_task" {
  name = "${var.project_name}-ecs-task-role"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "ecs-tasks.amazonaws.com" }
Action = "sts:AssumeRole"
 }]
  })

  tags = {
 Name = "${var.project_name}-ecs-task-role"
  }
}

# ─────────────────────────────────────────
# ECS Infrastructure Role
# (ECS ServiceがVPC Lattice Target GroupにタスクIPを自動登録するために使用)
# vpc_lattice_configurations の role_arn に指定する。
# ─────────────────────────────────────────
resource "aws_iam_role" "ecs_infrastructure" {
  name = "${var.project_name}-ecs-infrastructure-role"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "ecs.amazonaws.com" }
Action = "sts:AssumeRole"
 }]
  })

  tags = {
 Name = "${var.project_name}-ecs-infrastructure-role"
  }
}

resource "aws_iam_role_policy" "ecs_infrastructure_lattice" {
  name = "${var.project_name}-ecs-infrastructure-lattice-policy"
  role = aws_iam_role.ecs_infrastructure.id

  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Action = [
  "vpc-lattice:RegisterTargets",
  "vpc-lattice:DeregisterTargets",
  "vpc-lattice:GetTargetGroup"
]
Resource = "*"
 }]
  })
}

# ─────────────────────────────────────────
# EventBridge Invoke Role
# (EventBridge RuleがAPI Destinationを呼び出し、
#VPC Lattice Resource Configurationにアクセスするために使用)
# ─────────────────────────────────────────
resource "aws_iam_role" "eventbridge_invoke" {
  name = "${var.project_name}-eventbridge-invoke-role"

  assume_role_policy = jsonencode({
 Version = "2012-10-17"
 Statement = [{
Effect = "Allow"
Principal = { Service = "events.amazonaws.com" }
Action = "sts:AssumeRole"
 }]
  })

  tags = {
 Name = "${var.project_name}-eventbridge-invoke-role"
  }
}

resource "aws_iam_role_policy" "eventbridge_invoke" {
  name = "${var.project_name}-eventbridge-invoke-policy"
  role = aws_iam_role.eventbridge_invoke.id

  policy = jsonencode({
 Version = "2012-10-17"
 Statement = [
{
  Effect= "Allow"
  Action= ["events:InvokeApiDestination"]
  Resource = "*"
},
{
  # EventBridge ConnectionがVPC Lattice Resource Configurationにアクセスするために必要
  Effect = "Allow"
  Action = [
 "vpc-lattice:CreateServiceNetworkResourceAssociation",
 "vpc-lattice:GetResourceConfiguration",
 "vpc-lattice:AssociateViaAWSService-EventsAndStates"
  ]
  Resource = "*"
}
 ]
  })
}

5-6. ecs.tf — ECS Fargate

ECRリポジトリ・ECSクラスター・タスク定義・ECSサービスを定義します。サービスの vpc_lattice_configurations ブロックが、VPC Lattice Target GroupへのFargateタスク自動登録のポイントです。

# ─────────────────────────────────────────
# ECRリポジトリ
# ─────────────────────────────────────────
resource "aws_ecr_repository" "api" {
  name  = "${var.project_name}-api"
  image_tag_mutability = "MUTABLE"

  image_scanning_configuration {
 scan_on_push = true
  }

  tags = {
 Name = "${var.project_name}-api"
  }
}

# ─────────────────────────────────────────
# CloudWatch Logs グループ
# ─────────────────────────────────────────
resource "aws_cloudwatch_log_group" "ecs_api" {
  name  = "/ecs/${var.project_name}-api"
  retention_in_days = 7

  tags = {
 Name = "${var.project_name}-ecs-api-logs"
  }
}

# ─────────────────────────────────────────
# ECS クラスター
# ─────────────────────────────────────────
resource "aws_ecs_cluster" "main" {
  name = "${var.project_name}-cluster"

  tags = {
 Name = "${var.project_name}-cluster"
  }
}

# ─────────────────────────────────────────
# ECS タスク定義
# (シンプルHTTP API: ポート80で待機)
# ─────────────────────────────────────────
resource "aws_ecs_task_definition" "api" {
  family = "${var.project_name}-api"
  network_mode = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu = 256
  memory = 512
  execution_role_arn = aws_iam_role.ecs_task_execution.arn
  task_role_arn= aws_iam_role.ecs_task.arn

  container_definitions = jsonencode([{
 name  = "api"
 image = var.container_image
 portMappings = [{
containerPort = 80
protocol= "tcp"
name = "api-port"
 }]
 logConfiguration = {
logDriver = "awslogs"
options = {
  "awslogs-group"= "/ecs/${var.project_name}-api"
  "awslogs-region"  = var.aws_region
  "awslogs-stream-prefix" = "ecs"
}
 }
  }])

  tags = {
 Name = "${var.project_name}-task-def"
  }
}

# ─────────────────────────────────────────
# ECS サービス
# vpc_lattice_configurations でTarget Groupへ自動登録
# ─────────────────────────────────────────
resource "aws_ecs_service" "api" {
  name= "${var.project_name}-api"
  cluster= aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.api.arn
  desired_count= 2
  launch_type  = "FARGATE"

  network_configuration {
 subnets = aws_subnet.private[*].id
 security_groups  = [aws_security_group.fargate.id]
 assign_public_ip = false
  }

  # VPC Lattice Target GroupにFargateタスクIPを自動登録する
  vpc_lattice_configurations {
 role_arn= aws_iam_role.ecs_infrastructure.arn
 target_group_arn = aws_vpclattice_target_group.api.arn
 port_name  = "api-port"
  }

  depends_on = [
 aws_iam_role_policy_attachment.ecs_task_execution,
 aws_iam_role_policy.ecs_infrastructure_lattice
  ]

  tags = {
 Name = "${var.project_name}-api-service"
  }
}
⚠️ vpc_lattice_configurations 削除時の既知バグ(issue #41600)

aws_ecs_servicevpc_lattice_configurations ブロックを後から削除すると、perpetual diff(差分が解消されない状態) が発生するバグが報告されています。

回避策は2つあります:

1. lifecycle ブロックで変更を無視する(完全な削除は不可):

lifecycle {
  ignore_changes = [vpc_lattice_configurations]
}

2. ECS サービスを再作成する: 削除が必要な場合はサービス全体を terraform destroyterraform apply する。

ハンズオン終了後のクリーンアップは terraform destroy で行えば問題ありません。


5-7. lattice.tf — VPC Lattice構成

VPC Lattice Service Network・Service・Target Group・Listener・Service Network関連付け・Resource Gateway・Resource Configuration を定義します。

# ─────────────────────────────────────────
# Target Group(IPタイプ)
# ECS FargateタスクのIPを直接ターゲットとして受け付ける
# ─────────────────────────────────────────
resource "aws_vpclattice_target_group" "api" {
  name = "${var.project_name}-tg"
  type = "IP"

  config {
 port= 80
 protocol  = "HTTP"
 vpc_identifier  = aws_vpc.main.id
 ip_address_type = "IPV4"

 health_check {
enabled = true
healthy_threshold= 2
unhealthy_threshold = 2
interval_seconds = 30
path = "/health"
port = 80
protocol= "HTTP"
protocol_version = "HTTP1"
 }
  }

  tags = {
 Name = "${var.project_name}-tg"
  }
}

# ─────────────────────────────────────────
# VPC Lattice Service
# FargateへのルーティングをFQDNで提供する
# ─────────────────────────────────────────
resource "aws_vpclattice_service" "api" {
  name= "${var.project_name}-service"
  auth_type = "NONE"

  tags = {
 Name = "${var.project_name}-service"
  }
}

# ─────────────────────────────────────────
# Listener(HTTP:80 → Target Group転送)
# ─────────────────────────────────────────
resource "aws_vpclattice_listener" "http" {
  name= "${var.project_name}-listener"
  protocol  = "HTTP"
  port= 80
  service_identifier = aws_vpclattice_service.api.id

  default_action {
 forward {
target_groups {
  target_group_identifier = aws_vpclattice_target_group.api.id
  weight= 100
}
 }
  }

  tags = {
 Name = "${var.project_name}-listener"
  }
}

# ─────────────────────────────────────────
# Service Network
# ServiceとVPCを論理的にグループ化する
# ─────────────────────────────────────────
resource "aws_vpclattice_service_network" "main" {
  name= "${var.project_name}-sn"
  auth_type = "NONE"

  tags = {
 Name = "${var.project_name}-service-network"
  }
}

# Service Network ↔ Service 関連付け
resource "aws_vpclattice_service_network_service_association" "api" {
  service_network_identifier = aws_vpclattice_service_network.main.id
  service_identifier= aws_vpclattice_service.api.id
}

# Service Network ↔ VPC 関連付け
# (Resource GatewayのSGを指定して通信制御)
resource "aws_vpclattice_service_network_vpc_association" "main" {
  service_network_identifier = aws_vpclattice_service_network.main.id
  vpc_identifier = aws_vpc.main.id
  security_group_ids= [aws_security_group.lattice_rg.id]
}

# ─────────────────────────────────────────
# Resource Gateway
# VPC内に配置されるネットワークエントリーポイント。
# EventBridgeからの通信(ポート443)を受け付け、
# Fargate APIへの橋渡しをする。
# ─────────────────────────────────────────
resource "aws_vpclattice_resource_gateway" "main" {
  name= "${var.project_name}-rg"
  ip_address_type = "IPV4"
  vpc_identifier  = aws_vpc.main.id
  subnet_ids= aws_subnet.private[*].id

  security_group_ids = [aws_security_group.lattice_rg.id]

  tags = {
 Name = "${var.project_name}-resource-gateway"
  }
}

# ─────────────────────────────────────────
# Resource Configuration
# EventBridge ConnectionからARNで参照される。
# VPC Lattice Service FQDNをDNSリソースとして指定。
# ─────────────────────────────────────────
resource "aws_vpclattice_resource_configuration" "api" {
  name= "${var.project_name}-rc"
  type= "SINGLE"
  resource_gateway_identifier = aws_vpclattice_resource_gateway.main.id

  port_ranges = ["80-80"]

  resource_configuration_definition {
 dns_resource {
domain_name  = aws_vpclattice_service.api.dns_entry[0].domain_name
ip_address_type = "IPV4"
 }
  }

  tags = {
 Name = "${var.project_name}-resource-configuration"
  }
}
💡 Resource GatewayのプロビジョニングはTime-consuming

aws_vpclattice_resource_gateway の作成には10〜15分程度かかることがあります。terraform apply 実行中に長時間待機状態になっても正常です。タイムアウトが懸念される場合は、timeouts ブロックで延長してください。


5-8. eventbridge.tf — EventBridge構成

⚠️ aws_cloudwatch_event_connection の private connectivity 対応状況

invocation_connectivity_parameters(VPC Lattice Resource ConfigurationのARNを指定するブロック)の Terraform AWS Provider v5.x での対応状況は 要検証 です。

このブロックが未対応の場合、Terraform でConnectionを作成した後、AWS CLIで update-connection を実行してprivate connectivityを追加する必要があります(後述のCLI代替手順を参照)。

# ─────────────────────────────────────────
# S3 バケット(デモ用イベントソース)
# ─────────────────────────────────────────
resource "aws_s3_bucket" "demo" {
  bucket = "${var.project_name}-demo-${var.account_id}"

  tags = {
 Name = "${var.project_name}-demo-bucket"
  }
}

# S3 → EventBridge 通知を有効化
resource "aws_s3_bucket_notification" "eventbridge" {
  bucket= aws_s3_bucket.demo.id
  eventbridge = true
}

# ─────────────────────────────────────────
# EventBridge Connection
# VPC Lattice Resource Configurationを参照し、
# プライベートAPIへの接続を確立する
# ─────────────────────────────────────────
resource "aws_cloudwatch_event_connection" "lattice" {
  name= "${var.project_name}-connection"
  authorization_type = "API_KEY"

  auth_parameters {
 api_key {
key= "x-api-key"
value = "demo-key-12345"
 }
  }

  # ─────────────────────────────────────────────────────────────
  # ⚠️ 以下のブロックは Terraform AWS Provider v5.x での対応が
  # 未確認のため、コメントアウトしています。
  #
  # 対応確認方法:
  #terraform init && terraform plan
  #で "An argument named invocation_connectivity_parameters is
  #not expected here" エラーが出た場合は未対応。
  #下記のCLI代替手順を使用してください。
  # ─────────────────────────────────────────────────────────────
  # invocation_connectivity_parameters {
  #resource_parameters {
  #  resource_configuration_arn = aws_vpclattice_resource_configuration.api.arn
  #}
  # }
}

# ─────────────────────────────────────────
# EventBridge API Destination
# Connection経由でVPC Lattice Service FQDNを呼び出す
# ─────────────────────────────────────────
resource "aws_cloudwatch_event_api_destination" "lattice" {
  name  = "${var.project_name}-api-destination"
  connection_arn = aws_cloudwatch_event_connection.lattice.arn
  invocation_endpoint  = "https://${aws_vpclattice_service.api.dns_entry[0].domain_name}/process"
  http_method = "POST"
  invocation_rate_limit_per_second = 10
}

# ─────────────────────────────────────────
# EventBridge Rule
# S3 PutObject イベントをフィルタリング
# ─────────────────────────────────────────
resource "aws_cloudwatch_event_rule" "s3_put" {
  name  = "${var.project_name}-s3-to-lattice"
  description = "S3 PutObject イベントをVPC Lattice経由でFargate APIに転送"

  event_pattern = jsonencode({
 source= ["aws.s3"]
 detail-type = ["Object Created"]
 detail = {
bucket = {
  name = [aws_s3_bucket.demo.id]
}
 }
  })

  tags = {
 Name = "${var.project_name}-s3-rule"
  }
}

# ─────────────────────────────────────────
# EventBridge Target
# RuleをAPI Destinationに接続
# ─────────────────────────────────────────
resource "aws_cloudwatch_event_target" "lattice_api" {
  rule  = aws_cloudwatch_event_rule.s3_put.name
  arn= aws_cloudwatch_event_api_destination.lattice.arn
  role_arn = aws_iam_role.eventbridge_invoke.arn

  http_target {
 path_parameter_values = []
  }
}
💡 CLI代替手順: private connectivity の後付け追加

invocation_connectivity_parameters が Terraform 未対応の場合、Connection作成後に以下のAWS CLIコマンドで private connectivity を設定します。

# ConnectionのARNをterraform outputから取得
CONN_ARN=$(terraform output -raw connection_arn)
# Resource Configuration ARNをterraform outputから取得
RC_ARN=$(terraform output -raw resource_configuration_arn)

# CLIでprivate connectivityを追加
aws events update-connection \
  --name "${var.project_name}-connection" \
  --invocation-connectivity-parameters \
  "{\"ResourceParameters\":{\"ResourceConfigurationArn\":\"${RC_ARN}\"}}"

CLIコマンド実行後、AWSコンソールのEventBridge > Connections から private connectivity が設定されていることを確認してください。


5-9. outputs.tf — 出力値

output "vpc_lattice_service_fqdn" {
  description = "VPC Lattice ServiceのFQDN(API Destinationのエンドポイントに使用)"
  value = aws_vpclattice_service.api.dns_entry[0].domain_name
}

output "resource_configuration_arn" {
  description = "VPC Lattice Resource ConfigurationのARN(EventBridge Connectionの設定に使用)"
  value = aws_vpclattice_resource_configuration.api.arn
}

output "connection_arn" {
  description = "EventBridge ConnectionのARN(CLI代替手順で使用)"
  value = aws_cloudwatch_event_connection.lattice.arn
}

output "s3_bucket_name" {
  description = "デモ用S3バケット名(動作確認でファイルアップロードに使用)"
  value = aws_s3_bucket.demo.id
}

output "ecr_repository_url" {
  description = "ECRリポジトリURL(container_image変数に指定するURI)"
  value = aws_ecr_repository.api.repository_url
}

5-10. デプロイ手順

Step 1: 初期化

cd eventbridge-lattice-fargate
terraform init

Step 2: ECRリポジトリ作成・イメージのpush

terraform apply 前にECRリポジトリだけ先に作成し、コンテナイメージをpushします。

# ECRリポジトリのみ先にapply
terraform apply \
  -target=aws_ecr_repository.api \
  -var="container_image=dummy" \
  -var="account_id=$(aws sts get-caller-identity --query Account --output text)"

# ECRリポジトリURLを取得
ECR_URL=$(terraform output -raw ecr_repository_url)
AWS_REGION="ap-northeast-1"

# Dockerイメージをビルド・タグ付け・push
aws ecr get-login-password --region ${AWS_REGION} | \
  docker login --username AWS --password-stdin ${ECR_URL}

docker build -t ${ECR_URL}:latest .
docker push ${ECR_URL}:latest

Step 3: 全リソースのapply

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

terraform plan \
  -var="container_image=${ECR_URL}:latest" \
  -var="account_id=${ACCOUNT_ID}"

terraform apply \
  -var="container_image=${ECR_URL}:latest" \
  -var="account_id=${ACCOUNT_ID}"
💡 apply 完了まで10〜15分程度かかります

VPC Lattice Resource Gatewayのプロビジョニングに時間がかかるため、aws_vpclattice_resource_gateway.main: Still creating... が数分続きますが正常です。

Step 4: private connectivity の設定(CLI代替手順)

invocation_connectivity_parameters が Terraform 未対応の場合のみ実行します。

CONN_ARN=$(terraform output -raw connection_arn)
RC_ARN=$(terraform output -raw resource_configuration_arn)
CONN_NAME="${var.project_name}-connection"  # 実際の値: eventbridge-lattice-connection

aws events update-connection \
  --name "eventbridge-lattice-connection" \
  --invocation-connectivity-parameters \
  "{\"ResourceParameters\":{\"ResourceConfigurationArn\":\"${RC_ARN}\"}}"

Step 5: 動作確認

S3_BUCKET=$(terraform output -raw s3_bucket_name)

# S3バケットにファイルをアップロードしてEventBridgeをトリガー
aws s3 cp README.md s3://${S3_BUCKET}/test-$(date +%s).md

# EventBridgeのルール実行状況を確認(約30秒後)
aws events describe-rule \
  --name "eventbridge-lattice-s3-to-lattice" \
  --query "{Name:Name, State:State}"

# ECS FargateタスクのCloudWatch Logsでリクエスト受信を確認
aws logs tail "/ecs/eventbridge-lattice-api" --follow

クリーンアップ

# S3バケットを空にしてからdestroy
aws s3 rm s3://${S3_BUCKET} --recursive

terraform destroy \
  -var="container_image=${ECR_URL}:latest" \
  -var="account_id=${ACCOUNT_ID}"
📋 Resource Associationの手動削除について

EventBridge Connectionを作成すると、VPC Lattice側に Resource Association が自動生成されます。このリソースはAWSコンソールや terraform destroy で直接削除できない場合があります。terraform destroy でエラーが出た場合は、AWS CLIで aws vpc-lattice delete-service-network-resource-association を実行してから再度 destroy してください。


まとめ

本記事で実現できたこと

  • EventBridge → VPC Lattice → ECS Fargate の直接連携を、中継Lambdaなしで構築
  • VPC Lattice Resource Gateway/Configuration を使ったプライベートAPIへのセキュアなアクセスパターンを習得
  • ECS Serviceの vpc_lattice_configurations パラメータによるFargateタスクの自動ターゲット登録
  • S3イベントをトリガーにしてFargate APIを非同期呼び出しするイベント駆動アーキテクチャの実装
  • Terraform(全22リソース) でコンソール手順と同等の構成を完全コード化

EventBridge API Destination + VPC Lattice Resource Gatewayパターンの利点

観点利点
セキュリティFargateタスクにパブリックIPなし。EventBridgeからResource Gateway経由でのみアクセス可能
スケーラビリティECS Serviceのスケールアウト時にFargateタスクIPがTarget Groupに自動登録・自動解除
シンプルな構成Lambda Proxyパターン不要。EventBridge → VPC Lattice → Fargateの直接経路
コスト効率Lambda不要のためコールドスタートなし。常時稼働のFargate Serviceへ直接ルーティング
運用性VPC Lattice Service FQDNを変えずにバックエンドを入れ替え可能(Blue/Green的な切り替えが可能)

応用例

📋 このパターンを発展させたアーキテクチャ

マルチサービス構成:
複数のFargate Serviceを同一のVPC Lattice Service Networkに接続し、EventBridge Ruleのイベントパターンでルーティング先を切り替える構成が可能です。サービスごとに別のAPI Destinationを定義し、Ruleのターゲットを複数設定するだけで実現できます。

クロスアカウント共有:
VPC Lattice Service NetworkはAWS Resource Access Manager(RAM)でクロスアカウント共有が可能です。EventBridgeは別アカウントに置き、VPC LatticeとFargateは共有サービスアカウントに集約するマルチアカウント構成に発展させられます。

Webhook受信パターン:
S3イベント以外にも、API GatewayやEventBridge APIのPutEventsでイベントを生成し、同じVPC Lattice経由でFargateにルーティングするWebhook受信アーキテクチャにも応用できます。


参考リンク

AWS公式ドキュメント

Terraform Registry

GitHub Issues(既知のバグ・制限)