Amazon API Gateway のカスタムアクセスログを使って API キーの使用量を独自に可視化してみた

2023.04.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

いわさです。

API Gateway では API キーと使用量プランを使うことで、API キーごとの使用量を記録・管理することが出来ます。
しかし標準の使用量プランの機能では、どの API に対してキーごとにどの程度使用されたのかがわかりますが、リソース別メソッド別の粒度で使用量を把握することは出来ません。

そこで、今回 API Gateway のアクセスログを分析することで API キーごとに細かい使用量を算出出来るのかを確認してみました。
標準よりも粒度を細かくした使用量を出力することが出来たので、検証した内容を紹介したいと思います。

検証対象の API Gateway リソースを用意

今回、REST API を前提としています。
hoge1hoge2は API キーを要求し、hoge3は API キー不要でどこからでもアクセス出来るようにします。

適当な使用量プランと適当な API キーを用意しますがこのあたりの設定方法は割愛します。
こちらの記事などを参考にしてください。

作成出来たら API キーでアクセスが出来るのかを確認してみます。

# API キーなし
% curl "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge1"
{"message":"Forbidden"}
% curl "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge3"
hoge3

# API キーあり
% curl -H "x-api-key:yZaSPGcM5C3X4ylKXlvM19jS6zrtOJkG6EFKSDHh" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge1"
hoge1
% curl -H "x-api-key:yZaSPGcM5C3X4ylKXlvM19jS6zrtOJkG6EFKSDHh" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge3"
hoge3

hoge1には API キーが設定されていないとアクセス出来ないことが確認出来ました。

カスタムアクセスログを設定

デプロイした API ステージのカスタムアクセスログを有効化します。

次の公式ドキュメントはAPI Gateway のアクセスログ出力時に使用出来る変数のリファレンスです。
ここから可視化に必要なパラメータを探しましょう。

今回はパス別、API キー別に使用量を算出したかったので、リソースパスと API キーの情報が必須となります。
リファレンスから、以下あたりが候補になりそうです。

対象 変数
リソースパス $context.path, $context.resourcePath
API キー $context.identity.apiKeyId, $context.identity.apiKey

リファレンスの説明から判断出来る場合もありますが、判断に迷ったり、解釈誤り(あるいは記述誤り?)の可能性もあるので、一度ログ出力して期待どおりの出力がされているか事前に確認しておきましょう。

今回は次のようなカスタムアクセスのログ構造を指定してみました。

$context.requestId,$context.path,$context.resourcePath,$context.identity.apiKeyId,$context.identity.apiKey

出力結果は以下です。

$context.path$context.resourcePathはステージ名が出力されるかどうかの違いですね。
API キーは$context.identity.apiKeyIdを出力するのが良さそうです。$context.identity.apiKeyはキーの値がそのまま出力されてしまうようです。

カスタムメトリクス用

先日 API Gateway のログ設定から EMF を使ってそのままカスタムメトリクスを生成する方法を紹介しました。
今回可視化する方法については同じ方法を使いたいと思います。
ログから集計さえ出来ることが確認出来れば、EMF を使わずとも S3 へ出力して Athena でクエリするなど可視化の方法は色々と応用出来ると思います。

先程のログ出力結果から、今回は EMF 向けに以下のような設定にしました。
ディメンションが API キー別と API キー + パス別の 2 つ用意しています。

{
    "_aws": {
      "Timestamp": "$context.requestTimeEpoch",
      "CloudWatchMetrics": [
        {
          "Namespace": "hoge0329namespace2",
          "Dimensions": [["ApiKeyId"],["ApiKeyId","Path"]],
          "Metrics": [
            {
              "Name": "Count",
              "Unit": "Count",
              "StorageResolution": 60
            }
          ]
        }
      ]
    },
    "ApiKeyId": "$context.identity.apiKeyId",
    "Path": "$context.path",
    "Count": 1,
    "requestId": "$context.requestId"
  }

使用量を計測してみる

カスタムアクセスログを設定出来たら API リクエストを送信しましょう。

# Key1
% curl -H "x-api-key:yZaSPGcM5C3X4ylKXlvM19jS6zrtOJkG6EFKSDHh" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge1"
hoge1
% curl -H "x-api-key:yZaSPGcM5C3X4ylKXlvM19jS6zrtOJkG6EFKSDHh" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge1"
hoge1
% curl -H "x-api-key:yZaSPGcM5C3X4ylKXlvM19jS6zrtOJkG6EFKSDHh" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge1"
hoge1
% curl -H "x-api-key:yZaSPGcM5C3X4ylKXlvM19jS6zrtOJkG6EFKSDHh" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge1"
hoge1
% curl -H "x-api-key:yZaSPGcM5C3X4ylKXlvM19jS6zrtOJkG6EFKSDHh" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge1"
hoge1
% curl -H "x-api-key:yZaSPGcM5C3X4ylKXlvM19jS6zrtOJkG6EFKSDHh" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge2"
hoge2
% curl -H "x-api-key:yZaSPGcM5C3X4ylKXlvM19jS6zrtOJkG6EFKSDHh" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge2"
hoge2
% curl -H "x-api-key:yZaSPGcM5C3X4ylKXlvM19jS6zrtOJkG6EFKSDHh" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge3"
hoge3
% curl -H "x-api-key:yZaSPGcM5C3X4ylKXlvM19jS6zrtOJkG6EFKSDHh" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge3"
hoge3

# Key2
% curl -H "x-api-key:PpjSqIJeoVaYSprg1a2uk3FgK1rWxw622tu6o4c6" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge2"
hoge2
% curl -H "x-api-key:PpjSqIJeoVaYSprg1a2uk3FgK1rWxw622tu6o4c6" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge2"
hoge2
% curl -H "x-api-key:PpjSqIJeoVaYSprg1a2uk3FgK1rWxw622tu6o4c6" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge2"
hoge2
% curl -H "x-api-key:PpjSqIJeoVaYSprg1a2uk3FgK1rWxw622tu6o4c6" "https://de2mhoq3z2.execute-api.ap-northeast-1.amazonaws.com/hogestage/hoge2"
hoge2

上記のような感じで適当に送信しました。

API キー hoge1 hoge2 hoge3
キー1 5 回 2 回 2 回
キー2 0 回 4 回 0 回

ディメンションを確認

ディメンションは、キー別とキー&パス別の 2 つが期待どおり作成されていますね。

キー別の計測結果

キー別から確認してみましょう。

キー 1 が 9 回、キー 2 が 4 回と、正しく集計されていますね。

キー・パス別の計測結果

キー・パス別も次のように期待どおり集計されています。

注意点

API キーの使用量を計測する際にはいくつか注意事項があります。
以下の記事がとても良いので是非見てもらえると。

また、公式ドキュメントでは使用量プランの計測値はベストエフォートであるという点が言及されています。
どこまでを計測範囲とするべきかはよく検討が必要だと思います。

さいごに

本日は Amazon API Gateway でカスタムアクセスログから API キーの使用量を計算して可視化までさせてみました。

使用量の計算は出来ましたね。
スロットリング目的ではなく使用量の把握までを行いたい場合ですと、今回の方法を使えば標準よりも解像度の高い使用量が把握出来そうです。
ただし、どのリクエストパターンを計測対象とすべきか(レスポンスステータスを考慮すべきか、など)は検討と対策が必要です。