line

초당 100만 건, LINE 앱에 Apache Kafka 종단 간 암호화 적용기 (새 탭에서 열림)

LINE의 대규모 Kafka 환경에서는 TLS·인증·인가만으로는 브로커에 저장된 평문 데이터를 충분히 보호하기 어렵기 때문에, 프로듀서부터 컨슈머까지 메시지 페이로드를 암호화하는 종단 간 암호화를 도입했다. 레코드 단위 암호화와 DEK-KEK 구조를 결합해 Kafka 표준 확장성을 유지하면서 성능 오버헤드를 줄였고, 공유 KEK·평문 폴백·점진적 배포로 초당 최대 100만 건 규모의 토픽에 무중단 적용했다.

Kafka 기본 보안 모델의 한계

  • TLS/SSL은 프로듀서·컨슈머와 브로커 사이의 전송 구간만 보호한다.
  • SASL 인증은 클라이언트의 신원을 확인하고, ACL 인가는 토픽 접근 권한을 통제한다.
  • 그러나 브로커에 저장된 메시지 페이로드 자체는 평문일 수 있다.
  • 따라서 접근 권한이 우회되거나 브로커 내부 데이터가 노출되면 민감 정보가 보호되지 않는다.
  • 데이터 생성 시점부터 컨슈머의 복호화 시점까지 암호화 상태를 유지하는 심층 방어 전략이 필요하다.

레코드 단위 암호화

  • 배치 단위 암호화는 압축 효율과 처리 성능이 좋지만, Kafka 클라이언트 내부 동작을 수정해야 한다.
  • Kafka의 인터셉터와 같은 공식 확장 포인트는 레코드 단위로 동작한다.
  • 레코드 단위 암호화는 압축 효율이 낮고 메시지 크기가 다소 증가하지만 다음 장점이 있다.
    • 표준 Kafka API를 활용할 수 있다.
    • Kafka 버전 업그레이드 시 호환성과 안정성이 높다.
    • 기존 프로듀서·컨슈머 클라이언트 코드를 직접 수정하지 않아도 된다.
  • 이러한 이유로 레코드 단위 암호화를 선택했다.

DEK-KEK 이중 키 구조

  • DEK(Data Encryption Key)
    • 메시지 페이로드 암호화에 사용하는 AES 대칭 키다.
    • AES-GCM을 사용해 빠른 암·복호화와 무결성 검증을 제공한다.
  • KEK(Key Encryption Key)
    • DEK를 암호화하는 ECC 기반 비대칭 키 쌍이다.
    • KMS가 키를 관리하며, 프로듀서는 공개 키를 사용하고 컨슈머는 인가된 비공개 키를 사용한다.
    • DEK 암호화에는 ECIES와 secp521r1 곡선을 사용한다.
  • 대용량 데이터는 빠른 대칭 키로 처리하고, 짧은 DEK에만 비대칭 암호화를 적용해 성능 부담을 줄인다.
  • 프로듀서는 페이로드를 한 번만 암호화하므로 컨슈머 수가 늘어도 메시지 크기를 크게 늘리지 않는다.
  • 공개 키를 이용한 암호화 권한과 비공개 키를 이용한 복호화 권한을 분리해 최소 권한 원칙을 적용한다.

암호화 메시지 구조

    • Kafka 파티션을 결정하는 기존 메시지 키를 그대로 유지한다.
  • 헤더
    • 컨슈머가 사용할 KEK ID와 KEK로 암호화된 DEK를 저장한다.
  • 바디
    • DEK로 암호화된 실제 페이로드를 담는다.
  • 외부 DB나 캐시 없이 메시지 자체에 복호화 메타데이터를 포함해 시스템 의존성을 줄였다.
  • 컨슈머는 헤더의 KEK ID를 확인한 뒤 DEK를 복호화하고, 복호화한 DEK로 바디의 페이로드를 복호화한다.

