Avatar
이형석
좋아요
댓글
kafka_security

2021.07.06 | 에스코어 오픈소스SW그룹


 

목차

  • kafka 보안
    • kafak의 보안 필요성
  • SASL 
    • SASL 이란
    • kafka에 사용되는 보안종류
  • JAAS
    • JAAS 란
    • PLAINTEXT로 간단한 kafka 보안 구현
  • kerberos
    • 아키텍처 & 동작설명
    • 설치
    • 구성
  • 추가
    • 마무리글

 

kafka 보안

Apache Kafka는 내부 중간 계층으로, 백엔드 시스템이 kafka 주제를 통해 서로 실시간 데이터 피드를 공유할 수 있도록 합니다.

표준 kafka 설정을 사용하면 모든 사용자 또는 응용프로그램이 모든 주제에 대한 메시지를 쓰거나 모든 주제의 데이터를 읽을 수 있게 되고, 기본적으로 SSL 기능이 비활성화 되어 있어

추가적으로 설정하지 않은 경우Broker와 Client 평문 노출로 인한 정보가 유출될 가능성이 있습니다.

따라서, 업무상 동일한 Kafka cluster를 사용하거나 kafka cluster가 중요한 기밀 정보를 소유한 경우 보안 기능을 구현해야 합니다.

 


SASL(Simple Authentication and Security Layer)

SASL은 SSL/TLS같은 프로토콜이 아닌 인증 및 데이터 보안 서비스를 제공하는 프레임워크입니다.

따라서, 통신 패킷에 관여하는 것이 아닌 통신 기능을 가지고 있는 프로그램이라면 거쳐가게 되는 보안용 라이브러리로 볼 수 있습니다.

 

이를 kafka 입장에서 보게되면 kafka 프로토콜이 데이터 교환 과정에서 kafka가 지원하는 매커니즘을 사용하여 인증(Authentication)/인가(Authorization)를 할 수 있도록 하며,

인증(Authentication)/인가(Authorization) 교환이 끝난 후 데이터 교환은 data security layer 에서 할 수 있도록 하는 기술입니다.

 

SASL diagram

SASL은 개념적으로 다음 다이어그램과 같이 프로토콜 - 매커니즘 간 추상화 계층을 제공하는 프레임 워크입니다.

                  SMTP    LDAP    XMPP   Other protocols ...
                     \       |    |      /
                      \      |    |     /
                     SASL abstraction layer
                      /      |    |     \
                     /       |    |      \
              EXTERNAL   GSSAPI  PLAIN   Other mechanisms ...     <참조: SASL_RFC4422>
 
kafka의 경우 SASL이 지원하는 대표적인 매커니즘은 2020/07 현재 아래와 같습니다.

SASL/PLAINTEXT

  • PLAINTEXT로 username/password 를 설정하여 인증을 하는 가장 기본적이나 고전적인 방식입니다.
  • PLAINTEXT로 사용되는 username과 password는 kafka 브로커에 미리 저장되어 있어야 하며, 변경될 때마다 재시작이 필요합니다.
  • 평문을 주고 받으며, TLS등을 사용하지 않을 경우 탈취 및 변조의 위험이 있어 권장되는 종류의 보안이 아닙니다.

SASL/SCRAM

  • PBKDF2 암호화 알고리즘을 활용해 생성된 해시를 활용하며  username/password 조합에 salt / count를 부가적으로 전달하여 보안을 높인 방법입니다.
  • username 과 password의 해시는 zookeeper에 저장되므로 브로커를 재부팅하지 않아도 됩니다.
  • 네트워크에서 자격증명이 PAINTEXT로 전송되지 않도록 ssl 암호화를 활성화해야합니다.

SASL/OAUITHBEARER

  • OAuth2 토큰을 기반으로 인증하는 방법으로 KIP(Kafka Improvement Proposals)를 통해 읽습니다.

