Tutorial : Secure your API with x509 Mutual Authentication on OpenShift

Mutual authentication or two-way authentication refers to two parties authenticating each other at the same time, being a default mode of authentication in some protocols (IKE, SSH) and optional in others (TLS).

As it requires provisioning of the certificates to the clients and involves less user-friendly experience, it’s rarely used in end-user applications.

Mutual TLS authentication (mTLS) is much more widespread in business-to-business (B2B) applications, where a limited number of programmatic and homogeneous clients are connecting to specific web services, the operational burden is limited, and security requirements are usually much higher as compared to consumer environments. [2]

This tutorial will guide you step by step to implement x509 mutual authentication. With Red Hat OpenShift we can leverage existing spring boot REST application to become a secured x509 mTLS application. Below is our tutorial flow

Prerequisite

  1. Pre-installed openssl cli tool on your OS.
  2. Pre-installed keytool cli tool on your OS.
  3. Pre-installed oc cli tool on your OS
  4. Deploy Spring Boot sample apps on Openshift using s2i java:11. Source code here.

Step 1 : Create Root CA

To be able to sign our server-side and client-side certificates, we need to create our own self-signed root CA certificate first. On This tutorial we will act as our own certificate authority.

Let’s now create the CA certificate:

$ openssl req -x509 -sha256 -days 3650 -newkey rsa:4096 -keyout rootCA.key -out rootCA.crt

Note: for this tutorial i use “changeit” as rootCA passphrase and erfinfeluzy.com as Common Name (CN). the rest is empty

Step 2 : Server-side Certificate

Let’s start with creating a so-called certificate signing request (CSR):

$ openssl req -new -newkey rsa:4096 -keyout localhost.key

Similarly, as for the CA certificate, we have to provide the password for the private key. Additionally, let’s use localhost as a common name (CN). Copy-then-paste previous result to certificate signing request (.csr)

$ vi localhost.csr
...
-----BEGIN CERTIFICATE REQUEST-----
...
-----END CERTIFICATE REQUEST-----
...

Before we proceed, we need to create a configuration file — localhost.ext. It’ll store some additional parameters needed during signing the certificate.

$ vi localhost.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost

Now, it’s time to sign the request with our rootCA.crt certificate and its private key:

$ openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in localhost.csr -out localhost.crt -days 365 -CAcreateserial -extfile localhost.ext

we finally have a ready to use localhost.crt certificate signed by our own certificate authority.

To print our certificate’s details in a human-readable form we can use the following command:

$ openssl x509 -in localhost.crt -text

Step 3 : Create KeyStore

A keystore is a repository that our Spring Boot application will use to hold our server’s private key and certificate. In other words, our application will use the keystore to serve the certificate to the clients during the SSL handshake [1].

We’ll use the PKCS 12 archive, to package our server’s private key together with the signed certificate. Then we’ll import it to the newly created keystore.jks

$ openssl pkcs12 -export -out localhost.p12 -name “localhost” -inkey localhost.key -in localhost.crt

import localhost.p12 file to keystore.jks

$ keytool -importkeystore -srckeystore localhost.p12 -srcstoretype PKCS12 -destkeystore keystore.jks -deststoretype JKS

Step 4 : Create TrustStore

A truststore in some way is the opposite of a keystore. It holds the certificates of the external entities that we trust. [1]

In our case, it’s enough to keep the root CA certificate in the truststore.

Let’s see how to create a truststore.jks file and import the rootCA.crt using keytool:

$ keytool -import -trustcacerts -noprompt -alias ca -ext san=dns:localhost,ip:127.0.0.1 -file rootCA.crt -keystore truststore.jks

Step 5 : Enable Mutual Authentication on Your Spring Boot Application on OpenShift

upload your keystore and truststore on your local machine as configmap on OpenShift, then mount it to your application deployment

$ cp keystore.jks security-config/keystore.jks$ cp truststore.jks security-config/truststore.jks$ oc create configmap my-x509-config --from-file=security-config/

Note: Only copy keystore.jks and truststore.jks files.

add config map to your deployment, mount it to pods with mount-path:

/my-x509-config

$ oc get deployments
...
NAME READY UP-TO-DATE AVAILABLE AGE
springboot-sample-apps-git 1/1 1 1 6h28m
...
$ oc set volume deployment/springboot-sample-apps-git \
--add \
--type=configmap \
--configmap-name=my-x509-config \
--mount-path=/my-x509-config

Set Environment Variable on Deployment

current Spring Boot apps will enable https and x509 client authentication

server.port=8443server.ssl.enabled=true
server.ssl.client-auth=need
server.ssl.key-store=/my-x509-config/keystore.jks
server.ssl.key-store-password=changeit
server.ssl.trust-store=/my-x509-config/truststore.jks
server.ssl.trust-store-password=changeit

Create Secure Route with Passthrough mode

Open routes on browser, it will ask for client certificate:

if you use wrong certificate, Browser will not allow you to access

Step 6 : Create Client Certificate

$ openssl req -new -newkey rsa:4096 -nodes -keyout clientErfin.key

In this tutorial i use “ClientErfin” as Common Name (CN), rest left blank. copy from begin certificate reqeust to end cert request from output to new certifcate sign request (.csr) file

$ vi clientErfin.csr-----BEGIN CERTIFICATE REQUEST-----

...
-----END CERTIFICATE REQUEST-----

Generate Client Certificate (.crt) file

$ openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in clientErfin.csr -out clientErfin.crt -days 365 -CAcreateserial

Last step, package client key (.key) and client signed certificate (.crt) in PKCS format

$ openssl pkcs12 -export -out clientErfin.p12 -name “clientErfin” -inkey clientErfin.key -in clientErfin.crt

Again, i use “changeit” as client password.

Note: in reality you can give this p12 file to your api consumer.

Step 7 : Import Client Certificate to Browser

writer use macOS on this tutorial, thus i use KeyChain and add new certificate, add clientErfin.p12 file on KeyChain, it will ask you for password of p12 file.

Now you can successfully open the Apps on your favorite browser after input the right certificate.

Test it on Postman

You can add certificate on PostMan > settings > choose clientErfin.p12 as PFX file, input passphrase for the file > Add

Conclusions

Rd Hat OpenShift can be used for application that need custom security mechanism like X509 Mutual Authentication. This is one of use case when to use passthrough method as TLS termination on OpenShift route. TLS termination not happened on the edge, but directly handled by the application inside the pod.

References

--

--

Erfin Feluzy
Development using RedHat Product. (This is an Unofficial Blog)

Kuli Ketik dan AppDev Solution Architect at Red Hat. Eat, Code, Sleep — repeat.