[MSA] Netfilx는 MSA에서 어떻게 인증/인가를 처리할까? : Netfilx Passport

AMUD·2023년 10월 29일
10

Architecture & MSA

목록 보기
1/2

설계 관련 고민을 하면서 재밌는 글을 찾았다. 바로 [ 서비스 엣지에서의 인증과 토큰에 구애 받지 않는 id 전파 ] 라는 주제의 넷플릭스 기술 블로그 글이다. 2021년 글이지만 관련 레퍼런스가 많이 없어서 아직 유용한 포스트 같다.

Edge Authentication and Token-Agnostic Identity Propagation

이 포스트는

  • MSA 설계에서 인증/인가 처리 방법을 고민하시는 분
  • 다양한 형태의 토큰을 지원하는 서비스 개발하시는 분
  • 인증/인가 처리 과정을 최소화하고자 하시는 분
  • 머찐 개발자라면 누구나

정도에게 추천하고 싶다.

직접 번역(기 돌리는 거)하면서 포스트 내용을 정리한 내용을 나의 견해 조금씩과 함께 공유하고자 한다.

⛔ Netfilx 기존 문제 상황

개발자들은 보안 프로토콜, 신원 토큰, 사용자 및 장치 인증과 같은 문제를 처리하는 것이 어려울 수 있습니다. Netflix는 200M+의 사용자와 수천 종류의 장치를 가지고 있어 이러한 문제의 범위가 훨씬 더 커집니다. 이러한 복잡성을 줄이기 위해 Netflix는 네트워크의 가장자리에 사용자 및 장치 인증 및 다양한 보안 프로토콜 및 토큰의 복잡한 처리를 이동하기로 결정했습니다.

Netflix의 배경

초기 Netflix는 DVD 대여를 위한 웹사이트였습니다. 시간이 지나며 스트리밍 콘텐츠 기능이 추가되었고, 그 후 다양한 장치로 확장되었습니다. 이러한 변화로 인해 서비스는 사용자와 장치를 인식하고 접근 권한을 부여하기 위해 여러 토큰과 보안 프로토콜을 이해해야하는 부담을 지게 되었습니다.

복잡한 인증/인가 과정


예전의 로그인 플로우는 여러 단계를 거쳐야 했으며, 이는 토큰 관리의 복잡성을 높였습니다. 토큰은 여러 시스템에 의해 소비되거나 변경될 수 있었습니다. Netflix의 규모는 지속적으로 확장되었고, 많은 요청들이 인증을 필요로 했습니다.

다양한 종류의 토큰

한 종류의 토큰 뿐만 아니라 다양한 프로토콜의 요청을 위해 토큰의 종류도 다양하여 이에 대응하기에 많은 부담이 있었습니다.

EdgePaaS의 도입

Edge 엔지니어링 팀은 오래된 API 서버 아키텍처에서 새로운 PaaS 기반 접근법으로의 마이그레이션 중이었습니다. 이로 인해 복잡성이 더해졌습니다. 새로운 PaaS 모델에서는 어떻게 이러한 신원 토큰을 다룰 것인가의 문제가 제기되었습니다.

그래서 Netflix는 대규모에서 인증 및 신원 토큰을 처리하기 위한 복잡하고 비효율적인 솔루션을 가지고 있었습니다. 여러 종류의 신원 토큰, 각각의 특별한 처리가 필요하며, 이러한 로직은 다양한 시스템에서 복제되었습니다. 중요한 신원 데이터는 서버 시스템 전체에서 일관되지 않게 전파되었습니다.

→ 간단하게 요약하자면 로그인이 복잡했고, 토큰 종류가 많아서 여러 서비스에서 부담이 커져서 해결책이 필요했다는 내용이다.

🧤 복잡성 해결방법 : 인증/인가를 서비스 호출 가장 바깥쪽에서 처리하기!

Netflix는 인증 문제를 해결하기 위한 통합된 신원 모델이 필요하다고 판단했습니다. 네트워크의 가장자리로 인증 및 프로토콜 종료를 옮김으로써 이를 실현하였고, 서버 시스템 전체에 전파하기 위한 새로운 무결성이 보호된 토큰에 무관한 신원 객체를 생성하였습니다.

인증을 Edge로 이동

보안 향상, 복잡성 감소 및 사용자 경험 개선을 목표로, 장치 인증 작업 및 사용자 식별과 인증 토큰 관리를 서비스 가장자리에 중앙집중화하는 방법을 고려하였습니다. 이를 위해 Zuul (클라우드 게이트웨이)이 토큰 검사 및 페이로드 암/복호화의 종료 지점이 되도록 설계하였습니다.

Edge 인증 서비스

Edge 인증 서비스(EAS)는 장치 및 사용자의 인증 및 식별을 스택의 상위로 이동하는 구조적 개념이자 각 토큰 유형을 처리하기 위해 개발된 서비스 세트입니다.

