CDK + Lambda@EdgeでCloudFrontのルーティングを柔軟に制御する方法

## ◾️ はじめに
　現在、CDKを使用し、インフラを構築する中で、各アプリケーションごとに異なるAPIパスが定義されていました。しかし、管理画面側では統一されたパスで管理したいという要件があり、CloudFront単体ではルーティングの柔軟性に限界があることがわかりました。

そこで登場するのが**Lambda@Edge**です。
これを活用することで、CloudFront経由のリクエストパスを書き換えることが可能になります。

本記事では、Lambda@Edgeの概要から、実際の構成・コード例、設定方法までをまとめています。

ぜひ最後まで一読していただけますと幸いです。

## ◾️ Lambda@Edgeとは？
Lambda@Edgeは、CloudFrontのリクエスト処理に直接介入できる**グローバル実行のLambda関数**です。

もう少し具体的に言うと、CloudFrontは、世界中に配置された「エッジロケーション」でリクエストを処理する仕組みを持っていますが、CloudFront 単体では以下のような処理ができません...
- パスの書き換え
- ヘッダーの追加/検証
- Cookieによる制御

このような制限を補う形で登場するのが**Lambda@Edge**です！！

Lambda@Edgeは、CloudFrontの以下4つのフェーズで任意の処理を挟むことができます。
| フェーズ名         | タイミング                   | 主な用途                                   |
|------------------|----------------------------|--------------------------------------------|
| Viewer Request   | ブラウザ → CloudFront       | リクエスト書き換え、認証など               |
| Origin Request   | CloudFront → オリジン       | パスの調整、ヘッダー追加など               |
| Origin Response  | オリジン → CloudFront       | レスポンス加工、キャッシュ制御など         |
| Viewer Response  | CloudFront → ブラウザ       | Cookie・ヘッダー追加、カスタムレスポンスなど |

#### 通常のLambdaとの違い
では、通常のLambdaと何が違うのかを具体的にまとめました。
| 特徴                  | 通常のLambda                    | Lambda@Edge                                      |
|-----------------------|----------------------------------|--------------------------------------------------|
| 実行される場所        | 特定リージョン（例：東京）       | 世界中のCloudFrontエッジ                         |
| レイテンシ             | 距離によって変動                | 超低レイテンシ（近いエッジで実行）               |
| CloudFrontとの連携     | ❌ できない                     | ⭕️ 完全統合                                       |
| 使用例                | API処理、バッチ処理など         | CloudFrontパス制御、動的ルーティング、認証など   |

これまでの説明で分かる通り、普通のLambdaではCloudFrontのリクエスト処理の前に介入できないということです。

Lambda@Edgeで関数を作成する際に、注意点があります⚠️
Lambda@Edgeの関数は必ず **us-east-1（バージニア北部）** にデプロイする必要があります。
これは「グローバルにコピーされる」仕様のため、デプロイ元が us-east-1 に限定されているためだそうです。

## ◾️ 今回のケース
今回取り上げるのは、以下のようなパスリライトです。

変換例：`/api/{project名}/create` → `/api/create`

背景：URLにプロジェクト名が含まれているが、実際に呼び出すAPIは共通のエンドポイントを使用したい。

目的：CloudFront側で見せかけのパスだけを変えて、APIの内部ロジックは共通化する。

## ◾️ Lambda@Edge のCDKでの定義
```typescript
const rewriteApiPathFunction = new experimental.EdgeFunction(this, `RewriteApiPathFn`, {
  functionName: `cloudFront-rewrite-api-path`,
  runtime: lambda.Runtime.NODEJS_22_X,
  handler: 'rewriteApiPath.handler',
  code: lambda.Code.fromAsset(path.join(__dirname, 'rewriteApiPath'))
})
```

## ◾️ 実際の作成する関数内容（例：viewer-request）
```javascript
exports.handler = async (event) => {
　// HTTP リクエストオブジェクト
  const request = event.Records[0].cf.request;
  request.uri = request.uri.replace(/^\/api\/{project名}/, '/api');
  return request;
};
```

## ◾️ CloudFrontに組み込み
書き換えたいパスに対応するBehaviorに、作成したEdgeFunctionを設定します。
今回は、リクエストをオリジンに送る前に書き換えたいので、**Origin Request**に割り当てます。
![スクリーンショット 2025-04-23 10.09.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3748502/f51b7176-ab61-48bf-9664-2d7e459e2bbb.png)

実際にリライトを行いたいAPIを叩いて、APIが関数で指定したパスに書き換わっていたら完了です✨

## ◾️ デバッグ・ログのコツ
- console.log() は CloudWatch Logs（us-east-1） に出力されます。
エラーや期待通りに動かない場合、まずはログを確認してみてください！

![スクリーンショット 2025-04-23 10.14.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3748502/b19d83ec-227c-4ce7-859b-e72c35fff7e8.png)

#### ✅ 注意点
- デプロイ後の 反映に時間がかかる 場合があります。
- us-east-1限定デプロイに注意（他リージョンでは設定できません）

## ◾️ まとめ
　最後までご覧いただきありがとうございました！
CloudFront のルーティングに柔軟性を持たせたいときは、Lambda@Edge の活用が非常に有効です。
通常の CloudFront では難しいパスの書き換えや条件分岐も、Lambda 関数を使えば自在に制御できます。
同じような課題に直面している方の参考になれば幸いです！