프로듀서 암호화 처리

  • Kafka 인터셉터가 전송 직전 DEK를 생성하고 KEK 공개 키로 암호화한다.
  • 암호화된 DEK는 메시지 헤더에 삽입한다.
  • 기존 시리얼라이저를 감싼 래퍼가 직렬화된 페이로드를 DEK로 암호화한다.
  • 인터셉터와 시리얼라이저가 같은 실행 스레드를 공유한다는 점을 활용해 DEK를 ThreadLocal로 전달한다.
  • 매 메시지마다 DEK를 새로 만들지 않고 일정 시간 캐싱해, 반복적인 비대칭 키 연산을 줄였다.

컨슈머 복호화 처리

  • 컨슈머는 KMS에서 인가된 KEK 비공개 키를 조회한다.
  • 디시리얼라이저가 헤더에서 암호화된 DEK를 추출하고 비공개 키로 복호화한다.
  • 복호화된 DEK로 페이로드를 복호화한 후 기존 역직렬화를 수행한다.
  • 여러 프로듀서가 생성한 암호화 DEK와 복호화된 DEK의 쌍을 캐싱한다.
  • 동일한 암호화 DEK가 반복되면 비공개 키 연산을 생략해 컨슈머 성능을 높인다.

KMS 기반 키 관리

  • 토픽 오너가 KEK 키 쌍을 생성하고 KMS에 등록한다.
  • 프로듀서는 공개 키를, 승인된 컨슈머는 비공개 키를 KMS에서 조회한다.
  • 신규 컨슈머는 비공개 키 접근 권한을 요청하고 토픽 오너의 승인을 받아야 한다.
  • KEK의 생성·배포·접근 제어·교체를 KMS를 통해 일관되게 관리한다.

공유 KEK로 메시지 크기 제어

  • 컨슈머마다 별도의 KEK를 사용하면 컨슈머 수에 비례해 헤더 메타데이터가 증가한다.
  • 메시지 크기 증가는 배치당 레코드 수 감소, 네트워크 대역폭 증가, CPU·메모리 사용량 증가로 이어진다.
  • 특히 초당 최대 100만 건의 토픽에서는 컨슈머 추가에 따른 헤더 증가가 큰 성능 문제가 된다.
  • 여러 컨슈머가 하나의 KEK를 공유하면 헤더에는 하나의 메타데이터만 포함되어 메시지 크기를 일정하게 유지할 수 있다.
  • 대신 키 격리 수준은 낮아지므로 다음 보완책을 함께 적용한다.
    • KMS 기반 비공개 키 접근 인가
    • 주기적인 KEK 교체
    • 토픽 오너 중심의 키 관리

평문 폴백을 이용한 무중단 마이그레이션

  • 암호화 도입 과정에서는 기존 평문 메시지와 새로운 암호화 메시지가 함께 존재할 수 있다.
  • 디시리얼라이저가 헤더의 암호화 메타데이터 유무를 확인해 처리 방식을 결정한다.
    • 헤더가 있으면 복호화 후 역직렬화한다.
    • 헤더가 없으면 기존 평문 역직렬화만 수행한다.
  • 안전한 전환 순서는 다음과 같다.
    • 평문과 암호화 메시지를 모두 처리할 수 있는 컨슈머를 먼저 배포한다.
    • 모든 컨슈머가 준비된 뒤 프로듀서 암호화를 활성화한다.
    • 모니터링을 통해 평문 메시지 비중이 0%가 되었는지 확인한다.
  • 프로듀서 암호화 비율도 한 번에 100%로 변경하지 않고 점진적으로 높여 성능 저하나 암·복호화 오류에 대응한다.

실용적인 결론

Kafka의 TLS·인증·인가를 대체하기보다, DEK-KEK 기반 페이로드 암호화를 추가 보안 계층으로 적용하는 것이 적절하다. 대규모 환경에서는 레코드 단위 암호화, DEK 캐싱, 컨슈머 측 DEK 캐싱, 공유 KEK, 평문 폴백과 점진적 배포를 함께 설계해야 보안성과 성능, 무중단 운영을 동시에 확보할 수 있다.