SASL/KERBEROS(GSSAPI)

  • 노드간 통신에서 보안을 client가 티켓을 발급받아 본인의 신원을 증명하면 인증하는 매우 안전한 방법입니다.
  • 별도의 인증 및 티켓검증용 서버가 필요하며 서버가 불능이 될 경우 인증 불가하므로 관리에 주의해야합니다.
  • 가장 일반적인 구현으로 Microsoft Active Directory를 예로 들 수 있으며, 회사가 Kerberos 서버 내에서 보안을 관리하므로 대기업에 적합한 보안 방법입니다.
  • 위와 같은 이유로 설정하는 방법은 가장 어려우나 그만한 가치가 있는 보안방법으로 구성하는 방법을 살펴보겠습니다.

 


 

JAAS

Kafka 는 SASL 구성에 JAAS를 사용하여 모든 SASL 인증 메커니즘에 JAAS 구성을 제공해야 합니다. 따라서 JAAS에 대하여 알아보겠습니다.

JAAS란 무엇인가?

Java 인증 및 인가 서비스(Java Authentication and Authorization Service) 의 준말로 client 및 server 시스템을 보호하기 위한 유연하고 확장성 있는 Java 인증 및 권한 부여 서비스를 제공하는 표준 API 입니다.

기존 java ACL 방식에서 코드 수행의 주체에 대한 검증의 필요성으로 등장하였으며 J2SDK 1.3에서 선택적인 패키지로 소개되었고, J2SDK 1.4 부터 표준 확장 API로 배포되고 있습니다.

 

JAAS는 2가지 기본 목적이 있습니다.

  • Authentication - 현재 코드를 실행중인 엔티티 식별
  • Authorization - 인증이 되면 엔티티에 필요한 액세스 제어권 또는 sensitive code를 실행가능한 권한을 사용자가 소유하는지 확인한다. 

 

JAAS 기본 요소 

JAAS__.gif<JAAS1>

- JAAS 클라이언트: JAAS호환 인증 서비스를 사용하여 인증을 수행하려는 애플리케이션입니다.

- JAAS 구성 파일: JAAS 클라이언트가 JAAS 호환 서비스와의 통신에 필요한 LoginMOdule을 찾는데 사용하는 텍스트 파일입니다.

 

Message Queue 브로커가 JAAS를 사용하는 경우 예시

JAAS.gif<JAAS2>

인증 서비스는 하나 이상의 LoginModule 이 있으며 Broker와 동일한 JVM에서 실행됩니다.

인증서비스는 LoginModule에 대한 항목이 포함된 JAAS 구성파일을 제공합니다.  

 

JAAS API에 대한 자세한 내용은 JAASRefGuide.html 에서 확인하실 수 있습니다.

 

SASL 적용 예제

kafka 보안에서 가장 기본적인 보안방법인 SASL/PLAINTEXT 을 사용하여 JAAS 적용방식을 알아보겠습니다.

Kafka 운영 & 모니터링 에서 3대의 zookeeper와 kafka를 구성된 상태를 전제로 진행하겠습니다.

 

.jaas 파일 생성

#kafka_server_jaas.conf
KafkaServer {
    org.apache.kafka.common.security.plain.PlainLoginModule required
    username="admin"
    password="admin-secret"
    user_admin="admin-secret"
    user_{유저명}="{유저PWD}";
};
 
 
#Kafka_client_jaas.conf
KafkaClient {
        org.apache.kafka.common.security.plain.PlainLoginModule required
        username="{유저명}"
        password="{유저PWD}";
};

kafka_server_jaas.conf : Broker에 적용될 JAAS 입니다. 가장 아랫줄의 username-password 를 PLAINTEXT로 설정하여 인증을 진행합니다.

kafka_client_jaas.conf : Producer 와 Consumer에 적용될 JAAS입니다. Broker에서 message를 가져올 수 있도록 Broker의 PLAINTEXT에 적용된 username/password를 명시해줍니다.

 

server 설정변경

$ vi ~/kafka/config/server.properties
 
 
listeners=SASL_PLAINTEXT://kafka-01:9092
 
 
 
security.inter.broker.protocol=SASL_PLAINTEXT
sasl.mechanism.inter.borker.protocol=PLAIN
sasl.enabled.mechanisms=PLAIN

