#!/usr/bin/env bash set -eu KEYSTORE_FILENAME="kafka.keystore.jks" VALIDITY_IN_DAYS=3650 DEFAULT_TRUSTSTORE_FILENAME="kafka.truststore.jks" TRUSTSTORE_WORKING_DIRECTORY="truststore" KEYSTORE_WORKING_DIRECTORY="keystore" CA_CERT_FILE="ca-cert" KEYSTORE_SIGN_REQUEST="cert-file" KEYSTORE_SIGN_REQUEST_SRL="ca-cert.srl" KEYSTORE_SIGNED_CERT="cert-signed" export COUNTRY=US export STATE=IL export ORGANIZATION_UNIT=SE export CITY=Chicago export PASSWORD=secret COUNTRY=$COUNTRY STATE=$STATE OU=$ORGANIZATION_UNIT CN=kafka0 # COMMON NAME VERIFICATION GOES BRR LOCATION=$CITY PASS=$PASSWORD function file_exists_and_exit() { echo "'$1' cannot exist. Move or delete it before" echo "re-running this script." exit 1 } if [ -e "$KEYSTORE_WORKING_DIRECTORY" ]; then file_exists_and_exit $KEYSTORE_WORKING_DIRECTORY fi if [ -e "$CA_CERT_FILE" ]; then file_exists_and_exit $CA_CERT_FILE fi if [ -e "$KEYSTORE_SIGN_REQUEST" ]; then file_exists_and_exit $KEYSTORE_SIGN_REQUEST fi if [ -e "$KEYSTORE_SIGN_REQUEST_SRL" ]; then file_exists_and_exit $KEYSTORE_SIGN_REQUEST_SRL fi if [ -e "$KEYSTORE_SIGNED_CERT" ]; then file_exists_and_exit $KEYSTORE_SIGNED_CERT fi echo "Welcome to the Kafka SSL keystore and trust store generator script." trust_store_file="" trust_store_private_key_file="" if [ -e "$TRUSTSTORE_WORKING_DIRECTORY" ]; then file_exists_and_exit $TRUSTSTORE_WORKING_DIRECTORY fi mkdir $TRUSTSTORE_WORKING_DIRECTORY echo echo "OK, we'll generate a trust store and associated private key." echo echo "First, the private key." echo openssl req -new -x509 -keyout $TRUSTSTORE_WORKING_DIRECTORY/ca-key \ -out $TRUSTSTORE_WORKING_DIRECTORY/ca-cert -days $VALIDITY_IN_DAYS -nodes \ -subj "/C=$COUNTRY/ST=$STATE/L=$LOCATION/O=$OU/CN=$CN" trust_store_private_key_file="$TRUSTSTORE_WORKING_DIRECTORY/ca-key" echo echo "Two files were created:" echo " - $TRUSTSTORE_WORKING_DIRECTORY/ca-key -- the private key used later to" echo " sign certificates" echo " - $TRUSTSTORE_WORKING_DIRECTORY/ca-cert -- the certificate that will be" echo " stored in the trust store in a moment and serve as the certificate" echo " authority (CA). Once this certificate has been stored in the trust" echo " store, it will be deleted. It can be retrieved from the trust store via:" echo " $ keytool -keystore -export -alias CARoot -rfc" echo echo "Now the trust store will be generated from the certificate." echo keytool -keystore $TRUSTSTORE_WORKING_DIRECTORY/$DEFAULT_TRUSTSTORE_FILENAME \ -alias CARoot -import -file $TRUSTSTORE_WORKING_DIRECTORY/ca-cert \ -noprompt -dname "C=$COUNTRY, ST=$STATE, L=$LOCATION, O=$OU, CN=$CN" -keypass $PASS -storepass $PASS -storetype JKS trust_store_file="$TRUSTSTORE_WORKING_DIRECTORY/$DEFAULT_TRUSTSTORE_FILENAME" echo echo "$TRUSTSTORE_WORKING_DIRECTORY/$DEFAULT_TRUSTSTORE_FILENAME was created." # don't need the cert because it's in the trust store. rm $TRUSTSTORE_WORKING_DIRECTORY/$CA_CERT_FILE echo echo "Continuing with:" echo " - trust store file: $trust_store_file" echo " - trust store private key: $trust_store_private_key_file" mkdir $KEYSTORE_WORKING_DIRECTORY echo echo "Now, a keystore will be generated. Each broker and logical client needs its own" echo "keystore. This script will create only one keystore. Run this script multiple" echo "times for multiple keystores." echo echo " NOTE: currently in Kafka, the Common Name (CN) does not need to be the FQDN of" echo " this host. However, at some point, this may change. As such, make the CN" echo " the FQDN. Some operating systems call the CN prompt 'first / last name'" # To learn more about CNs and FQDNs, read: # https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/X509ExtendedTrustManager.html keytool -keystore $KEYSTORE_WORKING_DIRECTORY/$KEYSTORE_FILENAME \ -alias localhost -validity $VALIDITY_IN_DAYS -genkey -keyalg RSA \ -noprompt -dname "C=$COUNTRY, ST=$STATE, L=$LOCATION, O=$OU, CN=$CN" -keypass $PASS -storepass $PASS -storetype JKS echo echo "'$KEYSTORE_WORKING_DIRECTORY/$KEYSTORE_FILENAME' now contains a key pair and a" echo "self-signed certificate. Again, this keystore can only be used for one broker or" echo "one logical client. Other brokers or clients need to generate their own keystores." echo echo "Fetching the certificate from the trust store and storing in $CA_CERT_FILE." echo keytool -keystore $trust_store_file -export -alias CARoot -rfc -file $CA_CERT_FILE -keypass $PASS -storepass $PASS echo echo "Now a certificate signing request will be made to the keystore." echo keytool -keystore $KEYSTORE_WORKING_DIRECTORY/$KEYSTORE_FILENAME -alias localhost \ -certreq -file $KEYSTORE_SIGN_REQUEST -keypass $PASS -storepass $PASS echo echo "Now the trust store's private key (CA) will sign the keystore's certificate." echo openssl x509 -req -CA $CA_CERT_FILE -CAkey $trust_store_private_key_file \ -in $KEYSTORE_SIGN_REQUEST -out $KEYSTORE_SIGNED_CERT \ -days $VALIDITY_IN_DAYS -CAcreateserial # creates $KEYSTORE_SIGN_REQUEST_SRL which is never used or needed. echo echo "Now the CA will be imported into the keystore." echo keytool -keystore $KEYSTORE_WORKING_DIRECTORY/$KEYSTORE_FILENAME -alias CARoot \ -import -file $CA_CERT_FILE -keypass $PASS -storepass $PASS -noprompt rm $CA_CERT_FILE # delete the trust store cert because it's stored in the trust store. echo echo "Now the keystore's signed certificate will be imported back into the keystore." echo keytool -keystore $KEYSTORE_WORKING_DIRECTORY/$KEYSTORE_FILENAME -alias localhost -import \ -file $KEYSTORE_SIGNED_CERT -keypass $PASS -storepass $PASS echo echo "All done!" echo echo "Deleting intermediate files. They are:" echo " - '$KEYSTORE_SIGN_REQUEST_SRL': CA serial number" echo " - '$KEYSTORE_SIGN_REQUEST': the keystore's certificate signing request" echo " (that was fulfilled)" echo " - '$KEYSTORE_SIGNED_CERT': the keystore's certificate, signed by the CA, and stored back" echo " into the keystore" rm $KEYSTORE_SIGN_REQUEST_SRL rm $KEYSTORE_SIGN_REQUEST rm $KEYSTORE_SIGNED_CERT