Skip to content

Using SASL with librdkafka on Windows

Emanuele Sabellico edited this page Jul 19, 2023 · 56 revisions

Windows Zookeeper/Kafka SSPI

For a trivial zookeeper/kafka ensemble/cluster all running on machine: HOST, perform the following steps to enable SASL via SSPI.

For a Unix-based system (Debian/Ubuntu, RedHat, MacOS/OSX) please follow guide Using SASL with librdkafka.

Overview

Kerberos keytabs (file-based pre-authenticated keys) are created for each broker in the cluster. The client will use SSPI and does not need keytab files. They keytabs are distributed to the broker nodes.

Decide on the following things:

  • REALM - Your Kerberos realm, typically your operational domain in upper case. E.g., YOURDOMAIN.COM.
  • HOST - Broker hostname, E.g., broker1. Quantify as necessary. Any casing works.
  • HOST_FQDN - The fully qualified name of the HOST. E.g. broker1.yourcompany.com. Any casing works.
  • DOMAIN - The Windows domain of the broker HOST. E.g. LONDON. Any casing works.

AD Administrator setup

1. Setup AD users

Create AD user for Zookeeper/Kafka (the format is AD DOMAIN\AD user name):

• DOMAIN\Zookeeper_test (say the password is zk_password)

• DOMAIN\Kafka_test (say the password is kfk_password)

2. Create Kerberos principals

Ask the AD administrator to run:

SETSPN -S zookeeper/HOST@REALM DOMAIN\Zookeeper_test
SETSPN -S zookeeper/HOST_FQDN@REALM DOMAIN\Zookeeper_test

SETSPN -S kafka/HOST@REALM DOMAIN\Kafka_test
SETSPN -S kafka/HOST_FQDN@REALM DOMAIN\Kafka_test

3. Create Kerberos Keytabs

https://technet.microsoft.com/en-us/library/cc753771(v=ws.11).aspx

You will need the respective AD user password from step 1; the SPN from step 2; and a folder for the generated output (you can call this folder C:\keytabs).

We will create keytab data for both the simple and fully qualified DOMAIN name of the HOST.

Note that the ktpass utility might not be available on all versions of Windows:

ktpass -princ zookeeper/HOST@REALM -mapuser DOMAIN\Zookeeper_test -crypto RC4-HMAC-NT -ptype KRB5_NT_PRINCIPAL -pass zk_password -out C:\keytabs\zookeeper.ktab
ktpass -princ zookeeper/HOST_FQDN@REALM -mapuser DOMAIN\Zookeeper_test -crypto RC4-HMAC-NT -ptype KRB5_NT_PRINCIPAL -pass zk_password -in C:\keytabs\zookeeper.ktab -out C:\keytabs\zookeeper.ktab

ktpass -princ kafka/HOST@REALM -mapuser DOMAIN\Kafka_test -crypto RC4-HMAC-NT -ptype KRB5_NT_PRINCIPAL -pass kfk_password -out C:\keytabs\kafka.ktab
ktpass -princ kafka/HOST_FQDN@REALM -mapuser DOMAIN\Kafka_test -crypto RC4-HMAC-NT -ptype KRB5_NT_PRINCIPAL -pass kfk_password -in C:\keytabs\kafka.ktab -out C:\keytabs\kafka.ktab

Once the keytabs are created place them in a similar directory where Zookeeper/Kafka can access them. We will use these local files in the next sections.

Zookeeper config files (Optional)

Note: Zookeeper authentication is optional and not required for client->Kafka cluster authentication.

1.Add the following entries (at the end of the file) to the zookeeper config file (zoo.cfg):

authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider
jaasLoginRenew=3600000  

2.In the same directory where the zoo.cfg file is edit the jaas.conf file so that it has this content:

(Description of values) https://docs.oracle.com/javase/7/docs/jre/api/security/jaas/spec/com/sun/security/auth/module/Krb5LoginModule.html

Server {  
    com.sun.security.auth.module.Krb5LoginModule required  
    useKeyTab="true"  
    principal="zookeeper/HOST_FQDN@REALM"  
    storeKey="true"  
    serviceName="zookeeper"  
    keyTab="C:/keytabs/zookeeper.ktab";  
 };  

3.Edit the zookeeper runner batch file (zkServer.cmd) to have this:

-Djava.security.auth.login.config="%~dp0../conf/jaas.conf"  

Note: The %~dp0 (that’s a zero) variable will expand to the drive letter and path of the batch file.

The updated command file should look like this:

call %JAVA% "-Dzookeeper.log.dir=%ZOO_LOG_DIR%" "-Dzookeeper.root.logger=%ZOO_LOG4J_PROP%" -Dsun.security.krb5.debug=true -Djava.security.auth.login.config="%~dp0../conf/jaas.conf"  -cp "%CLASSPATH%" %ZOOMAIN% "%ZOOCFG%" %*

