API Gateway Lambda 권한 부여자 사용 - Amazon API Gateway

API Gateway Lambda 권한 부여자 사용

Lambda 권한 부여자(이전 사용자 지정 권한 부여자)를 사용하여 API에 대한 액세스를 제어할 수 있습니다. 클라이언트가 API의 메서드를 요청하면 API Gateway는 Lambda 권한 부여자를 직접적으로 호출합니다. Lambda 권한 부여자는 호출자의 자격 증명을 입력으로 사용하고 IAM 정책을 출력으로 반환합니다.

Lambda 권한 부여자를 사용하여 사용자 지정 권한 부여 체계를 구현할 수 있습니다. 이 체계는 요청 파라미터를 사용하여 호출자의 자격 증명을 확인하거나 OAuth 또는 SAML과 같은 보유자 토큰 인증 전략을 사용할 수 있습니다. AWS CLI 또는 AWS SDK를 사용하여 API Gateway REST API 콘솔에서 Lambda 권한 부여자를 생성합니다.

Lambda 권한 부여자 인증 워크플로

다음 다이어그램은 Lambda 권한 부여자에 대한 인증 워크플로를 보여줍니다.

API Gateway Lambda 권한 부여 워크플로
API Gateway Lambda 권한 부여 워크플로
  1. 클라이언트가 API Gateway API의 메서드를 직접적으로 호출하고 보유자 토큰 또는 요청 파라미터를 전달합니다.

  2. API Gateway는 메서드 요청에 Lambda 권한 부여자가 구성되어 있는지 확인합니다. 구성되어 있으면 API Gateway가 Lambda 함수를 호출합니다.

  3. Lambda 함수가 호출자를 인증합니다. 이 함수는 다음과 같은 방식으로 인증될 수 있습니다.

    • OAuth 공급자를 직접적으로 호출하여 OAuth 액세스 토큰을 받습니다.

    • SAML 공급자를 직접적으로 호출하여 SAML 어설션을 받습니다.

    • 요청 파라미터 값을 기반으로 IAM 정책을 생성합니다.

    • 데이터베이스에서 자격 증명을 가져옵니다.

  4. Lambda 함수가 IAM 정책과 보안 주체 식별자를 반환합니다. Lambda 함수가 해당 정보를 반환하지 않으면 직접 호출이 실패합니다.

  5. API Gateway가 IAM 정책을 평가합니다.

    • 액세스가 거부되면 API Gateway는 적절한 HTTP 상태 코드(예: 403 ACCESS_DENIED)를 반환합니다.

    • 액세스가 허용되면 API Gateway가 메서드를 간접 호출합니다.

      권한 부여 캐싱이 활성화된 경우, API Gateway는 Lambda 권한 부여자 함수가 다시 간접적으로 호출되지 않도록 정책을 캐싱합니다.

403 ACCESS_DENIED 또는 401 UNAUTHORIZED 게이트웨이 응답을 사용자 지정할 수 있습니다. 자세한 내용은 API Gateway의 REST API에 대한 게이트웨이 응답을 참조하십시오.

Lambda 권한 부여자 유형 선택

Lambda 권한 부여자는 두 가지 유형이 있습니다.

요청 파라미터 기반 Lambda 권한 부여자(REQUEST 권한 부여자)

REQUEST 권한 부여자는 헤더, 쿼리 문자열 파라미터, stageVariables, $context 변수 조합에 있는 호출자 자격 증명을 받습니다. REQUEST 권한 부여자를 사용하여 $context.path$context.httpMethod 컨텍스트 변수와 같은 여러 자격 증명 소스의 정보를 기반으로 세분화된 정책을 생성할 수 있습니다.

REQUEST 권한 부여자에 대한 권한 부여 캐싱을 켜면 API Gateway는 요청에 지정된 모든 자격 증명 소스가 있는지 확인합니다. 지정된 자격 증명 소스가 없거나, null이거나, 비어 있을 경우 API Gateway가 Lambda 권한 부여자 함수를 호출하지 않고 401 Unauthorized HTTP 응답을 반환합니다. 여러 개의 자격 증명 소스가 정의된 경우, 이들은 순서가 유지된 상태로 모두 권한 부여자의 캐시 키를 도출하는 데 사용됩니다. 여러 자격 증명 소스를 사용하여 세분화된 캐시 키를 정의할 수 있습니다.

캐시 키 부분을 변경하고 API를 재배포하면 권한 부여자가 캐시된 정책 문서를 폐기하고 새로 생성합니다.

REQUEST 권한 부여자에 대한 권한 부여 캐싱을 끄면 API Gateway가 요청을 Lambda 함수에 직접 전달합니다.

