마이크로서비스 구조(MSA)의 인증 및 인가(Authorization & Authentication)

SangminKim
Spoon Radio
Published in
8 min readDec 3, 2020

마이크로서비스 구조(MSA)는 하나의 큰 서비스(Monolithic Service)를 작은 기능 단위의 서비스로 분리함을 뜻한다. 분리된 서비스들은 필요에 따라 서로 통신하며 데이터를 주고받고 서로 의존성을 갖게 된다. 서비스 간 의존성이 생긴다는 것은 서비스 간 관계에서 발생할 수 있는 여러 변수를 고려해야 한다는 뜻이며 이로 인해 전체 구현 및 관리의 복잡도가 가중될 수 있다.

서비스 간 관계의 변수란 장애전파, 데이터 신뢰성 보장 등을 포함한 다양한 상황이 될 수 있다. 이러한 변수 관리를 위해 이미 정의된 많은 MSA 패턴들이 존재하지만, 이들을 구성하는 것도 쉽지만은 않다.

인증 및 인가 (이하 인증이라고 한다.)는 서비스 전체에 걸처 필요한 공통된 기능이다. 모든 서비스들은 요청된 명령을 처리하기 위해 해당 요청의 사용자(Client) 인증이 필요하며 이로 인해 인증 서비스와 강한 의존성을 갖게 된다. 인증에는 다양한 방법이 있을 수 있지만 이번 포스팅에서는 토큰 기반의 인증에 대해서 이야기해보자.

토큰 기반 인증 절차

  1. 서비스 사용자는 자신의 신원을 증명하기 위해서 인증 서비스로부터 토큰을 발급받는다.
  2. 사용자는 발급받은 토큰을 서비스 요청 명령에 첨부하여 서비스에게 전달한다.
  3. 명령을 수신한 서비스는 첨부된 토큰을 확인하여 인증 절차를 수행하고 사용자 인증 정보를 확인한다.

토큰 기반의 인증 방식은 크게 위에 절차를 따른다. 이 절차는 토큰의 종류와 처리방식에 따라 인증 서비스와 다른 서비스 간의 의존성 정도에도 큰 차이가 나타날 수 있다. 몇 가지 토큰과 다른 처리 방식을 알아보고 의존성에 어떠한 변화가 있는지 살펴보자.

`사용자 인증 정보`는 인증을 통해 얻을 수 있는 사용자 정보로 단순 사용자 ID 부터 권한 및 다양한 사용자 매타 정보까지, 시스템에 구현된 인증 서비스에 따라 다양할 수 있다.

엑세스 토큰(Access Token) 인증

엑세스 토큰은 사용자를 특정하기 위해 인증 서비스가 랜덤하게 생성한 고유 식별자로, 엑세스 토큰 자체로는 어떠한 정보도 담고 있지 않다. 그러나 인증 서비스는 토큰 발급 시 생성된 엑세스 토큰과 사용자 인증 정보를 맵핑하여 저장함으로써 엑세스 토큰을 키(Key)로 하여 사용자의 인증 정보를 확인 할 수 있다.

엑세스 토큰 인증 절차

  1. 사용자는 엑세스 토큰을 첨부하여 서비스에게 명령을 요청한다.
  2. 서비스는 엑세스 토큰을 인증 서비스에게 전달하여 사용자 인증 정보 확인을 요청한다.
  3. 인증 서비스는 수신된 엑세스 토큰에 맵핑된 사용자 인증 정보를 서비스에게 전달한다.
  4. 서비스는 인증 서비스로부터 전달받은 사용자 인증 정보를 기반으로 요청을 처리한다.

서비스는 요청된 모든 명령 처리를 위해 인증 서비스에 질의 해야 하며 그에 따라 강한 의존성을 갖게 된다. 이러한 상황에서 인증 서비스에 장애가 발생한다면 전체 서비스로 장애가 전파될 것이다.

JWT(Json Web Token) 인증

엑세스 토큰과 다르게 JWT는 토큰 스스로가 사용자 인증 정보를 가지고 있다. 인증 서비스는 토큰 발급 시 Base64로 인코딩된 제이슨(Json)형식의 사용자 인증 정보와 해당 인증 정보의 위변조 검증을 위한 시그니처(Signiture)를 토큰에 첨부하여 함께 제공한다. 첨부된 시그니처는 인증 서비스가 발급한 공개-키(Public-key)를 통해 검증 가능하다.

JWT 시그니처-검증 목적은 사용자 인증 정보 해석이 아닌 첨부된 인증 정보의 위변조가 없음을 확인하기 위함이다. 사용자 인증 정보는 Base64를 통해 쉽게 디코드(Decode) 가능하기 때문에 사용자의 개인정보 등 보안이 필요한 성격의 정보는 JWT에 포함해서는 안 된다.

JWT 검증 절차

  1. 사용자는 JWT를 첨부하여 서비스에게 명령을 요청한다.
  2. 서비스는 미리 발급받은 공개-키를 사용해 JWT의 유효성을 검증한다.
  3. 서비스는 유효성이 검증된 JWT를 Base64를 이용해 사용자 인증 정보를 디코드한다.
  4. 서비스는 디코드 된 사용자 인증 정보를 기반으로 요청을 처리한다.

토큰 스스로가 사용자 정보를 포함하고 있는 덕분에 서비스들은 인증 서비스와 별도의 의존성을 갖지 않게 되었다. 반면 이러한 특성으로 발생할 수 있는 문제점 또한 존재한다.

