---
title: "CloudFront×API Gateway×Lambdaの連携構成｜設定手順と403の原因・直アクセスの遮断方法"
url: "https://www.issoh.co.jp/tech/details/6799/"
published: 2025-05-19
updated: 2026-10-30
categories: ["AWS"]
publisher: "株式会社一創"
---

# CloudFront×API Gateway×Lambdaの連携構成｜設定手順と403の原因・直アクセスの遮断方法

CloudFrontをAPI Gatewayの前段に置き、その先でLambdaを動かす構成は、フロントエンドとAPIを同じドメインで配信したいとき、AWS WAFやAWS Shield AdvancedでAPIを守りたいときに採用されます。ただし3つのサービスを単純につなぐだけでは動きません。Hostヘッダーを転送すると403が返り、ステージ名とパスがずれると「Missing Authentication Token」、Lambdaの戻り値の形式が違えば502になり、API GatewayのURLを直接叩けばCloudFrontを素通りできてしまいます。この記事では、2026年10月時点のAWS公式ドキュメントをもとに、エンドポイントタイプの選び方、CDKで組んだ構成例（synthで生成テンプレートを確認済み）、つまずく箇所の原因、API GatewayをCloudFront経由に限定する4つの方法を整理します。

## まとめ：CloudFront×API Gateway×Lambda連携の設定要点

- **API Gatewayはリージョンエンドポイントで作る**：エッジ最適化はAWSが管理するCloudFrontを内部に持つため、自前のCloudFrontを前段に置くとCloudFrontが二重になる。HTTP APIはそもそもリージョンしか選べない。
- **オリジンリクエストポリシーは`AllViewerExceptHostHeader`**：ビューワーのHostヘッダーを転送するとAPI Gatewayが自分宛てと認識できず403になる。
- **キャッシュポリシーは`CachingDisabled`から始める**：利用者ごとに応答が変わるAPIでは、キャッシュキーの設計を誤ると他人のレスポンスを返すおそれがある。本記事では安全側の運用方針として、キャッシュ対象を公開GETに限定する。
- **REST APIはOrigin pathにステージ名**（例 `/prod`）を入れ、ビヘイビアのパスパターンとAPIのリソースパスを一致させる。HTTP APIの`$default`ステージはステージ名が付かない。
- **Lambdaは`statusCode`と文字列の`body`を返す**：REST APIのプロキシ統合は形式が違うと502を返す。CloudFrontは既定でAuthorizationヘッダーを削除するので、オーソライザーを使うならポリシーで転送する。
- **直アクセスの遮断はAPI種別で方法が変わる**：REST APIはカスタムヘッダー＋AWS WAF、HTTP APIはLambda側での検証かオリジンmTLS（2026年2月提供開始）。
- **APIの管理機能（スロットリング・APIキー・リクエスト検証）が不要なら**、API Gatewayを挟まずLambda関数URL＋OACで足りる。

## CloudFrontをAPI Gatewayの前段に置く理由とリクエストの流れ

API Gateway単体でもHTTPSのエンドポイントは公開できます。それでもCloudFrontを前に置くのは、API Gatewayに無い機能をCloudFront側で足すためです。

### 3サービスの役割分担

| サービス        | 担当             | この構成での主な設定         |
| ----------- | -------------- | ------------------ |
| CloudFront  | 入口・振り分け・保護     | ビヘイビア、ポリシー、WAF     |
| API Gateway | APIの公開・認可・流量制御 | ルート、ステージ、オーソライザー   |
| Lambda      | 業務処理           | ハンドラ、タイムアウト、IAMロール |

リクエストは「ブラウザ→CloudFrontのエッジ→パスパターンに一致したビヘイビア→API Gateway（オリジン）→Lambda」の順に流れます。静的ファイルはS3、`/api/*`だけAPI Gatewayへ、という振り分けを1つのディストリビューションで書けるのがCloudFrontを挟む最大の利点です。CloudFront自体の仕組みや料金プランは[Amazon CloudFrontとは？仕組み・料金プランとエッジ機能・採用判断を実装者目線で解説](/tech/details/15431/)、Lambdaの実行モデルは[AWS Lambdaとは？仕組み・料金体系とコールドスタート対策・採用判断を実装者目線で解説](/tech/details/15407/)で扱っています。

### CloudFront前段構成の同一オリジン化・保護・キャッシュ効果

