AWS Cognito の client credential grant を JWT オーソライザーで試してみた
REST API に無い HTTP API の機能の一つに JWT オーソライザーがあります。
JWT オーソライザーを使用した HTTP API へのアクセスの制御 - Amazon API Gateway
AWS Cognito UserPool 以外の ID プロバイダーを使っているときに、
場合によっては Lambda オーソライザーを作り込まなくても対応が可能となっています。
今回は、
AWS Cognito で client credential grant を使う場合の HTTP API の認可処理を
JWT オーソライザーを使って行ってみたいと思います。
概要
全体の構成は次のとおりです。
諸々のリソースの作成
- Cognito ユーザープール
- リソースサーバー
- アプリクライアント
- Lambda 関数
- HTTP API
基本的には既定の設定のままで大丈夫です。
ユーザープールのドメイン設定を行ってトークンエンドポイントへのアクセスを可能にしておきます。
また、アプリクライアントの設定で Client credentials の OAuth フローを有効にし、
作成したリソースサーバーのスコープにチェックを入れます。
JWT オーソライザーの作成
HTTP API に JWT オーソライザーを作成してルートにアタッチします。
JWT オーソライザーでは、こちらのドキュメントにあるような検証を行ってくれるそうです。
JWT オーソライザーを使用した HTTP API へのアクセスの制御 - Amazon API Gateway
設定する項目は次のとおりです。
設定項目 | 説明 |
---|---|
IDソース | Authorization ヘッダーを指定します。 |
発行者 | JWTに含まれる issuer を指定します。 発行者の jwks_uri から取得した公開鍵でトークンを検証します。 この場合のユーザープールの jwks_uri は https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_jD9OiE4y8/.well-known/jwks.json になります。 |
対象者 | Cognito ユーザープールが発行したアクセストークンを検証するために アプリクライアントの client_id を入力します。 |
認可スコープ | 設定しない場合は特にチェックが行われませんが、 今回はスコープを指定してみました。 「このルートへアクセスするには、いずれかのスコープが必要」 という設定が可能です。 |
テスト
Postman で動作を確認します。
1. アクセストークンの発行
トークンエンドポイントにアクセスしてアクセストークンを発行します。
次のようなレスポンスが得られ、
アクセストークンが取得できました。
2. HTTP API へのアクセス (アクセストークン無し)
まず、アクセストークンが無い状態でアクセスします。
アクセストークンが無い状態ではアクセスが拒否されました。
3. HTTP API へのアクセス (アクセストークンあり)
次に、アクセストークンを付与してアクセスします。
アクセスが許可され、Lambdaからレスポンスが返ることが確認できました。
4. Lambda の event に含まれる情報
Lambda の event を確認します。
{ "version": "2.0", "routeKey": "ANY /", "rawPath": "/", "rawQueryString": "", "headers": { "accept": "*/*", "accept-encoding": "gzip, deflate, br", "authorization": "Bearer eyJraWQiOiI0cXV3dnRpTG5TTVlaRzhTeEVcL0xQdHlkZUxiR1FoQ3ZkNUw5cXVcL2tkMDg9IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiI1YnVtdmVnYnRzbmtnODFlYWtlN2ozZGJvYSIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiY29tLmV4YW1wbGUudGVzdFwvdGVzdCIsImF1dGhfdGltZSI6MTYxNTAyODUwNywiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmFwLW5vcnRoZWFzdC0xLmFtYXpvbmF3cy5jb21cL2FwLW5vcnRoZWFzdC0xX2pEOU9pRTR5OCIsImV4cCI6MTYxNTAzMjEwNywiaWF0IjoxNjE1MDI4NTA3LCJ2ZXJzaW9uIjoyLCJqdGkiOiJiMzRjNjgyOC02NjUwLTQ5ZGMtYmU1YS01ZmExYjc4NTZiYjgiLCJjbGllbnRfaWQiOiI1YnVtdmVnYnRzbmtnODFlYWtlN2ozZGJvYSJ9.WZmp1r1VnGBbwfbH5_w9vtq41Fu4yqNQW-kPAUZOyrmBCR1ZRvrBpH11GVyNBUYSyx1uzTo7paPnfwmrO2B1YM0qg3H0Vv9rMtg4v_7ZnFQWdf1Kry8iGOPiHyBry2JeB0xeU7wx8Phg1amW_1SibgQ39Ta_8syD0gXbCU2UaAZi6xgWjFitHlB6jebJ7efWNi2YdzEAdpXZoH7Ct6K68mTD5lWDg0R-47ixyCTsLNlejVFxbyOGpFOVUlYiKlA8m_EOd9-D1UGihoRntgI9d87t9-1_K2tttQ7HyXOxsXucyHvwd0XqNETtEfUknxMF7s33J2A3INAJ8-d-9HRm8Q", "content-length": "0", "host": "0o5uiabhb4.execute-api.ap-northeast-1.amazonaws.com", "postman-token": "85d05ba0-36c4-4cb6-b197-f0252075af52", "user-agent": "PostmanRuntime/7.26.10", "x-amzn-trace-id": "Root=1-6043654a-64df179b5529cad61b9e1819", "x-forwarded-for": "<ipアドレス>", "x-forwarded-port": "443", "x-forwarded-proto": "https" }, "requestContext": { "accountId": "<アカウントid>", "apiId": "0o5uiabhb4", "authorizer": { "jwt": { "claims": { "auth_time": "1615028507", "client_id": "5bumvegbtsnkg81eake7j3dboa", "exp": "1615032107", "iat": "1615028507", "iss": "https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_jD9OiE4y8", "jti": "b34c6828-6650-49dc-be5a-5fa1b7856bb8", "scope": "com.example.test/test", "sub": "5bumvegbtsnkg81eake7j3dboa", "token_use": "access", "version": "2" }, "scopes": [ "com.example.test/test" ] } }, "domainName": "0o5uiabhb4.execute-api.ap-northeast-1.amazonaws.com", "domainPrefix": "0o5uiabhb4", "http": { "method": "GET", "path": "/", "protocol": "HTTP/1.1", "sourceIp": "106.72.178.224", "userAgent": "PostmanRuntime/7.26.10" }, "requestId": "bwzDmjpMNjMEJag=", "routeKey": "ANY /", "stage": "$default", "time": "06/Mar/2021:11:19:38 +0000", "timeEpoch": 1615029578123 }, "isBase64Encoded": false }
event.requestContext.authorizer.jwt
にて claims
と scopes
が渡ってきていることが確認できます。
制限事項
現時点での次のような引き上げ不能なクォータが設定されています。
要件を満たすか事前の確認を。
リソースまたはオペレーション | デフォルトのクォータ |
---|---|
オーソライザーあたりの対象者数 | 50 |
ルートあたりのスコープ数 | 10 |
JSON ウェブキーセットエンドポイントのタイムアウト | 1500 ms |
OpenID Connect 検出エンドポイントのタイムアウト | 1500 ms |
現時点では REST API の使用量プランのような
API Key を使ったスロットリングを行うことは出来ず、
ルートやアカウント単位でのスロットリング設定のみとなっているようです。
最後に
とても簡単な設定で認可処理の実装が出来ましたし、
HTTP API の使い勝手が非常に良いと感じました。
「早い、安い、シンプル」な
HTTP API を使える場面がこれからも増えるといいなぁと思います。