REST API の認証・使用量プラン・カスタムドメイン・WAF・VTL 統合まで踏み込む発展編
このハンズオンは、入門編「Lambda + API Gateway(HTTP API)」の発展版です。HTTP API がシンプルで低コストなのに対し、REST API はエンタープライズ向けの高度な機能(API キー認証、使用量プラン、リクエスト/レスポンス変換、WAF 連携、ステージ管理など)を備えています。ここでは REST API ならではの実践的な機能を一通り体験します。
| 項目 | 内容 |
|---|---|
| 対象サービス | API Gateway (REST)、Lambda、AWS WAF、ACM、Route 53、DynamoDB、CloudWatch |
| 主な学習内容 | ステージ管理・API キー・使用量プラン(スロットリング/クォータ)・カスタムドメイン・WAF・VTL マッピング |
| 所要時間 | 75〜90 分 |
| 難易度 | ★★★★☆(中〜上級者向け) |
| 前提知識 | Lambda・API Gateway の基本(入門編相当)、REST/HTTP の基礎 |
| 費用目安 | 約 1〜2 USD(WAF Web ACL 月額 + リクエスト課金。カスタムドメインは独自ドメイン必要) |
| 機能 | HTTP API(入門編) | REST API(本編) |
|---|---|---|
| 料金 | 安い(約 1/3) | 高い |
| レイテンシ | 低い | やや高い |
| API キー / 使用量プラン | 非対応 | 対応 ✅ |
| リクエスト/レスポンス変換 (VTL) | 非対応 | 対応 ✅ |
| AWS WAF 連携 | 非対応 | 対応 ✅ |
| プライベート API | 非対応 | 対応 ✅ |
| AWS サービス直接統合 | 限定的 | 豊富 ✅ |
「とにかく安くシンプルに公開したい」なら HTTP API、「API 製品として認証・課金・保護をきめ細かく管理したい」なら REST API という棲み分けです。
| パス | メソッド | 統合タイプ | 説明 |
|---|---|---|---|
| /items | GET / POST | Lambda プロキシ | Lambda 経由でアイテム取得・登録 |
| /raw | GET | AWS 統合(VTL) | Lambda を介さず DynamoDB を直接呼ぶ |
curl が使える環境(ローカル端末 or CloudShell)このハンズオンは ap-northeast-1(東京) で進めます。ただし カスタムドメイン用の ACM 証明書は、エッジ最適化エンドポイントの場合 us-east-1(バージニア北部)で発行する必要があります(Step3 で解説)。リージョナルエンドポイントなら同一リージョンで可。
バックエンド Lambda を用意し、REST API を構築して dev / prod の 2 ステージを作成します。
Lambda コンソール →「関数の作成」→ 一から作成。ランタイム Python 3.12、関数名 apigw-items-handler で作成し、以下のコードを貼り付けて「Deploy」します。
import json
def lambda_handler(event, context):
method = event.get("httpMethod", "GET")
stage = event.get("requestContext", {}).get("stage", "unknown")
if method == "POST":
body = json.loads(event.get("body") or "{}")
msg = f"created item: {body.get('name', 'noname')}"
else:
msg = "list of items"
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"message": msg, "stage": stage, "method": method})
}
API Gateway コンソール →「API を作成」→ 「REST API」(「REST API プライベート」ではない方)の「構築」をクリックします。
「API を作成」をクリックします。
「リソースを作成」→ リソース名 items で作成します。作成した /items を選択し「メソッドを作成」で GET を追加します。
| 設定項目 | 値 |
|---|---|
| 統合タイプ | Lambda 関数 |
| Lambda プロキシ統合 | オン |
| Lambda 関数 | apigw-items-handler |
同様に POST メソッドも同じ Lambda で作成します。
「API をデプロイ」をクリック →「新しいステージ」→ ステージ名 dev でデプロイします。発行された 呼び出し URL(例:https://abc123.execute-api.ap-northeast-1.amazonaws.com/dev)をメモします。
もう一度「API をデプロイ」→ 新しいステージ prod を作成します。これで同じ API を dev / prod で別々に運用できます。各ステージの「ステージ変数」タブで env=production のような変数を設定でき、統合先 Lambda のエイリアスやバックエンド URL をステージごとに切り替えられます。
${stageVariables.lambdaAlias} で統合先を動的に変更dev / prod 両ステージの URL で /items が叩け、レスポンスの stage フィールドがそれぞれ dev / prod になっていれば成功です。
REST API の代表機能である API キー認証とスロットリング/クォータ制御を設定します。
/items の GET メソッド →「メソッドリクエスト」の設定 →「API キーの必須」を true にします。POST も同様に設定し、API を再デプロイ(dev)します。
この状態でキー無しアクセスすると 403 Forbidden になります。
API Gateway 左メニュー →「使用量プラン」→「使用量プランを作成」。
| 設定項目 | 値 | 意味 |
|---|---|---|
| 名前 | handson-basic-plan | プラン名 |
| スロットリング - レート | 10 リクエスト/秒 | 定常的な秒間上限 |
| スロットリング - バースト | 20 | 瞬間的な許容上限 |
| クォータ | 1000 リクエスト/日 | 1 日あたりの総量上限 |
「API キー」→「API キーを作成」→ 名前 handson-key で作成します。次に使用量プランの「関連付けられた API ステージ」で handson-rest-api:dev を追加し、「API キー」タブで handson-key を追加します。
作成した API キーの値を「表示」でコピーし、x-api-key ヘッダーに付けて再アクセスします。
短時間に大量リクエストを送るとレート上限を超え 429 Too Many Requests が返ります。
キー無し → 403、キー有り → 200、過剰リクエスト → 429 と、使用量プランによるアクセス制御が機能していれば成功です。
デフォルトの execute-api URL を、独自ドメイン(例:api.example.com)で公開します。
ドメインを所有していない場合はこのステップをスキップして Step4 へ進んでください(他ステップに影響しません)。
ACM コンソール →「証明書をリクエスト」→ パブリック証明書。ドメイン名に api.example.com を入力し、DNS 検証で発行します。
ap-northeast-1 で発行us-east-1 で発行(CloudFront 配下のため)Route 53 を使っていれば「Route 53 にレコードを作成」ボタンで検証 CNAME を自動追加できます。状態が「発行済み」になるまで待ちます。
API Gateway 左メニュー →「カスタムドメイン名」→「作成」。
作成したカスタムドメインの「API マッピング」→「マッピングを設定」で、パスとステージを紐付けます。
| パス | API | ステージ |
|---|---|---|
| v1 | handson-rest-api | prod |
これで https://api.example.com/v1/items が prod ステージにマッピングされます。
カスタムドメインに表示される「API Gateway ドメイン名」(d-xxxx.execute-api...)を、Route 53 で api.example.com の A レコード(エイリアス)として登録します。数分後に名前解決され、独自ドメインでアクセス可能になります。
https://api.example.com/v1/items で API が応答すればカスタムドメイン設定は成功です。
REST API のステージに AWS WAF の Web ACL をアタッチし、IP 制限やレートベースのブロックを設定します。
WAF & Shield コンソール →「Web ACLs」→「Create web ACL」。
| 設定項目 | 値 |
|---|---|
| 名前 | handson-api-waf |
| リージョン | Asia Pacific (Tokyo) ※ API と同リージョン |
| Resource type | Regional resources (API Gateway) |
「Add AWS resources」で handson-rest-api の dev(または prod)ステージを関連付けます。
「Add rules」→「Add my own rules」→ Rule type Rate-based rule。
| 設定項目 | 値 |
|---|---|
| Name | rate-limit-rule |
| Rate limit | 100(5 分あたり同一 IP の上限) |
| Action | Block |
「IP sets」で自分のグローバル IP を含む IP セットを作成し、Web ACL に「その IP セット以外を Block」または「特定 IP を Block」するルールを追加できます。AWS マネージドルール(AWSManagedRulesCommonRuleSet 等)を追加すると一般的な攻撃パターンも自動防御できます。
Default action を Allow にして Web ACL を作成します(ルールにマッチしたものだけ Block)。数分後、レート上限を超えるアクセスは 403(WAF ブロック)が返るようになります。
429 を返す。課金・契約管理向け403 を返す。セキュリティ向け両者は目的が異なり、組み合わせて多層防御を構成します。
WAF の「Sampled requests」やメトリクスでブロックされたリクエストが確認できれば成功です。
REST API ならではの「AWS サービス統合」を使い、Lambda を介さずに API Gateway から DynamoDB を直接呼び出します。リクエスト/レスポンスの変換には VTL(Velocity Template Language)マッピングテンプレートを使います。
DynamoDB →「テーブルの作成」。
作成後、項目を 1 つ手動追加します(例:{ "id": "1", "name": "apple" })。
API Gateway が DynamoDB を呼ぶための実行ロールを作成します。信頼されたエンティティ apigateway.amazonaws.com、ポリシーに dynamodb:GetItem(対象テーブル)を許可した apigw-dynamodb-role を作成します。
API Gateway で /raw リソースを作成し、GET メソッドを以下で設定します。
| 設定項目 | 値 |
|---|---|
| 統合タイプ | AWS サービス |
| AWS リージョン | ap-northeast-1 |
| AWS サービス | DynamoDB |
| HTTP メソッド | POST |
| アクション | GetItem |
| 実行ロール | apigw-dynamodb-role の ARN |
「統合リクエスト」→「マッピングテンプレート」→ Content-Type application/json を追加し、クエリ文字列 ?id=1 を DynamoDB の GetItem リクエストへ変換します。
{
"TableName": "handson-items",
"Key": {
"id": { "S": "$input.params('id')" }
}
}
「統合レスポンス」→「マッピングテンプレート」で、DynamoDB の生レスポンスをクライアント向けの素直な JSON に整形します。
#set($item = $input.path('$.Item'))
{
"id": "$item.id.S",
"name": "$item.name.S"
}
API を再デプロイ(dev)して動作確認します。
curl -H "x-api-key: YOUR_API_KEY_VALUE" \ "https://abc123.execute-api.ap-northeast-1.amazonaws.com/dev/raw?id=1" # => {"id":"1","name":"apple"}/raw?id=1 が Lambda を経由せず DynamoDB の項目を返せば、VTL マッピングによる AWS サービス直接統合が成功です。
WAF Web ACL は作成時から月額固定費(約 $5/月 + ルール課金)が発生します。使い終わったら必ず削除してください。API Gateway・Lambda・DynamoDB はほぼ無料枠ですが、念のためすべて削除します。
handson-api-waf → 関連リソースの関連付けを解除してから削除(IP セットも削除)
handson-basic-plan 削除 → API キー handson-key 削除
handson-rest-api →「API を削除」
apigw-items-handler を削除
handson-items を削除
apigw-dynamodb-role および Lambda 実行ロールを削除
handson-rest-api が無い| 習得したスキル | 実践内容 |
|---|---|
| REST API とステージ管理 | dev / prod ステージ・ステージ変数の運用 |
| API キー / 使用量プラン | キー認証 + スロットリング + クォータで API を製品化 |
| カスタムドメイン | ACM 証明書 + Route 53 で独自ドメイン公開 |
| WAF 連携 | レート制限・IP 制限・マネージドルールで多層防御 |
| VTL 直接統合 | Lambda レスで DynamoDB を直接呼び出すマッピング |