Don’t Repeat Yourself / Don’t reinvent the wheel

있는 것 갖다 쓰고, 네가 만들지 마라

소프트웨어 개발 원칙 중에 “반복을 피하라”는 항목이 있습니다.

개발자에게 있어서 프로그래밍 능력도 중요하지만, 이미 만들어진 것을 잘 활용하는 능력 또한 효율성의 측면에서 아주 중요합니다.

내가 지금 만들어서 쓴다고 해도, 이미 만들어져서 여러 사람의 지식과 수고를 흡수해서 발전해온 것보다 품질이 좋을 가능성이 낮기 때문입니다. (예외도 있지만 대개는 그렇습니다)

그럼에도 불구하고 우리가 지금까지 무심하게 반복 개발해 왔던 부분이 있었습니다.

바로 인증권한 관리인데요.

사용자 정보, 로그인, 권한 관리 부분을 프로젝트마다 개발하는 등, 고전적인 자체 개발의 관행을 이어왔습니다.

21세기에는 이렇게 개발하면 안 된다는 기술적 죄책감이 점점 들었습니다. 😞

그러면 자체 개발하지 않고 갖다 쓰는 어떤 좋은 방법이 있을까요?

IDaaS

바야흐로 클라우드 시대가 도래하면서 XaaS, YaaS 하는 식으로 이름 붙은 클라우드 기반 서비스가 등장하기 시작했습니다.

그중에 IDaaS가 있는데, Identity as a Service 즉 갖다 쓰는 인증 서비스입니다.

기본적인 패스워드 기반 로그인부터 OAuth, Open ID, MFA, 연합 인증, 회원 가입, 가입 승인, 권한 관리, 보안 기능 등을 미리 갖춘 인증 서비스입니다.

처음부터 이걸 다 개발하려면 엄두가 나질 않는데, 이렇게 갖춰진 서비스가 있으니 잘 활용해야겠습니다.

무스마에서는 AWS 환경에서 서비스를 하고 있어서, AWS에서 제공하는 Cognito를 사용하려고 합니다.

그럼 Amazon Cognito에 대해서 알아보겠습니다.

Amazon Cognito

Cognito는 라틴어로 ‘인식’ 이라는 뜻입니다. 우리가 잘 아는 영어 단어 ‘cognition’, ‘recognize’에 들어있는 어근 ‘cogni’가 여기서 유래했습니다.

인증 서비스에 걸맞는 이름이네요.

실습 목표

직접 실습을 해보겠습니다.

목표는 다음과 같습니다.

  1. 사용자 풀 생성
  2. 회원가입
  3. 로그인
  4. 인증시 발급된 토큰으로 AWS API Gateway 호출

실습 #1: 사용자 풀 생성

image

사용자 풀 관리 클릭


사용자 풀 생성

image

사용자 풀 생성 클릭


사용자 풀 생성 > 이름

image

사용자 풀 이름을 쓰고, 설정을 순서대로 진행 클릭

무슨 설정이 있는지 하나하나 검토해보겠습니다.


사용자 풀 생성 > 속성

image

사용자 이름(username)으로 로그인, 이메일 주소로 로그인 허용

우리 서비스에서는 이메일 주소를 username으로 사용하니까, 이메일 주소로 로그인을 사용하겠습니다.


image

가입할 때 어떤 속성을 입력해야 하는가를 설정합니다. 사용자를 귀찮게 하지말고, 간단하게 이메일만 요구하겠습니다. 사용자 지정 속성도 생략하겠습니다.

다음 단계 클릭


사용자 풀 생성 > 정책

image

암호의 강도를 정합니다. 기본값을 사용하겠습니다. 사용자가 직접 회원가입을 할 수 있도록 합니다.

다음 단계 클릭


사용자 풀 생성 > MFA 및 확인

image

  • 멀티 팩터 인증 활성

    해제

    SMS나 이메일로 보안코드를 받아서 인증하는 추가 인증을 사용할지를 설정합니다. 일단 사용하지 않겠습니다.

  • 확인 수단

    이메일

    이메일을 통해 가입 확인, 비밀번호 재설정을 하도록 설정하겠습니다.

다음 단계 클릭


사용자 풀 생성 > 메시지 사용자 지정

image

Cognito를 설정하는데 갑자기 SES가 나옵니다. 대한민국 1세대 걸그룹

뭔지 모르므로 그냥 패스하겠습니다.

다음 단계 클릭


사용자 풀 생성 > 태그

image

패스합니다.

다음 단계 클릭


사용자 풀 생성 > 디바이스

image