producer 설정변경

#./config/producer.properties 아래 내용 추가
security.protocol=SASL_PLAINTEXT
sasl.mechanism=PLAIN

 

consumer 설정변경

#./config/consumer.properties 아래 내용 추가
security.protocol=SASL_PLAINTEXT
sasl.mechanism=PLAIN

SASL/PLAINTEXT 보안 방식이 적용될 수 있도록 사용되는 프로토콜/매커니즘을 명시해줍니다.

File
적용대상
server.properties Broker
producer.properties Producer
consumer.properties Consumer

 

#zookeeper 실행 - 설정 변경 없이 기존 방식대로 실행하여 주시면 됩니다.
 
 
#Broker 실행
KAFKA_OPTS=-Djava.security.auth.login.config=~/kafka/kafka_server_jaas.conf ./bin/kafka-server-start.sh  ./config/server.properties
 
 
#Producer 실행
KAFKA_OPTS=-Djava.security.auth.login.config=~/kafka/kafka_client_jaas.conf ./bin/kafka-console-producer.sh -broker-list kafka-01:9092 -topic test -producer.config ./config/producer.properties
 
 
#Consumer 실행
#기존의 message를 모두 보여주기 위해 -from-beginnig 옵션을 사용하였습니다.
KAFKA_OPTS=-Djava.security.auth.login.config=~/kafka/kafka_client_jaas.conf ./bin/kafka-console-consumer.sh -bootstrap-server kafka-01:9092 -topic test -from-beginning -consumer.config ./config/consumer.properties
 

 


KERBEROS

서버와 유저의 수가 적은 경우 서버별 수동으로 유저를 추가하거나 권한을 부여하는 방식으로 수동 관리가 가능합니다.

하지만 대규모의 서비스를 운영하는 경우 서버와 유저의 수가 늘어남에 따라 관리비용이 증가하게 됩니다. 

이러한 경우 client/server 외 AS(Authentication Servuice - 인증)를 별도로 구비하고, 이와 TGS(Ticket-Granting Service - 티켓 발급)를 연동하여 유효한 티켓을 소유하고 있는 유저만 운영서버(Application Server)에 접속하도록 제어하는 Kerberos 프로토콜을 도입하는 것이 보안에 적합합니다.

앞서 설명드린 것과 같이 kerberos는 별도의 서버가 필요하며 동작방식은 다음과 같습니다.

Kerberos_flow_overview.png <kerberos1>

(AS는 TGS의 비밀키 / TGS는 Service Server의 비밀키를 미리 알고 있습니다.)

Concepts

Kerberos Client - Kerberos 서비스를 사용하는 사용자

Kerberos Service - Kerberos Client에게 서비스를 제공하는 서버/애플리케이션

KDC(Key Distribution Center) - 도메인 서비스로 아래 두 가지 서비스를 제공하는 프로세스

  1. AS - 사용자 DB에 대해 Kerberos Client를 인증하고 클라이언트에 TGT를 부여
  2. TGS - Client가 요청한 Kerberos 서비스에 액세스 가능여부를 판단한 후에 해당 서비스에 대한 Ticket을 발행

TGT(Ticket Granting Ticket) - TGS로부터 발급며 TGS의 비밀키로 암호화 된 식별 Ticket

Service Ticket - 암호화 된 Client-Server Ticket. Kerberos Client 는 유효한 TGT를 제출해야 TGS로부터 이 Ticket을 발급받을 수 있다.

 

Flow

1. Kerberos client(이하 사용자)는 plaintext로 사용자 ID를 AS에 전송합니다.

2. AS는 ID가 사용자 DB에 있는지 확인 후 사용자에게 Client/TGS 세션키와 TGT를 생성하여 전송합니다.

3. 사용자는 AS로 받은 정보를 통해 Client/TGS 세션키를 해독하여 Authenticator를 생성후 TGT와 함께 TGS로 전송합니다.

