プロキシリソースを利用しCloudFront+API Gateway+Lambda構成をやってみる
はじめに
かつまたです。
今回はCloudFront + API Gateway + Lambda構成でAPI Gatewayにプロキシリソースとのプロキシ統合を設定し、構築してみました。プロキシリソースの実装により単一のLambda関数で複数のAPIエンドポイントを動的に処理可能となり、また個別のリソース定義が不要となります。
検証のため以下のようなセキュリティ施策は実施していません。
- API GatewayのリソースポリシーでCloudFrontからのアクセスのみ許可
- WAFの有効化
プロキシリソースとは
API Gatewayのプロキシリソースは、単一のリソース設定で複数の階層を持つ動的なAPIパスを処理できる強力な機能です。{proxy+}という特殊な記法を使用することで、任意の深さのサブパスをキャッチし、バックエンドのLambda関数やHTTPエンドポイントに転送できます。
プロキシリソースは、{proxy+} という特別なパスパラメータで示され、greedy パスパラメータとも呼ばれます。
動的なパスマッチングを実現可能であり以下のパスのような指定が可能です。
設定: /api/{proxy+}
マッチする例
- /api/users
- /api/users/123
- /api/users/123/orders/456
やってみた
Lambda作成
- コンソールからLambdaサービスを開き、「関数の作成」をクリックします。
- ランタイム: Python 3.11
- 実行ロール: 「基本的なLambdaアクセス権限で新しいロールを作成」を選択
- 以下のPythonコードを実装します。このコードは複数のHTTPエンドポイントを処理し、動的なレスポンスを返します。
import json
from datetime import datetime
import uuid
def lambda_handler(event, context):
# HTTPメソッドとパスを取得
http_method = event['httpMethod']
path = event['path']
# レスポンスヘッダー(CORS対応)
headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type'
}
try:
if http_method == 'OPTIONS':
# プリフライトリクエスト対応
return {
'statusCode': 200,
'headers': headers,
'body': json.dumps({'message': 'OK'})
}
elif http_method == 'GET' and path == '/':
# ルートパス
response_body = {
'message': 'CloudFront + API Gateway + Lambda 動的サイト',
'timestamp': datetime.now().isoformat(),
'version': '1.0.0'
}
elif http_method == 'GET' and path == '/status':
# ステータスチェック
response_body = {
'status': 'healthy',
'timestamp': datetime.now().isoformat(),
'services': {
'lambda': 'running',
'apigateway': 'connected'
}
}
elif http_method == 'POST' and path == '/data':
# POSTデータの処理
request_body = json.loads(event.get('body', '{}'))
response_body = {
'message': 'データを受信しました',
'received_data': request_body,
'request_id': str(uuid.uuid4()),
'timestamp': datetime.now().isoformat()
}
elif http_method == 'GET' and path.startswith('/user/'):
# パスパラメータの処理
user_id = path.split('/')[-1] if path.split('/')[-1] else 'unknown'
response_body = {
'user_id': user_id,
'message': f'ユーザー {user_id} の情報',
'timestamp': datetime.now().isoformat()
}
else:
# 404エラー
return {
'statusCode': 404,
'headers': headers,
'body': json.dumps({'error': 'Not Found', 'path': path})
}
return {
'statusCode': 200,
'headers': headers,
'body': json.dumps(response_body, ensure_ascii=False)
}
except Exception as e:
return {
'statusCode': 500,
'headers': headers,
'body': json.dumps({'error': 'Internal Server Error', 'message': str(e)})
}
- Lambda 詳細設定は以下の通り調整しました。
- タイムアウト: 30秒(デフォルト3秒)
- メモリ: 256 MB
API Gateway作成
- 「API Gateway」で新しいREST APIを作成します。
- プロトコル: REST
- 新しいAPIの作成: 新しいAPI
- エンドポイントタイプ: Regional
- 「アクション」→「メソッドの作成」からルートリソース(/)にANYメソッドを作成し、Lambda関数と統合します。
- メソッドタイプ:「ANY」
- 統合タイプ: Lambda関数
- Lambdaプロキシ統合の使用: ✓
- Lambda関数: 作成したLambda関数のリージョンと関数ARNを選択
-
すべてのサブパスをキャッチするプロキシリソースを追加します。
「リソースの作成」からリソースパス/
、リソース名{proxy+}
として、CORS (クロスオリジンリソース共有)を有効にしリソースを追加します。 -
{proxy+}リソースに先ほどと同様にANYメソッドを作成し、Lambda関数と統合します。
-
APIを本番ステージにデプロイします。
「アクション」→「APIのデプロイ」からデプロイされるステージを[新しいステージ]と選択し、任意のステージ名でデプロイを実行します。
デプロイ後に表示されるAPI Gatewayのエンドポイントは後ほど利用します。
CloudFront作成
- 「CloudFront」からディストリビューションを作成します。
- Origin type: API Gateway
- Origin: 作成したAPIを選択(Region: Asia Pacific、APIGATEWAY Version: REST API)
- Origin path: /prod
今回は検証環境のためWAFは有効化せずディストリビューションを作成します。
動作確認
Lambda、API Gateway、CloudFrontそれぞれから動作確認を実施します。
- Lambda
「Lambda」→該当の関数を選択→「テスト」からGETリクエストする以下イベントJSONを利用しテスト実行することで関数が実行成功することを確認できました。
{
"httpMethod": "GET",
"path": "/",
"headers": {
"Accept": "application/json",
"Content-Type": "application/json"
},
"queryStringParameters": null,
"pathParameters": null,
"body": null,
"isBase64Encoded": false
}
- API Gateway
# 基本テスト
curl https://YOUR_API_GATEWAY_URL/
# 結果
{"message": "CloudFront + API Gateway + Lambda 動的サイト", "timestamp": "2025-09-03T09:18:58.394048", "version": "1.0.0"}
# ステータスチェック
curl https://YOUR_API_GATEWAY_URL/status
# 結果
{"status": "healthy", "timestamp": "2025-09-03T09:18:28.269823", "services": {"lambda": "running", "apigateway": "connected"}}
# POSTテスト
curl -X POST https://YOUR_API_GATEWAY_URL/data \
-H "Content-Type: application/json" \
-d '{"test": "data", "message": "Hello World"}'
# 結果
{"message": "データを受信しました", "received_data": {"test": "data", "message": "Hello World"}, "request_id": "3c1529f6-cdf8-4c63-b4fc-c2f0a2be2732", "timestamp": "2025-09-03T09:19:48.30623}
# ユーザー確認
curl https://YOUR_API_GATEWAY_URL/user/123
# 結果
{
"userid": "123",
"message": "ユーザー123の情報",
"timestamp": "2025-09-04T05:24:58.932552"
}
- CloudFront
- 以下curlコマンドでいくつかのパスに対して疎通確認を実施します。
# CloudFront URL経由のテスト
curl https://YOUR_CLOUDFRONT_DOMAIN.cloudfront.net/
# 結果
{"message": "CloudFront + API Gateway + Lambda 動的サイト", "timestamp": "2025-09-01T07:22:54.215797", "version": "1.0.0"}
# 各エンドポイントのテスト
curl https://YOUR_CLOUDFRONT_DOMAIN.cloudfront.net/status
# 結果
{
"status": "healthy",
"timestamp": "2025-09-03T09:20:11.30322Z",
"services": {
"lambda": "running",
"apigateway": "connected"
}
}
おわりに
ご覧いただきありがとうございました。今回の構成にWAF設定や静的コンテンツ(S3)への複数オリジンの設定、CloudFrontのみからのAPI Gatewayへの接続設定等を加えてより実用的な構成を試してみたいと思います。
アノテーション株式会社について
アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。当社は様々な職種でメンバーを募集しています。「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイトをぜひご覧ください。