[アップデート]API GWのHTTP APIでIAMによる認可とLambdaオーソライザーが利用可能になりました
CX事業本部@大阪の岩田です。
2020/9/9付のアップデートにより、API GatewayのAPIタイプとしてHTTP APIを選択した場合でもオーソライザーとして
- IAM
- Lambdaオーソライザー
が選択可能になりました。
さっそく各機能を試してみたので、内容を簡単にご紹介します。
何がうれしいの?
API GatewayのAPIタイプ HTTP APIはre:invent2019で発表された比較的新しい機能です。従来のREST APIと比較して
- 低コスト
- 低レイテンシ
というメリットがありますが、REST APIの上位互換というわけではなくREST APIに存在するいくつかの機能は利用できず、なんでもかんでもHTTP APIに移行することはできません。
このREST APIには存在するものの、HTTP APIでは利用できない機能の代表格としてオーソライザー関連の機能が挙げられます。REST APIでは認可メソッドとして
- IAM
- Cognito
- Lambdaオーソライザー
が選択できますが、HTTP APIで選択可能なオーソライザーはJWTオーソライザー一択でした。REST APIの認可メソッドとしてCognitoを利用していた場合はHTTP APIのJWTオーソライザーで代替可能ですが、IAMもしくはLambdaオーソライザーを利用している場合は代替手段が存在しないため、HTTP APIに移行することはできませんでした。
今回のアップデートによってREST APIの認可メソッドとしてIAMもしくはLambdaオーソライザーを利用していたケースでもHTTP APIに移行できる可能性が高くなりました。是非REST APIからHTTP APIに移行できないか検討してみて下さい。
やってみる
実際にIAMによる認可とLambdaオーソライザーを試してみます。
IAM
まずはIAMからです。
マネコンからHTTP APIを作成し、「認可」→ 「オーソライザーを管理」と進むと「IAM(built-in)」という選択肢が増えていることが分かります。
適当にルートを作成し、オーソライザーとしてIAMをアタッチします。
普通にAPIを呼び出してみます。
$curl -i https://<API GWのID>.execute-api.ap-northeast-1.amazonaws.com/iam HTTP/2 403 date: Thu, 10 Sep 2020 00:48:07 GMT content-length: 23 apigw-requestid: Sn-nMhmnNjMEJLg= {"message":"Forbidden"}
403エラーになりました。
今度は適当にexecute-api:Invoke
の権限を持ったIAMユーザーを作成し、Postmanを使ってSIGV4の署名付きでAPIを呼び出してみます。
今度は200 OKでレスポンスが返却されてきました。想定通りに動作しています。
Lambdaオーソライザー
続いてLambdaオーソライザーを試してみます。
HTTP APIのLambdaオーソライザーではHTTP APIの「統合」と同様にペイロード形式として1.0もしくは2.0いずれかを選択可能です。さらに、ペイロード形式2.0を選択した場合はLambdaオーソライザーからのレスポンスとして
- Simple
- IAM Policy
の2つが選択可能になります。
IAM Policyを選択した場合は、REST APIにおけるLambdaオーソライザーと同様のフォーマットでLambdaからレスポンスを返却する必要があります。以下の公式ドキュメントからの引用ですが、以下のようなフォーマットです。
{ "principalId": "abcdef", // The principal user identification associated with the token sent by the client. "policyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow|Deny", "Resource": "arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/[{resource}/[{child-resources}]]" } ] }, "context": { "exampleKey": "exampleValue" } }
このResourceの部分を組み立てるのが地味に面倒なんですよね。。。
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html
HTTP APIで選択可能なSimpleフォーマットの場合は以下のようなフォーマットになります。こちらも公式ドキュメントの引用となります。
{ "isAuthorized": true/false, "context": { "exampleKey": "exampleValue" } }
context
は後続処理に引き渡したい情報をセットできる任意項目です認可OK/NGの判定だけであればSimpleフォーマットのレスポンスは
{"isAuthorized": true/false}
だけ返却すればOKです。IAM Policyと比較すると非常にシンプルですね!!
実際にLambdaオーソライザーを作成していきます。まずはオーソライザーとして指定するLambda Functionを作成します。公式ドキュメント記載のSimpleフォーマットのサンプルをそのまま拝借しました。リクエストヘッダのAuthorization
にsecretToken
という文字列が設定されていた場合に認可OKとするロジックです。
exports.handler = async(event) => { let response = { "isAuthorized": false, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": true, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } }; if (event.headers.authorization === "secretToken") { response = { "isAuthorized": true, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": true, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } }; } return response; };
作成したLambda Functionを指定してLambdaオーソライザーを作成します。ペイロード形式を2.0に、Response modeをSimpleにするのを忘れないで下さい。
オーソライザーの準備ができたので、適当なルートを用意してアタッチします。
準備ができたので呼び出してみます。
curl -i https://<API GWのID>.execute-api.ap-northeast-1.amazonaws.com/lambda HTTP/2 401 date: Thu, 10 Sep 2020 01:10:25 GMT content-length: 26 apigw-requestid: SoB4OgwttjMEJSA= {"message":"Unauthorized"}
401エラーになりました。
今度はHTTPヘッダーのAuthorization
にsecretToken
という文字列をセットして呼び出してみます。
curl -i https://<API GWのID>.execute-api.ap-northeast-1.amazonaws.com/lambda -H "Authorization: secretToken" HTTP/2 200 date: Thu, 10 Sep 2020 01:16:18 GMT content-type: text/plain; charset=utf-8 content-length: 1045 apigw-requestid: SoCvXinnNjMEPOQ= {"version": "2.0", ...略
今度は200 OKでレスポンスが返却されてきました!!今回はバックエンドのLambdaとしてeventデータをそのままレスポンスするLambdaを紐付けたのですが、レスポンスボディを整形すると以下のような形でした。
{ "version": "2.0", "routeKey": "GET /lambda", "rawPath": "/lambda", "rawQueryString": "", "headers": { "accept": "*/*", "authorization": "secretToken", "content-length": "0", "host": "<API GWのID>.execute-api.ap-northeast-1.amazonaws.com", "user-agent": "curl/7.64.1", "x-amzn-trace-id": "Root=1-5f597e8d-8ffbfd88e6f2dd12aa495e08", "x-forwarded-for": "126.83.27.201", "x-forwarded-port": "443", "x-forwarded-proto": "https" }, "requestContext": { "accountId": "<AWSアカウントIDEA>", "apiId": "<API GWのID>", "authorizer": { "lambda": { "arrayKey": [ "value1", "value2" ], "booleanKey": true, "mapKey": { "value1": "value2" }, "numberKey": 1, "stringKey": "value" } }, "domainName": "<API GWのID>.execute-api.ap-northeast-1.amazonaws.com", "domainPrefix": "<API GWのID>", "http": { "method": "GET", "path": "/lambda", "protocol": "HTTP/1.1", "sourceIp": "<アクセス元IPアドレス>", "userAgent": "curl/7.64.1" }, "requestId": "SoC2EivRNjMEPyw=", "routeKey": "GET /lambda", "stage": "$default", "time": "10/Sep/2020:01:17:01 +0000", "timeEpoch": 1599700621197 }, "isBase64Encoded": false }
注目したいのはrequestContext.authorizer.lambda
配下のデータ構造です。Lambdaオーソライザーのレスポンスでセットしたcontext
の情報が後続のLambdaまで渡っていることが分かります。また文字列やbool値だけでなく、arrayやmapのようなデータ構造も渡せていることが分かります。例えばですが、Lambdaオーソライザー側でDBから何かしらの情報を取得して後続のLambdaに引き渡して...といった制御が簡単に行えることが分かります。
まとめ
今回のアップデートによりREST APIからHTTP APIへの移行がさらに加速しそうです。現在REST APIを利用している方は、HTTP APIに移行できないか、是非再検討してみて下さい。