티스토리 뷰

반응형


API에 대한 액세스 권한을 제어하는데 Lambda 함수를 사용한다.
권한 부여자는 OAuth나 SAML 같은 보유자 토큰 인증 전략을 사용할 수 있고 헤더, 경로, 쿼리문자열, 단계 변수 또는 컨텍스트 변수 요청 파라미터 정보를 활용하여 인증을 할 수 있다.
*SAML : https://ko.wikipedia.org/wiki/SAML


간단히 요약하자면 Lambda로 권한 부여하기 위한 방법은 아래와 같이 두가지로 나눌 수 있다.
1. TOKEN을 사용하여 권한 부여
2. 헤더, 쿼리 문자열, 단계 변수, 컨텍스트 변수 같은 요청 파라미터를 사용하여 권한 부여



[API와 Lambda 연결하는 방법]


1. API Gateway 콘솔로 이동후 API를 선택하고 "권한 부여자"를 선택한다.
2. "+새로운 권한 부여자 생성" 클릭
3. 권한 부여자 생성 입력값
- 이름 : 권한 부여자 이름 입력
- 유형 : Lambda 선택
- Lambda : 권한 부여 로직이 구현된 Lambda 선택 (Lambda관련 내용을 아래 참고)
- Lambda 호출 역할
1> 비워둘 경우 : 리소스 기반 정책을 설정한다는 의미이다. Lambda함수를 호출할 수 있는 권한을 API Gateway에 부여함.

2> IAM 역할 이름 입력 가능
- Lambda 이벤트 페이로드 : TOKEN과 REQUEST중 선택
<TOKEN 선택시>
- 토큰 원본 : 헤더 이름 입력
- 토큰 확인 : 정규식 표현 입력 (정규식에 맞지 않을 경우 Lambda함수로도 가지 않고 실패 처리함)
<REQUEST 선택시>
- 자격 증명 원본 : 선택한 파라미터 유형의 요청 파라미터 이름 입력
- 권한 부여 캐싱 : 권한 부여 내용에 대한 캐싱 기능 사용 여부 입력
- TTL : 캐싱 유효 시간
(캐싱 기능을 사용하게 되면 TTL에 설정된 시간동안 토큰 또는 자격 증명 원본 요청 파라미터와 권한 정책값을 연결하여 캐시함.)
[단, 캐싱을 활성화하려면 권한 부여자가 API 전체의 모든 메서드에 적용 가능한 정책을 반환해야 한다. 메서드별로 정책을 적용하기 위해서는 TTL 값을 0으로 설정해 API 정책 캐싱을 비활성화해서 사용해야 한다.]




[권한 부여자 Lambda 함수에 대해 알아보자]

1. Lambda 함수 입력값 구조

- TOKEN
{
"type":"TOKEN",
"authorizationToken":"allow",
"methodArn":"arn:aws:execute-api:us-west-2:123456789012:ymy8tbxw7b/*/GET/"
}

- REQUEST
{
"type": "REQUEST",
"methodArn": "arn:aws:execute-api:us-east-1:123456789012:s4x3opwd6i/test/GET/request",
"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": "...",
"X-Forwarded-Proto": "https",
"CloudFront-Is-SmartTV-Viewer": "false",
"Host": "....execute-api.us-east-1.amazonaws.com",
"Accept-Encoding": "gzip, deflate",
"X-Forwarded-Port": "443",
"X-Amzn-Trace-Id": "...",
"Via": "...cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "...",
"X-Forwarded-For": "..., ...",
"Postman-Token": "...",
"cache-control": "no-cache",
"CloudFront-Is-Desktop-Viewer": "true",
"Content-Type": "application/x-www-form-urlencoded"
},
"queryStringParameters": {
"QueryString1": "queryValue1"
},
"pathParameters": {},
"stageVariables": {
"StageVar1": "stageValue1"
},
"requestContext": {
"path": "/request",
"accountId": "123456789012",
"resourceId": "05c7jb",
"stage": "test",
"requestId": "...",
"identity": {
"apiKey": "...",
"sourceIp": "..."
},
"resourcePath": "/request",
"httpMethod": "GET",
"apiId": "s4x3opwd6i"
}
}

2. Lambda 함수 출력값 구조

{
  "principalId": "yyyyyyyy", // 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}:{appId}/{stage}/{httpVerb}/[{resource}/[child-resources]]"
}
]
},
"context": {
"stringKey": "value",
"numberKey": "1",
"booleanKey": "true"
},
"usageIdentifierKey": "{api-key}"
}


[샘플 코드 (node.js)]

1. TOKEN 일때

// A simple TOKEN 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', the function
// returns the 'Unauthorized' error with an HTTP status code of 401. For any other token value,
// the authorizer returns an 'Invalid token' error.

exports.handler = function(event, context, callback) {
var token = event.authorizationToken;
switch (token.toLowerCase()) {
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");
}
};

// 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;

}


2. REQUEST 일때

exports.handler = function(event, context, callback) {
console.log('Received event:', JSON.stringify(event, null, 2));

// A simple REQUEST 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,
// stage variable of StageVar1 and the accountId in the request context all match
// specified values of 'headerValue1', 'queryValue1', 'stageValue1', and
// '123456789012', respectively.

// Retrieve request parameters from the Lambda function input:
var headers = event.headers;
var queryStringParameters = event.queryStringParameters;
var pathParameters = event.pathParameters;
var stageVariables = event.stageVariables;
var requestContext = event.requestContext;

// 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.
var authResponse = {};
var condition = {};
condition.IpAddress = {};

if (headers.HeaderAuth1 === "headerValue1"
&& queryStringParameters.QueryString1 === "queryValue1"
&& stageVariables.StageVar1 === "stageValue1"
&& requestContext.accountId === "123456789012") {
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);
}

Lambda로 권한 부여자를 사용하기 위해서는 Token발급과 사용자 관리는 별도로 개발을 해야 한다. 여기서 권한 부여 행위를 하는 Lambda 함수는 Token이 발행된 이후의 로직만을 담당한다.
[참고 자료:https://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html ]

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함