접속한 기기와 위치, 운영체제를 기억하는 기능입니다. “언제 누가 이걸로 접속했는데, 본인이 맞으신가요?” 확인할 때 사용하는 기능입니다. 여기서는 사용하지 않겠습니다.

다음 단계 클릭


사용자 풀 생성 > 앱 클라이언트

image

나중에 넣어야겠지만, 지금은 만들어진 것이 없으니 패스합니다.

다음 단계 클릭


사용자 풀 생성 > 트리거

image

사용자의 회원가입이나 인증시 호출(트리거)되는 람다 함수를 지정합니다. 이 부분은 고급 기능인데다, 아직 만들어둔 람다 함수도 없으니 그냥 패스합니다.

다음 단계 클릭


사용자 풀 생성 > 검토

image

지금까지 설정한 내용을 검토합니다. 대개 기본값을 그대로 사용했습니다.

풀 생성 클릭


사용자 풀 생성 > 생성 완료

image

사용자 풀을 생성했습니다. 사용자 풀을 생성하는 것은 어렵지 않았습니다.

아! 이렇게 하는 거군요.



실습 #1-1: 사용자 풀 생성 (CLI로 생성하기)

이번엔 같은 걸 AWS CLI로도 해보겠습니다.


CLI로 사용자 풀 생성하기 > 샘플 json 파일 생성

CLI 파라미터로 전달하는 것 보다 JSON으로 설정 파일을 작성해서 파일을 전달하는 것이 편리합니다.

$ aws cognito-idp create-user-pool --generate-cli-skeleton > example.json

해설: cognito-idp 서비스의 create-user-pool 커맨드를 실행합니다.


CLI로 사용자 풀 생성하기 > json 파일 내용

--generate-cli-skeleton 옵션으로 생성한 직후의 파일 내용입니다.

{
  "PoolName": "",
  "Policies": {
    "PasswordPolicy": {
      "MinimumLength": 0,
      "RequireUppercase": true,
      "RequireLowercase": true,
      "RequireNumbers": true,
      "RequireSymbols": true
    }
  },
  "LambdaConfig": {
    "PreSignUp": "",
    "CustomMessage": "",
    "PostConfirmation": "",
    "PreAuthentication": "",
    "PostAuthentication": "",
    "DefineAuthChallenge": "",
    "CreateAuthChallenge": "",
    "VerifyAuthChallengeResponse": "",
    "PreTokenGeneration": "",
    "UserMigration": ""
  },
  "AutoVerifiedAttributes": ["email"],
  "AliasAttributes": ["preferred_username"],
  "UsernameAttributes": ["email"],
  "SmsVerificationMessage": "",
  "EmailVerificationMessage": "",
  "EmailVerificationSubject": "",
  "VerificationMessageTemplate": {
    "SmsMessage": "",
    "EmailMessage": "",
    "EmailSubject": "",
    "EmailMessageByLink": "",
    "EmailSubjectByLink": "",
    "DefaultEmailOption": "CONFIRM_WITH_CODE"
  },
  "SmsAuthenticationMessage": "",
  "MfaConfiguration": "OPTIONAL",
  "DeviceConfiguration": {
    "ChallengeRequiredOnNewDevice": true,
    "DeviceOnlyRememberedOnUserPrompt": true
  },
  "EmailConfiguration": {
    "SourceArn": "",
    "ReplyToEmailAddress": ""
  },
  "SmsConfiguration": {
    "SnsCallerArn": "",
    "ExternalId": ""
  },
  "UserPoolTags": {
    "KeyName": ""
  },
  "AdminCreateUserConfig": {
    "AllowAdminCreateUserOnly": true,
    "UnusedAccountValidityDays": 0,
    "InviteMessageTemplate": {
      "SMSMessage": "",
      "EmailMessage": "",
      "EmailSubject": ""
    }
  },
  "Schema": [
    {
      "Name": "",
      "AttributeDataType": "String",
      "DeveloperOnlyAttribute": true,
      "Mutable": true,
      "Required": true,
      "NumberAttributeConstraints": {
        "MinValue": "",
        "MaxValue": ""
      },
      "StringAttributeConstraints": {
        "MinLength": "",
        "MaxLength": ""
      }
    }
  ],
  "UserPoolAddOns": {
    "AdvancedSecurityMode": "AUDIT"
  }
}

값을 어떻게 채워야 하는지 난감합니다. create-user-pool 문서를 참조해서 작성해야 합니다.


CLI로 사용자 풀 생성하기 > json 파일 내용 작성