4. TGS는 사용자로부터 받은 Authenticator & TGT를 복호화하여 사용자 정보를 확인한 후 Ticket과 운영서버 세션키를 발급합니다.

  • TGT 복호화 → TGS 세션키 획득 → Authenticator 복호화 → 두 개의 사용자 ID가 일치하는지 확인
  • 운영서버 세션 키는 TGS 세션키로 암호화

5. 사용자는 TGS로 부터 받은 암호화된 세션키를 복호화 하여 새로운 Authenticator를 생성하고, 새로운 Authenticator + Ticket을 운영서버에 전송합니다.

6. 운영서버는 사용자가 보낸 Authenticator & Ticket을 복호화 하여 사용자 ID를 확인 후 Authenticator의 timestamp를 운영서버 세션키로 암호화 하여 사용자에게 전달합니다.

7. 사용자는 최종적으로 받은 데이터를 운영서버 세션키로 복호화 하여 (6)에서 보낸 timestamp와의 일치여부를 확인합니다.

  • 두 timestamp가 일치하면 통신이 가능합니다.

 

간단하게 정리한다면

Kerberos는? 

  • Client - Server 구조에서 서버 접근권한에 대한 관리를 위해
  • 대칭키방식(symmetric-key algorithm)을 이용하여 인증하는
  • 네트워크 인증 암호화 프로토콜 입니다.

사용하는 경우는?

  • 서버 / 유저의 수가 많아저 사용자와 권한에 대한 관리비용이 높아지는 경우!
  • 서버별로 접근 가능한 사용자를 관리해야하는 경우!
  • 서버가 추가될 때마다 유저가 추가/삭제 되어 관리가 필요한 경우!

 

 

설치

zookeeper, kafka 구성

Kerberos를 설치하기 전에 Kafka 운영 & 모니터링 을 참조하여  쉽고 빠르게 3대의 zookeeper와 kafka를 구성할 수 있습니다.

이번 테스트의 경우 OS만 Ubuntu 16.04 로 진행되었으므로 사용되는 명령어에 혼동 없으시길 바랍니다.

#start zookeeper
zookeeper1/bin/zkServer.sh start &
zookeeper2/bin/zkServer.sh start &
zookeeper3/bin/zkServer.sh start &
 
 
#start kafka
kafka1/bin/kafka-server-start.sh -daemon kafka1/config/server.properties & 
kafka2/bin/kafka-server-start.sh -daemon kafka2/config/server.properties & 
kafka3/bin/kafka-server-start.sh -daemon kafka3/config/server.properties &

cmak_check.png 

broker 의 개수를 확인하여 구성이 잘 되었는지 먼저 확인을 한 후 보안 구성을 하시면 됩니다.

 

 

kerberos 구성

우선 서버를 설치하겠습니다.

cent - rpm -ivh krb5-server-1.10.3-10.el6_4.6.x86_64.rpm

ubuntu - sudo apt install krb5-kdc krb5-admin-server

$ sudo apt-get install krb5-config
Reading package lists... Done
Building dependency tree      
Reading state information... Done
The following packages were automatically installed and are no longer required:
  libgssrpc4 libkadm5clnt-mit11 libkadm5srv-mit11 libkdb5-9 libverto-libevent1 libverto1
Use 'sudo apt autoremove' to remove them.
The following NEW packages will be installed:
  krb5-config
0 upgraded, 1 newly installed, 0 to remove and 107 not upgraded.
Need to get 0 B/22.6 kB of archives.
After this operation, 63.5 kB of additional disk space will be used.
Preconfiguring packages ...
Selecting previously unselected package krb5-config.
(Reading database ... 297440 files and directories currently installed.)
Preparing to unpack .../krb5-config_2.6_all.deb ...
Unpacking krb5-config (2.6) ...
Setting up krb5-config (2.6) ...

 

*kerberos server setting (windows/ubuntu)

kerberos____.pngkerberos 영역 - 'EXAMPLE.COM'

 

Screenshot_from_2020-07-07_08-52-17.pngkerberos 서버 호스트 이름 - kafka-01

 

Screenshot_from_2020-07-07_10-24-16.pngMYREALM에 대한 관리(암호변경) 서버의 호스트 이름 - kafka-01

 