EAS는 Zuul 내에서 실행되는 일련의 필터로서, 그들의 도메인을 지원하기 위해 외부 서비스에 요청할 수 있습니다. EAS는 토큰의 읽기 전용 처리를 통해 "Passports"를 생성하는 것도 포함합니다.

EAS가 요청을 처리하는 기본 패턴은 아래와 같다.

  1. Netflix 서비스로 들어오는 각 요청에 대해 Zuul 내의 EAS 인바운드 필터가 장치 클라이언트에 의해 제공된 토큰을 검사하고, 요청을 Passport Injection 필터로 전달하거나 Edge 인증 서비스 중 하나에 위임하여 처리합니다.
  2. Passport Injection 필터는 서버 시스템의 나머지 부분을 통해 전파되는 토큰에 무관한 신원을 생성합니다.
  3. 응답 경로에서 EAS 아웃바운드 필터는 필요한 경우 Edge 인증 서비스의 도움을 받아 클라이언트 장치로 돌려 보낼 토큰을 생성합니다.

EAS의 유연함

정상적인 경우에는 Zuul이 유효하고 만료되지 않은 대다수의 토큰을 처리할 수 있으며, Edge Auth 서비스는 나머지 요청을 처리합니다. EAS 서비스는 장애에 대한 내성을 갖추도록 설계되었습니다. 실패 시나리오에서는 Zuul 내의 EAS 필터가 신원을 전달하도록 허용하고 다음 요청에서 갱신 호출이 다시 예약되도록 지시합니다.

📬 Passport: 바깥쪽에서 처리된 인증 정보 내부에서 주고 받기

토큰에 무관한 신원 (Passport)

서비스에서 서비스로 신뢰도가 낮은 신원을 전달하는 것을 의미하는 쉽게 변경 가능한 신원 구조는 충분하지 않습니다. 토큰에 무관한 신원 구조가 필요했습니다.

우리는 "Passport"라는 신원 구조를 도입하여 사용자와 장치의 신원 정보를 균일한 방식으로 전파할 수 있게 했습니다. Passport는 또한 토큰의 일종이지만, 내부 구조가 외부 토큰과 다르기 때문에 많은 이점이 있습니다. 그러나 하위 시스템은 여전히 사용자와 장치의 신원에 대한 접근이 필요합니다.

Passport와 사용자/장치 신원(ID)

Passport는 각 요청에 대해 Edge에서 생성된 단기 신원 구조입니다. 즉, 요청의 수명에 제한되며 Netflix 생태계 내에서 완전히 내부적입니다. 이러한 Passport는 Zuul에서 일련의 Identity Filters를 통해 생성됩니다. Passport는 사용자 및 장치의 신원을 모두 포함하며, protobuf 형식이며 HMAC에 의해 무결성이 보호됩니다.

간단히 말하면, Passport는 Netflix 시스템 내에서 일관된 방식으로 사용자와 장치의 신원을 전파하기 위한 내부 토큰입니다. 이는 보안을 강화하고 서비스 간의 통신을 단순화하는 데 도움을 줍니다.

Passport 구조

Passport는 앞서 언급했듯이 Protocol Buffer로 모델링되어 있습니다. 가장 상위 수준에서 Passport의 정의는 다음과 같습니다:

message Passport {
   Header header = 1;
   UserInfo user_info = 2;
   DeviceInfo device_info = 3;
   Integrity user_integrity = 4;
   Integrity device_integrity = 5;
}

여기서 Header 요소는 Passport를 생성한 서비스의 이름을 전달합니다. 더 흥미로운 것은 사용자와 장치에 관련된 정보입니다.

사용자 & 장치 정보:

UserInfo 요소는 요청을 하는 사용자를 식별하기 위해 필요한 모든 정보를 포함하고 있으며, DeviceInfo 요소는 사용자가 Netflix를 방문하는 장치에 대한 모든 필요한 정보를 포함하고 있습니다.

message UserInfo {
    Source source = 1;
    int64 created = 2;
    int64 expires = 3;
    Int64Wrapper customer_id = 4;
    ...
    PassportAuthenticationLevel authentication_level = 11;
    repeated UserAction actions = 12;
}

message DeviceInfo {
    Source source = 1;
    int64 created = 2;
    int64 expires = 3;
    StringValue esn = 4;
    Int32Value device_type = 5;
    repeated DeviceAction actions = 7;
    PassportAuthenticationLevel authentication_level = 8;
    ...
}

UserInfoDeviceInfo 모두 요청에 대한 SourcePassportAuthenticationLevel을 포함하고 있습니다. Source 목록은 사용되는 프로토콜과 주장을 검증하는데 사용되는 서비스와 관련된 주장의 분류입니다. PassportAuthenticationLevel은 우리가 인증 주장에 대입하는 신뢰도의 수준입니다.

