Skip to content

Instantly share code, notes, and snippets.

@DennisFederico
Last active June 21, 2023 10:00
Show Gist options
  • Save DennisFederico/b23b64e2794f7d312f626b7f42776277 to your computer and use it in GitHub Desktop.
Save DennisFederico/b23b64e2794f7d312f626b7f42776277 to your computer and use it in GitHub Desktop.
Creating Custom Certificates Using OpenSSL

Using Openssl

Certificate Authority

CA Key

openssl genrsa -des3 -out CA.key <2048|4096>
#Note: remove -des3 for a no password protected

CA Certificate

-- CA.conf --
[req]
default_bits=4096
default_md=sha256
prompt=no
distinguished_name=dn_details
x509_extensions=v3_ca

[dn_details]
C=ES
ST=Valencia
L=Paterna
CN=DENNIS CERTIFICATE AUTHORITY

[v3_ca]
basicConstraints = critical, CA:TRUE
keyUsage = critical, cRLSign, digitalSignature, keyCertSign

---
openssl req -x509 -new -nodes -key CA.key -sha256 -days 365 -config CA.conf -reqexts v3_ca -out CA.pem

Put something useful for the Common Name


Servers Certificates

Option 1 - Using config file

Specifying a config file with the following content

-- brokers.prd.conf --
[req]
default_bits=4096
default_md=sha256
prompt=no
distinguished_name=dn_details
x509_extensions=v3_req
req_extensions=v3_req

[dn_details]
C=ES
ST=Valencia
L=Paterna
CN=kafka.mycompany.com

[v3_req]
keyUsage = keyEncipherment, dataEncipherment, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
IP.1=172.30.19.215
IP.2=172.30.18.14
IP.3=172.30.21.33
DNS.1=ip-172-30-19-215.eu-west-1.compute.internal
DNS.2=ip-172-30-18-14.eu-west-1.compute.internal
DNS.3=ip-172-30-21-33.eu-west-1.compute.internal

---

# Create he CSR with the SANs
openssl req -new -key servers.key -out servers.csr -config sans.conf

#CREATES ALSO THE KEY USING -keyout

openssl req -new -nodes -keyout brokers.prd.key -out brokers.prd.csr -config brokers.prd.conf -reqexts v3_req

Option 2 - Using command-line only

This steps should be done for each server/appliance that needs a trusted certificate from CA

Create the certificate key

openssl genrsa -out dev.mydomain.com.key 2048

Create the (CSR) Certificate Sign Request

This is where you specify the details of the certificate you want to generate. This request will be processed by the owner of the Root Key - IMPORTANT: when creating this request, you should specify the IP address or domoin in the Common Name ... otherwise the certificate cannot be verified

Method A - Interactive

Doing it this way, openssl will ask you all the questions related to the certificate...

openssl req -new -key dev.mydomain.com.key -out dev.mydomain.com.csr

Method B - One Liner

openssl req -new -sha256 -key dev.mydomain.com.key \
  -subj "/C=ES/ST=CV/O=MyOrg/CN=<IP or DOMAIN>" \
  -out dev.mydomain.com.csr

One certificate can be used to secure several domains/sub-domains and IP address via the SAN (Subject Alternative Name), in a one line command these are specified using the -config

openssl req -new -sha256 -key dev.mydomain.com.key \
  -subj "/C=ES/ST=CV/O=MyOrg/CN=<IP or DOMAIN>" \
  -out dev.mydomain.com.csr \
  -reqexts SAN \
  -extensions SAN \
  -config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:mydomain.com,DNS:www.mydomain.com")) \
  -out dev.mydomain.csr

Create Signed Certificate

openssl x509 -req -in dev.deliciousbrains.com.csr -CA myCA.crt -CAkey myCA.key -CAcreateserial \
-out dev.deliciousbrains.com.crt -days 825 -sha256

#CERTIFICATE WITH ALTERNATIVE SUBJECTS (SAN)
openssl x509 -req -in kafka.csr -CA CA.crt -CAkey CA.key -CAcreateserial -out kafka.crt -days 365 -extfile kafka.conf -extensions v3_req