Screenshot_from_2020-07-07_08-51-30.png

설정하기 편한 기본적인 값들을 예시용 사용하였습니다.

 

설치 다음으로는 로컬 데이터베이스를 암호화하는데 사용되는 데이터베이스 마스터 비밀번호를 묻습니다.

###PW =  test로 진행하였습니다.
 
$ sudo krb5_newrealm
 
This script should be run on the master KDC/admin server to initialize
a Kerberos realm.  It will ask you to type in a master key password.
This password will be used to generate a key that is stored in
/etc/krb5kdc/stash.  You should try to remember this password, but it
is much more important that it be a strong password than that it be
remembered.  However, if you lose the password and /etc/krb5kdc/stash,
you cannot decrypt your Kerberos database.
Loading random data
Initializing database '/var/lib/krb5kdc/principal' for realm 'MyREALM',
master key name 'K/M@MyREALM'
You will be prompted for the database Master Password.
It is important that you NOT FORGET this password.
Enter KDC database master key: ####
Re-enter KDC database master key to verify:####
 
 
Job for krb5-kdc.service failed because the control process exited with error code.
See "systemctl status krb5-kdc.service" and "journalctl -xe" for details.
 
 
Now that your realm is set up you may wish to create an administrative
principal using the addprinc subcommand of the kadmin.local program.
Then, this principal can be added to /etc/krb5kdc/kadm5.acl so that
you can use the kadmin program on other computers.  Kerberos admin
principals usually belong to a single user and end in /admin.  For
example, if jruser is a Kerberos administrator, then in addition to
the normal jruser principal, a jruser/admin principal should be
created.
 
Don't forget to set up DNS information so your clients can find your
KDC and admin servers.  Doing so is documented in the administration
guide.

 

#krb5_newrealm 도중 

kdb5_util: Cannot open DB2 database '/etc/krb5kdc/principal': File exists while creating database '/etc/krb5kdc/principal'

과 같은 오류가 발생하는 경우에는

krb5-kdc (krb5kdc)

krb5-admin-server

위 2개의 서비스를 중지시킨 후 시작하시어 해결하실 수 있습니다.

 

다음으로 '/etc/krb5kdc/kadm5.acl' 을 편집하여 기존에 생성한 kafka 계정에 대한 관리 원칙을 액세스 제어 목록에 추가해야합니다.

vim /etc/krb5kdc/kadm5.acl

마지막 */admin * 의 주석을 해제한 후 *root/admin * 로 변경하여 추후 변경에 대해 관리자로 제어할 수 있도록 변경해두었습니다.

 

적용 이후 service를 재가동 하여줍니다.

 

