Reload SSL certificates from HashiCorp Vault for Spring Boot
Update applications with new certificates from Vault’s PKI secrets engine using SSL hot reload in Spring Boot.
Spring Boot includes an embedded web server with the ability to configure SSL certificates to secure connections. In this post, learn how to use Vault Agent to generate certificates for a file and configure SSL hot reload in Spring Boot to automatically update web servers with new certificates. This approach automates the handling of expiring certificates without restarting the application while keeping the application code agnostic of Vault (i.e. you don’t need to add code to your application to connect to Vault). Review a complete example of using SSL hot reload with Vault on GitHub.
» Set up PKI secrets engine
Vault has the ability to generate dynamic X.509 certificates using the PKI secrets engine. You can use Vault as a root certificate authority (CA) or bring your own offline root CA. Refer to your Vault operations team to determine how to best enable the PKI secrets engine.
If you have the ability to configure secrets engines on your Vault server, set up the PKI secrets engine with a root CA. The example configuration here sets up a root certificate that expires in one day and configures a Vault role named payments-app
for the web server using the certificate.
vault secrets enable pki
vault secrets tune -max-lease-ttl="24h" pki
vault write -field=certificate pki/root/generate/internal \
common_name="${COMMON_NAME}" \
issuer_name="root-2024" \
ttl="12h" > certs/root_2024_ca.crt
vault write pki/config/urls \
issuing_certificates="${VAULT_ADDR}/v1/pki/ca" \
crl_distribution_points="${VAULT_ADDR}/v1/pki/crl"
vault write pki/roles/payments-app allow_any_name=true
Generate an intermediate CA for the web server that uses the certificate. The intermediate CA will issue certificates that expire every six hours.
vault secrets enable -path=pki_int pki
vault secrets tune -max-lease-ttl=12h pki_int
vault pki issue \
--issuer_name=example-intermediate \
/pki/issuer/$(vault read -field=default pki/config/issuers) \
/pki_int/ \
common_name="${COMMON_NAME} Intermediate Authority" \
key_type="rsa" \
key_bits="4096" \
max_depth_len=1 \
ttl="12h"
vault write pki_int/roles/payments-app \
issuer_ref="$(vault read -field=default pki_int/config/issuers)" \
allow_any_name=true \
max_ttl="6h"
Before configuring the application, make sure its Vault role has a policy to use the PKI secrets engine. For example, the payments-app
role should have access to issue the intermediate certificates at pki_int/issue/payments-app
using the update
capability.
path "pki_int/issue/payments-app" {
capabilities = ["update"]
}
For additional configurations of the PKI secrets engine, refer to our developer documentation.
» Deploy Vault Agent
Spring Boot’s SSL hot reload capability can reference SSL certificates from a file. How do you get the certificates from Vault and write them to a file for the application to reference? Vault Agent automatically authenticates to Vault and writes secrets to a file based on a template. Run Vault Agent as a separate process on the same machine as your application, and it will automatically handle authentication and secret retrieval.
The template for certificates generated by Vault references the API path to issue the certificate and any other attributes required by the PKI secrets engine configuration, such as common name. The Vault Agent template writes the certificate’s CA, private key, and public key to separate files. Vault Agent needs the template file in order to check for differences in the certificate and get a new one when it expires. This example requests a certificate that expires every five minutes.
{{- with pkiCert "pki_int/issue/payments-app" "common_name=payments.${COMMON_NAME}" "alt_names=localhost" "ttl=5m" -}}
{{ .Cert }}{{ .CA }}{{ .Key }}
{{ .Key | trimSpace | writeToFile "/vault-agent/config/certs/payments.key" "" "" "0400" }}
{{ .CA | trimSpace | writeToFile "/vault-agent/config/certs/ca.pem" "" "" "0644" }}
{{ .Cert | trimSpace | writeToFile "/vault-agent/config/certs/payments.crt" "" "" "0644" }}
{{- end -}}
Reference the template file in Vault Agent’s configuration and set a destination to write out all certificate information for Vault Agent to track. The example below automatically authenticates to Vault using the approle
auth method. The auto_auth
configuration will change depending on your auth method and where you run Vault Agent and your application.
pid_file = "/vault-agent/pidfile"
// Define Vault Agent's connection to Vault server.
// This example uses docker-compose with the Vault server at http://vault:8200.
vault {
address = "http://vault:8200"
}
auto_auth {
// This example uses AppRole authentication. When you set up Vault,
// the scripts wrote the role-id and secret-id to a file. You can think of
// AppRole authentication method as a username/password combination
// for automation.
method {
type = "approle"
config = {
role_id_file_path = "/vault-agent/role-id"
secret_id_file_path = "/vault-agent/secret-id"
remove_secret_id_file_after_reading = false
}
}
}
template {
source = "/vault/templates/cert.tpl"
destination = "/vault-agent/config/all-certs"
}
When you run Vault Agent with vault agent -config=/vault/config.hcl
, you can find the CA, private key, and public key written to /vault-agent/config/certs
.
$ ls vault-agent/config/certs
ca.pem payments.crt payments.key
The Spring Boot application references the certificates from the vault-agent/config/certs
directory.
» Configure application
The application needs to reference the certificates from a file using Spring’s application properties. Configure application.properties
with spring.ssl.bundle.pem
, which references the directory with the certificates created by Vault Agent. The properties should set reload-on-update
to true
so the application hot reloads when Vault Agent updates the certificates.
spring.ssl.bundle.pem.demo.reload-on-update=true
spring.ssl.bundle.pem.demo.keystore.certificate=/vault-agent/config/certs/payments.crt
spring.ssl.bundle.pem.demo.keystore.private-key=/vault-agent/config/certs/payments.key
server.ssl.bundle=demo
Start the application. The logs show that the application uses the certificates from the /vault-agent/config/certs
directory.
2024-08-26T15:27:07.187Z INFO 8 --- [payments-app] [main]
c.h.paymentsapp.PaymentsApplication :
Starting PaymentsApplication v0.0.1-SNAPSHOT
using Java 22.0.2 with PID 8 (/app/app.jar started by root in /)
...
2024-08-26T15:27:10.519Z INFO 8 --- [payments-app] [main]
o.a.t.util.net.NioEndpoint.certificate :
Connector [https-jsse-nio-8081], TLS virtual host [_default_], certificate type [UNDEFINED]
configured from keystore [/root/.keystore] using alias [tomcat] with trust store [null]
2024-08-26T15:27:10.531Z INFO 8 --- [payments-app] [main] o.s.b.w.embedded.tomcat.TomcatWebServer :
Tomcat started on port 8081 (https) with context path ''
...
2024-08-26T15:27:10.570Z INFO 8 --- [payments-app] [main]
c.h.paymentsapp.PaymentsApplication :
Started PaymentsApplication in 4.002 seconds (process running for 4.545)
Access the application over HTTPS. The curl
command needs to reference the files containing the certificate authority, certificate, and private key written by Vault Agent in order to verify the connection to the application.
$ curl --cacert vault-agent/config/certs/ca.pem --cert vault-agent/config/certs/payments.crt --key vault-agent/config/certs/payments.key https://localhost:8081/payments
[{"billing_address":"8 Eastern Himalayas Drive","created_at":"2024-08-26T00:00:00Z","id":"2310d6be-0e80-11ed-861d-0242ac120002","name":"Red Panda","status":"paid"}]
Use openssl to verify the certificate. The certificate includes the expiration date five minutes after it was generated.
$ openssl s_client -showcerts -connect localhost:8081 </dev/null
Connecting to ::1
CONNECTED(00000003)
## omitted
---
Certificate chain
0 s:CN=payments.${COMMON_NAME}
i:CN=${COMMON_NAME} Intermediate Authority
a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
v:NotBefore: Aug 26 15:43:20 2024 GMT; NotAfter: Aug 26 15:48:50 2024 GMT
-----BEGIN CERTIFICATE-----
MIIEmDCCAoCgAwIBAgIUEpiJgaQX8eNokLqN5I/cwxRV1PkwDQYJKoZIhvcNAQEL
## omitted
---
Server certificate
subject=CN=payments.${COMMON_NAME}
issuer=CN=${COMMON_NAME} Intermediate Authority
---
## omitted
When the certificate nears expiration, Vault Agent requests a new certificate and writes it to the files. The Spring application automatically reloads itself with the new certificate.
2024-08-26T15:47:03.532Z INFO 8 --- [payments-app] [-bundle-watcher]
o.a.t.util.net.NioEndpoint.certificate : Connector [https-jsse-nio-8081],
TLS virtual host [_default_], certificate type [UNDEFINED]
configured from keystore [/root/.keystore] using alias [tomcat]
with trust store [null]
When you review the certificate information, you will find a new certificate with an updated expiration.
$ openssl s_client -showcerts -connect localhost:8081 </dev/null
Connecting to ::1
CONNECTED(00000003)
## omitted
---
Certificate chain
0 s:CN=payments.${COMMON_NAME}
i:CN=${COMMON_NAME} Intermediate Authority
a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
v:NotBefore: Aug 26 15:47:52 2024 GMT; NotAfter: Aug 26 15:53:22 2024 GMT
-----BEGIN CERTIFICATE-----
MIIElzCCAn+gAwIBAgITa0OvvyCQ2qpKa7RCV24wI9dVLzANBgkqhkiG9w0BAQsF
## omitted
---
Server certificate
subject=CN=payments.${COMMON_NAME}
issuer=CN=${COMMON_NAME} Intermediate Authority
## omitted
The application now automatically loads a new certificate to its web server without the need to manually restart the application or introduce application downtime.
» Learn more
By combining SSL hot reload in Spring applications with certificates generated by Vault Agent, your application automatically handles certificate expiration without introducing downtime. This approach accounts for the dynamic behavior of certificates and avoids the need for manual configuration and restart. Rather than directly connecting the application to the Vault API, Vault Agent decouples your application’s dependency on Vault by handling the authentication and retrieval of certificates. The application can read the certificates from a certificate file created by Vault Agent. This helps minimize the overall application refactoring effort.
Find a more complete example of hot reloading Spring applications for secrets and certificates generated by Vault on GitHub. Additional configuration for SSL hot reloading in Spring Boot can be found in the Spring documentation. For more on how to use HashiCorp Vault with Spring applications, check out our tutorials on reloading secrets with the Spring Cloud Vault library or encrypting Spring application data with transit secrets engine.
Sign up for the latest HashiCorp news
More blog posts like this one
Vault 1.18 introduces support for IPv6 and CMPv2 while improving security team user experience
HashiCorp Vault 1.18 brings UI support for AWS Workload Identity Federation (WIF), PKI CMPv2 for 5G, and more.
False positives: A big problem for secret scanners
False positives can distract security teams, exhaust resources, and increase the potential for actual threats to go unnoticed, but HCP Vault Radar can help minimize them.
Integrating Azure DevOps Pipelines with HashiCorp Vault
Use Microsoft Azure DevOps’ workload identity federation (WIF) feature to seamlessly integrate Azure DevOps pipelines with HashiCorp Vault