Dev/AWS

AWS Lambda 사용 시 Cognito 를 활용한 인증 인가 구현

싯벨트 2023. 6. 3. 17:55
728x90

개요

AWS Cognito란 인증, 인가(권한 부여) 및 사용자 관리를 제공하는 서비스입니다.

이번 글에서는 다음 3가지 방법론을 샘플 코드 혹은 콘솔 화면과 함께 다뤄볼 것입니다.

1) Cognito UserPool 설정

2) Cognito UserPool 에서 사용자 생성 및 토큰 발급 

2) AWS Sam Template에서 권한 부여자 적용 

Cognito UserPool 설정

1. 코그니토 콘솔에 로그인 하고, <사용자 풀 생성>을 클릭합니다.

2. Cognito 사용자 풀 로그인 옵션은 이메일로 설정해줍니다.

3. 암호 정책은 디폴트로 대문자가 포함되어 있지만, <사용자 지정>을 통해 커스텀 가능합니다. 

4. 멀티팩터 인증은 하지 않고, 이메일 확인을 체크했습니다. 

5. 사용자 지정 속성으로 approved를 추가했습니다. Gateway 수준에서 인가를 할 때, 사용할 속성입니다. 

사용자 지정 속성의 경우는 유형으로 string, number 두 가지 타입만 존재하기 때문에 Boolean을 값으로 사용하고 싶더라도 string 타입 설정 및 추후 토큰 내부 속성 검증 시에도 string으로 비교를 해주어야 합니다.

6. Cognito를 사용하여 이메일 전송을 선택하면 유저풀에 가입 시, AWS 자체적인 폼으로 이메일 인증을 진행해줍니다.

AWS SES를 선택하면 커스텀 한 이메일을 보낼 수 있으며, 앱 인증을 받기 전에는 sendBox에 등록된 이메일 사이서만 테스트를 진행할 수 있습니다. 더불어, 인증을 위한 랜덤 코드 생성, 코드의 검증 등을 redis 등을 통해 구현해야 하므로.. 편하게 사용하시려면 cognito에서 제공하는 이메일 검증을 사용하길 권장합니다. 

7. <Cognito 호스팅 UI 사용>을 선택하고 도메인을 입력해줍니다. 추후 토큰을 요청하는 uri로 사용됩니다.

8. 앱 클라이언트 이름 설정 및 콜백 uri를 http://localhost:3000 로 설정합니다.

추후 토큰을 요청할 때 콜백 uri 도 입력해야 하는데, https / http 를 헷갈리지 않게 합니다.

9. 인증 흐름에 ALLOW_CUSTOM_AUTH를 추가하고 나머지는 디폴트 값으로 구성합니다.

더불어, OpenID Connect 범위에 <profile>을 추가해야 위에서 설정한 approved 와 같은 사용자 지정 속성을 토큰 정보에 넣을 수 있습니다.

10. 완성하면 다음과 같이 유저풀이 생성됩니다.

 

사용자 생성 및 토큰 발급

1. 앱통합에 들어가서 맨 아래 앱 클라이언트를 클릭합니다. <호스팅 UI 보기> 를 클릭하여 회원가입을 진행하면,
이메일로 인증번호가 전송되고, 해당 번호를 입력하여 인증을 완료하면 사용자 생성이 완료됩니다.

2. 사용자 생성과 동일하게 <호스팅 UI 보기> 에서 signin을 진행하면 브라우저에 유저풀을 만들었을 때 설정한 uri
(http://localhost:3000)로 code가 쿼리파라미터로 전달됩니다.

3. 해당 코드를 https://test-user-pool.auth.ap-northeast-2.amazoncognito.com/oauth2/token uri 에 아래 4가지 쿼리파라미터 중 code 에 기입하고 Post 요청을 해줍니다.

그러면 응답값으로 id_token / access_token / refresh_token 이 리턴되며, 이후 예시 코드에서는 id_token을 사용할 것입니다. 

grant_type: authorization_code
redirect_uri: http://localhost:3000 (설정한 리다이렉트 uri)
client_id: 생성한 앱 클라이언트의 ID
code: 1번에서 쿼리파라미터로 받은 code

코드 살펴보기

👉 AWS Cognito Authorizer 깃헙 코드

전체 코드는 깃헙 레포를 살펴보시기 바라며, 해당 글에서는 중요한 부분들만 다뤄보도록 하겠습니다.

1. API Gateway 전체에 디폴트 권한 부여자 설정하기

1) LambdaTokenAuthorizer는 동일한 템플릿 파일에서 test-authorizer 라는 함수명을 가진 람다 함수입니다. 해당 함수를 !Sub 를 통해 참조하려면 함수가 먼저 형성되어 있어야 하므로, 처음 배포 시 (sam deploy 명령어 실행) LambdaTokenAuthorizer 및 DefaultAuthorizer를 주석 처리한 뒤, 다시 배포를 진행해주시기 바랍니다. 

2) 또한 authorizer를 NONE으로 설정한 get-public-info의 경우, DefaultAuthorizer 존재를 전제하기 때문에 Authorizer: NONE 코드 또한 첫 번째 배포에서는 주석처리 해주시면 됩니다.

  Auth:
    Authorizers:
      TestUserAuth:
        UserPoolArn: !Sub arn:aws:cognito-idp:${AWS::Region}:${AWS::AccountId}:userpool/${TestUserPoolId}
      LambdaTokenAuthorizer:
        FunctionArn: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:test-authorizer
    DefaultAuthorizer: LambdaTokenAuthorizer

2. samconfig.toml을 통한 환경변수 설정

s3 버킷을 형성한 뒤, 배포에서 사용될 환경변수들을 아래와 같이 작성해줍니다.

version = 0.1
[my]
[my.deploy]
[my.deploy.parameters]
profile = "my"
stack_name = "test-cognito"
region = "ap-northeast-2"
capabilities = "CAPABILITY_IAM"
parameter_overrides = "TestUserPoolId=YourUserPoolId"
s3_bucket = "YourS3BucketName"
image_repositories = []

3. 람다 권한 부여자 핸들러

👉 람다 권한 부여자 공식문서

앱클라이언트 사용자 지정 속성으로 만들었던 approved 는 코그니토의 디폴트 속성이 아니므로, custom: 이라는 접두사가 붙은 형태가 되어 id_token에 반영됩니다. 하여, 해당 속성값이 "true"인 유저들에게만 api 호출을 허용하는 핸들러를 구성하여 API Gateway의 디폴트 권한 부여자로 적용했습니다.

 

4. 요청 결과

userPool에 있는 사용자의 id_token을 헤더에 넣고 api를 호출한 결과는 다음과 같습니다.

1) get-method (userPool 존재 여부를 체크를 통한 인가)

2) get-public-info (권한 부여자 적용 안 함)

3) post-method (디폴트 권한 부여자로, 커스텀 속성 체크)