$ sudo systemctl restart krb5-admin-server.service
$ systemctl status krb5-admin-server.service
● krb5-admin-server.service - Kerberos 5 Admin Server
Loaded: loaded (/lib/systemd/system/krb5-admin-server.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2020-07-07 09:15:14 KST; 12s ago
Main PID: 23590 (kadmind)
Tasks: 1 (limit: 4915)
CGroup: /system.slice/krb5-admin-server.service
└─23590 /usr/sbin/kadmind -nofork

7월 07 09:15:14 kykil-PNVKB0A0-Samsung-DeskTop kadmind[23590]: Setting up TCP socket for address 0.0.0.0.464
7월 07 09:15:14 kykil-PNVKB0A0-Samsung-DeskTop kadmind[23590]: Setting up TCP socket for address ::.464
7월 07 09:15:14 kykil-PNVKB0A0-Samsung-DeskTop kadmind[23590]: setsockopt(12,IPV6_V6ONLY,1) worked
7월 07 09:15:14 kykil-PNVKB0A0-Samsung-DeskTop kadmind[23590]: Setting up RPC socket for address 0.0.0.0.749
7월 07 09:15:14 kykil-PNVKB0A0-Samsung-DeskTop kadmind[23590]: Setting up RPC socket for address ::.749
7월 07 09:15:14 kykil-PNVKB0A0-Samsung-DeskTop kadmind[23590]: setsockopt(14,IPV6_V6ONLY,1) worked
7월 07 09:15:14 kykil-PNVKB0A0-Samsung-DeskTop kadmind[23590]: set up 6 sockets
7월 07 09:15:14 kykil-PNVKB0A0-Samsung-DeskTop kadmind[23590]: Seeding random number generator
7월 07 09:15:14 kykil-PNVKB0A0-Samsung-DeskTop kadmind[23590]: kadmind: starting...
7월 07 09:15:14 kykil-PNVKB0A0-Samsung-DeskTop kadmind[23590]: starting

 

kerberos kdc 서버의 구성이 완료되었습니다.

 

이제 작업할 내용은 다음과 같습니다.

  • KDC Kerberos 서버의 관리자 작성
  • Kerberos 서버 호스트 이름을 데이터베이스에 추가
  • Kerberos 서버의 keytab을 작성해야합니다.

 

'kadmin.local' 를 실행하여 다음과 같이 kerberos를 관리하겠습니다.

$ sudo kadmin.local
Authenticating as principal root/admin@EXAMPLE.COM with password.
 
 
#kadmin 권한을 가진 계정을 생성하여 계정 액세스 관리가 필요한 경우 사용할 수 있도록 하였습니다. PW - test
kadmin.local:  addprinc root/admin
WARNING: no policy specified for root/admin@EXAMPLE.COM; defaulting to no policy
Enter password for principal "root/admin@EXAMPLE.COM":
Re-enter password for principal "root/admin@EXAMPLE.COM":
Principal "root/admin@EXAMPLE.COM" created.
 
quit
 
# kadmin.local로 접속하여 principal 생성과 keytab 생성을 할 수 있지만 다음과 같은 쿼리문 작성으로도 진행이 가능합니다.
# kadmin.local에서 하시는 경우 " " 안의 내용을 입력해주시면 됩니다.
 
$ sudo kadmin.local -q "addprinc -randkey kafka/kafka-01@EXAMPLE.COM"
Authenticating as principal root/admin@EXAMPLE.COM with password.
WARNING: no policy specified for kafka/kafka-01@EXAMPLE.COM; defaulting to no policy
Principal "kafka/kafka-01@EXAMPLE.COM" created.
 
 
$ sudo kadmin.local -q "ktadd -k /tmp/kafka.service.keytab kafka/kafka-01@EXAMPLE.COM"
Authenticating as principal root/admin@EXAMPLE.COM with password.
Entry for principal kafka/kafka-01@EXAMPLE.COM with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/kafka.service.keytab.
Entry for principal kafka/kafka-01@EXAMPLE.COM with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/kafka.service.keytab.

 

DB에 사용자를 추가하고 Keytab을 생성하였습니다.

이제 연결을 위한 JAAS파일을 생성하겠습니다.

# broker_jaas.conf
KafkaServer {
        com.sun.security.auth.module.Krb5LoginModule required
        useKeyTab=true
        storeKey=true
        keyTab="/tmp/kafka.service.keytab"
        principal="kafka/kafka-01@EXAMPLE.COM";
};
 
 
 
# client_jaas.conf
KafkaClient {
        com.sun.security.auth.module.Krb5LoginModule required
        useKeyTab=true
        storeKey=true
        serviceName="kafka"
        keyTab="/tmp/writer.keytab"
        principal="writer@EXAMPLE.COM";
};

Broker에 사용되는 부분과 Producer/consumer에 사용되는 부분을 구분하여 보여드리기 위해 두 개의 파일로 구분하여 생성하였습니다.

 

 

JAAS 파일을 생성한 이후에 kerberos 연결을 위한 전용 properties 파일을 생성해야 합니다.

#sasl.properties
 
 
bootstrap.servers=kafka-01:9092
security.protocol=SASL_PLAINTEXT

 

모든 설정을 끝마쳤고 다음 순서대로 실행하시면 kafka가 실행되어 집니다.

  1. zookeeper 실행(이전 설정과 변경 없습니다.)
  2. Broker 실행
  3. Producer 실행
  4. Consumer 실행
# broker 시작
$ sudo KAFKA_OPTS=-Djava.security.auth.login.config=/home/kykil/1TB/score/kafka/kafka_security/kafka1/kafka_broker_jaas.conf ./bin/kafka-server-start.sh ./config/server.properties
 
 
 
# Producer 시작
$ sudo KAFKA_OPTS=-Djava.security.auth.login.config=./kafka_client_jaas.conf ./bin/kafka-console-producer.sh --broker-list kafka-01:9092 --topic test --producer.config ./config/sasl.properties
 
 
# Consumer 시작
$ sudo KAFKA_OPTS=-Djava.security.auth.login.config=./kafka_client_jaas.conf ./bin/kafka-console-consumer.sh -bootstrap-server kafka-01:9092 -topic test -from-beginning -consumer.config ./config/sasl.properties

 

실행되었을 경우 아래와 같이 정상 연결된 것을 보실 수 있으십니다.

....
Debug is  true storeKey true useTicketCache false useKeyTab true doNotPrompt false ticketCache is null isInitiator true KeyTab is /tmp/kafka.service.keytab refreshKrb5Config is false principal is kafka/kafka-01@EXAMPLE.COM tryFirstPass is false useFirstPass is false storePass is false clearPass is false
principal is kafka/kafka-01@EXAMPLE.COM
Will use keytab
Commit Succeeded
 
[2020-07-09 09:48:38,901] INFO Successfully logged in. (org.apache.kafka.common.security.authenticator.AbstractLogin)
[2020-07-09 09:48:38,902] INFO [Principal=kafka/kafka-01@EXAMPLE.COM]: TGT refresh thread started. (org.apache.kafka.common.security.kerberos.KerberosLogin)
[2020-07-09 09:48:38,907] INFO [Principal=kafka/kafka-01@EXAMPLE.COM]: TGT valid starting at: Thu Jul 09 09:48:38 KST 2020 (org.apache.kafka.common.security.kerberos.KerberosLogin)
[2020-07-09 09:48:38,907] INFO [Principal=kafka/kafka-01@EXAMPLE.COM]: TGT expires: Thu Jul 09 19:48:38 KST 2020 (org.apache.kafka.common.security.kerberos.KerberosLogin)
[2020-07-09 09:48:38,907] INFO [Principal=kafka/kafka-01@EXAMPLE.COM]: TGT refresh sleeping until: Thu Jul 09 18:07:26 KST 2020 (org.apache.kafka.common.security.kerberos.KerberosLogin)
[2020-07-09 09:48:38,915] INFO [SocketServer brokerId=0] Created data-plane acceptor and processors for endpoint : EndPoint(kafka-01,9092,ListenerName(SASL_PLAINTEXT),SASL_PLAINTEXT) (kafka.network.SocketServer)
[2020-07-09 09:48:38,915] INFO Awaiting socket connections on kafka-02:9093. (kafka.network.Acceptor)
...
[2020-07-09 09:48:39,078] INFO Registered broker 0 at path /brokers/ids/0 with addresses: ArrayBuffer(EndPoint(kafka-01,9092,ListenerName(SASL_PLAINTEXT),SASL_PLAINTEXT), EndPoint(kafka-02,9093,ListenerName(PLAINTEXT),PLAINTEXT)), czxid (broker epoch): 137438953487 (kafka.zk.KafkaZkClient)
....

 

kerberos에서 Ticket발급을 받지 않는 경우 아래와 같이 에러가 발생합니다.

  • kafka-01:9092 - kerberos 적용
  • kafka-02:9093 - kerberos 미적용
# kafka-01:9092
$ sudo KAFKA_OPTS=-Djava.security.auth.login.config=./kafka_client_jaas.conf ./bin/kafka-console-consumer.sh -bootstrap-server kafka-01:9092 -topic test -from-beginning -consumer.config ./config/sasl.properties
Debug is  true storeKey true useTicketCache false useKeyTab true doNotPrompt false ticketCache is null isInitiator true KeyTab is /tmp/writer.keytab refreshKrb5Config is false principal is writer@EXAMPLE.COM tryFirstPass is false useFirstPass is false storePass is false clearPass is false
principal is writer@EXAMPLE.COM
Will use keytab
Commit Succeeded
 
 
test
message
 
 
 
# kafka-02:9093
$ sudo KAFKA_OPTS=-Djava.security.auth.login.config=./kafka_client_jaas.conf ./bin/kafka-console-consumer.sh -bootstrap-server kafka-02:9093 -topic test -from-beginning -consumer.config ./config/sasl.properties
Debug is  true storeKey true useTicketCache false useKeyTab true doNotPrompt false ticketCache is null isInitiator true KeyTab is /tmp/writer.keytab refreshKrb5Config is false principal is writer@EXAMPLE.COM tryFirstPass is false useFirstPass is false storePass is false clearPass is false
principal is writer@EXAMPLE.COM
Will use keytab
Commit Succeeded
 
[2020-07-08 15:57:34,826] ERROR [Consumer clientId=consumer-console-consumer-53795-1, groupId=console-consumer-53795] Connection to node -1 (kafka-02/172.21.70.142:9093) failed authentication due to: Unexpected handshake request with client mechanism GSSAPI, enabled mechanisms are [] (org.apache.kafka.clients.NetworkClient)
[2020-07-08 15:57:34,826] WARN [Consumer clientId=consumer-console-consumer-53795-1, groupId=console-consumer-53795] Bootstrap broker kafka-02:9093 (id: -1 rack: null) disconnected (org.apache.kafka.clients.NetworkClient)
[2020-07-08 15:57:34,827] ERROR Error processing message, terminating consumer process:  (kafka.tools.ConsoleConsumer$)
org.apache.kafka.common.errors.IllegalSaslStateException: Unexpected handshake request with client mechanism GSSAPI, enabled mechanisms are []
[2020-07-08 15:57:34,834] WARN [Principal=writer@EXAMPLE.COM]: TGT renewal thread has been interrupted and will exit. (org.apache.kafka.common.security.kerberos.KerberosLogin)
Processed a total of 0 messages

 

연결에 문제가 발생한 경우 우선 생성하신 JAAS 파일 내용에

        debug=true

를 추가하시면 디버그를 해주신다면 실행하실때에 좀 더 자세한 Log 내용을 보실 수 있습니다.

 

[Krb5LoginModule] 에서 계속된 오류가 발생한다면 keytab 생성이 잘못되었을 경우가 가장 큽니다.

위의 내용으로 올라가 principal 생성 및 keytab생성을 다시 하신다면 해결될 수 있습니다.

$ sudo kadmin.local
kadmin.local:
 
 
#principal 목록확인
kadmin.local: list_principals
 
 
#principal 삭제
kadimn.local: delprinc {principal 이름}

 

마무리 (Summary)

오픈 소스 분산형 메시징 시스템인 kafka는 오픈소스라는 이점과 설치 및 적용법이 쉬워 점차 사용량이 증가되고 있습니다.

하지만 구성이 쉬운만큼 표준 Kakfa 설정을 사용한다면 중간에서 모든 message를 읽거나 작성할 수 있어 보안에 취약합니다.

따라서, 이 문서를 통해 간단한 방법과 대규모 서비스에서 관리가 용이한 방법을 제시하여 kafka의 보안성을 높일 수 있는 경우를 제시하였습니다.

 

이 문서가 현재 운영중인 Kafka 클러스터에 대한 보안설정에 도움이 되기를 바랍니다.

감사합니다.

 

 

https://devidea.tistory.com/79

https://www.howtoforge.com/how-to-setup-kerberos-server-and-client-on-ubuntu-1804-lts/

SASL_RFC4422: https://tools.ietf.org/html/rfc4422

JAAS1, JAAS2: https://docs.oracle.com/cd/E19717-01/820-3192/gefou/index.html

JAAS 참조: https://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/JAASRefGuide.html

Kerberos1: https://docs.axway.com/bundle/APIGateway_762_IntegrationKerberos_allOS_en_HTML5/page/Content/KerberosIntegration/kerberos_overview.html