この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
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に移行できないか、是非再検討してみて下さい。