no

Mutual TLS with Spring: Ensuring Secure Communication Between Applications

Overview

mTLS or Mutual Transport Layer Security is a type of mutual authentication where two parties, the client and the server, validate each other certificate. In this manner, the client and the server trust each other, and the connection is verified.

To be able to create lower environments as well as local ones, we need to create and sign our own certificates.

Digital Certificates

It is an electronic file composed of a public/private key pair that authenticates the identity of an entity. It facilitates secure online communication and data exchange between two entities. These two files are commonly associated with file extensions:

  • key - private
  • pem - public

Generating the Certificates

In the succeeding steps, we will generate 3 certificates:
  1. Root
  2. Client
  3. Server
We will use OpenSSL, available at https://sourceforge.net/projects/openssl.

A default password will be used for all the certificates "ca_pass_123".

Root Certificate - Private Key

This command will generate a root certificate that we will use to sign both the client and server certificates. We will use the default password.

Output: rootCA.key
  openssl genrsa -aes256 -out rootCA.key

Root Certificate - Public Key

Request a public certificate from the root certificate that we have just created.

It will ask for the root certificate's password and the following information.
  • Country Name=PH
  • State/Province=Laguna
  • Locality=Filipino
  • Organization Name=Czetsuya Tech
  • Organizational Unit=IT
  • Common Name=localhost
  • Email Address=czetsuya@gmail.com
CN=localhost should be replaced when creating certificates for different environments. It should match the domain name.

This certificate will be valid for 365 days.

Output: rootCA.pem
openssl req -new -x509 -key rootCA.key -sha256 -days 365 -out rootCA.pem

Server Certificate

Let's create our server certificate.

Output: server.key
openssl genrsa -aes256 -out server.key

Request for a CSR with the key as input.

It will ask for the root certificate's password and the following information same as the root.
  • Country Name=PH
  • State/Province=Laguna
  • Locality=Filipino
  • Organization Name=Czetsuya Tech
  • Organizational Unit=IT
  • Common Name=localhost
  • Email Address=czetsuya@gmail.com
It will ask for the server's password; use the default one. It will also ask for a challenge password and an optional company name that you can leave blank.

A CSR contains information that is required when requesting a certificate from a Certificate Authority.

Output: server.csr
openssl req -new -sha256 -key server.key -out server.csr

Sign the Server Certificate

We will ask a Certificate Authority to sign our server certificate in the following step. We will do this by using the root certificate that we created earlier. It will ask for the root certificate's password.

Outputs: server.pem, rooCA.srl
openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.pem -days 365 
  1. Client
  2. Server
We will use OpenSSL, available at https://sourceforge.net/projects/openssl.

A default password will be used for all the certificates "ca_pass_123".

Client Certificate

Since we will be doing mutual TLS, we also need to create a client certificate. The client will present its certificate, the server will validate it, and vice-versa.

Output: client.key
openssl genrsa -aes256 -out client.key
Request for a CSR with the key as input.

It will ask for the root certificate's password and the following information same as the server.
  • Country Name=PH
  • State/Province=Laguna
  • Locality=Filipino
  • Organization Name=Czetsuya Tech
  • Organizational Unit=IT
  • Common Name=localhost
  • Email Address=czetsuya@gmail.com
It will ask for the client's password; use the default one. It will also ask for a challenge password and an optional company name that you can leave blank.

A CSR contains information that is required when requesting a certificate from a Certificate Authority.

Output: client.csr
openssl req -new -key client.key -out client.csr

Sign the Client Certificate

We will ask a Certificate Authority to sign the client certificate in the following step. We will do this by using the root certificate that we created earlier. It will ask for the root certificate's password.

Outputs: client.pem, rooCA.srl
openssl x509 -req -in client.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out client.pem -days 365

mTLS on Spring Boot Application

Now, it's time to create a Spring project to demonstrate TLS. It is enough to have spring-boot-starter-web dependency for this exercise.

Postman is also needed to perform tests.

One Way TLS

We will start with one-way TLS, where the client will verify that the server certificate is valid. Spring Boot will do the heavy lifting through configuration, but we must provide it with our bundled server's private and public keys.

It will ask for the server password, and you will need to specify a new one for export. Remember this password, as we will use it in our Spring application.

Output: keystore.p12

openssl pkcs12 -export -in server.pem -out keystore.p12 -name server -inkey server.key
You can explore its content using a Keystore Explorer.


Copy the keystore.p12 file into your Spring project's src/main/resources folder.

Update the application.xml property file.
server:
  ssl:
    enabled: true
    key-store: "classpath:keystore.p12"
    key-store-password: ca_pass_123
    key-store-type: PKCS12
Since we import the keys with a password, we must provide it in the Spring configuration.

Let's create a test controller.

@RestController
public class MtlsController {
 
    @GetMapping("/mtls-test")
    public String hello() {
 
        return "Hello mTLS";
    }
}
When we run the application, we should see the following log, indicating that HTTPS is on.

2023-02-21T17:29:25.167+08:00  INFO 21536 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (https) with context path ''

Testing the Certificate

If we access the endpoint using HTTP protocol, we will get the following:

Bad Request
This combination of host and port requires TLS.
Changing the protocol to HTTPS doesn't solve the issue.


The reason is that Postman is unaware that we are a certificate authority and doesn't know our root certificate. Thus, we need to make some changes in Postman.

At the top, click the gear icon and Settings. Open the certificate tab. Enable CA Certificates and select the rootCA.pem file.


Postman should be able to call the endpoint correctly.

Two Way TLS

We must make several changes to enable mutual authentication, where the server validates the client's certificate.

First, we must tell the Spring Boot app to validate the client's certificate by simply adding a config server.client-auth=need.

Running the same test in Postman will fail because the server will now look for the client's certificate. Let's add the certificate to Postman. Once again, go back to Settings / Certificates, and under the client certificates section, add our certificate.
  • host=localhost
  • port=8080
  • CRT file=client.pem
  • Key file=client.key
  • PassPhrase=ca_pass_123

However, enabling client certificate authentication introduces a new problem. The application needs a store to validate the client's certificate, which is called a trust store. Similar to the Keystore, we must add this store to our application.
The command will ask to trust the certificate; type 'yes'.

keytool -import -file rootCA.pem -alias rootCA -keystore truststore.p12
Update the application.xml file.

server:
  ssl:
    key-store: "classpath:keystore.p12"
    key-store-password: ca_pass_123
    key-store-type: PKCS12
    enabled: true
    key-password: ca_pass_123
    client-auth: need
    trust-store: "classpath:truststore.p12"
    trust-store-password: ca_pass_123
    trust-store-type: PKCS12
And with that, we should be able to successfully call our REST endpoint with mutual authentication.

What's Next?

I plan to build 2 Spring application that communicates with mTLS. Stay tuned!

Related

spring-security 2530010153380937626

Post a Comment Default Comments

item