33 Which Provider to Use for Kafka Authentication

33 Which Provider to Use for Kafka Authentication #

Hello, I am Hu Xi. Today, I want to share with you the topic of Kafka’s authentication mechanism.

What is the authentication mechanism? #

Authentication, also known as verification or authentication, is a process of confirming a user’s identity through certain means. The main purpose of authentication is to confirm that the user claiming a certain identity is indeed the user they claim to be.

In the field of computer science, a term often confused with authentication is authorization. Authorization generally refers to defining and granting appropriate access permissions to resources related to information security or computer security.

To differentiate between the two, here’s a simple example: authentication addresses the question of proving who you are, while authorization addresses the question of what you can do.

In Kafka, authentication and authorization are two separate security configurations. Today, we will primarily discuss Kafka’s authentication mechanism, while we will cover authorization mechanisms in the next section of this column.

Kafka Authentication Mechanism #

Starting from version 0.9.0.0, Kafka officially introduced authentication mechanisms to enable basic security user authentication. This is a necessary step for deploying Kafka on the cloud or managing multi-tenancy. Up to the latest version 2.3, Kafka supports SSL-based and SASL-based authentication mechanisms.

SSL-based authentication mainly refers to the mutual authentication between the Brokers and clients (2-way authentication). Generally, SSL encryption (Encryption) enables one-way authentication, which means the client authenticates the Broker’s certificate. To enable SSL authentication, we need to enable mutual authentication, which means the Broker also authenticates the client’s certificate.

By the way, you may say that SSL is outdated, right? Nowadays, we call it TLS (Transport Layer Security), right? However, in the Kafka source code, SSL is still used instead of TLS to represent this type of thing. But for today’s discussion, you can consider all mentions of SSL to be equivalent to TLS.

Kafka also supports client authentication through SASL. SASL is a framework that provides authentication and data security services. Kafka supports five SASL mechanisms, which were introduced in different versions. You need to choose the authentication mechanism supported by the version you are using:

  1. GSSAPI: It is the security interface used by Kerberos and was introduced in version 0.9.
  2. PLAIN: This mechanism uses simple username/password authentication and was introduced in version 0.10.
  3. SCRAM: It is a new mechanism mainly used to address the security issues of the PLAIN mechanism and was introduced in version 0.10.2.
  4. OAUTHBEARER: It is a new mechanism based on the OAuth 2 authentication framework and was introduced in version 2.0.
  5. Delegation Token: It is a lightweight authentication mechanism that complements the existing SASL mechanisms and was introduced in version 1.1.0.

Comparison of Authentication Mechanisms #

Kafka offers us a variety of authentication mechanisms, but how should we choose the appropriate authentication framework in practice? Let’s compare them below.

Currently, there are more cases of using SSL for channel encryption, but using SSL for authentication is not as good as using SASL. After all, SASL can support different authentication mechanisms like GSSAPI, SCRAM, and PLAIN. Therefore, my suggestion is that you can use SSL for communication encryption and use SASL for Kafka authentication implementation.

SASL can be further divided into many authentication mechanisms, so how do we choose?

SASL/GSSAPI is mainly used for Kerberos. If your company has implemented Kerberos authentication (such as using Active Directory), then using GSSAPI is the most convenient. Because you don’t need to set up Kerberos separately, just ask your Kerberos administrator to apply a principal for each broker and the operating system user who needs to access the Kafka cluster. In summary, GSSAPI is suitable for scenarios where Kerberos authentication has already been implemented, and SASL/GSSAPI can achieve seamless integration.

As mentioned earlier, SASL/PLAIN is a simple username/password authentication mechanism that is usually used in conjunction with SSL encryption. Note that PLAIN and PLAINTEXT in this context are two different things. PLAIN is an authentication mechanism, while PLAINTEXT refers to unencrypted transmission without SSL. For some small companies, it may not be necessary to set up a company-level Kerberos, and their user systems may not be complex, especially when there are not many users accessing the Kafka cluster. For SASL/PLAIN, this is a very suitable scenario. Overall, the configuration and maintenance costs of SASL/PLAIN are relatively low, making it suitable for Kafka clusters in small companies.

However, SASL/PLAIN has a downside: it does not allow the dynamic addition or removal of authentication users, and you have to restart the Kafka cluster to make the changes take effect. Why? This is because all authentication user information is stored in a static file, so only restarting the broker can reload the changed static file.

We know that restarting the cluster is unpleasant in many scenarios, even with rolling upgrades. SASL/SCRAM solves this problem. It avoids the need to restart the broker for dynamic modifications by storing authentication user information in ZooKeeper. In actual usage, you can use Kafka’s provided commands to dynamically create and delete users without restarting the entire cluster. Therefore, if you plan to use SASL/PLAIN, you might want to try using SASL/SCRAM. However, please note that the latter was introduced in version 0.10.2. You need to upgrade to this version or later to use it.

