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