토큰 기반 Lambda 권한 부여자(TOKEN 권한 부여자)

TOKEN 권한 부여자는 보유자 토큰(JSON Web Token(JWT) 또는 OAuth 토큰)에 있는 호출자의 자격 증명을 받습니다.

TOKEN 권한 부여자에 대한 인증 캐싱을 켜는 경우 토큰 소스에 지정된 헤더 이름이 캐시 키가 됩니다.

또한 토큰 검증을 사용하여 정규 표현식 문을 입력할 수 있습니다. API Gateway는 이 표현식에 대해 입력 토큰의 초기 검증을 수행하고 검증에 성공할 경우 Lambda 권한 부여자 함수를 간접적으로 호출합니다. 이렇게 하면 API 호출을 줄일 수 있습니다.

IdentityValidationExpression 속성은 TOKEN 권한 부여자에만 지원됩니다. 자세한 내용은 x-amazon-apigateway-authorizer 객체 단원을 참조하십시오.

참고

REQUEST 권한 부여자를 사용하여 API에 대한 액세스를 제어하는 것이 좋습니다. TOKEN 권한 부여자를 사용할 때는 단일 자격 증명 소스를 기반으로 하지만 REQUEST 권한 부여자를 사용할 때는 여러 자격 증명 소스를 기반으로 하여 API에 대한 액세스를 제어할 수 있습니다. 또한 REQUEST 권한 부여자의 경우 여러 자격 증명 소스를 사용하여 캐시 키를 분리할 수 있습니다.

REQUEST 권한 부여자 Lambda 함수 예제

다음 예제 코드는 클라이언트가 제공한 HeaderAuth1 헤더, QueryString1 쿼리 파라미터 및 스테이지 변수 StageVar1이 모두 headerValue1, queryValue1, stageValue1의 지정된 값과 각각 일치하는 경우 요청을 허용하는 Lambda 권한 부여 함수를 생성합니다.

Node.js
// A simple request-based authorizer example to demonstrate how to use request // parameters to allow or deny a request. In this example, a request is // authorized if the client-supplied HeaderAuth1 header, QueryString1 // query parameter, and stage variable of StageVar1 all match // specified values of 'headerValue1', 'queryValue1', and 'stageValue1', // respectively. export const handler = function(event, context, callback) { console.log('Received event:', JSON.stringify(event, null, 2)); // Retrieve request parameters from the Lambda function input: var headers = event.headers; var queryStringParameters = event.queryStringParameters; var pathParameters = event.pathParameters; var stageVariables = event.stageVariables; // Parse the input for the parameter values var tmp = event.methodArn.split(':'); var apiGatewayArnTmp = tmp[5].split('/'); var awsAccountId = tmp[4]; var region = tmp[3]; var restApiId = apiGatewayArnTmp[0]; var stage = apiGatewayArnTmp[1]; var method = apiGatewayArnTmp[2]; var resource = '/'; // root resource if (apiGatewayArnTmp[3]) { resource += apiGatewayArnTmp[3]; } // Perform authorization to return the Allow policy for correct parameters and // the 'Unauthorized' error, otherwise. if (headers.HeaderAuth1 === "headerValue1" && queryStringParameters.QueryString1 === "queryValue1" && stageVariables.StageVar1 === "stageValue1") { callback(null, generateAllow('me', event.methodArn)); } else { callback("Unauthorized"); } } // Help function to generate an IAM policy var generatePolicy = function(principalId, effect, resource) { // Required output: var authResponse = {}; authResponse.principalId = principalId; if (effect && resource) { var policyDocument = {}; policyDocument.Version = '2012-10-17'; // default version policyDocument.Statement = []; var statementOne = {}; statementOne.Action = 'execute-api:Invoke'; // default action statementOne.Effect = effect; statementOne.Resource = resource; policyDocument.Statement[0] = statementOne; authResponse.policyDocument = policyDocument; } // Optional output with custom properties of the String, Number or Boolean type. authResponse.context = { "stringKey": "stringval", "numberKey": 123, "booleanKey": true }; return authResponse; } var generateAllow = function(principalId, resource) { return generatePolicy(principalId, 'Allow', resource); } var generateDeny = function(principalId, resource) { return generatePolicy(principalId, 'Deny', resource); }
Python
# A simple request-based authorizer example to demonstrate how to use request # parameters to allow or deny a request. In this example, a request is # authorized if the client-supplied headerauth1 header, QueryString1 # query parameter, and stage variable of StageVar1 all match # specified values of 'headerValue1', 'queryValue1', and 'stageValue1', # respectively. import json def lambda_handler(event, context): print(event) # Retrieve request parameters from the Lambda function input: headers = event['headers'] queryStringParameters = event['queryStringParameters'] pathParameters = event['pathParameters'] stageVariables = event['stageVariables'] # Parse the input for the parameter values tmp = event['methodArn'].split(':') apiGatewayArnTmp = tmp[5].split('/') awsAccountId = tmp[4] region = tmp[3] restApiId = apiGatewayArnTmp[0] stage = apiGatewayArnTmp[1] method = apiGatewayArnTmp[2] resource = '/' if (apiGatewayArnTmp[3]): resource += apiGatewayArnTmp[3] # Perform authorization to return the Allow policy for correct parameters # and the 'Unauthorized' error, otherwise. if (headers['HeaderAuth1'] == "headerValue1" and queryStringParameters['QueryString1'] == "queryValue1" and stageVariables['StageVar1'] == "stageValue1"): response = generateAllow('me', event['methodArn']) print('authorized') return response else: print('unauthorized') raise Exception('Unauthorized') # Return a 401 Unauthorized response # Help function to generate IAM policy def generatePolicy(principalId, effect, resource): authResponse = {} authResponse['principalId'] = principalId if (effect and resource): policyDocument = {} policyDocument['Version'] = '2012-10-17' policyDocument['Statement'] = [] statementOne = {} statementOne['Action'] = 'execute-api:Invoke' statementOne['Effect'] = effect statementOne['Resource'] = resource policyDocument['Statement'] = [statementOne] authResponse['policyDocument'] = policyDocument authResponse['context'] = { "stringKey": "stringval", "numberKey": 123, "booleanKey": True } return authResponse def generateAllow(principalId, resource): return generatePolicy(principalId, 'Allow', resource) def generateDeny(principalId, resource): return generatePolicy(principalId, 'Deny', resource)