SASL/OAUTHBEARER is a new authentication mechanism introduced in version 2.0, mainly for integration with the OAuth 2 framework. OAuth is a development standard that allows users to authorize third-party applications to access their resources on a certain website without providing their username and password to the third-party application. Kafka does not advocate the use of OAUTHBEARER alone because the generated JSON Web Tokens are insecure and must be used in production environments with SSL encryption. Of course, since it was introduced in version 2.0 and there aren’t many actual use cases for it yet, we can observe it for a while before applying it to a production environment.

Delegation Token was introduced in version 1.1. It is a lightweight authentication mechanism primarily designed to complement existing SASL or SSL authentication. If you want to use Delegation Token, you need to configure SASL authentication first and then use Kafka’s provided API to obtain the corresponding Delegation Token. In this way, the Broker and client can use this token directly for authentication, without the need to obtain the corresponding ticket from the KDC (Kerberos authentication) or transfer the Keystore file (SSL authentication) every time.

To help you better understand and remember, I have summarized these authentication mechanisms in the table below. You can use this table for reference to distinguish them.

SASL/SCRAM-SHA-256 Configuration Example #

Next, I will provide an example configuration for SASL/SCRAM to demonstrate how to enable authentication in a Kafka cluster. The configuration steps for other authentication mechanisms are similar, such as creating authentication users, configuring specific parameters for the Broker and Client.

In my test environment, I have a Kafka cluster consisting of two Brokers running on my local Mac, with connection ports 9092 and 9093 respectively.

Step 1: Creating Users #

The first step in configuring SASL/SCRAM is to create users who can connect to the Kafka cluster. In this test, I will create three users: an admin user for inter-Broker communication, a writer user for producing messages, and a reader user for consuming messages.

We use the following three commands to create these users:

$ cd kafka_2.12-2.3.0/
$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --add-config 'SCRAM-SHA-256=[password=admin],SCRAM-SHA-512=[password=admin]' --entity-type users --entity-name admin
Completed Updating config for entity: user-principal 'admin'.


$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --add-config 'SCRAM-SHA-256=[password=writer],SCRAM-SHA-512=[password=writer]' --entity-type users --entity-name writer
Completed Updating config for entity: user-principal 'writer'.


$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --add-config 'SCRAM-SHA-256=[password=reader],SCRAM-SHA-512=[password=reader]' --entity-type users --entity-name reader
Completed Updating config for entity: user-principal 'reader'.

As mentioned earlier, the kafka-configs script is used to set topic-level parameters, but it also has many other functions. In this example, we use it to create user information for SASL/SCRAM authentication. You can use the following command to view the created user data:

$ bin/kafka-configs.sh --zookeeper localhost:2181 --describe --entity-type users  --entity-name writer
Configs for user-principal 'writer' are SCRAM-SHA-512=salt=MWt6OGplZHF6YnF5bmEyam9jamRwdWlqZWQ=,stored_key=hR7+vgeCEz61OmnMezsqKQkJwMCAoTTxw2jftYiXCHxDfaaQU7+9/dYBq8bFuTio832mTHk89B4Yh9frj/ampw==,server_key=C0k6J+9/InYRohogXb3HOlG7s84EXAs/iw0jGOnnQAt4jxQODRzeGxNm+18HZFyPn7qF9JmAqgtcU7hgA74zfA==,iterations=4096,SCRAM-SHA-256=salt=MWV0cDFtbXY5Nm5icWloajdnbjljZ3JqeGs=,stored_key=sKjmeZe4sXTAnUTL1CQC7DkMtC+mqKtRY0heEHvRyPk=,server_key=kW7CC3PBj+JRGtCOtIbAMefL8aiL8ZrUgF5tfomsWVA=,iterations=4096

This command includes the encrypted algorithm SCRAM-SHA-256 and SCRAM-SHA-512 for the writer user, along with the corresponding salt, server key, and stored key. These are specific terms used in the SCRAM mechanism, but we do not need to understand their meanings because they do not affect our subsequent configurations.

Step 2: Creating JAAS Files #

After configuring the users, we need to create a JAAS file for each Broker. In this example, I only created one JAAS file because the two Broker instances are on the same machine. However, in a real scenario, you need to create a separate JAAS file for each physical Broker machine.

The content of the JAAS file is as follows:

KafkaServer {
org.apache.kafka.common.security.scram.ScramLoginModule required
username="admin"
password="admin";
};

Regarding the content of this file, you need to note the following two points:

  • Do not forget the semicolons at the end of the last and penultimate lines;
  • There should be no space in the JAAS file.

Here, we use the admin user for inter-Broker communication. Next, we configure the server.properties file for the Broker. The following contents need to be configured separately:

sasl.enabled.mechanisms=SCRAM-SHA-256

sasl.mechanism.inter.broker.protocol=SCRAM-SHA-256

security.inter.broker.protocol=SASL_PLAINTEXT

listeners=SASL_PLAINTEXT://localhost:9092

The first line indicates enabling the SCRAM authentication mechanism and using the SHA-256 algorithm. The second line means enabling SCRAM authentication for inter-Broker communication, also using the SHA-256 algorithm. The third line indicates that SSL is not configured for inter-Broker communication; this example does not demonstrate SSL configuration. The last line sets listeners to use SASL_PLAINTEXT, still without using SSL.