enum Source {
    NONE = 0;
    COOKIE = 1;
    COOKIE_INSECURE = 2;
    MSL = 3;
    PARTNER_TOKEN = 4;
    ...
}

enum PassportAuthenticationLevel {
    LOW = 1; // 신뢰할 수 없는 전송
    HIGH = 2; // TLS 위의 보안 토큰
    HIGHEST = 3; // MSL 또는 사용자 자격증명
}

하위 응용 프로그램은 이러한 값을 사용하여 권한 및/또는 사용자 경험 결정을 내릴 수 있습니다.

간단히 말하면, Passport는 사용자와 장치에 대한 식별 정보를 안전하게 전달하기 위한 구조로, Netflix 서비스 내부에서 사용됩니다. 각 요소와 열거형 값은 Netflix 서비스의 인증 및 권한 부여에 필요한 중요한 정보를 제공합니다.

Passport의 무결성

Passport의 무결성은 HMAC (hash-based message authentication code)를 통해 보호됩니다. HMAC은 특정 유형의 MAC으로서 암호 해시 함수와 비밀 암호 키를 포함합니다. 이를 사용하여 메시지의 데이터 무결성 및 인증성을 동시에 검증할 수 있습니다.

사용자와 장치의 무결성은 다음과 같이 정의됩니다:

message Integrity {
    int32 version = 1;
    string key_name = 2;
    bytes hmac = 3;
}

Integrity 요소의 버전 1은 HMAC에 SHA-256을 사용하며 ByteArray로 인코딩됩니다. Integrity의 미래 버전은 다른 해시 함수 또는 인코딩을 사용할 수 있습니다. 버전 1에서 HMAC 필드는 MacSpec.SHA_256에서의 256비트를 포함합니다.

무결성 보호는 Passport가 생성된 후 Passport 필드가 변경되지 않음을 보장합니다. 클라이언트 응용 프로그램은 포함된 모든 값의 사용 전에 Passport의 무결성을 검사하기 위해 Passport Introspector를 사용할 수 있습니다.

요약하면, Passport의 무결성은 암호화된 HMAC을 통해 보장되며, 이로 인해 Passport의 데이터가 생성된 후에 변경되지 않았음을 확인할 수 있습니다.

Passport Introspector : Passport의 속성

Passport 객체 자체는 불투명합니다(추상화 되어있다). 클라이언트는 Passport Introspector를 사용하여 헤더에서 Passport를 추출하고 그 안의 내용을 검색할 수 있습니다. Passport Introspector는 Passport 바이너리 데이터 위에 있는 래퍼입니다. 클라이언트는 팩토리를 통해 Introspector를 생성한 후 기본 접근자 메서드에 액세스 할 수 있습니다.

public interface PassportIntrospector {
    Long getCustomerId();
    Long getAccountOwnerId();
    String getEsn();
    Integer getDeviceTypeId();
    String getPassportAsString();
    ...
}

Passport Actions

위에 표시된 Passport 프로토콜 버퍼 정의에서는 Passport Actions가 정의되어 있습니다.

message UserInfo {
    repeated UserAction actions = 12;
    ...
}

message DeviceInfo {
    repeated DeviceAction actions = 7;
    ...
}

Passport Actions는 사용자 또는 장치 신원에 대한 업데이트가 수행되었을 때 하위 서비스에서 보낸 명시적 신호입니다. 이 신호는 EAS에서 해당 유형의 토큰을 생성하거나 업데이트하는 데 사용됩니다.

로그인 플로우

이 모든 솔루션들이 함께 작동하는 예를 들어 설명을 마무리하겠습니다.

인증 및 프로토콜 종료를 Edge로 이동하고 신원으로서의 Passport 도입으로 이전에 설명된 Login Flow는 다음과 같이 변형되었습니다:

  • 사용자가 자신의 자격 증명을 입력하고 Netflix 클라이언트는 장치의 ESN과 함께 자격 증명을 Edge 게이트웨이인 Zuul로 전송합니다.
  • Zuul에서 실행되는 Identity 필터는 장치에 바인딩 된 Passport를 생성하고 API /login 엔드포인트로 전달합니다.
  • API 서버는 Passport를 사용자를 인증하는 중간 계층 서비스로 전파합니다.
  • 제공된 주장의 성공적인 인증 후, 이러한 서비스는 Passport Action을 생성하고 원래의 Passport와 함께 API와 Zuul로 다시 보냅니다.
  • Zuul은 Passport와 Passport Actions를 해결하기 위해 Cookie Service를 호출하고 Cookies를 Netflix 클라이언트로 돌려 보냅니다.

요약하면, 이 새로운 로그인 플로우는 인증을 통합하고, 보다 안전하게 처리하며, Passport라는 새로운 신원 메커니즘을 도입함으로써 보다 간소화되었습니다.