이 예제에서 Lambda 권한 부여자 함수는 입력 파라미터를 확인하고 다음과 같이 동작합니다.

  • 필요한 모든 파라미터 값이 예상 값과 일치하면 권한 부여자 함수가 200 OK HTTP 응답 및 다음과 같은 IAM 정책을 반환하고 메서드 요청이 성공합니다.

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
  • 일치하지 않으면 권한 부여자 함수가 401 Unauthorized HTTP 응답을 반환하고 메서드 요청이 실패합니다.

Lambda 권한 부여자 함수는 IAM 정책을 반환하는 것 외에 호출자의 보안 주체 ID도 반환해야 합니다. 선택적으로 통합 백엔드로 전달될 수 있는 추가 정보를 포함하는 context 객체를 반환할 수 있습니다. 자세한 내용은 API Gateway Lambda 권한 부여자의 출력 단원을 참조하십시오.

프로덕션 코드에서는 권한 부여를 허용하기 전에 사용자를 인증해야 할 수 있습니다. 해당 공급자의 설명서에 나온 대로 인증 공급자를 직접적으로 호출하여 Lambda 함수에 인증 로직을 추가할 수 있습니다.

TOKEN 권한 부여자 Lambda 함수 예제

다음 예제 코드는 클라이언트 제공 토큰 값이 allow이면 호출자가 메서드를 간접적으로 호출하도록 허용하는 TOKEN Lambda 권한 부여자 함수를 생성합니다. 토큰 값이 deny이면 호출자가 요청을 간접적으로 호출할 수 없습니다. 토큰 값이 unauthorized 또는 빈 문자열인 경우 권한 부여자 함수는 401 UNAUTHORIZED 응답을 반환합니다.