GUI 콘솔에서 만들었던 설정을 그대로 적용하면 아래와 같습니다. (필요 없는 속성은 거두절미)

{
  "PoolName": "musma",
  "Policies": {
    "PasswordPolicy": {
      "MinimumLength": 8,
      "RequireUppercase": true,
      "RequireLowercase": true,
      "RequireNumbers": true,
      "RequireSymbols": true
    }
  },
  "AutoVerifiedAttributes": ["email"],
  "AliasAttributes": ["email"],
  "UsernameAttributes": ["email"],
  "MfaConfiguration": "OFF",
  "AdminCreateUserConfig": {
    "AllowAdminCreateUserOnly": false,
    "UnusedAccountValidityDays": 7
  }
}


CLI로 사용자 풀 생성하기 > 생성

$ aws cognito-idp create-user-pool --cli-input-json file://example.json

주의: 파일 이름 앞에 file://를 붙여야합니다.

AWS CLI 사용자가 Amazon Cognito에서 User Pool을 생성할 권한을 갖고 있어야 합니다.

생성에 성공하면 결과가 출력됩니다.

{
    "UserPool": {
        "Id": "ap-northeast-2_XyXyXyXy",
        "Name": "musma",
        "Policies": {
          ...
        },
        ...
    }
}

이상 CLI를 사용해서 사용자 풀을 생성해보았습니다.



실습 #1-2: 사용자 풀 생성 (Terraform으로 생성하기)

이번에도 같은 걸 Terraform으로도 해보겠습니다.

왜 Terraform 인가?

이것만으로도 꽤 큰 주제가 되기 때문에 길게 말씀드리지 않겠습니다.

단적으로 관리 효율성 측면을 따지자면, 제 주관적인 생각으로는 다음과 같은 순서가 매겨집니다.

AWS 관리 콘솔(GUI) < AWS CLI < AWS CloudFormation << HashiCorp Terraform

일단 CloudFormation 미만으로는 설정을 재활용 할 수 없습니다. (명령형, 단발성)

개발자는 코드를 좋아합니다. 코드로 인프라를 관리할 수 있고, 또 선언적으로 관리할 수 있다는 장점이 있습니다.

심지어 Terraform 홈페이지의 Document가 AWS Document 보다 더 친절합니다.

Terraform으로 사용함으로써 Infrastructure As CodeImmutable Infrastructure를 달성할 수 있습니다.

테라폼 설정 파일(*.tf)은 VSCode에서 지원합니다.


Terraform으로 사용자 풀 생성하기 > cognito-idp.tf 파일 내용 작성

  • Terraform: aws_cognito_user_pool

  • main.tf

    provider "aws" {
      region = "ap-northeast-2"
    }
    
  • cognito-idp.tf

    resource "aws_cognito_user_pool" "pool" {
      alias_attributes        = ["email"]
      auto_verified_attributes = ["email"]
      mfa_configuration        = "OFF"
      name                    = "musma"
      password_policy {
        minimum_length    = 8
        require_lowercase = true
        require_numbers   = true
        require_symbols   = true
        require_uppercase = true
      }
    }
    

Terraform으로 사용자 풀 생성하기 > terraform plan

설정을 적용해서 사용자 풀을 생성하기 전에, 테라폼이 어떤 변경을 일으키는지 미리 검사합니다.

$ terraform plan

...

Plan: 1 to add, 0 to change, 0 to destroy.

Terraform으로 사용자 풀 생성하기 > terraform apply

이제 설정을 적용해서 사용자 풀을 생성합니다.

$ terraform apply

...

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

나중에 설정을 변경하고 싶으면 cognito-idp.tf 파일을 수정해서 다시 적용하면 됩니다.

AWS CLI와 다른 점은, create-user-pool 커맨드로는 생성 밖에 할 수 없었지만, 테라폼 설정 파일은 생성, 변경, 삭제 등 해당 인프라의 라이프사이클 동안 연동됩니다.


다음 편에 계속됩니다

시작이 반입니다

Amazon Cognito를 소개하고, 실습을 통해 사용자 풀을 생성해보았습니다.

설정한 내용을 통해서 Amazon Cognito 사용자 풀의 기능을 짐작해볼 수 있었습니다.

분량이 많아서 나머지 실습은 다음 편에 포스팅하도록 하겠습니다.

  • 실습 목표
    1. 사용자 풀 생성 ✔️️
    2. 회원가입
    3. 로그인
    4. 인증시 발급된 토큰으로 AWS API Gateway 호출

다음 실습을 통해서 본격적으로 Amazon Cognito의 기능을 알아보도록 하겠습니다.

감사합니다.


References