The configuration for the second Broker is basically the same, except for using a different port. In this example, the port is 9093.

Step 3: Starting Brokers #

Now let’s start these two Brokers separately. When starting, you need to specify the location of the JAAS file, as shown below:

$KAFKA_OPTS=-Djava.security.auth.login.config=<your_path>/kafka-broker.jaas bin/kafka-server-start.sh config/server1.properties
......
[2019-07-02 13:30:34,822] INFO Kafka commitId: fc1aaa116b661c8a (org.apache.kafka.common.utils.AppInfoParser)
[2019-07-02 13:30:34,822] INFO Kafka startTimeMs: 1562045434820 (org.apache.kafka.common.utils.AppInfoParser)
[2019-07-02 13:30:34,823] INFO [KafkaServer id=0] started (kafka.server.KafkaServer)
$KAFKA_OPTS=-Djava.security.auth.login.config=<your_path>/kafka-broker.jaas bin/kafka-server-start.sh config/server2.properties
......
[2019-07-02 13:32:31,976] INFO Kafka commitId: fc1aaa116b661c8a (org.apache.kafka.common.utils.AppInfoParser)
[2019-07-02 13:32:31,976] INFO Kafka startTimeMs: 1562045551973 (org.apache.kafka.common.utils.AppInfoParser)
[2019-07-02 13:32:31,978] INFO [KafkaServer id=1] started (kafka.server.KafkaServer)

At this point, both brokers have been successfully started.

Step 4: Sending Messages #

After creating the test topic, we use the kafka-console-producer script to attempt sending messages. Since authentication is enabled, the client needs to make some corresponding configurations. We create a configuration file named producer.conf with the following content:

security.protocol=SASL_PLAINTEXT
sasl.mechanism=SCRAM-SHA-256
sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username="writer" password="writer";

Afterward, we run the Console Producer program:

$ bin/kafka-console-producer.sh --broker-list localhost:9092,localhost:9093 --topic test  --producer.config <your_path>/producer.conf
>hello, world
>   

As seen above, the Console Producer program successfully sends the message.

Step 5: Consuming Messages #

Next, we consume the messages that were just produced using the Console Consumer program. Similarly, we need to create a script named consumer.conf for the kafka-console-consumer script with the following content:

security.protocol=SASL_PLAINTEXT
sasl.mechanism=SCRAM-SHA-256
sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username="reader" password="reader";

Afterward, we run the Console Consumer program:

$ bin/kafka-console-consumer.sh --bootstrap-server localhost:9092,localhost:9093 --topic test --from-beginning --consumer.config <your_path>/consumer.conf 
hello, world

Clearly, we can consume the messages normally.

Step 6: Dynamically Adding and Removing Users #

Finally, we demonstrate the scenario of dynamically adding and removing users for SASL/SCRAM. Suppose we delete the writer user and add a new user called new_writer. The commands we need to execute are as follows:

$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --delete-config 'SCRAM-SHA-256' --entity-type users --entity-name writer
Completed Updating config for entity: user-principal 'writer'.

$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --delete-config 'SCRAM-SHA-512' --entity-type users --entity-name writer
Completed Updating config for entity: user-principal 'writer'.

$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --add-config 'SCRAM-SHA-256=[iterations=8192,password=new_writer]' --entity-type users --entity-name new_writer
Completed Updating config for entity: user-principal 'new_writer'.

Now, we use the same producer.conf from before to verify that the Console Producer program cannot send messages, in order to confirm.

$ bin/kafka-console-producer.sh --broker-list localhost:9092,localhost:9093 --topic test  --producer.config /Users/huxi/testenv/producer.conf
>[2019-07-02 13:54:29,695] ERROR [Producer clientId=console-producer] Connection to node -1 (localhost/127.0.0.1:9092) failed authentication due to: Authentication failed during authentication due to invalid credentials with SASL mechanism SCRAM-SHA-256 (org.apache.kafka.clients.NetworkClient)
......

Obviously, the Console Producer can no longer send messages at this point. This is because it is using the producer.conf file, which specifies the already deleted writer user. If we modify the content of producer.conf to specify the newly created new_writer user, the result would be:

$ bin/kafka-console-producer.sh --broker-list localhost:9092,localhost:9093 --topic test  --producer.config <your_path>/producer.conf
>Good!  

Now, the Console Producer can send messages normally.

This process fully demonstrates how SASL/SCRAM can dynamically add and remove users without restarting the broker.

With that, the SASL/SCRAM configuration is complete. In the next article, I will explain in detail how to grant different permissions to the writer and reader users.

Summary #

Alright, let’s summarize. Today, we discussed several authentication mechanisms currently provided by Kafka. I presented their respective advantages, disadvantages, and recommended usage suggestions. In reality, authentication and authorization are often used together in real-world scenarios. In the next lecture, I will provide you with a detailed introduction to Kafka’s authorization mechanism, namely ACL mechanism. Stay tuned!

Open Discussion #

Please talk about the user authentication mechanism on your Kafka cluster and share a “pitfall” you have encountered.

Feel free to share your thoughts and answers, and let’s discuss together. If you find it insightful, feel free to share the article with your friends.