Spring Boot <-> Kafka (HTTPS)

In this article, we will be developing a Spring Boot application that works with Kafka and terminates traffic via HTTPS. So first of all we…

In this article, we will be developing a Spring Boot application that works with Kafka and terminates traffic via HTTPS.
So first of all we have to generate self-signed certificates by following the bash script

``` 
#!/bin/bash  
  
set -o nounset \  
 -o errexit \  
 -o verbose \  
 -o xtrace  
  
# Generate CA key  
openssl req -new -x509 -keyout snakeoil-ca-1.key -out snakeoil-ca-1.crt -days 365 -subj ‘/CN=localhost/OU=TEST/O=MEDIUM/L=PaloAlto/S=Ca/C=US’ -passin pass:medium -passout pass:medium  
# openssl req -new -x509 -keyout snakeoil-ca-2.key -out snakeoil-ca-2.crt -days 365 -subj ‘/CN=ca2.test.confluent.io/OU=TEST/O=MEDIUM/L=PaloAlto/S=Ca/C=US’ -passin pass:meduim -passout pass:medium  
  
# Kafkacat  
openssl genrsa -des3 -passout “pass:medmium” -out kafkacat.client.key 1024  
openssl req -passin “pass:medium” -passout “pass:medium” -key kafkacat.client.key -new -out kafkacat.client.req -subj ‘/CN=localhost/OU=TEST/O=MEDIUM/L=PaloAlto/S=Ca/C=US’  
openssl x509 -req -CA snakeoil-ca-1.crt -CAkey snakeoil-ca-1.key -in kafkacat.client.req -out kafkacat-ca1-signed.pem -days 9999 -CAcreateserial -passin “pass:medium”  
  
  
for i in broker1 consumer # we are going to generate certs for broker(zookeper) and cosumer(our app) 
do  
 echo $i  
 # Create keystores  
 keytool -genkey -noprompt \  
 -alias $i \ 
 -dname “CN=localhost, OU=TEST, O=MEDIUM, L=PaloAlto, S=Ca, C=US” \  
 -keystore kafka.$i.keystore.jks \  
 -keyalg RSA \  
 -storepass confluent \  
 -keypass confluent  
  
 # Create CSR, sign the key and import back into keystore  
 keytool -keystore kafka.$i.keystore.jks -alias $i -certreq -file $i.csr -storepass confluent -keypass medium  
  
 openssl x509 -req -CA snakeoil-ca-1.crt -CAkey snakeoil-ca-1.key -in $i.csr -out $i-ca1-signed.crt -days 9999 -CAcreateserial -passin pass:medium  
  
 keytool -keystore kafka.$i.keystore.jks -alias CARoot -import -file snakeoil-ca-1.crt -storepass meduim -keypass medium  
  
 keytool -keystore kafka.$i.keystore.jks -alias $i -import -file $i-ca1-signed.crt -storepass medium -keypass medium  
  
 # Create truststore and import the CA cert.  
 keytool -keystore kafka.$i.truststore.jks -alias CARoot -import -file snakeoil-ca-1.crt -storepass medium -keypass medium  
  
 echo “medium” > ${i}_sslkey_creds  
 echo “medium” > ${i}_keystore_creds  
 echo “medium” > ${i}_truststore_creds  
done

This script eventually generated for us following files
- broker1.csr
- broker1-ca-signed.crt
- broker1_keystore_creds
- broker1_sslkey_creds
- broker1_trustore_creds
- kafka.broker1.keystore.jks
- kafka.broker1.trustore.jks
Store this file at some easily accessible place, because we are going to use it to start docker containers of Kafka and Zookeeper

docker-compose.yml:

version: '3'  
  
services:  
 zookeeper:  
   image: confluentinc/cp-zookeeper:latest  
   container_name: zookeper  
   environment:  
     ZOOKEEPER_CLIENT_PORT: 2181  
     ZOOKEEPER_TICK_TIME: 2000  
   ports:  
     - 22181:2181  
 kafka:  
   image: confluentinc/cp-kafka:latest  
   container_name: kafka  
   depends_on:  
     - zookeeper  
   ports:  
     - 29093:29093  
   environment:  
     KAFKA_BROKER_ID: 1  
     KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181  
     KAFKA_ADVERTISED_LISTENERS: SSL://localhost:29093  
     KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1  
     KAFKA_SSL_KEYSTORE_FILENAME: kafka.broker1.keystore.jks  
     KAFKA_SSL_KEYSTORE_CREDENTIALS: broker1_keystore_creds  
     KAFKA_SSL_KEY_CREDENTIALS: broker1_sslkey_creds  
     KAFKA_SSL_TRUSTSTORE_FILENAME: kafka.broker1.truststore.jks  
     KAFKA_SSL_ENDPOINT_IDENTIFICATION_ALGORITHM: " "  
     KAFKA_SSL_TRUSTSTORE_CREDENTIALS: broker1_truststore_creds  
     KAFKA_SSL_CLIENT_AUTH: requested  
     KAFKA_SECURITY_INTER_BROKER_PROTOCOL: SSL  
     volumes:  
       - ./secrets:/etc/kafka/secrets

In my case secrets are laying at secrets folder and this folder will be mounted to /etc/kafka/secrets
Kafka HTTPS port is 29023

Now we can start Kafka by

docker compose up -d

After a few moments an instance of Kafka ready to accept data on the 29093 port
Now it’s time to write some YAML (again)

server:  
 port: 8080  
 forward-headers-strategy: framework  
spring:  
 kafka:  
   security:  
     protocol: “SSL”  
   producer:  
     bootstrap-servers:  
       — http://localhost:29093  
      key-serializer: org.apache.kafka.common.serialization.StringSerializer  
      value-serializer: io.vrnsky.support.AvroSerializer  
   consumer:  
     bootstrap-servers:  
       — http://localhost:29093  
     key-deserializer: org.apache.kafka.common.serialization.StringDeserializer  
     value-deserializer: io.vrnsky.support.AvroDeserializer  
   ssl:  
     trust-store-location: classpath:ssl/trustore.jks  
     trust-store-password: medium  
foorTopicConfig:  
 consumer:  
 topic: ‘FoodIsReady’  
 groupId: ‘quesaDilla’  
 producer:  
 topic: ‘IsFoodComing’

So trustrore.jks should be in the resources folder under the ssl folder according to the configuration above. While this app works perfectly on your local machine, it will fail on the production and on your local machine too. It happens because kafka client library could not resolve the classpath URL. There is official bug
So you have to copy your keystore to your container
Basically, Spring Boot Kafka Autoconfiguration creates all required beans for you, but you can configure it programmatically if you need some additional logic

I hope you enjoy this article
Follow me for more content

Subscribe to Egor Voronianskii | Java Development and whatsoever

Sign up now to get access to the library of members-only issues.
Jamie Larson
Subscribe