초당 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, 평문 폴백과 점진적 배포를 함께 설계해야 보안성과 성능, 무중단 운영을 동시에 확보할 수 있다.