- **同一ドメイン化**：画面とAPIが同じオリジンになるため、ブラウザのCORSプリフライトが発生しない。CORS設定の不備に起因する障害がまるごと消える。
- **エッジでの保護**：AWS WAFのウェブACLをCloudFrontに関連付けられ、AWS Shield Advancedの保護対象にもなる。HTTP APIはAWS WAFを直接関連付けられないため、HTTP APIをAWS WAFで保護する一般的な構成は、前段のCloudFrontにウェブACLを関連付ける方法である。
- **キャッシュ**：公開データを返すGET APIなら、CloudFrontのキャッシュヒット分だけAPI GatewayとLambdaの呼び出しが減る。

通常応答のキャッシュを無効にした動的APIでは、リクエストは原則として毎回オリジンまで届きます。ただし、CloudFrontのエラーキャッシュは別設定で、対象のエラー応答は既定で10秒間キャッシュされます。エラーもキャッシュさせない場合は、対象ステータスコードのError Caching Minimum TTLを0秒に設定してください。キャッシュしなくても、CloudFrontとオリジン間の接続再利用やAWSネットワーク経由の転送によって、遅延が短くなる場合はあります。速度改善を目的に採用する場合は、対象地域からの応答時間をCloudFront経由と直接アクセスで測定し、設定・運用の負担に見合うか判断してください。API Gatewayそのものの役割は[APIゲートウェイとは？役割・機能とリバースプロキシ／サービスメッシュとの違い・導入判断を解説](/tech/details/13210/)を参照してください。

## API Gatewayのエンドポイントタイプ：エッジ最適化とリージョンの違い

REST APIにはエッジ最適化・リージョン・プライベートの3種類のエンドポイントがあり、REST APIの既定はエッジ最適化です（[API Gatewayのエンドポイントタイプ](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-endpoint-types.html)）。エッジ最適化はリクエストを最寄りのCloudFront POPへ送る仕組みで、AWSが管理するCloudFrontディストリビューションを内部で使います。自前のCloudFrontをその前に置くとCloudFrontが二重になり、キャッシュやヘッダーの制御も自分では触れません。

| タイプ    | REST API | HTTP API | 自前CloudFrontの前段 |
| ------ | -------- | -------- | --------------- |
| エッジ最適化 | 対応（既定）   | 非対応      | 不向き（二重になる）      |
| リージョン  | 対応       | 対応       | 推奨              |
| プライベート | 対応       | 非対応      | 直接は不可（VPC内のみ）   |

AWSのドキュメントも、クライアントが地理的に分散している場合でも、リージョンエンドポイントと自前のCloudFrontを組み合わせる選択肢があると明記しています。エッジ最適化はヘッダー名を大文字始まりに変換する（例 `Cookie`）一方、リージョンは受け取ったヘッダー名をそのまま渡すという違いもあります。前段にCloudFrontを置くと決めた時点で、リージョン一択と考えてかまいません。

## REST APIとHTTP APIの選び方（CloudFront前段の場合）

CloudFrontを前に置く構成では、API GatewayをREST APIにするかHTTP APIにするかで、直アクセスの遮断方法とコストが変わります。

| 項目                | REST API               | HTTP API         |
| ----------------- | ---------------------- | ---------------- |
| AWS WAFの直接関連付け    | 可                      | 不可               |
| リソースポリシー          | 可                      | 不可               |
| APIキー・使用量プラン      | 可                      | 不可               |
| API Gateway側キャッシュ | 可                      | 不可               |
| 統合タイムアウト          | 既定上限29秒（リージョンは引き上げ申請可） | 最大30秒            |
| 東京の料金（100万件あたり）   | 4.25 USD（最初の3億3,300万件） | 1.29 USD（最初の3億件） |

機能差は[REST APIとHTTP APIの比較表](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html)、料金はAWS Price List API（2026年10月13日公開分）の東京リージョン単価です。HTTP APIは3分の1以下の単価ですが、WAF・リソースポリシー・APIキーが無いため、CloudFront経由に限定する仕組みを自分で用意する必要があります。判断の目安は次のとおりです。

- 外部パートナーにAPIキーを配る、クライアント単位でスロットリングする → REST API
- 自社のSPAやモバイルアプリだけが呼ぶ、認証はJWT（Cognito等）で足りる → HTTP API

## CDKで組むCloudFront→HTTP API→Lambdaの構成例

