본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2026. 4. 9. · 0 Views
Kafka 보안 설정 완벽 가이드
Apache Kafka의 보안 설정을 단계별로 학습합니다. SASL 인증부터 SSL/TLS 암호화, ACL 인가, mTLS 상호 인증까지 실무에 필요한 보안 기법을 모두 다룹니다.
목차
1. SASL 인증
김개발 씨가 사내 카프카 클러스터에 새로운 서비스를 연동하려다가 막혔습니다. 브로커에 접속하려고 하면 "Authentication failed"라는 에러가 뜨는 것입니다.
"어, 분명 아이디와 비밀번호는 맞게 넣었는데 왜 접근이 안 될까요?"
**SASL(Simple Authentication and Security Layer)**은 카프카에서 클라이언트와 브로커 간의 인증을 처리하는 프레임워크입니다. 마치 회사 건물의 출입문 보안 카드 시스템과 같아서, 카드를 제시한 사람만이 건물 안으로 들어올 수 있습니다.
SASL은 여러 가지 인증 메커니즘을 지원하며, 환경에 따라 적절한 방식을 선택할 수 있습니다.
다음 코드를 살펴봅시다.
# server.properties - SASL/PLAIN 설정
listeners=SASL_PLAINTEXT://:9092
security.inter.broker.protocol=SASL_PLAINTEXT
sasl.mechanism.inter.broker.protocol=PLAIN
sasl.enabled.mechanisms=PLAIN
# JAAS 설정 파일 (kafka_server_jaas.conf)
KafkaServer {
org.apache.kafka.common.security.plain.PlainLoginModule required
username="admin"
password="admin-secret"
user_admin="admin-secret"
user_producer="producer-secret"
user_consumer="consumer-secret";
};
# 클라이언트 JAAS 설정
KafkaClient {
org.apache.kafka.common.security.plain.PlainLoginModule required
username="producer"
password="producer-secret";
};
"Apache Kafka 완전 정복" 코스 13번째 시간입니다. 지난 12화에서는 카프카 스트림즈를 통해 실시간 데이터 처리 파이프라인을 구축하는 방법을 배웠습니다.
이번에는 카프카 클러스터의 보안을 담당하는 SASL 인증부터 시작해 보겠습니다. 김개발 씨는 입사 3개월 차 주니어 개발자입니다.
최근 팀에서 카프카를 도입하면서, 기존의 내부망 전용 클러스터를 외부 서비스에도 개방해야 하는 과제를 맡았습니다. 그런데 접속을 시도할 때마다 인증 에러가 발생했습니다.
분명 설정은 맞게 한 것 같은데 말이죠. 선배 개발자 박시니어 씨가 커피를 들고 다가왔습니다.
"SASL 설정을 추가해야 해요. 이제 카프카가 공용망에 노출되니, 아무나 접근할 수 있게 두면 안 되잖아요." 그렇다면 SASL이란 정확히 무엇일까요?
쉽게 비유하자면, SASL은 마치 호텔 프론트 데스크의 객실 키 카드 시스템과 같습니다. 투숙객이 프론트에 신분을 증명하면, 목적에 맞는 권한의 키 카드를 발급받습니다.
직원용 키, 손님용 키, VIP용 키처럼 역할에 따라 접근 권한이 다르죠. SASL도 마찬가지로, 클라이언트의 역할에 따라 적절한 인증 방식을 적용합니다.
SASL이 없던 시절에는 어땠을까요? 개발자들은 카프카 브로커를 내부망에만 두고, 방화벽으로 외부 접근을 차단하는 방식으로 보안을 유지했습니다.
하지만 클라우드 환경과 마이크로서비스 아키텍처가 보편화되면서, 네트워크 단독 보안만으로는 부족해졌습니다. 더 큰 문제는 내부망이라고 해서 항상 안전할 수 있다는 보장이 없다는 점이었습니다.
바로 이런 문제를 해결하기 위해 SASL이 등장했습니다. SASL을 사용하면 인증 정보를 암호화하여 전송할 수 있습니다.
또한 다양한 인증 메커니즘을 플러그인 형태로 교체할 수 있습니다. 무엇보다 운영체제 수준의 인증과 통합이 가능하다는 큰 이점이 있습니다.
위의 설정을 한 줄씩 살펴보겠습니다. 먼저 listeners 설정에서 브로커가 SASL_PLAINTEXT 프로토콜로 9092 포트를 리스닝하도록 지정합니다.
이는 암호화는 없지만 SASL 인증은 수행하겠다는 의미입니다. 다음으로 security.inter.broker.protocol에서 브로커 간 통신에도 SASL을 사용하도록 설정합니다.
sasl.enabled.mechanisms에서는 PLAIN 방식을 활성화합니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 금융 서비스를 개발한다고 가정해봅시다. 각 부서별로 다른 권한의 카프카 사용자를 생성하고, PLAIN 인증으로 접근을 제어하면 데이터 유출 위험을 크게 줄일 수 있습니다.
많은 기업에서 SASL을 첫 번째 보안 계층으로 적극적으로 사용하고 있습니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 PLAIN 방식에서 비밀번호를 평문으로 저장하는 것입니다. JAAS 설정 파일에 비밀번호가 그대로 노출되므로, 파일 권한을 600으로 제한하고, 더 나은 보안이 필요하면 SCRAM 방식을 고려해야 합니다.
따라서 프로덕션 환경에서는 비밀번호 해시를 지원하는 SCRAM을 권장합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다. "아, 그래서 비밀번호 평문 저장이 위험하다고 하셨군요.
SCRAM에 대해서도 알려주실 수 있나요?" SASL을 제대로 이해하면 더 안전한 카프카 클러스터를 구축할 수 있습니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - SASL/PLAIN은 개발 및 테스트 환경에서만 사용하고, 프로덕션에서는 SCRAM이나 GSSAPI를 사용하세요
- JAAS 설정 파일의 권한은 반드시 600 이하로 설정하여 비밀번호 노출을 방지하세요
- 이 카드뉴스는 "Apache Kafka 완전 정복" 코스의 13/15편입니다
2. SCRAM 인증 심화
김개발 씨가 PLAIN 인증에 대해 배운 뒤, 박시니어 씨에게 또 다른 질문을 던졌습니다. "PLAIN은 비밀번호가 평문이라 위험하다고 하셨는데, 비밀번호를 안전하게 저장하면서도 인증할 수 있는 방법은 없을까요?" 박시니어 씨가 미소를 지으며 답했습니다.
"그게 바로 SCRAM이에요."
**SCRAM(Salted Challenge Response Authentication Mechanism)**은 비밀번호를 해시 처리하여 안전하게 인증하는 SASL 메커니즘입니다. 마치 은행에서 비밀번호를 그대로 저장하지 않고, 복잡한 수학적 변환을 거친 값만 보관하는 것과 같습니다.
카프카는 SCRAM-SHA-256과 SCRAM-SHA-512 두 가지 버전을 지원합니다.
다음 코드를 살펴봅시다.
# server.properties - SCRAM-SHA-512 설정
listeners=SASL_PLAINTEXT://:9092
security.inter.broker.protocol=SASL_PLAINTEXT
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-512
sasl.enabled.mechanisms=SCRAM-SHA-512
# SCRAM 사용자 생성 (kafka-configs 명령어)
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--alter --add-config 'SCRAM-SHA-512=[password=my-secure-password]' \
--entity-type users --entity-name producer
# SCRAM 사용자 목록 확인
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--describe --entity-type users
# 클라이언트 JAAS 설정
KafkaClient {
org.apache.kafka.common.security.scram.ScramLoginModule required
username="producer"
password="my-secure-password";
};
김개발 씨는 SASL의 기본 개념을 이해한 뒤, 더 안전한 인증 방법이 없을지 고민하기 시작했습니다. PLAIN 방식의 취약점은 명확했습니다.
설정 파일에 비밀번호가 평문으로 노출되어 있다는 점, 그리고 네트워크를 통해 비밀번호가 전달될 때 암호화되지 않는다는 점이었습니다. 박시니어 씨가 화이트보드에 그림을 그리기 시작했습니다.
"SCRAM은 챌린지-응답 방식이에요. 서버가 난수를 보내면, 클라이언트가 비밀번호와 난수를 조합해 해시 값을 계산해서 응답하는 거죠." 그렇다면 SCRAM이란 정확히 무엇일까요?
쉽게 비유하자면, SCRAM은 마치 비밀번호가 적힌 봉투를 봉인하여 우체국에 맡기는 것과 같습니다. 우체국 직원(서버)은 봉투 안의 내용을 볼 필요 없이, 봉인이 정상적인지 외관만 확인하면 됩니다.
원본 비밀번호는 절대 네트워크를 통해 전송되지 않습니다. 대신 수학적 증명만 교환하죠.
PLAIN 방식에서는 어떤 문제가 있었을까요? 서버 측에 비밀번호를 평문으로 저장해야 했습니다.
데이터베이스가 유출되면 모든 사용자의 비밀번호가 고스란히 노출됩니다. 또한 클라이언트에서 서버로 비밀번호를 전송할 때도 평문으로 전달되므로, 네트워크 중간에 가로채는 공격에 취약합니다.
SCRAM은 이런 문제를 근본적으로 해결합니다. 먼저 서버에는 비밀번호 대신 Salt와 StoredKey, ServerKey가 저장됩니다.
클라이언트가 인증을 요청하면, 서버는 난수인 챌린지를 보냅니다. 클라이언트는 자신의 비밀번호와 챌린지를 조합하여 응답을 생성하고, 서버는 저장된 키로 이 응답을 검증합니다.
위의 설정을 한 줄씩 살펴보겠습니다. kafka-configs.sh 명령어로 SCRAM 사용자를 생성합니다.
--add-config 파라미터에 SCRAM-SHA-512=[password=...] 형식으로 비밀번호를 지정합니다. 이때 카프카 내부 토픽인 __cluster_metadata에 Salt와 해시 값이 저장됩니다.
클라이언트 측 JAAS 설정에서는 ScramLoginModule을 사용합니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 전자상거래 플랫폼에서 결제 서비스와 배송 서비스가 각각 다른 카프카 사용자로 인증한다고 가정해봅시다. SCRAM-SHA-512를 사용하면, 각 서비스의 비밀번호가 해시로 저장되므로 내부자가 데이터베이스에 접근하더라도 원본 비밀번호를 알 수 없습니다.
금융권과 같은 보안이 중요한 환경에서 특히 유용합니다. 하지만 주의할 점도 있습니다.
SCRAM 인증 정보가 카프카 내부 토픽에 저장된다는 점을 기억해야 합니다. 이 토픽이 암호화되지 않으면 의미가 없습니다.
따라서 SCRAM과 SSL/TLS를 함께 사용하는 것이 좋습니다. 또한 비밀번호 변경 시 클라이언트 재시작이 필요하므로, 비밀번호 관리 프로세스를 사전에 수립해야 합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. SCRAM의 원리를 이해한 김개발 씨는 감탄했습니다.
"비밀번호를 네트워크에 전송하지도, 서버에 평문으로 저장하지도 않다니, 정말 안전하겠네요!" SCRAM을 제대로 활용하면 PLAIN의 취약점을 보완하면서도 강력한 인증을 구현할 수 있습니다. 다음으로는 통신 자체를 암호화하는 SSL/TLS에 대해 알아보겠습니다.
실전 팁
💡 - SCRAM-SHA-512가 SHA-256보다 해시 길이가 길어 보안성이 높으므로 프로덕션에서는 SHA-512를 권장합니다
- 비밀번호 변경 시에는 클라이언트를 롤링 재시작하여 무중단으로 교체하세요
- 이 카드뉴스는 "Apache Kafka 완전 정복" 코스의 13/15편입니다
3. SSL/TLS 암호화 설정
김개발 씨가 보안 점검 결과를 받고 놀랐습니다. "네트워크 패킷 캡처를 하면 메시지 내용이 그대로 보인다고요?" 박시니어 씨가 진지하게 말했습니다.
"SASL로 인증은 했지만, 데이터 자체는 암호화되지 않았어요. 이제 SSL/TLS를 설정해서 통신을 암호화해야 합니다."
SSL/TLS는 클라이언트와 브로커 간의 모든 통신을 암호화하는 프로토콜입니다. 마치 은밀한 대화를 암호 용지에 적어서 전달하는 것과 같아서, 중간에 가로챈다고 해도 내용을 알 수 없습니다.
카프카에서는 Java의 JKS(Java KeyStore) 형식으로 인증서를 관리합니다.
다음 코드를 살펴봅시다.
# 1. 인증서 생성 (CA)
keytool -keystore kafka.ca.keystore.jks \
-alias CARoot -validity 365 \
-genkeypair -keyalg RSA -storetype JKS
# 2. 브로커 인증서 생성 및 서명
keytool -keystore kafka.server.keystore.jks \
-alias localhost -validity 365 \
-genkeypair -keyalg RSA -storetype JKS
# 3. server.properties - SSL 설정
listeners=SSL://:9093
ssl.keystore.location=/etc/kafka/ssl/kafka.server.keystore.jks
ssl.keystore.password=changeit
ssl.key.password=changeit
ssl.truststore.location=/etc/kafka/ssl/kafka.server.truststore.jks
ssl.truststore.password=changeit
ssl.client.auth=none
# 4. 프로듀서 SSL 설정
security.protocol=SSL
ssl.truststore.location=/etc/kafka/ssl/kafka.client.truststore.jks
ssl.truststore.password=changeit
김개발 씨는 보안 팀에서 받은 점검 결과를 보며 식은땀을 흘렸습니다. SASL/SCRAM으로 인증은 설정했지만, 메시지 내용 자체는 평문으로 전송되고 있었습니다.
개발 서버에서 테스트해보니 tcpdump로 패킷을 캡처하자 주문 정보와 고객 데이터가 고스란히 보였습니다. 박시니어 씨가 말했습니다.
"인증과 암호화는 다른 거예요. SASL은 '누구인지'를 확인하지만, 데이터가 안전하게 전달되는지는 SSL/TLS가 담당합니다." 그렇다면 SSL/TLS란 정확히 무엇일까요?
쉽게 비유하자면, SSL/TLS는 마치 투명한 유리관 대신 불투명한 강철 파이프로 통신로를 교체하는 것과 같습니다. 누가 파이프를 훔쳐보려 해도 내용물을 알 수 없습니다.
파이프 양끝에 있는 사람들만이 특별한 열쇠로 내용물을 확인할 수 있죠. 더 정확히 말하면, 공개키와 개인키라는 한 쌍의 열쇠를 사용하여 통신을 안전하게 암호화합니다.
SSL/TLS가 없던 시절에는 어떤 문제가 있었을까요? 데이터센터 내부망에서는 별 문제가 없었습니다.
하지만 클라우드 환경에서는 다릅니다. 같은 클라우드라도 다른 테넌트가 네트워크 트래픽을 스니핑할 수 있는 가능성이 존재합니다.
특히 AWS의 VPC 피어링이나 퍼블릭 서브넷을 경유하는 통신이라면 더더욱 위험합니다. 중간자 공격(Man-in-the-Middle)의 가능성도 무시할 수 없습니다.
SSL/TLS는 이런 위협을 근본적으로 차단합니다. 먼저 데이터 기밀성을 보장합니다.
암호화된 통신은 중간에 가로채더라도 복호화할 수 없습니다. 다음으로 데이터 무결성을 제공합니다.
전송 중에 데이터가 조작되면 감지할 수 있습니다. 무엇보다 서버 인증을 통해 연결하려는 대상이 진짜 카프카 브로커인지 확인할 수 있습니다.
위의 설정을 한 줄씩 살펴보겠습니다. 먼저 keytool 명령어로 CA(Certificate Authority) 인증서를 생성합니다.
이 CA 인증서로 브로커와 클라이언트의 인증서에 서명합니다. server.properties에서는 listeners를 SSL 프로토콜로 설정하고, KeyStore와 TrustStore의 경로를 지정합니다.
ssl.client.auth=none은 클라이언트 인증을 요구하지 않는다는 의미로, 일방향 SSL을 사용할 때 설정합니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 의료 정보 플랫폼에서 환자 데이터를 카프카로 전송한다고 가정해봅시다. 개인정보 보호법에 따라 데이터 전송 시 암호화가 의무화되어 있는 경우가 많습니다.
SSL/TLS를 적용하면 네트워크를 통한 데이터 유출을 방지할 수 있으며, 규제 요건도 충족할 수 있습니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 자체 서명 인증서(Self-Signed Certificate)를 프로덕션에 그대로 사용하는 것입니다. 이렇게 하면 클라이언트가 브로커의 신원을 제대로 검증할 수 없습니다.
가능하면 사내 CA나 Let's Encrypt 같은 공인 인증기관을 사용하세요. 또한 인증서 만료 일정을 관리하는 시스템을 구축해야 합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. SSL/TLS 설정을 완료한 후, 다시 패킷을 캡처해보니 이번에는 암호화된 데이터만 보였습니다.
"이제 데이터가 안전하게 전송되는군요!" 김개발 씨는 안도의 한숨을 내쉬었습니다. SSL/TLS를 설정하면 네트워크 통신의 기밀성과 무결성을 확실하게 보장할 수 있습니다.
다음으로는 특정 사용자나 서비스의 접근 권한을 세밀하게 제어하는 ACL에 대해 알아보겠습니다.
실전 팁
💡 - 프로덕션에서는 Let's Encrypt나 사내 PKI를 사용하여 신뢰할 수 있는 인증서를 발급받으세요
- 인증서 만료 30일 전에 알림을 설정하고, 자동 갱신 파이프라인을 구축하세요
- 이 카드뉴스는 "Apache Kafka 완전 정복" 코스의 13/15편입니다
4. ACL 기반 인가 설정
김개발 씨의 팀에 새로운 파트너사가 합류했습니다. "이 파트너사에는 주문 토픽만 읽을 수 있게 해주세요.
결제 토픽은 절대 보면 안 돼요." 김개발 씨는 고민에 빠졌습니다. SASL과 SSL로 인증과 암호화는 했지만, 누가 어떤 토픽에 접근할 수 있는지 제어하는 방법을 아직 모르기 때문입니다.
**ACL(Access Control List)**은 카프카에서 특정 사용자나 그룹의 접근 권한을 세밀하게 제어하는 인가 시스템입니다. 마치 빌딩의 각 층마다 출입 권한이 다른 보안 카드 리더기와 같습니다.
카프카 ACL은 리소스(토픽, 그룹, 클러스터)와 작업(읽기, 쓰기, 삭제 등)의 조합으로 권한을 정의합니다.
다음 코드를 살펴봅시다.
# server.properties - ACL 활성화
authorizer.class.name=kafka.security.authorizer.AclAuthorizer
allow.everyone.if.no.acl.found=false
super.users=User:admin
# 주문 토픽에 대한 읽기 권한 부여
bin/kafka-acls.sh --bootstrap-server localhost:9093 \
--add --allow-principal User:partner-service \
--operation Read --operation Describe \
--topic order-events
# 결제 토픽에 대한 쓰기 권한 부여
bin/kafka-acls.sh --bootstrap-server localhost:9093 \
--add --allow-principal User:payment-service \
--operation Write --operation Describe \
--topic payment-events
# ACL 목록 확인
bin/kafka-acls.sh --bootstrap-server localhost:9093 \
--list --topic order-events
김개발 씨는 파트너사의 접근 권한 설정을 맡게 되었습니다. SASL로 인증하고 SSL로 암호화까지 했지만, 파트너사가 주문 토픽만 읽고 결제 토픽은 접근하지 못하게 막는 방법이 필요했습니다.
모든 인증된 사용자가 모든 토픽에 접근할 수 있다면 보안의 의미가 없겠죠. 박시니어 씨가 말했습니다.
"ACL을 설정하면 돼요. 인증(Authentication)이 '누구인지' 확인하는 거라면, 인가(Authorization)는 '무엇을 할 수 있는지' 결정하는 거예요." 그렇다면 ACL이란 정확히 무엇일까요?
쉽게 비유하자면, ACL은 마치 도서관의 각 열람실마다 출입증을 요구하는 시스템과 같습니다. 일반 열람실은 누구나 들어갈 수 있지만, 특별 자료실은 사서의 허락이 필요합니다.
전문 자료실은 관장의 승인이 있어야만 출입 가능하죠. 카프카 ACL도 이처럼 리소스별로 다른 수준의 접근 권한을 설정할 수 있습니다.
ACL이 없던 시절에는 어떤 문제가 있었을까요? 모든 인증된 사용자가 모든 토픽에 접근할 수 있었습니다.
개발 환경에서는 편리했지만, 프로덕션에서는 심각한 보안 문제가 됩니다. 어떤 서비스가 실수로 결제 토픽을 구독해서 고객의 신용카드 정보를 읽어버릴 수도 있습니다.
또는 잘못된 서비스가 주문 토픽에 쓰기 권한을 가져서 가짜 주문을 발행할 수도 있죠. ACL은 이런 위험을 정밀하게 차단합니다.
카프카 ACL은 **최소 권한 원칙(Principle of Least Privilege)**을 실현합니다. 각 서비스에 필요한 권한만 부여하고, 나머지는 모두 거부합니다.
또한 allow.everyone.if.no.acl.found=false를 설정하면, ACL에 명시되지 않은 모든 접근이 기본적으로 차단됩니다. 위의 설정을 한 줄씩 살펴보겠습니다.
먼저 authorizer.class.name에 AclAuthorizer를 지정하여 ACL 기반 인가를 활성화합니다. super.users는 ACL 제한을 받지 않는 관리자 계정으로, 긴급 상황에서 사용합니다.
kafka-acls.sh 명령어로 특정 사용자에게 토픽에 대한 Read, Write, Describe 등의 권한을 부여합니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 대형 이커머스 플랫폼에서 여러 부서가 카프카를 공유한다고 가정해봅시다. 마케팅팀에는 고객 행동 토픽의 읽기 권한만 부여하고, 재고팀에는 재고 토픽의 쓰기 권한을 부여합니다.
재무팀의 결제 토픽은 아무도 읽을 수 없도록 설정하죠. 이처럼 부서별로 권한을 분리하면 데이터 유출 위험을 최소화할 수 있습니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 allow.everyone.if.no.acl.found=true(기본값)를 그대로 두는 것입니다.
이렇게 하면 ACL에 명시되지 않은 리소스에 모든 사용자가 접근할 수 있습니다. 반드시 false로 설정하고, 필요한 권한을 명시적으로 부여하세요.
또한 ACL 변경 이력을 문서화하고, 정기적으로 감사(Audit)를 수행해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
ACL 설정을 완료한 후, 파트너사 서비스에서 주문 토픽만 정상적으로 읽히고 결제 토픽은 접근이 거부되는 것을 확인했습니다. "이제 원하는 만큼만 권한을 줄 수 있겠네요!" ACL을 설정하면 인증된 사용자라도 필요한 리소스에만 접근할 수 있도록 보안을 한층 더 강화할 수 있습니다.
다음으로는 클라이언트와 서버가 서로의 신원을 확인하는 mTLS에 대해 알아보겠습니다.
실전 팁
💡 - allow.everyone.if.no.acl.found는 반드시 false로 설정하여 기본 접근을 차단하세요
- ACL 규칙을 버전 관리(Git 등)에 등록하여 변경 이력을 추적하세요
- 이 카드뉴스는 "Apache Kafka 완전 정복" 코스의 13/15편입니다
5. mTLS 상호 인증
김개발 씨가 박시니어 씨에게 물었습니다. "SSL은 브로커의 신원만 확인하는 거죠?
클라이언트의 신원도 확인할 수는 없나요?" 박시니어 씨가 고개를 끄덕였습니다. "그게 바로 mTLS, 양방향 TLS 인증이에요.
서버도 클라이언트를 검증하고, 클라이언트도 서버를 검증하는 거죠."
**mTLS(Mutual TLS)**는 서버와 클라이언트가 서로의 인증서를 교환하고 검증하는 양방향 인증 방식입니다. 마치 은행 창구에서 고객이 신분증을 제시하는 것뿐만 아니라, 은행 측에서도 정식 영업점임을 증명하는 것과 같습니다.
일반 SSL이 서버 인증만 수행하는 것과 달리, mTLS는 클라이언트 인증까지 함께 수행합니다.
다음 코드를 살펴봅시다.
# server.properties - mTLS 설정
listeners=SSL://:9093
ssl.keystore.location=/etc/kafka/ssl/kafka.server.keystore.jks
ssl.keystore.password=changeit
ssl.truststore.location=/etc/kafka/ssl/kafka.server.truststore.jks
ssl.truststore.password=changeit
ssl.client.auth=required
# 클라이언트 설정 (Java 프로듀서)
Properties props = new Properties();
props.put("bootstrap.servers", "kafka-broker:9093");
props.put("security.protocol", "SSL");
props.put("ssl.truststore.location", "/etc/kafka/client.truststore.jks");
props.put("ssl.truststore.password", "changeit");
props.put("ssl.keystore.location", "/etc/kafka/client.keystore.jks");
props.put("ssl.keystore.password", "changeit");
props.put("ssl.key.password", "changeit");
김개발 씨는 SSL/TLS 설정을 마친 후, 한 가지 의문이 생겼습니다. 현재 설정에서는 클라이언트가 브로커의 인증서를 검증하지만, 브로커는 클라이언트의 신원을 확인하지 않습니다.
즉, 유효한 인증서를 가진 클라이언트라면 누구나 접속할 수 있다는 뜻이었습니다. 박시니어 씨가 설명했습니다.
"일반 SSL은 클라이언트가 서버를 믿는 방식이에요. 하지만 서버 입장에서는 접속하는 클라이언트가 진짜 우리 서비스인지 알 수 없죠.
mTLS는 이 문제를 해결해요." 그렇다면 mTLS란 정확히 무엇일까요? 쉽게 비유하자면, mTLS는 마치 양쪽 모두 신분증을 제시하고 확인하는 국경 검문소와 같습니다.
출국하는 여행자도 여권을 보여주고, 입국 심사관도 공무원 신분증을 제시합니다. 양쪽 모두 상대방의 정체를 확인한 후에야 통과가 허용됩니다.
이처럼 mTLS는 통신의 양쪽 끝에서 서로를 검증합니다. 일반 SSL에서는 어떤 문제가 있었을까요?
일반 SSL(서버 인증만)에서는 SSL/TLS 연결 자체는 암호화되지만, 클라이언트의 신원 확인은 SASL에 의존해야 했습니다. 즉, 암호화와 인증이 별도의 레이어에서 처리됩니다.
이런 구조에서는 설정이 복잡해지고, 두 가지 보안 레이어를 모두 올바르게 구성해야 했습니다. mTLS는 인증과 암호화를 하나의 레이어에서 해결합니다.
먼저 양방향 신원 검증이 이루어집니다. 브로커는 클라이언트의 인증서가 신뢰할 수 있는 CA에서 발급되었는지 확인하고, 클라이언트도 브로커의 인증서를 검증합니다.
또한 인증서 기반의 접근 제어가 가능합니다. 특정 CA에서 발급한 인증서만 접근을 허용하거나, 인증서의 CN(Common Name)으로 ACL을 구성할 수 있습니다.
위의 설정을 한 줄씩 살펴보겠습니다. 핵심은 ssl.client.auth=required 설정입니다.
이 한 줄이 브로커가 클라이언트의 인증서를 요구하도록 만듭니다. 클라이언트 측에서는 ssl.keystore.location에 클라이언트 인증서가 포함된 KeyStore를 지정합니다.
서버의 TrustStore에는 클라이언트 CA의 인증서가, 클라이언트의 TrustStore에는 서버 CA의 인증서가 각각 포함되어 있어야 합니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 글로벌 금융 서비스에서 여러 지역의 마이크로서비스가 카프카에 연결된다고 가정해봅시다. mTLS를 적용하면 각 지역 서비스에 고유한 클라이언트 인증서를 발급하고, 해당 인증서로만 접근을 허용할 수 있습니다.
인증서가 유출되면 해당 인증서만 폐기하면 되므로, 비밀번호 기반 인증보다 키 관리가 훨씬 유연합니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 모든 서비스에 동일한 클라이언트 인증서를 사용하는 것입니다. 이렇게 하면 특정 서비스에서 인증서가 유출되었을 때 전체 서비스에 영향을 줍니다.
서비스별로 고유한 인증서를 발급하고, 만료 기간도 다르게 설정하세요. 또한 인증서 폐기 목록(CRL)이나 OCSP를 설정하여 해지된 인증서를 차단해야 합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. mTLS를 설정하고 테스트해보니, 인증서가 없는 클라이언트는 연결조차 할 수 없었습니다.
"서버도 클라이언트를 검증하니까 진짜 안전하겠네요!" 김개발 씨는 만족스러워했습니다. mTLS를 도입하면 단방향 SSL보다 강력한 보안을 구현할 수 있습니다.
다음으로는 브로커 간 통신도 보호하는 방법에 대해 알아보겠습니다.
실전 팁
💡 - 서비스별로 고유한 클라이언트 인증서를 발급하여 개별적으로 폐기할 수 있게 하세요
- 인증서 자동 발급 및 갱신을 위한 HashiCorp Vault나 cert-manager를 도입하는 것을 고려하세요
- 이 카드뉴스는 "Apache Kafka 완전 정복" 코스의 13/15편입니다
6. 브로커 간 통신 보안
김개발 씨가 클라이언트-브로커 간 보안을 모두 설정한 후, 박시니어 씨에게 자랑했습니다. "이제 카프카 보안이 완벽하게 끝났죠?" 박시니어 씨가 빙그레 웃으며 말했습니다.
"클라이언트와 브로커 사이만 보호하면 끝일까요? 브로커들끼리 통신할 때도 데이터가 오가는데, 그 부분은?"
브로커 간 통신 보안은 카프카 클러스터 내의 브로커들이 서로 통신할 때 인증과 암호화를 적용하는 설정입니다. 마치 회사 내부의 부서 간 문서 교환에도 보안 봉투를 사용하는 것과 같습니다.
외부에서의 공격뿐만 아니라, 내부 네트워크에서의 감청 위험까지 방어해야 합니다.
다음 코드를 살펴봅시다.
# server.properties - 브로커 간 통신 보안
# 클라이언트용 리스너 (SASL_SSL)
listeners=SASL_SSL://:9092
advertised.listeners=SASL_SSL://kafka1.example.com:9092
# 브로커 간 통신용 리스너 (별도 설정)
inter.broker.listener.name=BROKER_SECURE
listener.security.protocol.map=BROKER_SECURE:SASL_SSL,EXTERNAL:SASL_SSL
# 브로커 간 SASL 메커니즘
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-512
# 브로커 간 SSL 설정
ssl.keystore.location=/etc/kafka/ssl/broker.keystore.jks
ssl.keystore.password=changeit
ssl.truststore.location=/etc/kafka/ssl/broker.truststore.jks
ssl.truststore.password=changeit
김개발 씨는 클라이언트-브로커 간 보안 설정을 마무리하면서, 모든 보안 조치가 끝났다고 생각했습니다. 하지만 박시니어 씨의 질문에 뭔가 빠뜨린 게 있다는 걸 깨달았습니다.
카프카 클러스터는 여러 대의 브로커로 구성되고, 브로커들 사이에도 데이터 복제와 메타데이터 동기화 통신이 이루어집니다. "브로커 간 통신도 보호해야 하나요?
같은 클러스터 안에 있는데요?" 김개발 씨가 의아하게 물었습니다. 박시니어 씨가 대답했습니다.
"클러스터 내부라고 해서 안전하지는 않아요. 제로 트러스트(Zero Trust) 원칙을 적용해야 합니다." 그렇다면 브로커 간 통신 보안이란 정확히 무엇일까요?
쉽게 비유하자면, 이것은 마치 회사 내부의 부서 간 문서 이동에도 보안 봉투를 사용하는 것과 같습니다. 외부에서 오는 문서만 검사하는 것이 아니라, 같은 건물 안에서 부서 간에 전달되는 문서도 보안 봉투에 넣어서 이동시킵니다.
내부 직원의 정보 유출이나 해킹된 내부 서버로부터의 공격까지 방어할 수 있죠. 브로커 간 통신이 보호되지 않으면 어떤 문제가 있을까요?
카프카 클러스터에서 브로커 간에는 파티션 리더 선출, 데이터 복제, 컨트롤러 메시지 등 민감한 정보가 오갑니다. 이 통신이 평문이라면, 클러스터 내부의 한 대 브로커가 compromise(해킹)되었을 때 전체 클러스터의 데이터가 노출될 수 있습니다.
또한 내부망에서 패킷 캡처만으로도 파티션 데이터와 컨트롤러 정보를 읽을 수 있습니다. 브로커 간 보안은 이런 내부 위협을 차단합니다.
먼저 inter.broker.listener.name 설정으로 브로커 간 통신에 별도의 보안 프로토콜을 적용합니다. 클라이언트용 리스너와 분리하여 관리할 수 있습니다.
listener.security.protocol.map에서 각 리스너 이름에 대해 어떤 보안 프로토콜을 사용할지 매핑합니다. 이렇게 하면 클라이언트와 브로커 간, 브로커와 브로커 간에 서로 다른 보안 수준을 적용할 수 있습니다.
위의 설정을 한 줄씩 살펴보겠습니다. listeners에서는 클라이언트용 리스너와 내부 통신용 리스너를 모두 정의합니다.
inter.broker.listener.name=BROKER_SECURE로 브로커 간 통신이 BROKER_SECURE라는 이름의 리스너를 사용하도록 지정합니다. sasl.mechanism.inter.broker.protocol에서 브로커 간 인증에 SCRAM-SHA-512를 사용하도록 설정합니다.
이렇게 하면 브로커 간 통신이 SASL 인증과 SSL 암호화 모두로 보호됩니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 3개의 데이터센터에 걸쳐 카프카 클러스터를 운영한다고 가정해봅시다. 데이터센터 간 통신은 공용 네트워크를 경유할 수 있으므로, 브로커 간 통신에 SSL/TLS 암호화가 필수입니다.
특히 크로스 데이터센터 복제(MirrorMaker 2)를 사용하는 경우, 원격 브로커와의 통신을 반드시 암호화해야 합니다. 많은 글로벌 기업에서 이런 구조를 사용하고 있습니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 브로커 간 통신에 SSL/TLS만 적용하고 SASL 인증은 생략하는 것입니다.
암호화만으로는 충분하지 않습니다. 브로커 간에도 서로의 신원을 확인해야 합니다.
또한 브로커 간 통신에 SSL을 적용하면 CPU 사용량이 증가하므로, 하드웨어 가속(AES-NI)을 활용하거나 성능 영향을 사전에 테스트해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
브로커 간 통신 보안까지 설정을 완료한 후, 김개발 씨는 카프카 클러스터의 전체 통신 경로가 보호되는 것을 확인했습니다. "클라이언트에서 브로커, 브로커에서 브로커까지 모두 암호화되네요!" 브로커 간 통신 보안까지 설정하면 카프카 클러스터의 모든 통신 경로가 보호됩니다.
마지막으로 보안 설정의 베스트 프랙티스를 정리해보겠습니다.
실전 팁
💡 - 브로커 간 통신에도 클라이언트와 동일한 수준의 인증과 암호화를 적용하세요
- listener.security.protocol.map을 활용하여 클라이언트용과 브로커 간 통신을 분리 관리하세요
- 이 카드뉴스는 "Apache Kafka 완전 정복" 코스의 13/15편입니다
7. 보안 설정 베스트 프랙티스
카프카 보안 설정을 모두 마친 김개발 씨가 박시니어 씨에게 최종 확인을 요청했습니다. "이제 보안이 완벽한 건가요?" 박시니어 씨가 잠시 생각하더니 말했습니다.
"설정은 잘 했어요. 하지만 보안은 설정만으로 끝나지 않아요.
운영하면서 지켜야 할 원칙들이 있죠."
보안 설정 베스트 프랙티스는 카프카 클러스터를 안전하게 운영하기 위한 종합적인 가이드라인입니다. 마치 건물을 지을 때 설계도만 잘 그리는 게 아니라, 완공 후에도 정기적인 안전 점검과 관리가 필요한 것과 같습니다.
기술적 설정뿐만 아니라 운영 프로세스와 모니터링까지 포함하는 전체적인 보안 체계가 필요합니다.
다음 코드를 살펴봅시다.
# 보안 점검 체크리스트 스크립트
#!/bin/bash
# 1. 열린 포트 확인
echo "=== 브로커 포트 상태 ==="
netstat -tlnp | grep -E '9092|9093'
# 2. 인증서 만료일 확인
echo "=== 인증서 만료일 ==="
for cert in /etc/kafka/ssl/*.jks; do
echo "$cert: $(keytool -list -v -keystore $cert \
-storepass changeit 2>/dev/null | grep 'Valid until')"
done
# 3. ACL 규칙 백업
echo "=== ACL 백업 ==="
bin/kafka-acls.sh --bootstrap-server localhost:9093 --list \
> /backup/acl-rules-$(date +%Y%m%d).txt
# 4. SASL 사용자 목록
echo "=== 등록된 사용자 ==="
bin/kafka-configs.sh --bootstrap-server localhost:9093 \
--describe --entity-type users
김개발 씨는 SASL 인증, SSL/TLS 암호화, ACL 인가, mTLS, 브로커 간 보안까지 모든 보안 설정을 완료했습니다. 이제 카프카 클러스터는 꽤나 견고한 보안을 갖추게 되었습니다.
하지만 박시니어 씨의 말에 김개발 씨는 다시 생각에 빠졌습니다. "보안은 설정만으로 끝나지 않는다"는 말의 의미를 곱씹으며 말이죠.
"보안 설정은 출발점일 뿐이에요." 박시니어 씨가 화이트보드에 핵심 원칙들을 적기 시작했습니다. "실제 보안은 운영 과정에서 지켜지는 거예요." 그렇다면 보안 베스트 프랙티스란 무엇을 의미할까요?
쉽게 비유하자면, 이것은 마치 새로운 보안 시스템이 설치된 건물의 관리 매뉴얼과 같습니다. 출입 통제 시스템을 설치했다고 해서 끝이 아닙니다.
정기적으로 보안 카드를 교체하고, 폐지된 카드를 회수하며, 출입 기록을 감사하고, 시스템을 업데이트해야 합니다. 카프카 보안도 이와 같은 지속적인 관리가 필요합니다.
보안을 설정만 하고 방치하면 어떤 문제가 있을까요? 가장 흔한 문제는 인증서 만료입니다.
SSL/TLS 인증서에는 유효 기간이 있으며, 만료되면 브로커 간 통신이 끊어집니다. 또한 비밀번호 관리가 소홀해지기 쉽습니다.
퇴사한 직원의 계정이 여전히 활성화되어 있거나, 모든 서비스가 동일한 비밀번호를 공유하는 경우가 많습니다. 시간이 지나면서 ACL 규칙이 누적되어, 어떤 권한이 왜 부여되었는지 알 수 없게 되기도 합니다.
보안 베스트 프랙티스는 이런 문제를 체계적으로 예방합니다. 첫 번째는 제로 트러스트(Zero Trust) 원칙입니다.
"신뢰하되 검증하라"가 아니라, "절대 신뢰하지 말고 항상 검증하라"는 철학입니다. 내부망이라고 해서 통신을 신뢰하지 않고, 모든 통신에 인증과 암호화를 적용합니다.
두 번째는 최소 권한 원칙입니다. 각 서비스에 필요한 최소한의 권한만 부여합니다.
세 번째는 **방어의 심화(Depth in Defense)**입니다. 여러 보안 계층을 겹쳐서, 한 계층이 뚫려도 다른 계층이 방어합니다.
위의 스크립트를 한 줄씩 살펴보겠습니다. 이 스크립트는 정기적인 보안 점검을 자동화합니다.
첫 번째로 열린 포트를 확인하여 불필요한 포트가 노출되지 않았는지 검사합니다. 두 번째로 SSL 인증서의 만료일을 확인하여 갱신 시기를 놓치지 않도록 합니다.
세 번째로 ACL 규칙을 백업하여 변경 이력을 보존합니다. 네 번째로 등록된 SASL 사용자 목록을 확인하여 불필요한 계정이 있는지 점검합니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 대규모 카프카 클러스터를 운영하는 기업에서는 매월 보안 점검을 자동화하고, 분기별로 보안 감사를 수행합니다.
Prometheus와 Grafana로 보안 관련 메트릭을 모니터링하고, 인증서 만료 30일 전에 PagerDuty 알림을 설정합니다. 또한 HashiCorp Vault를 사용하여 비밀번호와 인증서를 중앙에서 관리하고, 자동 갱신 파이프라인을 구축합니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 보안 설정을 한 번만 하고 잊어버리는 것입니다.
보안은 지속적인 프로세스입니다. 새로운 서비스가 추가될 때마다 적절한 권한을 부여하고, 서비스가 종료되면 권한을 회수해야 합니다.
또한 카프카 버전 업그레이드 시 보안 설정이 변경될 수 있으므로, 릴리스 노트의 보안 관련 변경 사항을 반드시 확인해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 보안 베스트 프랙티스 설명을 들은 김개발 씨는 노트를 꼼꼼히 적었습니다. "보안은 설정이 아니라 프로세스군요.
앞으로 정기적으로 점검하고 관리하겠습니다!" 보안 베스트 프랙티스를 따르면 카프카 클러스터를 장기적으로 안전하게 운영할 수 있습니다. 다음 카드뉴스에서는 카프카 모니터링과 운영에 대해 알아보겠습니다.
실전 팁
💡 - 제로 트러스트 원칙을 기반으로 내부망 통신도 반드시 보안하세요
- 인증서 만료, ACL 변경, 사용자 관리를 자동화하는 보안 점검 파이프라인을 구축하세요
- 보안 관련 설정과 변경 이력은 Git 등 버전 관리 시스템에서 관리하세요
- 다음 카드뉴스에서는 카프카 모니터링과 운영에 대해 다룹니다
- 이 카드뉴스는 "Apache Kafka 완전 정복" 코스의 13/15편입니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
카프카 모니터링과 운영 완벽 가이드
Apache Kafka의 모니터링과 운영 실무를 다룹니다. JMX 메트릭부터 Prometheus+Grafana, 컨슈머 랙 알림, 로그 관리, 매니지먼트 도구까지 카프카를 안정적으로 운영하는 데 필요한 모든 것을 배웁니다.
Kafka Connect 완벽 가이드
Kafka Connect를 활용하여 외부 시스템과 카프카를 손쉽게 연동하는 방법을 배웁니다. Source Connector와 Sink Connector의 개념부터 JDBC, Elasticsearch 연동까지 실무 예제와 함께 알아봅니다.
Kafka CLI 명령어 완벽 실습 가이드
카프카의 핵심 CLI 명령어를 실습 중심으로 학습합니다. 토픽 관리부터 메시지 송수신, 컨슈머 그룹 관리, 오프셋 제어, 브로커 설정 확인까지 터미널에서 직접 실행해보며 카프카의 동작 원리를 체득할 수 있습니다.
토픽과 파티션의 이해 완벽 가이드
Kafka의 핵심 데이터 구조인 토픽과 파티션의 개념부터 오프셋, 메시지 순서 보장, 삭제 정책까지 실무에 필요한 모든 내용을 다룹니다. 카프카를 제대로 이해하기 위해 반드시 알아야 할 기초를 탄탄하게 다집니다.
Kafka 설치 및 환경 설정 완벽 가이드
Apache Kafka의 설치부터 환경 설정까지 단계별로 안내합니다. JDK 설치, ZooKeeper 구성, Kafka 브로커 설정, Docker Compose 활용, KRaft 모드까지 실무에 필요한 모든 환경 구축 방법을 다룹니다.