Node.js
// A simple token-based authorizer example to demonstrate how to use an authorization token // to allow or deny a request. In this example, the caller named 'user' is allowed to invoke // a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke // the request if the token value is 'deny'. If the token value is 'unauthorized' or an empty // string, the authorizer function returns an HTTP 401 status code. For any other token value, // the authorizer returns an HTTP 500 status code. // Note that token values are case-sensitive. export const handler = function(event, context, callback) { var token = event.authorizationToken; switch (token) { case 'allow': callback(null, generatePolicy('user', 'Allow', event.methodArn)); break; case 'deny': callback(null, generatePolicy('user', 'Deny', event.methodArn)); break; case 'unauthorized': callback("Unauthorized"); // Return a 401 Unauthorized response break; default: callback("Error: Invalid token"); // Return a 500 Invalid token response } }; // Help function to generate an IAM policy var generatePolicy = function(principalId, effect, resource) { var authResponse = {}; authResponse.principalId = principalId; if (effect && resource) { var policyDocument = {}; policyDocument.Version = '2012-10-17'; policyDocument.Statement = []; var statementOne = {}; statementOne.Action = 'execute-api:Invoke'; statementOne.Effect = effect; statementOne.Resource = resource; policyDocument.Statement[0] = statementOne; authResponse.policyDocument = policyDocument; } // Optional output with custom properties of the String, Number or Boolean type. authResponse.context = { "stringKey": "stringval", "numberKey": 123, "booleanKey": true }; return authResponse; }
Python
# A simple token-based authorizer example to demonstrate how to use an authorization token # to allow or deny a request. In this example, the caller named 'user' is allowed to invoke # a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke # the request if the token value is 'deny'. If the token value is 'unauthorized' or an empty # string, the authorizer function returns an HTTP 401 status code. For any other token value, # the authorizer returns an HTTP 500 status code. # Note that token values are case-sensitive. import json def lambda_handler(event, context): token = event['authorizationToken'] if token == 'allow': print('authorized') response = generatePolicy('user', 'Allow', event['methodArn']) elif token == 'deny': print('unauthorized') response = generatePolicy('user', 'Deny', event['methodArn']) elif token == 'unauthorized': print('unauthorized') raise Exception('Unauthorized') # Return a 401 Unauthorized response return 'unauthorized' try: return json.loads(response) except BaseException: print('unauthorized') return 'unauthorized' # Return a 500 error def generatePolicy(principalId, effect, resource): authResponse = {} authResponse['principalId'] = principalId if (effect and resource): policyDocument = {} policyDocument['Version'] = '2012-10-17' policyDocument['Statement'] = [] statementOne = {} statementOne['Action'] = 'execute-api:Invoke' statementOne['Effect'] = effect statementOne['Resource'] = resource policyDocument['Statement'] = [statementOne] authResponse['policyDocument'] = policyDocument authResponse['context'] = { "stringKey": "stringval", "numberKey": 123, "booleanKey": True } authResponse_JSON = json.dumps(authResponse) return authResponse_JSON

이 예제에서는 API가 메서드 요청을 받을 때 API Gateway가 소스 토큰을 이 Lambda 권한 부여자 함수의 event.authorizationToken 속성에 전달합니다. Lambda 권한 부여자 함수는 토큰을 읽고 다음과 같이 동작합니다.

  • 토큰 값이 allow인 경우 권한 부여자 함수는 200 OK HTTP 응답 및 다음과 같은 IAM 정책을 반환하고 메서드 요청이 성공합니다.

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
  • 토큰 값이 deny인 경우 권한 부여자 함수는 200 OK HTTP 응답 및 다음과 같은 Deny IAM 정책을 반환하고 메서드 요청이 실패합니다.

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Deny", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
    참고

    테스트 환경 밖에서는 API Gateway가 403 Forbidden HTTP 응답을 반환하고 메서드 요청이 실패합니다.

  • 토큰 값이 unauthorized이나 빈 문자열인 경우 권한 부여자 함수는 401 Unauthorized HTTP 응답을 반환하고 메서드 호출이 실패합니다.

  • 그 외 토큰의 경우 클라이언트는 500 Invalid token 응답을 수신하고, 메서드 호출은 실패합니다.

Lambda 권한 부여자 함수는 IAM 정책을 반환하는 것 외에 호출자의 보안 주체 ID도 반환해야 합니다. 선택적으로 통합 백엔드로 전달될 수 있는 추가 정보를 포함하는 context 객체를 반환할 수 있습니다. 자세한 내용은 API Gateway Lambda 권한 부여자의 출력 단원을 참조하십시오.

프로덕션 코드에서는 권한 부여를 허용하기 전에 사용자를 인증해야 할 수 있습니다. 해당 공급자의 설명서에 나온 대로 인증 공급자를 직접적으로 호출하여 Lambda 함수에 인증 로직을 추가할 수 있습니다.

Lambda 권한 부여자 함수의 추가 예제

다음 목록은 Lambda 권한 부여자 함수의 추가 예제를 보여줍니다. API를 생성한 계정과 동일한 계정이나 다른 계정에서 Lambda 함수를 생성할 수 있습니다.

이전 Lambda 함수 예제는 다른 AWS 서비스를 직접적으로 호출하지 않으므로 기본으로 제공되는 AWSLambdaBasicExecutionRole을 사용할 수 있습니다. Lambda 함수가 다른 AWS 서비스를 호출한다면 Lambda 함수에 IAM 실행 역할을 할당해야 합니다. 역할을 생성하려면 AWS Lambda 실행 역할의 지침을 따르십시오.

Lambda 권한 부여자 함수의 추가 예제