静的ファイルをS3から、`/api/*`をHTTP API経由でLambdaから返す構成をAWS CDK（TypeScript、aws-cdk-lib 2.275.0）で書いた例です。CDKのsynthでCloudFormationテンプレートを生成し、ディストリビューションの設定値まで確認しています（実デプロイは行っていません）。

### Lambda関数でのCloudFront秘密ヘッダーの検証

HTTP APIはWAFもリソースポリシーも使えないため、CloudFrontがオリジンへ付けるカスタムヘッダーをLambda側で照合し、一致しなければ403を返します。この例が検証するのはCloudFront経由かどうかであり、利用者の本人確認や操作権限ではありません。非公開データを扱う場合は、JWTオーソライザーなどによる利用者認証・認可を別途設定してください。HTTP APIのペイロード形式2.0ではヘッダー名がすべて小文字になるので、小文字で参照します。次のコードはESモジュールとしてプロジェクト直下のlambdaディレクトリにindex.mjsという名前で保存してください。

```
// CloudFront が付けた秘密ヘッダーが無いリクエスト（API Gateway への直アクセス）を拒否する
export const handler = async (event) => {
  if (!process.env.ORIGIN_SECRET || event.headers?.['x-origin-verify'] !== process.env.ORIGIN_SECRET) {
    return { statusCode: 403, body: JSON.stringify({ message: 'forbidden' }) };
  }
  return {
    statusCode: 200,
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({ path: event.rawPath, viewerCountry: event.headers['cloudfront-viewer-country'] ?? null }),
  };
};
```

### CDKスタック：ビヘイビアとポリシーの設定

TypeScriptのCDKプロジェクトを用意し、次のコードをアプリのエントリーポイントに配置します。依存パッケージとしてaws-cdk-lib 2.275.0とconstructsを用意してください。S3バケットへの静的ファイル配置はこのコードに含まれないため、画面も確認する場合は作成されたバケットにindex.htmlを配置します。

