AWS Lambda オーソライザーを使用して HTTP API へのアクセスを制御する - Amazon API Gateway

AWS Lambda オーソライザーを使用して HTTP API へのアクセスを制御する

Lambda オーソライザーを使用し、Lambda 関数を使用して HTTP API へのアクセスを制御します。次に、クライアントが API を呼び出すと、API Gateway が Lambda 関数を呼び出します。API Gateway は、Lambda 関数からのレスポンスを使用して、クライアントが API にアクセスできるかどうかを判断します。

ペイロード形式バージョン

オーソライザーの’ペイロード形式バージョンでは、API Gateway が Lambda 認証に送信するデータの形式と、API Gateway が Lambda からのレスポンスをどのように解釈するかを指定します。ペイロード形式バージョンを指定しない場合、AWS Management Console はデフォルトで最新バージョンを使用します。AWS CLI、AWS CloudFormation、または SDK を使用して Lambda オーソライザーを作成する場合は、authorizerPayloadFormatVersion を指定する必要があります。サポートされる値は 1.02.0 です。

REST APIとの互換性が必要な場合は、バージョン 1.0 を使用してください。

次の例は、各ペイロード形式バージョンの構造を示しています。

2.0
{ "version": "2.0", "type": "REQUEST", "routeArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request", "identitySource": ["user1", "123"], "routeKey": "$default", "rawPath": "/my/path", "rawQueryString": "parameter1=value1&parameter1=value2&parameter2=value", "cookies": ["cookie1", "cookie2"], "headers": { "header1": "value1", "header2": "value2" }, "queryStringParameters": { "parameter1": "value1,value2", "parameter2": "value" }, "requestContext": { "accountId": "123456789012", "apiId": "api-id", "authentication": { "clientCert": { "clientCertPem": "CERT_CONTENT", "subjectDN": "www.example.com", "issuerDN": "Example issuer", "serialNumber": "1", "validity": { "notBefore": "May 28 12:30:02 2019 GMT", "notAfter": "Aug 5 09:36:04 2021 GMT" } } }, "domainName": "id.execute-api.us-east-1.amazonaws.com", "domainPrefix": "id", "http": { "method": "POST", "path": "/my/path", "protocol": "HTTP/1.1", "sourceIp": "IP", "userAgent": "agent" }, "requestId": "id", "routeKey": "$default", "stage": "$default", "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, "pathParameters": { "parameter1": "value1" }, "stageVariables": { "stageVariable1": "value1", "stageVariable2": "value2" } }
1.0
{ "version": "1.0", "type": "REQUEST", "methodArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request", "identitySource": "user1,123", "authorizationToken": "user1,123", "resource": "/request", "path": "/request", "httpMethod": "GET", "headers": { "X-AMZ-Date": "20170718T062915Z", "Accept": "*/*", "HeaderAuth1": "headerValue1", "CloudFront-Viewer-Country": "US", "CloudFront-Forwarded-Proto": "https", "CloudFront-Is-Tablet-Viewer": "false", "CloudFront-Is-Mobile-Viewer": "false", "User-Agent": "..." }, "queryStringParameters": { "QueryString1": "queryValue1" }, "pathParameters": {}, "stageVariables": { "StageVar1": "stageValue1" }, "requestContext": { "path": "/request", "accountId": "123456789012", "resourceId": "05c7jb", "stage": "test", "requestId": "...", "identity": { "apiKey": "...", "sourceIp": "...", "clientCert": { "clientCertPem": "CERT_CONTENT", "subjectDN": "www.example.com", "issuerDN": "Example issuer", "serialNumber": "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1", "validity": { "notBefore": "May 28 12:30:02 2019 GMT", "notAfter": "Aug 5 09:36:04 2021 GMT" } } }, "resourcePath": "/request", "httpMethod": "GET", "apiId": "abcdef123" } }

Lambda オーソライザーのレスポンス形式

ペイロード形式バージョンによって、Lambda 関数から返す必要のあるレスポンスの構造も決まります。

Lambda 関数レスポンス形式 1.0

1.0 形式バージョンを選択した場合、Lambda オーソライザーは API ルートへのアクセスを許可または拒否する IAM ポリシーを返す必要があります。ポリシーでは、標準の IAM ポリシー構文を使用できます。IAM ポリシーの例については、「API を呼び出すためのアクセスの制御」を参照してください。$context.authorizer.property を使用して、コンテキストプロパティを Lambda 統合に渡したり、ログにアクセスしたりできます。context オブジェクトはオプションです。claims は予約されたプレースホルダーであり、コンテキストオブジェクトとしては使用できません。詳細については、「HTTP API アクセスログをカスタマイズする」を参照してください。

{ "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" } }

Lambda 関数レスポンス形式 2.0

2.0 形式バージョンを選択した場合は、Lambda 関数から、ブール値を返すか、標準の IAM ポリシー構文を使用する IAM ポリシーを返すことができます。ブール値を返すには、オーソライザーの簡易レスポンスを有効にします。以下の例では、Lambda 関数から返すようにコーディングする必要のある形式を示しています。context オブジェクトはオプションです。$context.authorizer.property を使用して、コンテキストプロパティを Lambda 統合に渡したり、ログにアクセスしたりできます。詳細については、「HTTP API アクセスログをカスタマイズする」を参照してください。

Simple response
{ "isAuthorized": true/false, "context": { "exampleKey": "exampleValue" } }
IAM policy
{ "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" } }