발급된 토큰 관리의 어려움, 엑세스 토큰의 경우, 인증 서비스가 발급된 토큰 정보를 중앙에 저장, 관리하고 있으며 각 서비스들은 토큰 검증을 위해서 인증 서비스에 질의해야 하는 반면, JWT의 경우 한번 발급된 토큰은 분산되어 의존성 없이 스스로 인증되기 때문에 비교적 관리에 여려움이 있다. 몇 가지 예를 들어보자.

  • 접근 제어, 이미 토큰이 발급된 특정 사용자의 접근을 제재하려고 한다. 엑세스 토큰의 경우 인증 서비스에 저장된 토큰 정보를 삭제함으로써 더 이상 해당 토큰의 사용이 불가능하도록 할 수 있지만 JWT의 경우 토큰에 명시된 만료 시간 전까지는 제어가 불가능하다.
  • 변경된 정보 적용, 토큰이 발급된 사용자의 권한 정보가 변경되었다. 엑세스 토큰의 경우 토큰에 맵핑된 정보를 수정하여 즉시 변경 적용이 가능한 반면, JWT의 경우 접근 제어와 마찬가지로 JWT에 명시된 만료 시간 전까지는 잘못된 정보로 서비스에 접근할 수 있다.

이러한 관리 어려움으로 JWT는 가능한 토큰의 만료 시간을 짧게 가져가는 것이 좋다. 그러나 토큰 만료시간이 짧아질수록 토큰 갱신을 위해 발생되는 비용이 커지기 때문에 적절한 시간 선택이 중요하다.

JWT를 사용함으로써 인증 서비스와 다른 서비스 간에 많은 의존성을 줄였지만, 여전히 각 서비스들은 인증 서비스가 발급한 공개-키를 관리해야 하며 JWT라는 인증 방식에 묶여 있다.

API Gateway를 활용한 공통 인증

MSA에서 API Gateway는 여러 분리된 서비스 환경에서 사용자에게 하나의 엔드포인트를 제공하기 위해 사용되는 패턴이다. API Gateway는 서비스 최전방에 위치하며, 모든 사용자 요청은 API Gateway를 통해서만 각 서비스에 접근 가능하게 된다. 따라서 API Gateway는 서비스 전체에 미들웨어 계층으로써 공통된 로직을 처리할 수 있으며, 인증도 API Gateway가 처리할 수 있는 공통 로직 중 하나이다.

API Gateway 인증 절차

  1. 사용자는 JWT를 첨부하여 API Gateway를 통해 서비스에게 명령을 요청한다.
  2. API Gateway는 요청된 명령을 수신하여 JWT 인증 로직을 수행한다.
  3. 인증된 사용자 정보를 요청에 추가로 첨부하여 뒷단 서비스에게 전달한다.
  4. 서비스는 API Gateway가 첨부한 사용자 인증 정보를 기반으로 요청을 처리한다.

앞단에 API Gateway가 공통된 인증 절차를 수행하면서 뒷단의 서비스들은 인증 방식으로부터 완전히 독립되어 인증 서비스와 의존성이 사라지게 되었다. 이후 인증 절차에 어떠한 변화에도 다른 서비스들은 영향이 없을 것이다. 예를 들어 JWT의 인증 방식이 앞서 설명한 엑세스 토큰으로 변경되어도 API Gateway가 동일한 사용자 인증 정보를 반환할 수 있다면 뒷단의 다른 서비스들은 어떠한 변경 사항도 없을 것이다.

모든 서비스의 요청은 API Gateway를 통해 각 서비스에 전달된다. 이러한 구조로 API Gateway는 API Gateway 하나의 장애로 서비스 전체가 먹통이 되는 SPOF(Single Point of Failure)가 될 수 있다. 이러한 상황을 대비하기 위해 API Gateway 도입 시에는 철저한 이중화가 준비되어야 한다.

인증 캐시

토큰을 이용한 사용자 인증 결과는 가변성이 크지 않은 데이터이다. 방금 막 유효성이 확인된 토큰이 다음 요청에 결과가 변경되어 있을 가능성을 크지 않다. 이러한 데이터 성격으로 토큰을 키로 하여 사용자 인증 데이터를 캐시 하여 재사용할 수 있다. 재사용된 캐시 데이터는 아래의 이점을 갖는다.

  • 통신 오버해드 감소, 캐시 데이터를 재사용함으로써 반복되는 인증 오버해드(엑세스 토큰: 통신 오버해드, JWT: 시그니처 검증 연산 오버해드)를 줄일 수 있다.
  • 장애 전파 최소화, 인증 서비스 장애 발생 시에도 캐시 데이터를 사용함으로써 장애 영향도를 최소화할 수 있다.

그러나 캐시의 사용은 상황에 따라 이미 내용이 변경되어 유효하지 않은 데이터를 참조 할 수도 있음을 뜻한다. 따라서 각 서비스 성격과 정책에 따라 알맞는 캐시 만료 시간이 설정되어야 하며, 일부 인증의 유효성 판단이 크리티컬(Critical)한 경우, 캐시 사용을 배제해야 한다.

결론

지금까지 MSA에서 사용될 수 있는 사용자 인증 전략을 살펴보았다. 소개된 전략의 핵심은 서비스 전반으로 사용될 인증 서비스 기능과 다른 서비스의 의존성을 줄이는 것이었다. 앞서 설명한 내용을 요약하자면 아래와 같다.

  • JWT를 적용하여 인증 서비스와 의존성 없이 각 서비스가 스스로 사용자 인증을 수행할 수 있도록 하자.
  • API Gateway에서 공통 인증 절차를 수행하여 각 서비스와 인증 절차를 추상화하자.
  • 인증 캐시를 사용하여 반복된 인증 절차를 줄이자.

--

--