Enable HTTPS in Spring Boot with Azure Key Vault certificates
This tutorial shows you how to secure your Spring Boot (including Azure Spring Apps) apps with TLS/SSL certificates using Azure Key Vault and managed identities for Azure resources.
Production-grade Spring Boot applications, whether in the cloud or on-premises, require end-to-end encryption for network traffic using standard TLS protocols. Most TLS/SSL certificates you come across are discoverable from a public root certificate authority (CA). Sometimes, however, this discovery isn't possible. When certificates aren't discoverable, the app must have some way to load such certificates, present them to inbound network connections, and accept them from outbound network connections.
Spring Boot apps typically enable TLS by installing the certificates. The certificates are installed into the local key store of the JVM that's running the Spring Boot app. With Spring on Azure, certificates aren't installed locally. Instead, Spring integration for Microsoft Azure provides a secure and frictionless way to enable TLS with help from Azure Key Vault and managed identity for Azure resources.
Important
Currently, Spring Cloud Azure Certificate starter version 4.x or higher don't support TLS/mTLS, they only auto-configure the Key Vault certificate client. Therefore, if you want to use TLS/mTLS, you cannot migrate to version 4.x.
Prerequisites
An Azure subscription - create one for free.
A supported Java Development Kit (JDK) with version 11.
Apache Maven version 3.0 or higher.
cURL or a similar HTTP utility to test functionality.
An Azure virtual machine (VM) instance. If you don't have one, use the az vm create command and the Ubuntu image provided by UbuntuServer to create a VM instance with a system-assigned managed identity enabled. Grant the
Contributor
role to the system-assigned managed identity, and then set the accessscope
to your subscription.An Azure Key Vault instance. If you don't have one, see Quickstart: Create a key vault using the Azure portal.
A Spring Boot application. If you don't have one, create a Maven project with the Spring Initializr. Be sure to select Maven Project and, under Dependencies, add the Spring Web dependency, then select Java version 8 or higher.
Important
Spring Boot version 2.5 or higher is required to complete the steps in this article.
Set a self-signed TLS/SSL certificate
The steps in this tutorial apply to any TLS/SSL certificate (including self-signed) stored directly in Azure Key Vault. Self-signed certificates aren't suitable for use in production, but are useful for dev and test applications.
This tutorial uses a self-signed certificate. To set the certificate, see Quickstart: Set and retrieve a certificate from Azure Key Vault using the Azure portal.
Note
After setting the certificate, grant VM access to Key Vault by following the instructions in Assign a Key Vault access policy.
Secure connection through TLS/SSL certificate
You now have a VM and a Key Vault instance and have granted the VM access to Key Vault. The following sections show how to connect securely via TLS/SSL certificates from Azure Key Vault in the Spring Boot application. This tutorial demonstrates the following two scenarios:
- Run a Spring Boot application with secure inbound connections
- Run a Spring Boot application with secure outbound connections
Tip
In the following steps, the code will be packaged into an executable file and uploaded to the VM. Don't forget to install OpenJDK in the VM.
Run a Spring Boot application with secure inbound connections
When the TLS/SSL certificate for the inbound connection comes from Azure Key Vault, configure the application by following these steps:
Add the following dependencies to your pom.xml file:
<dependency> <groupId>com.azure.spring</groupId> <artifactId>azure-spring-boot-starter-keyvault-certificates</artifactId> <version>3.14.0</version> </dependency>
Configure Key Vault credentials in the application.properties configuration file.
server.ssl.key-alias=<the name of the certificate in Azure Key Vault to use> server.ssl.key-store-type=AzureKeyVault server.ssl.trust-store-type=AzureKeyVault server.port=8443 azure.keyvault.uri=<the URI of the Azure Key Vault to use>
These values enable the Spring Boot app to perform the load action for the TLS/SSL certificate, as mentioned at the beginning of the tutorial. The following table describes the property values.
Property Description server.ssl.key-alias
The value of the --name
argument you passed toaz keyvault certificate create
.server.ssl.key-store-type
Must be AzureKeyVault
.server.ssl.trust-store-type
Must be AzureKeyVault
.server.port
The local TCP port on which to listen for HTTPS connections. azure.keyvault.uri
The vaultUri
property in the return JSON fromaz keyvault create
. You saved this value in an environment variable.The only property specific to Key Vault is
azure.keyvault.uri
. The app is running on a VM whose system-assigned managed identity has been granted access to the Key Vault. Therefore, the app has also been granted access.These changes enable the Spring Boot app to load the TLS/SSL certificate. In the next step, you'll enable the app to perform the accept action for the TLS/SSL certificate, as mentioned at the beginning of the tutorial.
Edit the startup class file so that it has the following contents.
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class SsltestApplication { public static void main(String[] args) { SpringApplication.run(SsltestApplication.class, args); } @GetMapping(value = "/ssl-test") public String inbound(){ return "Inbound TLS is working!!"; } @GetMapping(value = "/exit") public void exit() { System.exit(0); } }
Calling
System.exit(0)
from within an unauthenticated REST GET call is only for demonstration purposes. Don't useSystem.exit(0)
in a real application.This code illustrates the present action mentioned at the beginning of this tutorial. The following list highlights some details about this code:
- There's now a
@RestController
annotation on theSsltestApplication
class generated by Spring Initializr. - There's a method annotated with
@GetMapping
, with avalue
for the HTTP call you make. - The
inbound
method simply returns a greeting when a browser makes an HTTPS request to the/ssl-test
path. Theinbound
method illustrates how the server presents the TLS/SSL certificate to the browser. - The
exit
method causes the JVM to exit when invoked. This method is a convenience to make the sample easy to run in the context of this tutorial.
- There's now a
Run the following commands to compile the code and package it into an executable JAR file.
mvn clean package
Verify that the network security group created within
<your-resource-group-name>
allows inbound traffic on ports 22 and 8443 from your IP address. To learn about configuring network security group rules to allow inbound traffic, see the Work with security rules section of Create, change, or delete a network security group.Put the executable JAR file on the VM.
cd target sftp azureuser@<your VM public IP address> put *.jar
Now that you've built the Spring Boot app and uploaded it to the VM, use the following steps to run it on the VM and call the REST endpoint with
curl
.Use SSH to connect to the VM, then run the executable JAR.
set -o noglob ssh azureuser@<your VM public IP address> "java -jar *.jar"
Open a new Bash shell and execute the following command to verify that the server presents the TLS/SSL certificate.
curl --insecure https://<your VM public IP address>:8443/ssl-test
Invoke the
exit
path to kill the server and close the network sockets.curl --insecure https://<your VM public IP address>:8443/exit
Now that you've seen the load and present actions with a self-signed TLS/SSL certificate, make some trivial changes to the app to see the accept action as well.
Run a Spring Boot application with secure outbound connections
In this section, you modify the code in the previous section so that the TLS/SSL certificate for outbound connections comes from Azure Key Vault. Therefore, the load, present, and accept actions are satisfied from the Azure Key Vault.
Add the Apache HTTP client dependency to your pom.xml file:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency>
Add a new rest endpoint called
ssl-test-outbound
. This endpoint opens up a TLS socket to itself and verifies that the TLS connection accepts the TLS/SSL certificate. Replace the previous part of the startup class with the following code.import java.security.KeyStore; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import com.azure.security.keyvault.jca.KeyVaultLoadStoreParameter; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContexts; @SpringBootApplication @RestController public class SsltestApplication { public static void main(String[] args) { SpringApplication.run(SsltestApplication.class, args); } @GetMapping(value = "/ssl-test") public String inbound(){ return "Inbound TLS is working!!"; } @GetMapping(value = "/ssl-test-outbound") public String outbound() throws Exception { KeyStore azureKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault"); KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter( System.getProperty("azure.keyvault.uri")); azureKeyVaultKeyStore.load(parameter); SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(azureKeyVaultKeyStore, null) .build(); HostnameVerifier allowAll = (String hostName, SSLSession session) -> true; SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, allowAll); CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(csf) .build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory); String sslTest = "https://localhost:8443/ssl-test"; ResponseEntity<String> response = restTemplate.getForEntity(sslTest, String.class); return "Outbound TLS " + (response.getStatusCode() == HttpStatus.OK ? "is" : "is not") + " Working!!"; } @GetMapping(value = "/exit") public void exit() { System.exit(0); } }
Run the following commands to compile the code and package it into an executable JAR file.
mvn clean package
Upload the app again using the same
sftp
command from earlier in this article.cd target sftp <your VM public IP address> put *.jar
Run the app on the VM.
set -o noglob ssh azureuser@<your VM public IP address> "java -jar *.jar"
After the server is running, verify that the server accepts the TLS/SSL certificate. In the same Bash shell where you issued the previous
curl
command, run the following command.curl --insecure https://<your VM public IP address>:8443/ssl-test-outbound
You should see the message
Outbound TLS is working!!
.Invoke the
exit
path to kill the server and close the network sockets.curl --insecure https://<your VM public IP address>:8443/exit
You've now observed a simple illustration of the load, present, and accept actions with a self-signed TLS/SSL certificate stored in Azure Key Vault.
Deploy to Azure Spring Apps
Now that you have the Spring Boot application running locally, it's time to move it to production. Azure Spring Apps makes it easy to deploy Spring Boot applications to Azure without any code changes. The service manages the infrastructure of Spring applications so developers can focus on their code. Azure Spring Apps provides lifecycle management using comprehensive monitoring and diagnostics, configuration management, service discovery, CI/CD integration, blue-green deployments, and more. To deploy your application to Azure Spring Apps, see Deploy your first application to Azure Spring Apps.
Next steps
To learn more about Spring and Azure, continue to the Spring on Azure documentation center.