```
import { App, Stack, CfnOutput } from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigwv2 from 'aws-cdk-lib/aws-apigatewayv2';
import { HttpLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
import * as s3 from 'aws-cdk-lib/aws-s3';

const app = new App();
const stack = new Stack(app, 'ApiBehindCloudFront', { env: { region: 'ap-northeast-1' } });
const originSecret = app.node.tryGetContext('originSecret');
if (typeof originSecret !== 'string' || !originSecret.trim() || originSecret === 'change-me') {
  throw new Error('Specify a unique, randomly generated originSecret.');
}

const fn = new lambda.Function(stack, 'ApiFn', {
  runtime: lambda.Runtime.NODEJS_24_X,
  handler: 'index.handler',
  code: lambda.Code.fromAsset('lambda'),
  environment: { ORIGIN_SECRET: originSecret },
});

// HTTP API は $default ステージ＝URLにステージ名が付かない
const api = new apigwv2.HttpApi(stack, 'HttpApi');
api.addRoutes({
  path: '/api/{proxy+}',
  methods: [apigwv2.HttpMethod.ANY],
  integration: new HttpLambdaIntegration('ApiInt', fn),
});

const apiOrigin = new origins.HttpOrigin(
  `${api.apiId}.execute-api.${stack.region}.amazonaws.com`,
  { customHeaders: { 'x-origin-verify': originSecret } },
);

// フロントエンド（静的ファイル）は S3、/api/* だけ API Gateway へ振り分ける
const siteBucket = new s3.Bucket(stack, 'SiteBucket');

const dist = new cloudfront.Distribution(stack, 'Dist', {
  defaultRootObject: 'index.html',
  defaultBehavior: {
    origin: origins.S3BucketOrigin.withOriginAccessControl(siteBucket),
    viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
  },
  additionalBehaviors: {
    '/api/*': {
      origin: apiOrigin,
      allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
      cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED,
      originRequestPolicy: cloudfront.OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER,
      viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.HTTPS_ONLY,
    },
  },
});

new CfnOutput(stack, 'Url', { value: `https://${dist.distributionDomainName}/api/hello` });
app.synth();
```

`originSecret`は`cdk deploy -c originSecret=...`で渡す想定です。この値はCloudFormationテンプレートとLambdaの環境変数に平文で残るため、本番ではAWS Secrets Managerで管理し、CloudFrontのカスタムヘッダーとLambda側の検証値を連動して更新してください。Secrets Managerの値を変更するだけでは既存リソースへ自動反映されないため、配信設定の反映中は旧値と新値を受け付けるなど、切替中の403を防ぐ手順も必要です。

### synth結果で確かめる3つの値

生成されたテンプレートの`/api/*`ビヘイビアには、次の値が入っていました。手でコンソール設定した場合も、この3点を見れば設定漏れを判別できます。

| 設定                                               | 値                                            |
| ------------------------------------------------ | -------------------------------------------- |
| CachePolicyId（CachingDisabled）                   | 4135ea2d-6df8-44a3-9df3-4b5a84be39ad         |
| OriginRequestPolicyId（AllViewerExceptHostHeader） | b689b0a8-53d0-40ab-baf2-68738e2966ac         |
| AllowedMethods                                   | GET, HEAD, OPTIONS, PUT, PATCH, POST, DELETE |

関数単体はNode.jsで正しいヘッダーのときに200、ヘッダー無しのときに403を返すことを確認しました。デプロイやCI/CDの仕組みを別ツールで組む場合は[Serverless Frameworkとは？v4の料金・使い方・無料の代替まで【2026年最新】](/tech/details/8464/)も比較対象になります。

## 連携でつまずく7つの箇所と原因

### Hostヘッダー転送による403エラー

オリジンリクエストポリシーで「すべてのビューワーヘッダー」（`AllViewer`）を選ぶと、Hostヘッダーに`dxxxx.cloudfront.net`や独自ドメインが入ったままAPI Gatewayへ届きます。API GatewayはHostヘッダーで宛先のAPIを判別するため、自分宛てと認識できず403を返します。AWSの管理ポリシー`AllViewerExceptHostHeader`は、API GatewayとLambda関数URLのオリジン向けに用意されたもので、Hostだけを外し、代わりにオリジンのドメイン名をHostに入れて転送します（[管理オリジンリクエストポリシーの一覧](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html)）。

### ステージ名とパスのずれで「Missing Authentication Token」

CloudFrontはビヘイビアのパスパターンで振り分けるだけで、パスを書き換えません。`https://example.com/api/users`への要求は、Origin pathに`/prod`を設定したREST APIへ`/prod/api/users`として届きます。API Gateway側のリソースが`/users`しか無ければ、存在しないパスへの要求としてこのエラーが返ります。解決策は「API Gateway側のリソースを`/api`配下に作る」か「CloudFront Functionsでパスの`/api`を剥がす」のどちらかです。上のCDK例はルートを`/api/{proxy+}`にして前者で揃えています。

### OPTIONSの許可漏れによるCORSプリフライトの失敗

別オリジンのフロントエンドから、単純リクエストの条件を満たさない要求を送る場合、ブラウザは本リクエストの前にOPTIONSを送ります。ビヘイビアの許可メソッドが「GET, HEAD」のままだとOPTIONSがCloudFrontで拒否され、CORSエラーとして表面化します。GET・HEADとプリフライトだけなら`ALLOW_GET_HEAD_OPTIONS`を選び、POSTなども使う場合は`ALLOW_ALL`を選んだうえで、API Gateway側で必要なメソッドだけを受け付けます。画面とAPIを同一オリジン（スキーム・ホスト・ポートが一致するURL）で配信し、そのURLへ要求する場合は、CORSプリフライトは発生しません。

### Authorizationヘッダーの削除による401とIAM認証の署名不一致

CloudFrontは既定で、オリジンへ転送する前にビューワーの`Authorization`ヘッダーを削除します（[Authorizationヘッダーを転送する設定](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/add-origin-custom-headers.html)）。転送するヘッダーを個別に指定する自作のオリジンリクエストポリシーでAuthorizationを入れ忘れると、JWTオーソライザーやLambdaオーソライザーにトークンが届かず、401が返ります。管理ポリシー`AllViewerExceptHostHeader`はHost以外のビューワーヘッダーをすべて含むので、上のCDK例ならAuthorizationも届きます。AWSは、Authorizationをキャッシュキーに入れずに転送する場合、キャッシュを無効にしないと認可済みと未認可の利用者に同じキャッシュを返しうると注意しています。オーソライザーを使うビヘイビアが`CachingDisabled`であることを確かめてください。

REST APIでIAM認証（SigV4）を使う場合は、署名の作り方にも注意が要ります。[AWS re:Postのナレッジセンター](https://repost.aws/knowledge-center/api-gateway-cloudfront-distribution)は、署名のhostにAPI Gatewayの呼び出しURLのドメイン（execute-api）を、送信先にCloudFrontのドメインを指定する手順を案内しています。CloudFrontはHostをオリジンのドメインに置き換えて転送するため、CloudFrontのドメインをhostにして署名すると、API Gateway側で計算する署名と一致しません。

### Lambdaの戻り値の形式による502と、呼び出し権限不足によるInternal Server Error

REST APIのLambdaプロキシ統合では、関数が`statusCode`・`headers`・`body`などを持つ決められたJSONを返す必要があり、形式が違うとAPI Gatewayは`502 Bad Gateway`を返します（[Lambdaプロキシ統合の出力形式](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html)）。`body`は文字列なので、オブジェクトを返すときは`JSON.stringify`で文字列にします。HTTP APIのペイロード形式2.0はもう少し寛容で、`statusCode`を含まない有効なJSONを返すと、ステータス200・`content-type: application/json`・戻り値全体を本文とみなします（[ペイロード形式2.0の応答](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html)）。

HTTP APIが`{"message":"Internal Server Error"}`を返すときは、ステージのアクセスログの形式に`$context.integrationErrorMessage`を足すと、原因がログに出ます。AWSのトラブルシューティングが例に挙げるのは、API GatewayにLambdaを呼び出す権限が無いケースです（[HTTP APIのLambda統合のトラブルシューティング](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-troubleshooting-lambda.html)）。コンソールで統合を作れば権限は自動で付きますが、AWS CLI・CloudFormation・SDKで作った場合は関数のリソースベースポリシーへの追加が要ります。上のCDK例では、`HttpLambdaIntegration`がsynthのテンプレートに`AWS::Lambda::Permission`（送信元ARNの末尾は`/*/*/api/{proxy+}`）を生成していました。CLIで同じ権限を付けると次のようになります。

```
aws lambda add-permission \
  --function-name my-function \
  --statement-id apigateway-invoke-permissions \
  --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com \
  --source-arn 'arn:aws:execute-api:ap-northeast-1:123456789012:a1b2c3d4e5/*/*/api/{proxy+}'
