Table of Contents
How to enable communication over https between 2 spring boot applications using self signed certificate
Introduction
In this tutorial, we will try to cover how we can enable HTTPS communication over 2 Spring boot applications. HTTPS was developed for exchanging confidential information in a secured manner by making use of encryption using public and private keys in order to prevent unauthorized access.
In the production environment, you will need to install a certificate issued by a certificate authority (CA) which will validate identity and then and issue certificates. CA certificates contain a public key corresponding to a private key. The CA owns the private key and uses it to sign the certificates it issues. Certificates help prevent the use of fake public keys for impersonation.
However, CA-signed certificates might not be available in the lower environments like DEV or for local testing, in this case, you might want to establish that your API’s are able to talk over HTTPS and this is where you can make use of the self-signed certificate.
Generating a self-signed certificate
We will use a self-signed certificate, to generate one we will need OpenSSL installed on our machine. In MacOs and Linux machines it is preinstalled, however, in windows you have to install it. Keytool can also be used to generate the self-signed certificates
- You can use below command to generate a self-signed certificate and private key. Also, note that the CN (the Common name is localhost) as we will be running the application on localhost. If you want to run on a domain name you can either replace the CN name with Domain name or use Subject Alt Names to use multiple domains. Read here —> how to
- Generate Public and Private keys123openssl req -x509 -nodes -newkey rsa:2048 -keyout private.key -out selfsigned.pem -subj '/C=gb/ST=XX/L=XX/O=XX/OU=XX/CN=localhost/emailAddress=postmaster@example.com' -days 365
The above command should generate set of public and private keys. The private key will be generated in a file called private.key and the public key or certificate will be generated in a file called selfsigned.pem.Also please note that above command also defines the country, state, location, organization name for simplification only XX has been added and the validity for above certificate is for a year which is controlled by ‘-days 365’. Feel free to change as per your needs.
- Check if the generated PEM file is correct123openssl x509 -in selfsigned.pem -text -noout
If the certificate has been generated successfully, then basically above command should generate something like this, basically listing out the expiry date, the signature algorithm etc.
12345678910111213Certificate:Data:Version: 1 (0x0)Serial Number: 10095699467019317110 (0x8c1b212d0ac96f76)Signature Algorithm: sha256WithRSAEncryptionIssuer: C=gb, ST=XX, L=XX, O=XX, OU=XX, CN=loclhost/emailAddress=postmaster@example.comValidityNot Before: Jun 27 10:52:32 2018 GMTNot After : Jun 27 10:52:32 2019 GMTSubject: C=gb, ST=XX, L=XX, O=XX, OU=XX, CN=loclhost/emailAddress=postmaster@example.comSubject Public Key Info: - Combine your key and certificate in a PKCS#12 (P12) bundle: The PKCS#12 or PFX format is a binary format for storing the server certificate, any intermediate certificates, and the private key into a single encryptable file. The below command will generate a file called keystore.12123openssl pkcs12 -export -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in selfsigned.pem -inkey private.key -name selfsigned -out keystore.p12
- Create a JKS from self-signed PEM: To implement X.509 authentication in a Spring application, we’ll first create a keystore in the Java Key-Store (JKS) format.123keytool -importkeystore -srcstoretype PKCS12 -srckeystore keystore.p12 -destkeystore keystore.jks -deststoretype pkcs12
Adding the Keystore.jks in the Spring boot application
Add the following configuration to your spring boot application.yaml file and copy the above-generated keystore.jks file in src/main/resources folder
1 2 3 4 5 6 7 8 | server: ssl: key-store-type: PKCS12 key-store: 'classpath:keystore.jks' key-store-password: changeit key-alias: selfsigned |
Now restart your application and see if you can see something in the logs ” Tomcat started on port(s): 8080 (https) with context path.. ”
This confirms that application will work only on https and not on http.
Calling from one Spring Boot application to another
Considering the above changes went well and both the Spring boot application has started and run on different ports with HTTPS enabled (server.port: port_number property can be used to configure different port numbers)
To call the other spring Boot application all we need is change the URL to use ‘https’
You can use RestTemplate to make a call
1 2 3 4 5 6 7 8 | @Autowired RestTemplate restTemplate; void someRandomFunction(){ restTemplate.getForObject("https://localhost:8090/SpringBootApp1", Response.class) } |
If you get the below exception
1 2 3 | org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://localhost:8100/customer/session/1b63e4b8-a91b-4742-b70a-8f113271212": sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target |
If you get SSL Handshake exception
1 2 3 4 | ****javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) |