ちょっと話題の記事

Amazon API Gatewayの新機能「HTTP API」のJWT Authorizersを理解する #reinvent

2019.12.30

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

Amazon API Gatewayの新機能「HTTP API」

re:Invent 2019期間中、Amazon API Gatewayの新機能「HTTP API」が発表されました。現在プレビューとして、US East (Ohio), US East (N. Virginia), US West (N. California), US West (Oregon), Asia Pacific (Sydney), Asia Pacific (Tokyo), EU (Frankfurt), EU (Ireland)で提供されています。

従来の方式より低コストで利用可能である点が強調されますが、本記事ではJWT Authorizersについて焦点を当てて調べました。

下記ドキュメントを参考にしています。

本記事はプレビュー版として公開されているドキュメントを参考にした考察です。本リリース時には仕様などが変わる可能性がありますのでご容赦ください。

JWTとは

まずはじめにJWTを使った認証について理解しましょう。

JWTはJSON Web Tokenの略で、JSONで作られたトークンの規格です。RFC 7519で標準化されています。

JSONといっても、トークンの文字列がそのままJSON形式になっているわけではなく、Base64形式でエンコードされた文字列でやり取りを行います。例えば以下のような文字列になります。

この文字列の中には3つの情報で構成され、それぞれ . で区切られています。

トークンの中身は以下のように構成されています。

要素 説明 具体例
ヘッダー 署名生成に使用したアルゴリズム情報。 {"alg" : "HS256", "typ" : "JWT"}
ペイロード 認証情報などのクレーム。ユーザー情報など。 {"loggedInAs" : "admin", "iat" : 1422779638}
署名 正規に発行されたトークンか検証するための署名情報。 HMAC-SHA256(base64urlEncoding(header) + '.' + base64urlEncoding(payload), secret)

ペイロードの中身にユーザー情報が含まれているので、どのようなユーザーのIDなどをトークンから取得できるようになっています。トークンからユーザー情報を引けるのは非常に便利ですが、トークンが確実に信用できるものでなければいけません。そこでヘッダーとペイロードの情報を使って、正規に署名されたものかどうか検証できるようになっています。

署名の検証は、JWT発行側が用意する公開鍵を使って行います。jwks_uri として公開することになっており、例えばGoogleからは以下のようなJSONが取得できます(JWK Setと言います)。

{
  "keys": [
    {
      "kid": "57b1928f2f63329f2e92f4f278f94ee1038c923c",
      "e": "AQAB",
      "kty": "RSA",
      "alg": "RS256",
      "n": "1Zi0-4bNwZ7gGefz17U2NoKT4xBq-nzAa899teHxB2Q9KVCZYDhbQkpiIrBNg2u8s6TtoSljpq6MJpsKJVJgpT70gDCCgaUsGNYql9-kwWNKd80FlU1sjDEGouUIVEoYHzooPyn9r027KzMnTv5LGRYjxb5lvGnb4UCw5MF_EeSTNpGD7zb0b6juXwBxPi0oIUbQxAcGgH3oS40hXAjJ_U2T3Hln8lBlnVhLbrh-5qF-uoYDxjtAY9XyEJQH_rGiRfXWgBfSM02t9DCB46sQbEMM2iLe7mkGrZtCHR4zbAsAP0s2VGqSmwszNTWqqsdOccbfXp3i_ThkR3pDdTSIQQ",
      "use": "sig"
    },
    {
      "alg": "RS256",
      "n": "rEpSQ8IO8Gauj5AGRbgfwfaxHRMGONuTog4fWKWzZYxdWa76khbynWTAzUJVzw_FaAiZGnl7tlmD7pdKWOHszrcK2Hru87KzeRnnqvWlSqdKValu6x5TfBnJwxgr-L8Mnu4xNnrMG2AWcRkjFVWQmwZyEF3WroRzbxrVTlChD_UydnRuiV1z0BPkLOxTzF5RH21ukImElOm3AFIFXP5h8Z0yLrFEcxzLgDIt7wC68apH7uRmy2-a9D4b4Jwi3HRlAgsYAKXYeEQC3f8Mv03liJBv3CPZU4EyXLQUJA28b8l5NUSDI9tnbrfP8SIXlqLz8mNfuKR18LAU3s9sv-sR3Q",
      "use": "sig",
      "kid": "47456b8069e4365e517ca5e29757d1a9efa567ba",
      "e": "AQAB",
      "kty": "RSA"
    }
  ]
}

JWT Authorizersの認証の仕組み

次に、API GatewayのJWT Authorizersの認証の仕組みを確認しましょう。

  1. identitySource のトークンを取得する
  2. トークンをデコードする
  3. jwks_uri を使ってトークンを検証する
  4. クレームをバリデーションする
    • iss : JWTの発行元の識別子
    • aud : JWTの想定される利用者の識別子
    • exp : JWTが無効になる日時
    • nbf : JWTが有効になる日時
    • scope : 認可された権限

identitySource および jwks_uri は、APIのAuthorizerの設定です。作成時などに設定できます。以下はCLIリクエストの例です。

$ aws apigatewayv2 create-authorizer \
    --name authorizer-name \
    --api-id api-id \
    --authorizer-type JWT \
    --identity-source '$request.header.Authorization' \
    --jwt-configuration "Issuer='https://cognito-idp.us-east-2.amazonaws.com/userPoolID', Audience='audience'"

検証が成功した後はプロキシ先にリクエストが飛びますが、例えばLambda Functionの場合は $context.authorizer.claims からクレームの情報を取得できます。従来の方式と大きく変更になるのが Lambda Functionに到着している時点でJWTの検証が完了している点です。Lambda Function内のコードでは、ビジネスロジックにより集中できるようになります。

Amazon API GatewayのV2とも言える「HTTP API」に期待!

従来のAuthorizerはCognito User Poolsの場合のみがサポートされており、その他の認証プロバイダではLambda Functionでの実装が必要になっていました。HTTP APIのJWT Authorizersを使うとCognito User Pools以外の認証プロバイダの場合でも、OpenID ConnectまたはOAuth 2.0の標準仕様に準拠していれば簡単にAuthorizerを設定することができるので、非常に便利になると思います。