AWS Lambda 권한 부여자를 사용하여 HTTP API에 대한 액세스 제어 - Amazon API Gateway

AWS Lambda 권한 부여자를 사용하여 HTTP API에 대한 액세스 제어

Lambda 권한 부여자를 사용하여 HTTP API에 대한 액세스를 제어하는 Lambda 함수를 사용합니다. 그런 다음 클라이언트가 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 함수에서 반환되어야 하는 응답 구조도 결정합니다.

형식 1.0에 대한 Lambda 함수 응답

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

형식 2.0에 대한 Lambda 함수 응답

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 Lamdba 함수는 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

자격 증명 원본

선택적으로 Lambda 권한 부여자에 대한 자격 증명 원본을 지정할 수 있습니다. 자격 증명 원본은 요청에 권한을 부여하는 데 필요한 데이터의 위치를 지정합니다. 예를 들어 헤더 또는 쿼리 문자열 값을 자격 증명 원본으로 지정할 수 있습니다. 자격 증명 원본을 지정하는 경우 클라이언트에서 해당 소스를 요청에 포함해야 합니다. 클라이언트의 요청에 자격 증명 원본이 포함되어 있지 않은 경우 API Gateway는 Lambda 권한 부여자를 호출하지 않으며 클라이언트가 401 오류를 수신합니다.

다음 표에서는 Lambda 권한 부여자에 대해 지원되는 자격 증명 소스를 설명합니다.

유형

참고

헤더 값 $request.header.name 헤더 이름은 대/소문자를 구분하지 않습니다.
쿼리 문자열 값 $request.querystring.name 쿼리 문자열 이름은 대/소문자를 구분합니다.
컨텍스트 변수 $context.variableName 지원되는 컨텍스트 변수의 값입니다.
단계 변수 $stageVariables.variableName 스테이지 변수의 값입니다.

권한 부여자 응답 캐싱

authorizerResultTtlInSeconds를 지정하여 Lambda 권한 부여자에 대한 캐싱을 활성화할 수 있습니다. 권한 부여자에 대해 캐싱이 활성화되면 API Gateway에서 권한 부여자의 자격 증명 원본을 캐시 키로 사용합니다. 클라이언트가 구성된 TTL 내의 자격 증명 원본에서 동일한 파라미터를 지정하는 경우 API Gateway에서 Lambda 함수를 호출하는 대신 캐싱된 권한 부여자 결과를 사용합니다.

캐싱을 활성화하려면 권한 부여자에게 자격 증명 원본이 하나 이상 있어야 합니다.

권한 부여자에 대해 간단한 응답을 활성화하면 권한 부여자의 응답이 캐싱된 자격 증명 원본 값과 일치하는 모든 API 요청을 완전히 허용하거나 거부합니다. 보다 세분화된 권한이 필요한 경우 간단한 응답을 비활성화하고 IAM 정책을 반환합니다.

기본적으로 API Gateway에서는 권한 부여자를 사용하는 API의 모든 라우팅에 캐싱된 권한 부여자 응답을 사용합니다. 라우팅별로 응답을 캐싱하려면 권한 부여자의 자격 증명 원본에 $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가 함수를 호출할 권한이 없다고 표시되면 함수의 리소스 정책을 업데이트하거나 권한 부여자를 호출할 수 있는 권한을 API Gateway에 부여하는 IAM 역할을 제공합니다.

로그에 Lambda 함수가 잘못된 응답을 반환한다고 표시되면 Lambda 함수가 필요한 형식으로 응답을 반환하는지 확인합니다.