Data & Platform/Event Streaming

Kafka - 12. operations

운영과 보안 — 클러스터 건강 유지와 "누가 뭘 할 수 있는가" 통제

Kafka를 기본 설정으로 두면 통신이 평문(PLAINTEXT)이고, 아무나 topic에 쓸 수 있다. 개발/테스트에만 허용되는 상태다. 프로덕션에선 (1) 클러스터가 건강한지 감시하고, (2) 누가 접속하고 무엇을 할 수 있는지 통제해야 한다.

이 두 축은 독립이 아니다 — 보안이 없으면 누구나 topic을 지울 수 있고, 모니터링이 없으면 broker 장애를 알 수 없다. 프로덕션 운영은 SASL_SSL/SCRAM 설정, 인증서, ACL, JMX 모니터링, KRaft quorum 관리가 얽힌 종합 작업이다. 각 설정이 어떤 위협을 막고 어떤 비용이 드는지를 짚으면서, broker와 client에 보안을 설정하는 단계를 한 호흡으로 추적한다.

운영의 두 축

  1. 클러스터 건강 — broker가 살아있고, 복제가 따라잡고, 리더가 정상인가.
  2. 보안 — 인증(누가), 인가(뭘 할 수 있는가), 암호화(통신 노출 여부).

클러스터 건강 — 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 → payments topic READ + payment-processors group READ.
  • 로그 수집 producer → app-logs topic 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.

생각해 볼 문제

  1. 보안 3계층이 각각 해결하는 위협을 말하라.
  2. SASL/PLAIN을 SSL 없이 쓰면 왜 위험한가? SCRAM이 상대적으로 안전한 이유는?
  3. SCRAM 자격증명을 broker에 추가하는 명령을 써 보라.
  4. SASL_SSL을 적용하기 위한 broker 설정 항목 5가지를 말하라.
  5. ACL로 "User:alice가 orders topic에 쓰기·읽기" 권한을 부여하는 명령은?
  6. URP가 운영 경보의 핵심인 이유는? JMX로 뭘 봐야 하는가?

참고

'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