Passport의 주요 이점

  1. 단순화된 인가
    • 외부 토큰들이 다운스트림 시스템으로 흘러들어가는 주된 이유 중 하나는 토큰 내의 인증 정보와 각 토큰 유형과 관련된 신뢰도에 기반한 인가 결정이 필요했기 때문입니다.
    • Passport 구조에서는 이러한 신뢰도에 레벨을 할당함으로써, 인가 결정이 필요한 시스템이 여러 서비스에서 코드로 신뢰 규칙을 복제하는 대신 Passport 주변에 합리적인 규칙을 작성할 수 있게 되었습니다.
  2. 명시적이고 확장 가능한 신원 모델
    • 신원을 나타내는 공식적인 구조를 가지는 것은 매우 유용합니다.
    • 신원 기본 요소를 전달하는 대안 방법들은 취약하며 디버깅하기 어렵습니다.
    • 주요 시스템을 통과한 후에는 새로운 외부 토큰 유형, 새로운 신뢰 수준 또는 신원을 나타내는 새로운 방법을 쉽게 추가할 수 있습니다.
  3. 운영 문제 및 가시성
    • Passport와 같은 구조를 가지게 되면, Passport를 작성할 수 있는 서비스를 정의하고 다른 서비스에서 유효성을 검사할 수 있게 됩니다.
    • 디버깅이 훨씬 쉬워졌습니다.
  4. 다운스트림 시스템의 복잡성 및 부하 감소
    • 다운스트림 시스템에 균일한 구조를 전달함으로써 해당 시스템은 내부 검사 라이브러리를 사용하여 장치와 사용자 신원을 쉽게 찾을 수 있습니다.
  5. 개발자 생산성 향상
    • 이러한 인증 및 신원 관련 문제를 마이크로서비스의 개발자들로부터 추상화함으로써 그들은 자신의 핵심 도메인에 집중할 수 있게 되었습니다.

이후 계획

  1. 더 강력한 인증:
    • 현재 Edge 인증 서비스를 "Resistor"라는 새로운 서비스를 통해 다중 요소 인증(Multi-Factor Authentication)을 지원하기 위해 확장하고 있습니다.
    • 기계 학습 모델을 기반으로 의심스러운 연결에 대해 두 번째 요소를 선택적으로 도입합니다.
    • 새로운 플로우를 도입하면서 이메일이나 전화로 보낸 일회용 비밀번호(OTP), 모바일 장치로의 푸시 알림, 타사 인증기 애플리케이션과 같은 새로운 요소를 도입하고 있습니다.
    • 계정의 추가 보안을 원하는 사용자를 위한 선택적 다중 요소 인증도 탐색할 예정입니다.
  2. 유연한 인가:
    • 시스템을 통해 검증된 신원이 흐르고 있으므로 인가 결정에 대한 강력한 신호로 사용할 수 있습니다.
    • 지난해, 우리는 새로운 Product Access Strategy (PACS)를 탐색하기 시작했으며, 현재 Netflix 스트리밍 제품에서 여러 새로운 경험을 위한 생산으로 이동하는 작업을 진행 중입니다.
    • PACS는 인도에서 무료 Netflix의 주말인 Streamfest의 경험 접근 제어를 최근에 지원했습니다.

(→ 아마 2년 전이기 때문에 더 많은 내용이 개선되었을 것이다)

🧸 개인적인 정리 및 생각

외부 토큰과 내부 토큰을 분리하는 것이 가장 큰 컨셉인 것으로 보인다. 그래서 내부에서의 통신은 더 신뢰할 수 있게 되고, 통일된 형태이기 때문에 처리 비용이 줄고, edge에서 외부 토큰을 처리하기 때문에 각 서비스에서는 관련 로직을 대폭 줄일 수 있을 뿐만 아니라 User 저장소의 트래픽도 줄일 수 있다. 여러 설계 고민이 있는 내게 너무너무 필요한 개념이었다.

해당 글의 passport는 protobuf를 기반으로 한다고 하였다.

Practical API Design at Netflix, Part 1: Using Protobuf FieldMask

더 찾아보니 이 글도 재미있다. gRPC로 주로 마이크로 서비스들 간의 통신을 하는데, 그때 주로 사용되는 직렬화 프로토콜이 protobuf(Protocol Buffer)이다.

아직 http/https 프로토콜만 익숙해서 Spring Cloud OpenFeign으로만 마이크로 서비스들끼리 통신하는데, 만약 기존 프로젝트에 passport라는 개념을 적용하게 된다면 그 형태를 조금 커스텀 해야할 것 같다.

profile
210's Velog :: Ambition Makes Us Diligent

1개의 댓글

comment-user-thumbnail
2023년 10월 30일

개쩐다

답글 달기