```

### バッファリング型統合のタイムアウトとペイロード上限

以下はレスポンス全体を受け取ってから返す構成の制約です。REST APIのレスポンスストリーミングは別仕様で、最大15分のストリームと10 MBを超える応答に対応します。Lambdaもストリーミング応答には別の上限があるため、表の6 MBを一律に適用しないでください。自前のCloudFrontの後ろでREST APIのストリーミングを使う場合は、CloudFrontのオリジン応答タイムアウトを延ばさないと、30秒を超えるアイドル時間を待てません。

| サービス                     | 時間の上限            | サイズの上限           |
| ------------------------ | ---------------- | ---------------- |
| CloudFront（オリジン応答タイムアウト） | 既定30秒（1〜120秒で設定） | —                |
| API Gateway REST         | 既定29秒            | 10 MB            |
| API Gateway HTTP         | 30秒（引き上げ不可）      | 10 MB            |
| Lambda（同期呼び出し）           | 最大900秒           | リクエスト・レスポンス各6 MB |

実効値は一番小さいものになります。Lambdaのタイムアウトを5分にしても、API Gatewayが29〜30秒で504を返します。REST API（リージョンとプライベート）の統合タイムアウトは2024年6月からクォータ申請で29秒より延ばせるようになりましたが（アカウントのスロットリング上限が下がる場合あり）、その場合はCloudFrontのオリジン応答タイムアウトも合わせて延ばさないと、今度はCloudFrontが先に切ります。またAPI Gatewayは10 MBまで受け付けても、Lambdaの同期呼び出しはリクエスト・レスポンス各6 MBが上限です。この上限にはプロキシ統合のJSON構造やヘッダーなども含まれるため、HTTP本文に使えるサイズは6 MB未満になります。数十秒を超える処理は非同期（SQSやStep Functions）に逃がすか、ファイルはS3の署名付きURLで直接アップロードさせる設計に変えてください。

### 既存カスタムドメインの移行時に起きるCNAMEの競合

API Gatewayのエッジ最適化カスタムドメインは、内部でそのドメイン名を持つCloudFrontディストリビューションを作ります。同じ代替ドメイン名（CNAME）を2つのディストリビューションに設定できないため、運用中のAPIに後からCloudFrontを足そうとすると、新しいディストリビューションに同じドメインを登録できません。別名で検証した後、既存カスタムドメインをリージョンへ移行し、古いエッジ最適化エンドポイントの削除とCNAMEの解放を確認してからCloudFrontへ切り替える方法があります。カスタムドメイン全体の削除は必須ではありません。なお、CloudFrontに独自ドメインを設定する場合のACM証明書はバージニア北部（us-east-1）で発行したものしか使えません。

## API GatewayへのアクセスをCloudFront経由だけに限定する4つの方法

CloudFrontでWAFをかけても、`xxxx.execute-api.ap-northeast-1.amazonaws.com`を直接叩かれれば素通りされます。API Gatewayの`disableExecuteApiEndpoint`でこのデフォルトエンドポイントは無効化できますが、そうするとCloudFrontのオリジンもカスタムドメインに向け直す必要があり、そのカスタムドメイン自体は誰でも呼べるまま残ります。無効化だけでは塞がらないので、次のいずれかを組み合わせます。

| 方法                       | REST | HTTP | 判定する場所          |
| ------------------------ | ---- | ---- | --------------- |
| カスタムヘッダー＋AWS WAF         | 可    | 不可   | API GatewayのWAF |
| リソースポリシー（aws:Referer条件）  | 可    | 不可   | API Gateway     |
| Lambda側の検証・Lambdaオーソライザー | 可    | 可    | Lambda          |
| オリジンmTLS                 | 可    | 可    | TLSハンドシェイク      |

- **カスタムヘッダー＋AWS WAF**：CloudFrontのオリジン設定で秘密の値を持つヘッダー（例 `x-origin-verify`）を付け、API Gatewayのステージに関連付けたWAFで「ヘッダーが一致しない要求をブロック」する。Lambdaまで届く前に止まるので、不正な要求にLambdaの課金が発生しない。WAFの基本は[WAFとは？仕組み・ファイアウォール／IPS・IDSとの違いと企業の選び方を解説](/tech/details/13275/)を参照。
- **リソースポリシー**：CloudFrontがRefererヘッダーに秘密の値を付け、REST APIのリソースポリシーで`aws:Referer`が一致しない呼び出しを拒否する。WAFの料金がかからない反面、アプリがRefererを別用途で使っていると使えない。
- **Lambda側の検証**：HTTP APIで証明書の運用なしに実現できる手段で、上のCDK例がこれ。ただし不正な要求でもAPI GatewayとLambdaの料金は発生する。Lambdaオーソライザーに切り出すと業務ロジックと分離できるが、オーソライザーの呼び出し分の遅延と料金が増える。
- **オリジンmTLS**：2026年2月2日にCloudFrontがオリジン向けの相互TLSに対応した（[AWSの発表](https://aws.amazon.com/about-aws/whats-new/2026/01/amazon-cloudfront-mutual-tls-for-origins/)）。CloudFrontがACMにインポートしたクライアント証明書をTLSハンドシェイクで提示し、API Gatewayのリージョンカスタムドメイン側でトラストストアと照合する。この方式で迂回を防ぐには、既定のexecute-apiエンドポイントを無効化し、同じAPIへ通じるmTLSなしのカスタムドメインも残さない。秘密ヘッダーの値だけが漏れてもmTLS認証は突破されず、CloudFrontのオリジンmTLS機能自体には追加料金がかからない。代わりに私設CAとトラストストア（S3に配置）の運用、証明書の期限管理が発生する。

選ぶ順番ははっきりしています。REST APIならカスタムヘッダー＋WAF。HTTP APIで小規模ならLambda側の検証、決済や外部公開APIのように「ヘッダー漏えいで突破される」リスクを許容できないならオリジンmTLSです。API認証そのものの設計は[API認証の設計｜方式選定マトリクスとトークン寿命・監査ログの決め方](/tech/details/17232/)で整理しています。

なお、ALBやEC2で使える「CloudFront VPCオリジン」はAPI Gatewayをオリジンにできません。VPC内のオリジンを非公開のまま配信する方法は[CloudFront VPCオリジンとは？ALB・EC2をプライベートのまま公開する設定と制約](/tech/details/4767/)を参照してください。

## APIレスポンスをCloudFrontでキャッシュしてよい条件

管理キャッシュポリシー`CachingDisabled`を既定にし、キャッシュしてよいAPIだけ別のビヘイビアに切り出すのが事故の起きにくい設計です。CloudFrontがキャッシュするのはGETとHEAD（設定によりOPTIONS）の応答だけで、POSTなどは常にオリジンへ転送されます。

- **キャッシュしてよい**：誰が呼んでも同じ結果になる公開GET（商品一覧、為替レート、設定値）。クエリ文字列で結果が変わるなら、そのパラメータをキャッシュキーに含める。
- **キャッシュしてはいけない**：AuthorizationヘッダーやCookieで利用者ごとに結果が変わるAPI。キャッシュキーに認証ヘッダーを含めれば技術的には分けられるが、キーの設計ミスがそのまま情報漏えいになるため、利用者別データはキャッシュしない方がよい。

REST APIにはAPI Gateway側のキャッシュもありますが、こちらはキャッシュ容量に応じた時間課金です。CloudFrontにはキャッシュ容量の時間課金がなく、従量課金ではキャッシュヒットの有無にかかわらず対象のリクエストとデータ転送に課金されるため、前段にCloudFrontがあるならキャッシュはCloudFrontに寄せるのが合理的です。キャッシュキーとTTLの考え方は[CDNとは？仕組み・キャッシュ制御からサービスの選び方まで実装目線で解説](/tech/details/13095/)に詳しくまとめています。

## API Gatewayを挟まない選択肢：Lambda関数URL＋OAC

2024年4月から、CloudFrontのオリジンアクセスコントロール（OAC）がLambda関数URLに対応しています。関数URLの認証タイプを`AWS_IAM`にし、CloudFrontが署名（SigV4）付きで呼び出すことで、CloudFront以外からの呼び出しを拒否できます（[Lambda関数URLへのアクセス制限](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-lambda.html)）。S3にOACを使う構成（[CloudFront OAC（オリジンアクセスコントロール）とは？OAIとの違いとS3バケットポリシー設定手順](/tech/details/3684/)）と同じ考え方です。API Gatewayの料金がまるごと消え、直アクセスの遮断も標準機能で済みます。

ただし制約が2つあります。

- **POSTとPUTはクライアントがボディのハッシュを送る必要がある**：Lambdaは署名なしペイロードに対応していないため、利用者がリクエストボディのSHA256を計算して`x-amz-content-sha256`ヘッダーに入れる必要がある。ブラウザから任意のフォームを送る用途では実装負担になる。
- **関数側に2つの権限が要る**：AWSのドキュメントの例では、CloudFrontのサービスプリンシパルに`lambda:InvokeFunctionUrl`と`lambda:InvokeFunction`の両方を、ディストリビューションのARNを条件にして付与している。

スロットリング、APIキー、リクエスト検証、複数関数へのルーティングが要らず、GET中心の単一関数で済むなら関数URL＋OACで十分です。ルートごとに別の関数へ振り分けたい、利用者ごとに流量を制限したい場合はAPI Gatewayを残してください。API Gateway＋Lambdaを含むサーバーレス構成の全体像は[サーバーレスアーキテクチャとは？構成パターン・AWS実装・採用判断を実装者目線で解説](/tech/details/13125/)で比較しています。CloudFront・API Gateway・Lambdaの構成設計から構築・運用までを外部に任せたい場合は、弊社の[インフラ構築（AWS・Google Cloud・Azure）](/service/system/aws/)でも支援しています。

## CloudFrontを足したときの料金の見積もり方

CloudFrontには常時無料枠があり、毎月1 TBのインターネットへの転送と1,000万件のHTTP・HTTPSリクエストまでは課金されません（アカウント内の全ディストリビューションの合計）。API GatewayなどAWSのオリジンからCloudFrontへのデータ転送（オリジンフェッチ）も無料です。無料枠を超えた分の日本の従量単価（AWS Price List API、2026年10月19日公開分）は次のとおりです。

| 項目                      | 単価（日本）           |
| ----------------------- | ---------------- |
| HTTPSリクエスト              | 1万件あたり0.012 USD  |
| インターネットへの転送（無料枠の次の9 TB） | 1 GBあたり0.114 USD |
| オリジンへの転送（POSTのボディ等）     | 1 GBあたり0.060 USD |

月1,000万リクエスト・転送1 TBに収まる規模なら、CloudFrontのリクエストと転送の料金は無料枠で賄えます。ただし無料枠はアカウント内の他の配信と合算で、オリジンへの転送（POSTのボディ等）やAWS WAFなどの追加機能は別に課金されます。規模が大きくなると話が変わります。月1億リクエスト・応答平均5 KB（約500 GB）でキャッシュなしの場合、HTTP APIが129 USD、CloudFrontのリクエスト料金が無料枠を除く9,000万件分で108 USDとなり、API Gatewayとほぼ同額が上乗せされます。この規模で費用を比べるときは、キャッシュヒットで減るAPI GatewayとLambdaの呼び出しに加え、データ転送の差も入れてください。API Gatewayから利用者へ直接返す場合はAPI Gatewayのデータ転送料がかかり、CloudFront経由ならオリジンからCloudFrontへの転送は無料で、CloudFrontの転送料（無料枠あり）に置き換わります。キャッシュできないAPIでは、WAFや同一ドメイン化の対価として払う費用と割り切って判断してください。2025年11月に始まった定額プラン（Free・Pro・Business・Premium）との損益分岐は[CloudFrontの料金を実額で計算する：定額プラン4階層と従量課金の分岐点](/tech/details/17751/)で試算しています。

運用に入ったら、CloudFrontのキャッシュヒット率とAPI Gatewayの4xx・5xx、LambdaのエラーをCloudWatchで並べて見ると、どの層で失敗しているかを切り分けられます。Lambdaのログの読み方は[AWS Lambdaのログ運用ガイド｜CloudWatch Logsの見方・JSON構造化・S3出力とコスト削減](/tech/details/4031/)にまとめています。

## よくある質問

### API GatewayとCloudFrontの違いは何ですか？

CloudFrontはコンテンツをエッジで配信・キャッシュするCDNで、API GatewayはAPIの公開・認可・流量制御を担うサービスです。役割が違うため、どちらかを選ぶのではなく、CloudFrontを入口、API Gatewayをその奥のAPI管理層として組み合わせます。

### Lambdaのコードを更新したらAPI Gatewayの再デプロイは必要ですか？

関数コードの更新だけなら不要です。API Gatewayのデプロイはルートや統合設定などAPI側の設定のスナップショットで、修飾子なしの関数ARNを呼ぶ場合は更新後の$LATESTが実行されます。公開バージョンやエイリアスを指定している場合は、その参照先のコードが実行されるため、新バージョンの発行やエイリアスの参照先更新が別途必要です。統合先を別のエイリアスへ変えるなどAPI側の設定を変えた場合、REST APIは再デプロイが必要で、HTTP APIは自動デプロイを有効にしたステージならすぐ反映されます。

### エッジ最適化のAPIの前にCloudFrontを置くとどうなりますか？

AWS管理のCloudFrontと自前のCloudFrontが二重になるため、動作を前提にしないでください。AWSはディストリビューションの多段配置を推奨せず、403の原因として説明しています。自前のCloudFrontを置くなら、既存REST APIのエンドポイントタイプをリージョンへ変更し、再デプロイしてください。

### API GatewayをCloudFrontからのアクセスのみに制限する一番簡単な方法は？

REST APIなら、CloudFrontでカスタムヘッダーを付け、API GatewayにAWS WAFを関連付けてヘッダーが一致しない要求をブロックする方法です。HTTP APIはWAFを使えないため、Lambda側でヘッダーを検証するか、オリジンmTLSを使います。

### CloudFrontとAPI Gatewayのキャッシュはどちらを使うべきですか？

CloudFrontを前段に置くならCloudFrontです。API Gateway（REST）のキャッシュは容量に応じた時間課金で、HTTP APIには機能自体がありません。認証付きで利用者ごとに結果が変わるAPIはどちらでもキャッシュしないでください。

## 関連記事

- [Amazon CloudFrontとは？仕組み・料金プランとエッジ機能・採用判断を実装者目線で解説](/tech/details/15431/)
- [AWS Lambdaとは？仕組み・料金体系とコールドスタート対策・採用判断を実装者目線で解説](/tech/details/15407/)
- [サーバーレスアーキテクチャとは？構成パターン・AWS実装・採用判断を実装者目線で解説](/tech/details/13125/)
- [APIゲートウェイとは？役割・機能とリバースプロキシ／サービスメッシュとの違い・導入判断を解説](/tech/details/13210/)
- [CloudFront OAC（オリジンアクセスコントロール）とは？OAIとの違いとS3バケットポリシー設定手順](/tech/details/3684/)

---

出典: [CloudFront×API Gateway×Lambdaの連携構成｜設定手順と403の原因・直アクセスの遮断方法](<https://www.issoh.co.jp/tech/details/6799/>)（株式会社一創）
