API Gatewayで使用料プラン+APIキーでの認証を実装してみた

はじめに

API Gatewayはデフォルトで公開してしまうと、エンドポイントにアクセスできれば誰でもAPIを使用できてしまいます。
それを防ぐためにAPI Gatewayではいくつか認証方法が設定できます。
今回はAPIキーを使用して、curlコマンドでPOSTしてみてAPI Gatewayの背後にあるLambdaからのレスポンスを受け取れるか検証をしてみました。
この方法では、API Gatewayで「使用料プラン」を設定する必要があります。

APIキーのメリットとデメリット

メリット

  1. 実装が簡単

    • API Gateway や他の多くのサービスでネイティブ対応しており、すぐに導入可能。
    • クライアントは x-api-key ヘッダーにキーを付けるだけでアクセス可能。
  2. 個別の利用制御ができる

    • API キーごとに 使用量プラン(Usage Plan) を設定し、アクセス回数制限(レート、クォータ)を行える。
    • APIキー単位でアクセス制御や分析が可能(誰がどれだけ使ったか把握できる)。
  3. 匿名ユーザーでも制御できる

    • ユーザー登録やOAuthのような仕組みが不要なので、簡単なAPI公開に適している。
    • 「登録不要だが制限あり」という形でAPIを提供できる。

デメリット

  1. セキュリティが弱い

    • APIキーは単なる文字列(トークン)であり、流出すると不正利用される可能性がある。
    • 誰でもキーさえ知っていればアクセスできる(ユーザーの正当性はチェックされない)。
  2. キーの使い回し・共有が容易

    • ユーザーがキーを複製・共有しやすいため、利用者の追跡やアクセス制御が難しくなる。
    • 不正利用の発見・遮断は「手動対応」や監視が必要になることも。
  3. 失効・ローテーションが面倒

    • キーをローテーションする仕組みが必要になる(セキュリティ維持のため)。
    • 利用者が多いと、個別にキーの無効化や再発行を管理するのが煩雑。
  4. アクセス制御の粒度が粗い

    • ユーザー認証(ID単位)ではなくキー単位なので、細かいアクセス権管理ができない。

使いどころ

APIキー認証は「ライトな公開APIや、信頼できるクライアント向けにアクセス制御を行いたい場合」に適しています。
しかし「セキュリティを重視する場合やユーザーごとの詳細なアクセス制御が必要な場合」は、CognitoやOAuth、Lambdaオーソライザーなどのより強力な認証方式の併用・切り替えを検討すべきです。

API Gatewayの使用料プランとは

REST APIでのみ利用できる機能です。
APIキーやデプロイステージの紐づけを行います。

APIキーが紐づいているプラン毎に、下記のことが可能になります。

  • スロットリングの制限(頻度で制限)
  • クォータ制限(回数で制限)

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-api-usage-plans.html
https://www.cview.co.jp/cvcblog/2022.09.28.0yhjkgycqopilr55wbavo

テスト用Lambdaの作成

下記のような簡単なLambdaを作成しておきます。

import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

APIの作成

API GatewayでメソッドをPOSTで作成していきます。
先ほど作成したLambdaを指定します。
また、メソッドリクエストの設定で「API キーは必須です」をチェックしておきましょう。

この状態で一度デプロイをします。
今回はtestステージにデプロイします。

この状態で下記でリクエストを送ってみると{"message":"Forbidden"}がでるはずです。
APIキーを必須にしているがキーの設定をしていないので、これが正常です。

curl -X POST https://xxxx.execute-api.ap-northeast-1.amazonaws.com/test/

APIキーの作成

名前を入力し、今回は自動生成で作成していきます。
自動生成は、小英数字の40文字で生成されるようです。

使用料プランの設定

今回はテストなので、すべて10で設定します。

リクエストに関しては、1か月あたり1週間あたり1日あたりで設定できるようです。

作成しましたら、作った使用料プランを選択し、デプロイステージを指定します。
今回は、testです。

次に先ほど作成したAPIキーを紐づけます。既存のキーを選択します。
(ここでも新規で作成できるみたいですね)

こちらで設定は完了です。

テスト

リクエストのテストをしていきましょう。
下記コマンドでHTTPリクエストを送ってみます。

curl -X POST https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/test \
  -H "Content-Type: application/json" \
  -H "x-api-key: "<APIキー>"

"Hello from Lambda!"が返ってくれば成功です!

ちなみに上記を10回リクエストを送ってみると・・・
{"message":"Limit Exceeded"}になりますね。
正常な動きです。

使用量データの確認方法

使用料データプランは、誰がどれだけ使ったかを確認できることもメリットです。

使用量データをエクスポートで確認

設定部分からjsoncsvでエクスポートができます。

今回1か月でエクスポートしたので、1日ずつ配列が増えていくんですね。
5月30日に全量使ったので、[10, 0]になっています。

{
  "{APIキーID}": [
    [0, 10],   # 5月1日の使用量, 残使用量
    [0, 10],   # 5月2日の使用量, 残使用量
    [0, 10],   # 5月3日の使用量, 残使用量
    [0, 10],   # 5月4日の使用量, 残使用量
    [0, 10],   # 5月5日の使用量, 残使用量
    [0, 10],   # 5月6日の使用量, 残使用量
    [0, 10],   # 5月7日の使用量, 残使用量
    [0, 10],   # 5月8日の使用量, 残使用量
    [0, 10],   # 5月9日の使用量, 残使用量
    [0, 10],   # 5月10日の使用量, 残使用量
    ・
    ・
    ・
    [10, 0]    # 5月30日の使用量, 残使用量
  ]
}

CloudWatch Logs(カスタムアクセスログ)で詳細なデータを確認する

まずAPI GatewayでCloudWatch Logsを有効化しておきます。

デプロイステージの設定で、CloudWatch Logsの設定をします。
この時出力したいロググループのARNを入力、カスタムのアクセスログを選択し、以下のJSON文字列を入力します。

{ "requestId":"$context.requestId", "ip":"$context.identity.sourceIp", "apiKeyId":"$context.identity.apiKeyId", "userAgent":"$context.identity.userAgent", "resourcePath":"$context.resourcePath", "httpMethod":"$context.httpMethod", "status":"$context.status", "responseLength":"$context.responseLength", "requestTime":"$context.requestTime" }

この変数はAWSドキュメントで公開されていますので、ご参照ください。
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-variables-for-access-logging.html

こんな形で詳細なログを取得することができます。

{
    "requestId": "xxx",
    "ip": "xxx",
    "apiKeyId": "xxx",
    "userAgent": "curl/8.5.0",
    "resourcePath": "/",
    "httpMethod": "POST",
    "status": "200",
    "responseLength": "20",
    "requestTime": "30/May/2025:03:11:48 +0000"
}

おわりに

以上がAPI Gatewayの使用料プラン+APIキーを使った認証方法でした。
Cognito、Lambdaオーソライザーでの認証より簡単に実装ができ、アクセス管理もできるので細かい制御が不要なAPIには向いているかもしれませんね。
次回はCognito、Lambdaオーソライザーも検証してみようと思います。

Last modified: 2025-06-01

Author