プロキシリソースを利用しCloudFront+API Gateway+Lambda構成をやってみる

プロキシリソースを利用しCloudFront+API Gateway+Lambda構成をやってみる

2025.09.05

はじめに

かつまたです。
今回はCloudFront + API Gateway + Lambda構成でAPI Gatewayにプロキシリソースとのプロキシ統合を設定し、構築してみました。プロキシリソースの実装により単一のLambda関数で複数のAPIエンドポイントを動的に処理可能となり、また個別のリソース定義が不要となります。
apifatewa.drawio.png

検証のため以下のようなセキュリティ施策は実施していません。

  • API GatewayのリソースポリシーでCloudFrontからのアクセスのみ許可
  • WAFの有効化

プロキシリソースとは

API Gatewayのプロキシリソースは、単一のリソース設定で複数の階層を持つ動的なAPIパスを処理できる強力な機能です。{proxy+}という特殊な記法を使用することで、任意の深さのサブパスをキャッチし、バックエンドのLambda関数やHTTPエンドポイントに転送できます。
プロキシリソースは、{proxy+} という特別なパスパラメータで示され、greedy パスパラメータとも呼ばれます。

動的なパスマッチングを実現可能であり以下のパスのような指定が可能です。
設定: /api/{proxy+}
マッチする例

  • /api/users
  • /api/users/123
  • /api/users/123/orders/456

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-method-settings-method-request.html#setup-method-resources

やってみた

Lambda作成

  1. コンソールからLambdaサービスを開き、「関数の作成」をクリックします。
  • ランタイム: Python 3.11
  • 実行ロール: 「基本的なLambdaアクセス権限で新しいロールを作成」を選択
  1. 以下のPythonコードを実装します。このコードは複数のHTTPエンドポイントを処理し、動的なレスポンスを返します。

スクリーンショット 2025-09-01 14.51.52.png

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)})
        }
  1. Lambda 詳細設定は以下の通り調整しました。
  • タイムアウト: 30秒(デフォルト3秒)
  • メモリ: 256 MB

API Gateway作成

  1. 「API Gateway」で新しいREST APIを作成します。
  • プロトコル: REST
  • 新しいAPIの作成: 新しいAPI
  • エンドポイントタイプ: Regional
    スクリーンショット 2025-09-01 15.32.42.png
  1. 「アクション」→「メソッドの作成」からルートリソース(/)にANYメソッドを作成し、Lambda関数と統合します。
  • メソッドタイプ:「ANY」
  • 統合タイプ: Lambda関数
  • Lambdaプロキシ統合の使用: ✓
  • Lambda関数: 作成したLambda関数のリージョンと関数ARNを選択

スクリーンショット 2025-09-01 15.39.17.png

  1. すべてのサブパスをキャッチするプロキシリソースを追加します。
    「リソースの作成」からリソースパス/、リソース名{proxy+}として、CORS (クロスオリジンリソース共有)を有効にしリソースを追加します。

  2. {proxy+}リソースに先ほどと同様にANYメソッドを作成し、Lambda関数と統合します。
    スクリーンショット 2025-09-01 15.55.38.png

  3. APIを本番ステージにデプロイします。
    「アクション」→「APIのデプロイ」からデプロイされるステージを[新しいステージ]と選択し、任意のステージ名でデプロイを実行します。

デプロイ後に表示されるAPI Gatewayのエンドポイントは後ほど利用します。

スクリーンショット 2025-09-01 15.56.12.png

CloudFront作成

  1. 「CloudFront」からディストリビューションを作成します。
  • Origin type: API Gateway
  • Origin: 作成したAPIを選択(Region: Asia Pacific、APIGATEWAY Version: REST API)
  • Origin path: /prod

今回は検証環境のためWAFは有効化せずディストリビューションを作成します。
スクリーンショット 2025-09-01 15.58.31.png

スクリーンショット 2025-09-01 16.00.13.png

動作確認

Lambda、API Gateway、CloudFrontそれぞれから動作確認を実施します。

  • Lambda
    「Lambda」→該当の関数を選択→「テスト」からGETリクエストする以下イベントJSONを利用しテスト実行することで関数が実行成功することを確認できました。
json例
{
  "httpMethod": "GET",
  "path": "/",
  "headers": {
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  "queryStringParameters": null,
  "pathParameters": null,
  "body": null,
  "isBase64Encoded": false
}

スクリーンショット 2025-09-03 18.31.12.png

  • 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
  1. 以下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 テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。当社は様々な職種でメンバーを募集しています。「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイトをぜひご覧ください。

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.