Create CSR and KEY in one go

openssl req -nodes -new -newkey rsa:4096 -out www.example.com.csr -keyout www.example.com.key

Create CSR for existing CRT and KEY

openssl x509 -x509toreq -in www.example.com.old.crt -signkey www.example.com.key -out www.example.com.csr

Verifications

Check the CSR (Certificate Request)

openssl req -text -noout -in brokers.prd.csr

Verify Certificate Content

openssl x509 -in brokers.prd.crt -text -noout

Verify IP and Hostname

openssl x509 -noout -in brokers.prd.crt -checkip 172.30.18.14

openssl x509 -noout -in brokers.prd.crt -checkhost ip-172-30-18-14.eu-west-1.compute.internal

Check HOST Handshake

openssl s_client -connect $KAFKA_SSL

openssl s_client -connect website.com:443 </dev/null 2>/dev/null | openssl x509 -noout -text | grep DNS:

Using Keytool

SSL uses private-key/certificate pairs, which are used during the SSL handshake process.

  • Each broker need its own private-ket/certificate pair or same-key/SAN certificate, and the client uses the certificate to authenticate the broker.
  • (Optional) If client authentication is enabled (mTLS), each client needs a private-key/certificate pair, and the broker uses the certificate to authenticate the client.

Each broker and client can be configured with a truststore that is used to determine which certificates (broker or logical client identities) to trust (authenticate).

  • The truststore contains one or many certificates: the broker or logical client will trust any certificate listed in the truststore.
  • The truststore contains a Certificate Authority (CA): the broker or logical client will trust any certificate that was signed by the CA in the truster.

Using the CA method is more convenient in operational terms, since you dont need to change the trustsore when brokers are added. However it is not possible to block authentication for individua brokers or clients previously trusted, certificate revocation is typically done using Certificate Revocation Lists or the Online Certificate Status Protocol, so you would have to rely on authorization mechanism to block access.

In contrast, if using many certificates, blocking authentication is achieved by removing the broker or client's certificate from the truststore.

SUMMARY: The keysotre stores each machine's own identity. The truststore stores all the certificates that the machine should trust and those signed by them.

Use ACL blacklists (specifically, the --deny-principal or --deny-host options) to remove a specific client. For details about ACLs, see Authorization using ACLs.

List keystore content
keytool -list -v -keystore server.keystore.jks
Generate Cert with SAN
keytool -keystore server.keystore.jks \
  -alias localhost \
  -validity {validity} \
  -genkey -keyalg RSA \
  -ext SAN=DNS:{FQDN}

...

Prepare keystores from certificates

Using the created certificate with SANs and the CA cert... we will create keystore and truststore for the server, as well as truststore for the client

#CREATE TRUSTORE FOR THE BROKERS (Usually anything signed by the CA)
keytool -keystore brokers.prd.trustore.jks \
  -alias CARoot -importcert -file myCARoot.crt

#CREATE TRUSTORE FOR THE CLIENT (Usually also anything signed by the CA)
keytool -keystore kafka.client.trustore.jks \
  -alias CARoot -importcert -file myCARoot.crt
   #(Optional) IMPORT THE BROKER(s) CERTIFICATES
keytool -keystore kafka.client.trustore.jks \
  -alias brokers.prd -importcert -file brokers.prd.crt

#CREATE KEYSTORE FOR THE BROKERS (Include the Priv-key, certificate and the CA)
#First convert the cert and pk into a pkcs 12 (.p12)
openssl pkcs12 -export \
  -in brokers.prd.crt -inkey brokers.prd.key \
  -out brokers.prd.p12
#Import key and certs
keytool -importkeystore \
  -deststorepass changeme -destkeystore brokers.prd.keystore.jks 
  -srckeystore brokers.prd.p12 -srcstoretype PKCS12 -srcstorepass changeme
#Import CA Cert
keytool -keystore brokers.prd.keystore.jks \
  -alias CARoot -importcert -file myCARoot.crt

