dev/Cloud & Infra

Kafka 보안 (1) - JAAS 및 SASL

lugi 2019. 8. 19. 08:43

연초부터 Kafka를 활용해야겠다고 마음 먹고 겪은 프로세스를 살펴보면, 처음엔 제대로 설정해서 올리는 것에 중점을 두고, 설치 및 설정에 어느 정도 익숙해지니 설치 자체는 쉘스크립트를 만들어 어느 정도 한 번에 설치 및 서비스 구성이 되도록 할 수 있게 되었다.

 

그 다음으로는 안정적으로 굴러가는 것에 신경을 쓰자고 마음 먹고 JMX 메트릭을 모니터링 한다거나, 로그 파일에서 나타나는 각종 메시지들에 관심을 가지게 되었다. 그러고 나니, 다음으로 관심이 가는 것은 얼마나 Kafka 클러스터를 안전하게 굴릴 수 있느냐. 라는 것이다, 물론 현재 운영하고 있는 환경에서는 네트워크 방화벽 장비라든가 OS의 방화벽 설정 등을 통해 IP를 기반으로 허가 받지 않은 접근을 통제하고 있지만, 꼭 이런 환경에서만 한다는 보장은 없으니, Kafka 의 보안 설정을 살펴보고 있다.

 

앞의 포스팅에서 살펴본 JAAS도 그런 맥락이고, 이번에는 Kafka 의 Security documentation에 자주 나타나는 SASL에 대해 살펴보려고 한다, 원래는 SASL 과 관련된 RFC 및 관련 메커니즘의 아키텍처에 대해서 살펴보려고 그걸 해석하는 중이었는데, Kafka 운영자의 관점에서는 해당 내용을 너무 세세하게 짚어 보는 것은 큰 의미가 없는 것 같아서 엎어버리고... 간단하게 Kafka documentation과 연관된 부분을 살펴보려고 한다.

 

SASL이란 무엇인가?

