HTTPAPIs透過 AWS Lambda 授權者控制存取 - Amazon API Gateway

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

HTTPAPIs透過 AWS Lambda 授權者控制存取

您可以使用 Lambda 授權器來使用 Lambda 函數來控制您的 HTTPAPI. 然後,當用戶端呼叫您的時候API,API閘道會叫用您的 Lambda 函數。API閘道會使用 Lambda 函數的回應來判斷用戶端是否可以存取您的API.

裝載格式版本

授權者承載資料格式版本可指定API閘道傳送給 Lambda 授權者的資料格式,以及API閘道如何解譯 Lambda 的回應。如果您未指定承載格式版本,預設 AWS Management Console 會使用最新版本。如果您使用 AWS CLI、 AWS CloudFormation或建立 Lambda 授權者SDK,則必須指定authorizerPayloadFormatVersion. 支援的值為 1.02.0

如果您需要兼容性 RESTAPIs,請使用版本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 函數必須傳回的回應結構。

格式 1.0 的 Lambda 函數回應

如果您選擇1.0格式版本,Lambda 授權者必須傳回允許或拒絕存取您API路由的IAM政策。您可以在IAM策略中使用標準策略語法。如需 IAM 政策範例,請參閱控制調用的訪問 API。您可以使用 $context.authorizer.property 將內容屬性傳遞給 Lambda 整合或存取日誌。context 物件為選擇性,claims是保留的預留位置,不能用作內容物件。如需進一步了解,請參閱自訂HTTPAPI存取記錄

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

格式 2.0 的 Lambda 函數回應

如果您選擇2.0格式版本,IAM則可以從 Lambda 函數傳回布林值或使用標準IAM原則語法的政策。要傳回一個布林值,請啟用授權方的簡易回應。下列範例會示範您必須編碼 Lambda 函數才能傳回的格式。該 context 物件是選用的物件。您可以使用 $context.authorizer.property 將內容屬性傳遞給 Lambda 整合或存取日誌。如需進一步了解,請參閱自訂HTTPAPI存取記錄

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 函數會示範您需要從 Lambda 函數傳回的 2.0 承載格式版本的必要回應格式。

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

身分識別來源

您可以選擇性地指定 Lambda 授權方的身分來源。身分來源會指定授權請求所需的資料位置。例如,您可以指定標頭或查詢字串值做為身分來源。如果您指定身分來源,用戶端必須將其包含在請求中。如果用戶端的要求不包含身分識別來源,APIGateway 不會叫用您的 Lambda 授權者,且用戶端會收到401錯誤訊息。

下表說明 Lambda 授權者支援的身分識別來源。

類型

範例

備註

標頭值 $ 請求. 頭。name 網域名稱需區分大小寫。
查詢字串值 $ 請求. 查詢字符串。name 查詢字串名稱區分大小寫。
環境變數 $ 上下文。variableName 支援的內容變數值。
階段變數 $stageVariables.variableName 階段變數的值。

快取授權方回應

您可以 Lambda 過指定 authorizerResultTtlInSeconds. 啟用授權者的快取時,APIGateway 會使用授權者的身分識別來源作為快取金鑰。如果用戶端在已設定的身分識別來源中指定相同的參數TTL,APIGateway 會使用快取的授權程式結果,而不是叫用 Lambda 函數。

若要啟用快取,您的授權方必須至少有一個身分來源。

如果您為授權者啟用簡單回應,則授權者的回應會完全允許或拒絕符合快取身分識別來源值的所有API要求。如需更精細的權限,請停用簡單回應並傳回IAM原則。

根據預設,APIGateway 會針對使用授權者的所有路由使用快取API的授權者回應。若要快取每個路由的回應,請新增 $context.routeKey 至授權方的身分來源。

建立 Lambda 授權方

建立 Lambda 授權者時,您可以指定要使用的API閘道器的 Lambda 函數。您必須使用函數的資源政策或IAM角色授與API閘道權限,才能叫用 Lambda 函數。在此範例中,我們更新函數的資源政策,以便它授與API閘道呼叫 Lambda 函數的權限。

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

下列命令授與API閘道權限來叫用您的 Lambda 函數。如果 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閘道無法呼叫 Lambda 授權者,或您的 Lambda 授權者傳回無效格式的回應,用戶端會收到. 500 Internal Server Error

若要疑難排解錯誤,請為您的API階段啟用存取記錄。在 $context.authorizer.error 記錄格式中包含日誌變數。

如果日誌指出 API Gateway 沒有調用您的函數的權限,請更新函數的資源策略或提供IAM角色以授予 API Gateway 調用您的授權者的權限。

如果日誌指出您的 Lambda 函數傳回無效的回應,請確認 Lambda 函數傳回所需格式的回應。