Kafka Configurations for SSL

Host Name Verification

By default hostname verification of servers is enable for client connectios as well as inter-broer connections to prevent man-in-the-middle attacks. It can be disabled by setting

ssl.endpoint.identification.algorithm=

For dynamically configured broker listeners, hostname verification may be disabled using kafka-configs tool.

kafka-configs --bootstrap-server $KAFKA \
  --entity-type brokers \
  --entity-name 0 \
  --alter \
  --add-config "listener.name.internal.ssl.enpoint.identification.algorithm="

Configuring Host Names in Certificates

If host name verification is enabled, clients will verify the server's full FQDN against one of the following two fields.

  • Common Name (CN)
  • Subject Alternative Name (SAN)

Setup with keytool

NOTE: this may not work with SAN as openssl x509 -checkhost doesnt match the SANS, instead, create a key/certificate for each server using this method identifying them with the -dname "CN:xxxx"

Generate Keys and certificates

for each Kafka broker in the cluster. Generate the key into a keystore called kafka.server.keystore, later we will export and sign it.

#With user prompts
keytool -keystore kafka.server.keystore.jks -alias localhost -genkey -keyalg RSA

#Without user prompts
keytool -keystore kafka.server.keystore.jks -alias localhost \
  -genkey -keyalg RSA -validity 365 \
  -storepass changeme -keypass changeme \
  -dname "CN:broker.domain" \
  -ext "SAN=DNS:{hostname},IP:{address}"

Create own Certificate Authority (CA)

openssl req -new -x509 -keyout ca-key -out ca-cert -days 365
Add the CA Cert to the "servers" truststore
keytool -keystore kafka.client.truststore.jks \
  -alias CARoot \
  -importcert -file ca-cert
Add the CA to the "clients" truststore
keytool -keystore kafka.server.truststore.jks \
  -alias CARoot \
  -importcert -file ca-cert

Sign the certificates

Export the certificate from the keystore
keytool -keystore kafka.server.keystore.jks -alias localhost \
  -certreq -file cert-file
Sign it with the CA
openssl x509 -req -CA ca-cert -CAkey ca-key -in cert-file \
  -out cert-signed -days 365 -CAcreateserial passin pass:changeme
Import both (CA and signed certificate) into the broker keystore
keytool -keystore kafka.server.keystore.jks -alias CARoot \
  -importcert -file ca-cert
keytool -keystore kafka.server.keystore.jks -alias localhost \
  -importcert -file cert-signed
keytool -keystore kafka.server.keystore.jks -alias localhost \
  -genkey -keyalg RSA -validity 365 \
  -storepass changeme -keypass changeme \
  -dname "CN=broker.domain" \
  -ext "SAN=IP:172.30.19.215,IP:172.30.18.14,IP:172.30.21.33,DNS:ip-172-30-19-215.eu-west-1.compute.internal,DNS:ip-172-30-18-14.eu-west-1.compute.internal,DNS:ip-172-30-21-33.eu-west-1.compute.internal"

-Djavaee.jmxremote.authenticate=false

REMOVE PASSWORD FROM KEY

openssl rsa -in futurestudio_with_pass.key -out futurestudio.key

ENCRYPT PEM

openssl rsa -in dfederico-key.pem -out dfederico.key -aes256

PKCS8 FORMAT

openssl pkcs8 -topk8 -inform PEM -in dfederico-key.pem -out dfederico.pkcs8 -nocrypt

CREATE KEYSTORE

openssl pkcs12 -export -in dfederico.pem -inkey dfederico-key.pem -out dfederico.p12

keytool -importkeystore -deststorepass changeme -destkeystore dfederico.jks -srckeystore dfederico.p12 -srcstoretype PKCS12 -srcstorepass changeme

CREATE WITH SAN USING KEYTOOL

https://docs.confluent.io/platform/current/security/security_tutorial.html#generate-the-keys-and-certificates

$ keytool -keystore server.keystore.jks -alias localhost -validity {validity} -genkey -keyalg RSA -ext SAN=DNS:{FQDN}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment