Enjoy My Posts

msa - 보안

Posted on By Geunwon Lim

이 포스트는 크리스 리처드슨의 마이크로서비스 패턴의 11장을 보고 작성했습니다.

보안의 4가지 요소

보안 측면에서만 본다면 마이크로서비스 아키텍처는 기존 모놀리식 아키텍처와 큰 차이점이 없습니다. 하지만 애플리케이션 수준의 일부 보안 요소는 구현 방법을 달리할 수밖에 없습니다. 예를 들어 서비스 간에 사용자 신워늘 전달하는 수단을 강구해야 합니다.

네 가지 보안 요소

  1. 인증(authenticatoin) : 애플리케이션에 접근하는 주체의 신원을 확인합니다.
  2. 인가(authorization) : 주체가 어떤 데이터에 어떤 작업을 요청하여 수행할 수 있는 권한이 있는지 확인합니다. 보통 역할 기반(role-based) 및 ACL(Access Control List)을 함께 사용합니다.
  3. 감사: 보안 이슈 탐지, 컴플라이언스 시행, 고객 지원을 위해 주체가 수행하는 작업을 추적합니다.
  4. 보안 IPC: 모든 서비스를 드나드는 통신이 TLS를 경유하는 것이 가장 이상적입니다.

기존 모놀리식 애플리케이션의 보안

  1. 사용자 ID/패스워드로 로그인 -> 자격 증명 요청
  2. 자격 증명이 맞으면 세션 토큰 반환
  3. 요청에 세션 토큰 포함시켜 전송

보안 아키텍처의 핵심은 세션입니다. 주체의 ID와 역할은 세션에 보관합니다. 세션은 토큰으로 식별하며 클라이언트는 요청할 때마다 세션 토큰을 같이 넣어 보냅니다.

인-메모리 세션의 한 가지 단점은 특정 세션의 요청을 모두 동일한 애플리케이션 인스턴스로 라우팅하는 것입니다. 이런 요건은 부하 분산 및 작업을 복잡하게 만듭니다. 이를테면 애플리케이션 인스턴스를 닫기 전에 모든 세션이 만료되길 기다리는 세션 배수 메커니즘을 구현해야 합니다. 아니면 DB에 세션을 저장하는 우회책도 있습니다.

마이크로서비스 아키텍처에서의 보안 구현

각각의 마이크로서비스는 각자 나름대로 보안을 구현해야 합니다. 마이크로서비스 아키텍처에서 보안을 구현하려면 먼저 사용자의 인증/인가 처리를 누가 담당할지부터 결정해야 합니다.

모놀리식에서 통했던 다음 두 가지 보안 요소가 msa에서는 해당되지 않기에 msa 보안 구현이 어렵습니다.

  1. 인-메모리 보안 컨텍스트: 서비스끼리 메모리를 공유할 수 없으므로 인-메모리 보안 컨텍스트로 사용자 신원을 전달할 수 없습니다.
  2. 중앙화 세션: 인-메모리 보안 컨텍스트가 의미 없으니 인-메모리 세션도 마찬가지입니다.

1. API 게이트웨이에서 인증 처리

서비스마다 알아서 사용자를 인증할 수 있습니다. 하지만 미인증 요청이 내부 네트워크로 들어올 수 있고, 모든 개발자가 제대로 보안을 구현하리라 보기 어렵기 때문에 보안 취약점이 노출될 위험성이 큽니다. 더구나 인증하는 방식은 클라이언트마다 다릅니다. 매 요청마다 자격증명을 전송할수도 있고, 한번 로그인한 이후로는 요청할 때마다 세션 토큰을 발급할수도 있습니다. 이처럼 다양한 인증 메커니즘을 서비스가 모두 알아서 처리하게 놔두는 것은 무리입니다.

요청을 서비스에 보내기 전에 API 게이트웨이가 요청을 인증하는 것이 좋습니다. API 게이트웨이에 인증 로직을 중앙화하면 나중에 문제가 생겨도 한곳만 바로잡으면 되기 때문에 보안 취약점이 노출될 가능성이 현저히 줄어듭니다. 또 다양한 인증 메커니즘을 API 게이트웨이가 전담해서 처리하므로 복잡한 코드도 서비스에서 감출 수 있습니다.

API 클라이언트는 자격 증명을 포함시켜 요청하고 API 게이트웨이는 이 요청을 인증합니다. 로그인 기반 클라이언트는 사용자 자격증명을 API 게이트웨이에 포스트 전송한 후 세션 토큰을 발급받습니다. API 게이트웨이는 요청을 인증한 후 하나 이상의 서비스를 호출합니다.

API 게이트웨이로부터 호출받은 서비스는 요청 주체가 누구인지 알아야하고, 인증을 마친 요청인지 아닌지 반드시 확인해야 합니다. 해결 방법은 API 게이트웨이가 매번 서비스에 요청할 때마다 토큰을 함께 넣어 보내는 것입니다. 서비스는 이 토큰을 이용하여 요청을 검증하거나 주체 정볼르 획득할 수 있습니다.

2. 인가 처리