Note: the bold entry is optional and only required if you want to see detailed information from the security module.

4.When you run Zookeeper process make sure it runs as DOMAIN\Zookeeper_test.

Kafka config files

1.Add the following entries (in the Socket Server Settings) to the kafka server config file (server.properties):

listeners=SASL_PLAINTEXT://HOST_FQDN:9093  
security.inter.broker.protocol=SASL_PLAINTEXT  
zookeeper.set.acl=true  
sasl.mechanism=GSSAPI  

2.In the same directory where server.properties file is edit the kafka_server_jaas.conf file so that it has this content:

//For connections to Kafka.  
KafkaServer {  
    com.sun.security.auth.module.Krb5LoginModule required   
    useKeyTab="true"  
    principal="kafka/HOST_FQDN@REALM"  
    storeKey="true"  
    serviceName="kafka"  
    keyTab="C:/keytabs/kafka.ktab";  
};

//For connections to Zookeeper.  
Client {  
    com.sun.security.auth.module.Krb5LoginModule required  
    useKeyTab="true"  
    principal="kafka/HOST_FQDN@REALM"  
    serviceName="kafka"  
    keyTab="C:/keytabs/kafka.ktab";  
};  

3.Edit the kafka runner batch file (windows\kafka-server-start.bat) to have this:

-Djava.security.auth.login.config="%~dp0../../config/kafka_server_jaas.conf"  

The updated command file should look like this:

set KAFKA_LOG4J_OPTS=-Dlog4j.configuration=file:"%~dp0../../config/log4j.properties" -Dkafka.logs.dir="%Dkafka_logs_dir%" -Djava.security.auth.login.config="%~dp0../../config/kafka_server_jaas.conf" -Dsun.security.krb5.debug=true  

Note: the bold entry is optional and only required if you want to see detailed information from the security module.

If all works immediately then great, otherwise you need to have a look at the console output with the following modifier in the jaas files (both Zookeeper and Kafka): debug="true"

4.When you run Kafka process make sure it runs as DOMAIN\Kafka_test.

Now you can try out the SASL_WIN32 kafka driver as updated by @zyzil. Please see here. For example:

rdkafka_example.exe -P -t SOME_TOPIC -b HOST_FQDN:9093 -X security.protocol=SASL_PLAINTEXT -X sasl.kerberos.service.name= kafka/HOST_FQDN@REALM -X sasl.kerberos.principal=kafka -d security,protocol,broker

Here is a sample output from a successful demonstration of running the above. Note the bold sections:

LOG-7-BRKMAIN: :0/internal: Enter main broker thread  
LOG-7-BROKER: sasl_plaintext://HOST_FQDN:9093/bootstrap: Added new broker with NodeId -1  
LOG-7-STATE: :0/internal: Broker changed state INIT -> UP  
Created producer rdkafka#producer-10.009000.  
LOG-7-BRKMAIN: sasl_plaintext://HOST_FQDN:9093/bootstrap: Enter main broker thread  
LOG-7-CONNECT: sasl_plaintext://HOST_FQDN:9093/bootstrap: broker in state INIT connecting  
LOG-7-CONNECT: sasl_plaintext://HOST_FQDN:9093/bootstrap: Connecting to ipv4#ip_address:9093 (sasl_plaintext) with socket 380  
LOG-7-STATE: sasl_plaintext://HOST_FQDN:9093/bootstrap: Broker changed state INIT -> CONNECT  
LOG-7-CONNECT: sasl_plaintext://HOST_FQDN:9093/bootstrap: Connected to ipv4#ip_address:9093  
LOG-7-CONNECTED: sasl_plaintext://HOST_FQDN:9093/bootstrap: Connected (#1)  
LOG-7-APIVERSION: sasl_plaintext://HOST_FQDN:9093/bootstrap: Using (configuration fallback) 0.9.0 protocol features  
LOG-7-FEATURE: sasl_plaintext://HOST_FQDN:9093/bootstrap: Updated enabled protocol features to BrokerBalancedConsumer,ThrottleTime,Sasl,BrokerGroupCoordinator,LZ4  
LOG-7-AUTH: sasl_plaintext://HOST_FQDN:9093/bootstrap: Auth in state CONNECT (handshake not supported)  
LOG-7-STATE: sasl_plaintext://HOST_FQDN:9093/bootstrap: Broker changed state CONNECT -> AUTH  
LOG-7-SASL: sasl_plaintext://HOST_FQDN:9093/bootstrap: Initializing SASL client: service name kafka/HOST_FQDN@REALM, hostname HOST_FQDN, mechanisms GSSAPI  
LOG-7-SASL: sasl_plaintext://HOST_FQDN:9093/bootstrap: Acquired Kerberos credentials handle (expiry in 2147483446.-711548929s)  
LOG-7-SASL: sasl_plaintext://HOST_FQDN:9093/bootstrap: Send SASL frame to broker (2473 bytes)  
LOG-7-SASL: sasl_plaintext://HOST_FQDN:9093/bootstrap: Received SASL frame from broker (103 bytes)  
LOG-7-SASLAUTH: sasl_plaintext://HOST_FQDN:9093/bootstrap: Initialized security  
LOG-7-SASL: sasl_plaintext://HOST_FQDN:9093/bootstrap: Send SASL frame to broker (0 bytes)  
LOG-7-SASL: sasl_plaintext://HOST_FQDN:9093/bootstrap: Received SASL frame from broker (50 bytes)  
LOG-7-SASLAUTH: sasl_plaintext://HOST_FQDN:9093/bootstrap: Validated server token  
LOG-7-SASLAUTH: sasl_plaintext://HOST_FQDN:9093/bootstrap: **Sending response message for user: WINDOWS_LOGON@REALM**  
LOG-7-SASL: sasl_plaintext://HOST_FQDN:9093/bootstrap: Send SASL frame to broker (68 bytes)  
LOG-7-SASLAUTH: sasl_plaintext://HOST_FQDN:9093/bootstrap: **Authenticated**  
LOG-7-STATE: sasl_plaintext://HOST_FQDN:9093/bootstrap: Broker changed state AUTH -> UP  
LOG-7-SEND: sasl_plaintext://HOST_FQDN:9093/bootstrap: Sent MetadataRequest (v0, 37 bytes @ 0, CorrId 1)  
LOG-7-RECV: sasl_plaintext://HOST_FQDN:9093/bootstrap: Received MetadataResponse (v0, 60 bytes, CorrId 1, rtt 141.00ms)  
LOG-7-UPDATE: sasl_plaintext://HOST_FQDN:9093/bootstrap: NodeId changed from -1 to 1  
LOG-7-UPDATE: sasl_plaintext://HOST_FQDN:9093/1: Name changed from sasl_plaintext://HOST_FQDN:9093/bootstrap to sasl_plaintext://HOST_FQDN:9093/1  
LOG-7-STATE: sasl_plaintext://HOST_FQDN:9093/1: Broker changed state UP -> UPDATE  
LOG-7-SEND: sasl_plaintext://HOST_FQDN:9093/1: Sent MetadataRequest (v0, 37 bytes @ 0, CorrId 2)  
LOG-7-STATE: sasl_plaintext://HOST_FQDN:9093/1: Broker changed state UPDATE -> UP  
LOG-7-RECV: sasl_plaintext://HOST_FQDN:9093/1: Received MetadataResponse (v0, 60 bytes, CorrId 2, rtt 125.00ms)  
LOG-7-SEND: sasl_plaintext://HOST_FQDN:9093/1: Sent MetadataRequest (v0, 37 bytes @ 0, CorrId 3)  
LOG-7-RECV: sasl_plaintext://HOST_FQDN:9093/1: Received MetadataResponse (v0, 60 bytes, CorrId 3, rtt 125.00ms)  
LOG-7-SEND: sasl_plaintext://HOST_FQDN:9093/1: Sent MetadataRequest (v0, 37 bytes @ 0, CorrId 4)  
LOG-7-RECV: sasl_plaintext://HOST_FQDN:9093/1: Received MetadataResponse (v0, 86 bytes, CorrId 4, rtt 125.00ms)  
LOG-7-TOPBRK: sasl_plaintext://HOST_FQDN:9093/1: Topic **SOME_TOPIC** [0]: joining broker (rktp 00826C80)  
**sending message**  
% Produced message (15 bytes)  
LOG-7-SEND: sasl_plaintext://HOST_FQDN:9093/1: Sent ProduceRequest (v1, 96 bytes @ 0, CorrId 5)  
LOG-7-RECV: sasl_plaintext://HOST_FQDN:9093/1: **Received ProduceResponse** (v1, 38 bytes, CorrId 5, rtt 140.00ms)  

Useful links:

  1. https://docs.oracle.com/javase/7/docs/jre/api/security/jaas/spec/com/sun/security/auth/module/Krb5LoginModule.html

  2. https://technet.microsoft.com/en-us/library/cc753771(v=ws.11).aspx

  3. http://serverfault.com/questions/573881/setting-kerberos-ktpass-ktab-all-that-jaas

  4. http://forums.devx.com/showthread.php?174746-NegotiateStream-can%92t-work-with-Kerberos-NTLM-GSSAPI-over-SASL-(POP3-IMAP-SMTP)

  5. https://community.hortonworks.com/questions/24853/client-not-found-in-kerberos-database-error.html

  6. http://www.coastrd.com/c-schannel-smtp