Lambda オーソライザー関数の例

以下のサンプルの Node.js Lambda 関数では、2.0 ペイロード形式バージョンの場合に Lambda 関数から返す必要のあるレスポンスの形式を示しています。

Simple response - Node.js
export const 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") { console.log("allowed"); response = { "isAuthorized": true, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": true, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } }; } return response; };
Simple response - Python
import json def lambda_handler(event, context): response = { "isAuthorized": False, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": True, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } } try: if (event["headers"]["authorization"] == "secretToken"): response = { "isAuthorized": True, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": True, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } } print('allowed') return response else: print('denied') return response except BaseException: print('denied') return response
IAM policy - Node.js
export const handler = async(event) => { if (event.headers.authorization == "secretToken") { console.log("allowed"); return { "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", "Resource": event.routeArn }] }, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": true, "arrayKey": ["value1", "value2"], "mapKey": { "value1": "value2" } } }; } else { console.log("denied"); return { "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": "Deny", "Resource": event.routeArn }] }, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": true, "arrayKey": ["value1", "value2"], "mapKey": { "value1": "value2" } } }; } };
IAM policy - Python
import json def lambda_handler(event, context): response = { # The principal user identification associated with the token sent by # the client. "principalId": "abcdef", "policyDocument": { "Version": "2012-10-17", "Statement": [{ "Action": "execute-api:Invoke", "Effect": "Deny", "Resource": event["routeArn"] }] }, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": True, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } } try: if (event["headers"]["authorization"] == "secretToken"): response = { # The principal user identification associated with the token # sent by the client. "principalId": "abcdef", "policyDocument": { "Version": "2012-10-17", "Statement": [{ "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": event["routeArn"] }] }, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": True, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } } print('allowed') return response else: print('denied') return response except BaseException: print('denied') return response

ID ソース

オプションで、Lambda オーソライザーの ID ソースを指定できます。ID ソースは、リクエストを認可するために必要なデータの場所を指定します。例えば、ヘッダーまたはクエリ文字列の値を ID ソースとして指定できます。ID ソースを指定する場合、クライアントはそれらのソースをリクエストに含める必要があります。クライアントのリクエストに ID ソースが含まれていない場合、API Gateway は Lambda オーソライザーを呼び出さず、クライアントは 401 エラーを受け取ります。

次の表は、Lambda オーソライザーでサポートされている ID ソースを示しています。

タイプ

Notes (メモ)

ヘッダー値 $request.header.name ヘッダー名では大文字と小文字は区別されません。
クエリ文字列値 $request.querystring.name クエリ文字列名では大文字と小文字が区別されます。
コンテキスト変数 $context.variableName サポートされているコンテキスト変数の値。
ステージ変数 $stageVariables.variableName ステージ変数の値。

オーソライザーのレスポンスのキャッシュ

authorizerResultTtlInSeconds を指定することで、Lambda オーソライザーのキャッシュを有効にすることができます。オーソライザーのキャッシュが有効になっていると、API Gateway はオーソライザーの ID ソースをキャッシュキーとして使用します。クライアントが設定済みの TTL 内の ID ソースで同じパラメータを指定した場合、API Gateway は、Lambda 関数を呼び出すのではなく、キャッシュされたオーソライザーの結果を使用します。

キャッシュを有効にするには、オーソライザーに 1 つ以上の ID ソースが必要です。

オーソライザーの簡易レスポンスを有効にすると、オーソライザーのレスポンスは、キャッシュされた ID ソース値に一致するすべての API リクエストを完全に許可するか、拒否するかになります。より詳細なアクセス許可が必要な場合は、簡易レスポンスを無効にし、IAM ポリシーが返されるようにします。

デフォルトでは、API Gateway は、オーソライザーを使用する API のすべてのルートに対して、キャッシュされたオーソライザーのレスポンスを使用します。ルートごとにレスポンスをキャッシュするには、オーソライザーの ID ソースに $context.routeKey を追加します。

Lambda オーソライザーの作成

Lambda オーソライザーを作成するときは、API Gateway で使用する Lambda 関数を指定します。関数のリソースポリシーまたは IAM ロールを使用して Lambda 関数を呼び出すには、API Gateway のアクセス許可を付与する必要があります。この例では、Lambda 関数を呼び出すアクセス許可を API Gateway に付与するように関数のリソースポリシーを更新します。

aws apigatewayv2 create-authorizer \ --api-id abcdef123 \ --authorizer-type REQUEST \ --identity-source '$request.header.Authorization' \ --name lambda-authorizer \ --authorizer-uri 'arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:my-function/invocations' \ --authorizer-payload-format-version '2.0' \ --enable-simple-responses

次のコマンドは、Lambda 関数を呼び出すためのアクセス許可を API Gateway に付与します。API Gateway に関数を呼び出すアクセス許可がない場合、クライアントは 500 Internal Server Error を受け取ります。

aws lambda add-permission \ --function-name my-authorizer-function \ --statement-id apigateway-invoke-permissions-abc123 \ --action lambda:InvokeFunction \ --principal apigateway.amazonaws.com \ --source-arn "arn:aws:execute-api:us-west-2:123456789012:api-id/authorizers/authorizer-id"

オーソライザーを作成し、呼び出すアクセス許可を API Gateway に付与したら、オーソライザーを使用するようにルートを更新します。

aws apigatewayv2 update-route \ --api-id abcdef123 \ --route-id acd123 \ --authorization-type CUSTOM \ --authorizer-id def123

Lambda オーソライザーのトラブルシューティング

API Gateway が Lambda オーソライザーを呼び出せない場合、または Lambda オーソライザーが無効な形式のレスポンスを返す場合、クライアントは 500 Internal Server Error を受け取ります。

エラーのトラブルシューティングを行うには、API ステージのアクセスログを有効にします。ログ形式に $context.authorizer.error ログ記録変数を含めます。

API Gateway に関数を呼び出すアクセス許可がないことがログに示されている場合は、関数のリソースポリシーを更新するか、IAM ロールを提供して API Gateway にオーソライザーを呼び出すアクセス許可を付与します。

Lambda 関数が無効なレスポンスを返すことがログに示されている場合は、Lambda 関数が必要な形式でレスポンスを返すことを確認してください。