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

APIキーのメリットとデメリット
メリット
- 
実装が簡単 - API Gateway や他の多くのサービスでネイティブ対応しており、すぐに導入可能。
- クライアントは x-api-key ヘッダーにキーを付けるだけでアクセス可能。
 
- 
個別の利用制御ができる - API キーごとに 使用量プラン(Usage Plan) を設定し、アクセス回数制限(レート、クォータ)を行える。
- APIキー単位でアクセス制御や分析が可能(誰がどれだけ使ったか把握できる)。
 
- 
匿名ユーザーでも制御できる - ユーザー登録やOAuthのような仕組みが不要なので、簡単なAPI公開に適している。
- 「登録不要だが制限あり」という形でAPIを提供できる。
 
デメリット
- 
セキュリティが弱い - APIキーは単なる文字列(トークン)であり、流出すると不正利用される可能性がある。
- 誰でもキーさえ知っていればアクセスできる(ユーザーの正当性はチェックされない)。
 
- 
キーの使い回し・共有が容易 - ユーザーがキーを複製・共有しやすいため、利用者の追跡やアクセス制御が難しくなる。
- 不正利用の発見・遮断は「手動対応」や監視が必要になることも。
 
- 
失効・ローテーションが面倒 - キーをローテーションする仕組みが必要になる(セキュリティ維持のため)。
- 利用者が多いと、個別にキーの無効化や再発行を管理するのが煩雑。
 
- 
アクセス制御の粒度が粗い - ユーザー認証(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"}になりますね。
正常な動きです。
使用量データの確認方法
使用料データプランは、誰がどれだけ使ったかを確認できることもメリットです。
使用量データをエクスポートで確認
設定部分からjsonやcsvでエクスポートができます。

今回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オーソライザーも検証してみようと思います。