인증처럼 인가 로직도 API 게이트웨이 내부에 중앙화하면 보안을 강화할 수 있습니다. 하지만 이렇게 API 게이트웨이에 인가 로직을 두면, API 게이트웨이와 서비스가 단단히 결합하게 되어 나중에 변경할 일이 생기면 서로 맞물리게 될 수 있습니다. 따라서 인가 로직은 서비스에 구현하는 것이 좋습니다. 서비스가 직접 역할 기반으로 URL과 메서드를 인가하고, ACL로 애그리거트 접근을 따로 관리하는 것입니다.

3. JWT로 사용자 신원/역할 전달

토큰 종류 첫째로 난독화 토큰이 있습니다. 보통 UUID를 많이 씁니다. 성능 및 가용성이 떨어지고 지연 시간이 길다는 것이 단점입니다. 토큰 수신자가 토큰의 유효성을 검증하고 보안 서비스를 동기 RPC 호출하여 사용자 정보를 조회해야 하기 때문입니다.

둘째, 보안 서비스 호출이 필요 없는 투명 토큰 입니다. JWT는 사실상 투명 토큰의 표준 규격입니다. 두 당사자 간의 사용자 신원/역할 등의 정보를 안전하게 표현하는 표준 수단이죠. 사용자 정보, 만료일자 등 각종 메타데이터가 포함된 JSON 객체를 페이로드에 담에 JWT 생성자(api 게이트웨이)와 JWT 수신자(서비스)만 알 수 있는 시크릿으로 서명합니다. 덕분에 악의적인 제삼자가 JWT를 위변조하기는 거의 불가능합니다.

하지만 JWT는 토큰 자체가 포함되어 있기 때문에 취소할 수 없다는 문제가 있습니다. 서비스가 JWT 서명과 만료일자를 확인 후 요청받은 작업을 수행하는 구조라서 토큰이 악의적인 해커의 손에 넘어가더라도 이를 취소할 방법이 마땅치 않습니다. 해결방법은 유효 기간이 짧은 JWT를 발행하는 것입니다. 그런데 이럴 경우 애플리케이션이 세션 유지를 위해 계속 JWT를 재발행해야 할 것입니다. 다행이 OAuth2.0이라는 보안 표준을 적용하여 해결할 수 있습니다.

4. OAuth 2.0 응용

자격증명, 역할 등 사용자 정보를 DB로 관리하는 사용자 서비스를 구현한다고 할 때, API 게이트웨이는 이 사용자 서비스를 호출해서 클라이언트 요청을 인증하고 JWT를 획득합니다.

  • 인증 서버: 사용자 인증 및 액세스/리프레시 토큰 획득 API를 제공합니다.
  • 액세스 토큰: 리소스 서버 접근을 허가하는 토큰.
  • 리프레시 토큰: 클라이언트가 새 액세스 토큰을 얻기 위해 필요한 토큰. 수명은 길지만 취소 가능한 토큰입니다.
  • 리소스 서버(보호자원): 액세스 토큰으로 접근을 허가하는 서비스. msa에서 각 서비스가 곧 리소스 서버입니다.
  • 자원 소유자: 서비스를 호출할 수 있는 애플리케이션 및 서비스에 접근할 수 있는 사용자, 그리고 서비스에서 수행할 수 있는 작업을 정의. 자원 소유자가 등록한 애플리케이션은 식별 가능한 애플리케이션 이름과 시크릿키를 받는다. 애플리케이션 이름과 시크릿 키는 OAuth2 토큰을 인증할 때 전달되는 자격 증명의 일부다.
  • 클라이언트: 리소스 서버에 접근하려는 클라이언트. msa에서 API 게이트웨이가 바로 OAuth 2.0의 클라이언트의 예시.
  1. 클라이언트는 기본 인증을 이용하여 자격증명과 함께 요청합니다.
  2. API 게이트웨이는 OAuth 2.0 인증 서버에 패스워드 승인을 요청합니다.
  3. 인증 서버는 API 클라이언트의 자격 증명을 검증하고 액세스/리프레시 토큰을 반환합니다.
  4. API 게이트웨이는 서비스에 요청할 때마다 발급받은 액세스 토큰을 넣어 보내고, 서비스는 액세스 토큰을 이용하여 요청을 인증합니다.

OAuth 2.0 기반의 API 게이트웨이는 액세스 토큰을 세션 토큰처럼 이용해서 세션 지향 클라이언트를 인증할 수 있습니다. API 클라이언트가 API 게이트웨이의 로그인 엔드포인트에 자격증명을 POST 하면 세션이 초기화됩니다. API 게이트웨이는 액세스/리프레시 토큰을 클라이언트에 반환하고, API 클라이언트는 API 게이트웨이에 요청을 할 때마다 두 토큰을 함께 넣어 보냅니다.

  • API 게이트웨이는 클라이언트 인증을 담당합니다.
  • API 게이트웨이 및 서비스는 투명 토큰(JWT등)을 이용해 주체 정보를 주고받습니다.
  • 서비스는 토큰을 이용하여 주체의 신원/역할 정보를 획득합니다.

Oauth2의 네 가지 그랜트 타입

  1. 패스워드
  2. 클라이언트 자격 증명
  3. 인가 코드
  4. 암시적