위키피디아의 설명(https://ko.wikipedia.org/wiki/SASL)에 따르면 인터넷 프로토콜에서 인증과 데이터 보안을 위한 프레임워크이며, 애플리케이션 프로토콜들로부터 인증 메커니즘을 분리시킨다. 라고 설명하고 있다. 또한 SASL로 제공된 어떤 인증 메커니즘도 허용하며, SASL에 의해 제공된 서비스를 보완하기 위해 전송 계층 보안(TLS)도 지원한다고 설명하고 있다.

 

SASL의 아키텍처

출처 - https://tools.ietf.org/html/rfc4422

SASL 은 연결 지향 프로토콜에서 교체 가능한 메커니즘을 통해 인증 및 데이터 보안 서비스를 제공하는 프레임워크이다. SASL 은 프로토콜과 메커니즘 간의 구조화 된 인터페이스를 제공한다. SASL 은 또한 데이터 보안 계층에서 후속 프로토콜의 교환을 위한 프로토콜을 제공한다. 데이터 보안 계층은 데이터 정합성, 기밀성 및 다른 서비스들을 제공할 수 있다. - 앞의 설명은 SASL 의 RFC 스펙(https://tools.ietf.org/html/rfc4422)에서 따온 소개인데, 굳이 Kafka 로 따지자면 Kafka 프로토콜이 데이터 교환 과정에서 Kafka가 지원하는 Kerberos, PLAIN, SCRAM, OAUTHBEARER 등의 메커니즘을 사용하여 인증/인가를 할 수 있도록 해주며, 인증/인가 교환이 성공했을 때, 후속 데이터 교환을 데이터 보안 계층 위에서 할 수 있도록 해 주는 기술이라고 보면 될 것 같다.

 

https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml 에 따르면 SASL 이 지원하는 메커니즘은 수십가지에 달한다.

 

Kafka의 경우 SASL이 지원하는 메커니즘 중 2019년 8월 현재

 

  • SASL/GSSAPI (Kerberos) - 0.9.0.0 부터
  • SASL/PLAIN - 0.10.0.0 부터
  • SASL/SCRAM-SHA-256 and SASL/SCRAM-SHA-512 - 0.10.2.0 부터
  • SASL/OAUTHBEARER - 2.0 부터

을 지원한다.

 

각 메커니즘의 특징을 간단하게 살펴보자면

- Kerberos는 노드간 통신에서 보안을 클라이언트가 티켓을 발급 받아 본인의 신원을 증명하면 인증을 하는 방식이다. 별도의 인증 및 티켓검증서버가 필요하며, 해당 서버가 불능이 될 경우 인증이 불가하다는 단점이 있다.

- PLAIN 은 PLAINTEXT로 username/password를 설정하여 인증을 하는 가장 기본적인 방식이다. 평문을 주고 받으며, TLS 등을 사용하지 않을 경우 탈취 및 변조의 위험이 있다.

- SCRAM은 PBKDF2 암호화 알고리즘을 활용해 생성된 해시를 활용하며, salt 와 count 를 부가적으로 전달하여 인증하는 방법이다.

- OAUTHBEARER 은 OAuth2 스펙에 부합하는 토큰을 기반으로 인증하는 방법이다.

 

카프카는 앞의 포스트에서 설명한 JAAS를 활용해 SASL을 구성한다.

SASL 구성을 통해 보안을 설정할 수 있는 부분은 아래와 같다.

  • Broker (inter-broker)

    • 브로커에 SASL 설정시 설정값의 우선 순위는 아래와 같다 

    • listener.name.{listenerName}.{saslMechanism}.sasl.jaas.config 프로퍼티 설정

    • JAAS Configuration 파일에서 {listenerName}.KafkaServer 섹션

    • JAAS Configuration 파일에서 KafkaServer 섹션

  • Brokder (zookeeper-connect)
    • Zookeeper 접속시 JAAS Configuration 파일에서 Server / Client 섹션을 사용한다
    • Zookeeper 의 service name (principal)의 기본값은 zookeeper이다. 이것을 변경하려면

      -Dzookeeper.sasl.client.username=zk 와 같은 식으로 VM args를 주고 실행해야 한다.

  • Client (Consumer / Producer)
    • sasl.jaas.config 프로퍼티를 설정하거나
    • KafkaClient 섹션을 명시한 JAAS Configuration 파일을 작성할 수 있다.
  • JAAS Configuration 파일을 작성했을 경우 애플리케이션 구동시 -Djava.security.auth.login.config={JAAS File} 을 VM Args 로 주고 실행해야 한다.
  • SASL을 구성했을 경우 server.properties 에 적용하는 listeners 속성에는 SASL_PLAINTEXT: 혹은 SASL_SSL: 스키마로 시작하는 리스너가 들어가야 하며 security.inter.broker.protocol 속성 설정을 통해 브로커 간의 통신에 사용할 스키마를 지정해줘야 한다.
  • 또한 여러개의 SASL 메커니즘을 동시에 설정했을 경우에는 sasl.mechanism.inter.broker.protocol 속성을 통해 브로커간 통신에서 사용할 메커니즘을 지정해주어야 한다.

 

앞서 JAAS 에서 살펴보았던 것과 같이, JAAS는 인증 과정에서 부가적인 상호작용이 필요할 경우 callback handler 를 별도로 구현할 수 있다고 설명하였는데, kafka의 경우 AuthenticationCallbackHandler 인터페이스를 implements 하여 작성한 클래스를 설정하여 사용할 수도 있다.

 

콜백핸들러 설정 및 내부적인 SASL 적용을 위하여 사용하는 공통적인 프로퍼티를 몇가지 소개하면 아래와 같다

 

sasl.client.callback.handler.class
설명 : AuthenticateCallbackHandler 인터페이스를 구현한 SASL 클라이언트 콜백 핸들러 클래스의 패키지명까지 포함한 풀네임
타입 : class

sasl.enabled.mechanisms
설명 : Kafka 서버에서 활성화 된 SASL 메커니즘의 리스트. 리스트는 보안 공급자를 사용 가능한 메커니즘을 포함할 수 있음
타입 : list
기본값 : GSSAPI

sasl.jaas.config
설명 : JAAS 구성 파일이 사용하는 형식의 SASL 연결을 위한 JAAS 로그인 컨텍스트 매개변수.

형식은 loginModuleClass controlFlag (optionName = optionValue) *; 

브로커의 경우 리스너 접두어와 SASL 메커니즘 이름이 소문자로 구성 접두어에 필요함. 

예를 들어 listener.name.sasl_ssl.scram-sha-256.sasl.jaas.config=com.example.Scram.LoginModule
타입 : password

- 개인적으로 이 구성은 파일로 분리하는 것이 훨씬 깔끔 해 보인다고 생각함


sasl.login.callback.handler.class
설명 : AuthenticateCallbackHandler인터페이스를 구현한 SASL로그인 콜백 핸들러 클래스의 패키지명을 포함한 풀네임

브로커에 대해서 로그인 콜백 핸들러 구성은 반드시 리스너 접두사 및 SASL 메커니즘의 이름이 소문자로 구성 접두어에 필요함. 

예를 들어 listener.name.sasl_ssl.scram-sha-256.sasl.login.callback.handler.class=com.example.CustomScramLoginCallbackHandler
타입 : class


sasl.login.class
설명 : Login 인터페이스를 구현한 클래스의 완전한 패키지명까지 포함한 풀네임. 

브로커에 대해서 로그인 구성은 반드시 리스너 접두사 및 SASL 메커니즘의 이름이 소문자로 구성 접두어에 필요함. 

예를 들어 listener.name.sasl_ssl.scram-sha-256.sasl.login.class=com.example.CustomScramLogin
타입 : class

sasl.mechanism.inter.broker.protocol
설명 : 브로커간 통신에 사용할 SASL 메커니즘, 기본값은 GSSAPI
타입 : string

sasl.server.callback.handler.class
설명 : AuthenticateCallbackHandler인터페이스를 구현한 SASL서버 콜백 핸들러 클래스의 패키지명을 포함한 풀네임. 

서버 콜백 핸들러는 반드시 리스너 접두사 및 SASL 메커니즘 이름이 소문자로 구성 접두사에 필요함. 

예를 들어, listener.name.sasl_ssl.plain.sasl.server.callback.handler.class=com.example.CustomPlainCallbackHandler
타입 : class


security.inter.broker.protocol
설명 : 브로커간 통신에 사용할 보안 프로토콜

유효값은 PLAINTEXTSSLSASL_PLAINTEXTSASL_SSL

inter.broker.listener.name 속성과 함께 사용할 경우 오류가 발생함
타입 : string
기본값 : plaintext

 

두 개나 올렸는데 소스가 거의 없고 내용만 있어서 좀 지루하다...

아마도 다음 포스트는 가장 간단한 SASL/PLAIN 을 통해서 실제로 Kafka의 보안 구성을 해보지 않을까 싶다...

차근차근 올려야지...