Data & Platform/Event Streaming
Kafka - 12. operations
운영과 보안 — 클러스터 건강 유지와 "누가 뭘 할 수 있는가" 통제
Kafka를 기본 설정으로 두면 통신이 평문(PLAINTEXT)이고, 아무나 topic에 쓸 수 있다. 개발/테스트에만 허용되는 상태다. 프로덕션에선 (1) 클러스터가 건강한지 감시하고, (2) 누가 접속하고 무엇을 할 수 있는지 통제해야 한다.
이 두 축은 독립이 아니다 — 보안이 없으면 누구나 topic을 지울 수 있고, 모니터링이 없으면 broker 장애를 알 수 없다. 프로덕션 운영은 SASL_SSL/SCRAM 설정, 인증서, ACL, JMX 모니터링, KRaft quorum 관리가 얽힌 종합 작업이다. 각 설정이 어떤 위협을 막고 어떤 비용이 드는지를 짚으면서, broker와 client에 보안을 설정하는 단계를 한 호흡으로 추적한다.
운영의 두 축
- 클러스터 건강 — broker가 살아있고, 복제가 따라잡고, 리더가 정상인가.
- 보안 — 인증(누가), 인가(뭘 할 수 있는가), 암호화(통신 노출 여부).
클러스터 건강 — KRaft와 복제 감시
Kafka 4.x는 KRaft로 메타데이터를 관리한다(장 01·06). 운영자가 봐야 할 것:
- URP(under-replicated partitions) — ISR < 복제본 수. 복제가 안 따라잡아 장애 내성 저하. 핵심 경보(장 06).
- ISR shrink/expand 빈도 — 잦으면 broker 불건강(GC·디스크·네트워크).
- controller 활성 상태 — active controller는 1개여야 정상.
- request latency — broker 응답 지연.
JMX(보통 포트 9999)로 메트릭 수집(Prometheus/JMX exporter). URP/ISR 모니터링 없이는 장애 감지 불가.
보안 3계층 — 암호화·인증·인가를 분리하는 이유
| 계층 | 담당 | 수단 |
|---|---|---|
| 암호화(encryption) | 통신 내용 보호 | SSL/TLS |
| 인증(authentication) | 접속 주체 확인 | SASL(PLAIN/SCRAM/GSSAPI/OAUTHBEARER) 또는 mTLS |
| 인가(authorization) | 권한 제어 | ACL(kafka-acls.sh) |
왜 3계층을 분리하는가 — 심층 방어(defense in depth). 한 계층이 뚫려도 다른 층이 방어.
각 계층이 막는 구체적 위협
- 암호화가 없으면: 네트워크 중간자(man-in-the-middle)가 통신을 도청할 수 있다. PLAINTEXT 환경에선 같은 네트워크 세그먼트의 누구나
tcpdump로 메시지를 볼 수 있다. - 인증이 없으면: 누구나 broker에 접속해 topic을 읽고 쓸 수 있다. 내부 네트워크라도 "신뢰할 수 있는 클라이언트만"을 강제할 수 없다.
- 인가가 없으면: 인증된 사용자라도 모든 topic·group에 접근할 수 있다. "결제 서비스는 payments topic만, 분석 서비스는 analytics topic만" 같은 최소 권한 원칙을 못 지킨다.
이 세 가지를 한꺼번에 켜야 "암호화된 통신 위에서 인증된 사용자가 자기 권한 내에서만 작업하는" 프로덕션 수준 보안이 된다. 하나라도 빠지면 특정 공격 벡터가 열린다 — 예를 들어 인증만 켜고 암호화를 안 켜면(SASL_PLAINTEXT), 자격증명이 평문으로 전송돼서 도청에 취약해진다.
SASL 메커니즘 — PLAIN은 평문이다
| 메커니즘 | 비고 |
|---|---|
| PLAIN | 자격증명 평문 전송 → 반드시 SSL과 함께(SASL_SSL) |
| SCRAM-SHA-256/512 | 자격증명이 broker에 저장(해시). SSL 없이도 상대적 안전 |
| GSSAPI(Kerberos) | 기업 환경, 복잡 |
| OAUTHBEARER | JWT/OAuth 연동 |
자주 틀리는 함정: "SASL만 켜면 안전하다" — SASL/PLAIN은 평문 → SSL 없이면 도청 취약. 반드시
SASL_SSL.
보안 프로토콜 조합
security.protocol |
암호화 | 인증 | 용도 |
|---|---|---|---|
PLAINTEXT |
X | X | 개발 전용 |
SSL |
O | mTLS(선택) | TLS 암호화 |
SASL_PLAINTEXT |
X | SASL | 인증만 (평문) |
SASL_SSL |
O | SASL | 프로덕션 표준 |
SASL_SSL/SCRAM 적용 방법 — 단계별 가이드
이제 실제로 보안을 어떻게 켜는지 단계별로 보자. SCRAM-SHA-256 + SSL 조합을 예로.
1단계: SCRAM 자격증명 생성 (broker에 사용자 추가)
# Kafka 4.3 — broker에 SCRAM 사용자 'alice' 추가
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--alter --add-config 'SCRAM-SHA-256=[password=alice-secret]' \
--entity-type users --entity-name alice
# 확인
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--describe --entity-type users --entity-name alice
이 자격증명은 KRaft 메타데이터에 저장된다(구 ZK와 다름).
2단계: broker 설정 (server.properties)
# 리스너 설정
listeners=SASL_SSL://:9092
advertised.listeners=SASL_SSL://broker1.example.com:9092
# SASL 메커니즘
sasl.enabled.mechanisms=SCRAM-SHA-256
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-256
# 인가(Authorizer) 활성화
authorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizer
# ACL 없을 때 기본 거부
allow.everyone.if.no.acl.found=false
# super.users (모든 권한)
super.users=User:admin
# SSL 설정
ssl.keystore.location=/etc/kafka/keystore.jks
ssl.keystore.password=changeit
ssl.key.password=changeit
ssl.truststore.location=/etc/kafka/truststore.jks
ssl.truststore.password=changeit
3단계: SSL 인증서 준비 (keytool)
# 1. 키스토어 생성 (broker 인증서)
keytool -keystore /etc/kafka/keystore.jks -alias broker1 -validity 365 \
-genkey -keyalg RSA -dname "CN=broker1.example.com" \
-storepass changeit -keypass changeit
# 2. CA 인증서로 서명 (실제 환경)
# (자체 서명 인증서는 학습용; 프로덕션은 정식 CA 사용)
# 3. 트러스트스토어 생성 (client가 broker 인증서 검증용)
keytool -keystore /etc/kafka/truststore.jks -alias CARoot -import \
-file ca-cert -storepass changeit -noprompt
4단계: client 설정 (producer/consumer)
# 보안 프로토콜
security.protocol=SASL_SSL
sasl.mechanism=SCRAM-SHA-256
# JAAS (자격증명)
sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required \
username="alice" \
password="alice-secret";
# SSL (broker 인증서 검증)
ssl.truststore.location=/etc/kafka/client-truststore.jks
ssl.truststore.password=changeit
또는 JAAS 파일 방식 (kafka_client_jaas.conf):
KafkaClient {
org.apache.kafka.common.security.scram.ScramLoginModule required
username="alice"
password="alice-secret";
};
5단계: ACL 부여
# alice에게 my-topic 쓰기 권한
bin/kafka-acls.sh --bootstrap-server localhost:9092 \
--add --allow-principal User:alice \
--operation WRITE --operation READ \
--topic my-topic
# alice에게 consumer group 'my-group' 권한
bin/kafka-acls.sh --bootstrap-server localhost:9092 \
--add --allow-principal User:alice \
--operation READ \
--group my-group
# ACL 확인
bin/kafka-acls.sh --bootstrap-server localhost:9092 --list
6단계: 보안 적용 후 producer/consumer 실행
# 보안 설정이 담긴 client properties 파일로 실행
bin/kafka-console-producer.sh --topic my-topic \
--producer.config /etc/kafka/client.properties \
--bootstrap-server broker1.example.com:9092
bin/kafka-console-consumer.sh --topic my-topic \
--consumer.config /etc/kafka/client.properties \
--bootstrap-server broker1.example.com:9092
보안 설정은 broker 재기동이 필요하다. 학습 환경에서는 무거울 수 있으니, PLAINTEXT 환경에서 동작을 먼저 확인한 뒤 보안을 적용하라.
ACL — 리소스와 작업
ACL은 리소스별로 "누가(principal) 무슨 작업(operation)을 할 수 있는가"를 정의한다:
| 리소스 종류 | 작업 예 |
|---|---|
topic |
READ, WRITE, CREATE, DELETE, ALTER, DESCRIBE |
group |
READ, DESCRIBE |
cluster |
CLUSTER_ACTION, DESCRIBE |
transactionalId |
WRITE, DESCRIBE |
# User:bob에게 orders topic 읽기 + my-group group 읽기
bin/kafka-acls.sh --add \
--allow-principal User:bob \
--operation READ --topic orders \
--operation READ --group my-group \
--bootstrap-server localhost:9092
# prefix 매칭 (모든 'logs-' topic에 쓰기)
bin/kafka-acls.sh --add \
--allow-principal User:logger \
--operation WRITE --topic logs- --resource-pattern-type prefixed \
--bootstrap-server localhost:9092
ACL 설계 원칙 — 최소 권한
프로덕션에선 "기본 거부(deny by default)" + "필요한 권한만 허용"이 원칙이다. allow.everyone.if.no.acl.found=false로 두면, ACL이 없는 리소스는 아무도 접근 못 한다. 각 서비스 consumer/producer에 필요한 최소 권한만 부여한다:
- 결제 서비스 consumer →
paymentstopic READ +payment-processorsgroup READ. - 로그 수집 producer →
app-logstopic WRITE. - admin → super.users로 전체 권한(운영자 전용).
prefix 매칭(--resource-pattern-type prefixed)을 쓰면 logs-* topic에 한번에 권한을 줄 수 있어, 새 topic이 생겨도 ACL을 매번 안 추가해도 된다. 단, prefix가 너무 넓으면 의도치 않은 topic까지 허용되므로 범위를 신중하게 잡아야 한다.
JMX 모니터링 설정
broker의 JMX 메트릭을 노출하려면:
# broker 기동 시 JMX 포트 지정
export JMX_PORT=9999
bin/kafka-server-start.sh config/server.properties
핵심 지표:
| 지표 | 의미 |
|------|------|
| kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions | URP 수 (0이 정상) |
| kafka.server:type=ReplicaManager,name=IsrShrinksPerSec | ISR 축소 빈도 |
| kafka.network:type=RequestMetrics,name=TotalTimeMs | 요청 지연 |
| kafka.controller:type=KafkaController,name=ActiveControllerCount | 활성 controller (1이 정상) |
| kafka.server:type=BrokerState | broker 상태 (RUNNING이 정상) |
Prometheus + JMX Exporter로 수집·Grafana로 시각화하는 게 운영 표준.
KRaft 운영 — broker 추가/제거
- broker 추가: 새 broker 기동 + partition 복제 이동(
kafka-reassign-partitions.sh). - controller 추가/제거: quorum 재구성(KIP-853 동적 quorum,
controller.quorum.bootstrap.servers).
# partition reassignment (broker 추가 후 부하 분산)
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
--topics-to-move-json-file topics.json \
--broker-list "0,1,2" --generate
# → 생성된 계획으로 --execute
broker 추가가 만드는 작업 흐름
운영자가 새 broker를 클러스터에 추가하면, 그 broker는 빈 상태로 합류한다 — 기존 partition이 자동으로 옮겨오지 않는다. partition을 새 broker에 분산하려면 명시적 reassignment가 필요하다. --generate로 "현재 할당 → 제안된 할당" 계획을 뽑고, --execute로 적용한다. 이 과정에서 대량 복제가 일어나므로 --throttle로 운영 트래픽 보호가 필수다(장 06).
controller quorum 변경은 KRaft 특유 작업이다. ZK 시절엔 ZK 앙상블을 별도로 관리했지만, KRaft에선 broker들이 controller 역할을 겸하거나 분리한다. controller를 추가/제거하려면 controller.quorum.bootstrap.servers와 KIP-853 동적 quorum 재구성을 쓴다 — 자세한 절차는 KIP-853과 operations/kraft.md를 따른다(미검증: 세부 단계는 1차 출처 확인).
ZK 시절의 운영 명령(
--zookeeper)은 4.x에서 동작하지 않는다. 모든 관리 명령은--bootstrap-server(client) 또는 controller quorum 대상이다(장 01·gotchas.md).
흔히 묻는 것, 흔히 틀리는 것
| 오해 | 정정 |
|---|---|
| "SASL만 켜면 안전하다" | PLAIN은 평문 자격증명 → SASL_SSL 필수 |
| "보안은 나중에 붙인다" | 재기동·호환성 비용. 설계 단계부터 권장 |
| "ACL 없으면 다 허용이다" | allow.everyone.if.no.acl.found 설정에 따라 다름 |
| "JMX는 옵션" | URP/ISR/지연 모니터링 없이는 장애 감지 불가 |
| "KRaft는 ZK와 운영 명령이 같다" | controller.quorum.bootstrap.servers(KIP-853)가 최신 |
| "mTLS는 클라이언트만" | broker 간 통신에도 권장 |
| "SCRAM 자격증명은 broker 재기동 없이 추가된다" | 맞다. 동적 추가 가능. 단, broker가 KRaft 메타데이터에 저장 |
| "super.users는 모든 ACL 검사를 우회한다" | 맞다. super.users는 운영자 전용. 남발하면 최소 권한 원칙이 무너짐 |
더 깊이
- 동적 broker 구성:
kafka-configs.sh --entity-type brokers로 재기동 없이 설정 변경. - partition reassignment throttle:
--throttle로 대량 복제 시 운영 트래픽 보호. - mTLS(상호 TLS): 클라이언트가 X.509 인증서 제시 → broker truststore로 검증. broker 간 통신 권장.
- OAUTHBEARER: JWT/OAuth 토큰 기반 인증(KIP-255). 클라우드 환경에서 유용.
요약 — 이 글의 결론
- 운영 2축: 클러스터 건강(KRaft/복제) + 보안 3계층.
- 건강 감시: JMX(포트 9999)로 URP·ISR·controller·지연. URP가 핵심 경보.
- 보안 3계층: 암호화(SSL), 인증(SASL/mTLS), 인가(ACL).
- SASL_SSL/SCRAM 적용: (1) SCRAM 자격증명 생성 → (2) broker 설정(listeners/SASL/SSL/ACL) → (3) SSL 인증서(keytool) → (4) client 설정(JAAS+truststore) → (5) ACL 부여 → (6) 보안 적용 후 실행.
- ACL:
kafka-acls.sh. 리소스(topic/group/cluster) × 작업(READ/WRITE/...). 기본 거부 권장. - KRaft 운영:
controller.quorum.bootstrap.servers(KIP-853 동적). broker 추가 시 reassignment.
생각해 볼 문제
- 보안 3계층이 각각 해결하는 위협을 말하라.
- SASL/PLAIN을 SSL 없이 쓰면 왜 위험한가? SCRAM이 상대적으로 안전한 이유는?
- SCRAM 자격증명을 broker에 추가하는 명령을 써 보라.
- SASL_SSL을 적용하기 위한 broker 설정 항목 5가지를 말하라.
- ACL로 "User:alice가 orders topic에 쓰기·읽기" 권한을 부여하는 명령은?
- URP가 운영 경보의 핵심인 이유는? JMX로 뭘 봐야 하는가?
참고
- Security Overview - 접근 2026-07-09 (암호화·인증·인가 3계층 개요)
- Security Model - 접근 2026-07-09 (principal, ACL, super.users 모델)
- Authentication using SASL - 접근 2026-07-09 (PLAIN/SCRAM/GSSAPI/OAUTHBEARER)
- SSL encryption - 접근 2026-07-09 (keystore/truststore, keytool)
- Authorization and ACLs - 접근 2026-07-09 (kafka-acls.sh, resource patterns)
- Operations — KRaft - 접근 2026-07-09 (controller quorum, KIP-853)
- JMX metrics reference - 접근 2026-07-09 (URP, ISR, request latency 지표)
'Data & Platform > Event Streaming' 카테고리의 다른 글
| Kafka - 13. MirrorMaker 2 (0) | 2026.07.10 |
|---|---|
| Kafka - 11. kafka streams (0) | 2026.07.09 |
| Kafka - 10. kafka connect (0) | 2026.07.09 |
| Kafka - 09. schema registry (1) | 2026.07.09 |
| Kafka - 08. delivery semantics (0) | 2026.07.09 |