In modern applications, security is paramount, and SSL/TLS ensures secure communication between clients and servers. Spring Boot makes it easy to enable SSL, but managing SSL certificates, especially when they need to be updated, can be challenging. In a Kubernetes environment, achieving SSL hot reload—updating certificates without downtime—is crucial for maintaining a secure and highly available application. This blog will guide you through enabling SSL hot reload for a Spring Boot application running on Kubernetes.
Table of Contents
- Introduction
- Prerequisites
- Setting Up a Spring Boot Application
- Enabling SSL in Spring Boot
- Configuring Kubernetes Secrets
- Mounting Secrets as Volumes
- Implementing SSL Hot Reload
- Deploying to Kubernetes
- Testing SSL Hot Reload
- Conclusion
Introduction
SSL/TLS certificates have expiration dates and need periodic renewal. Traditionally, updating these certificates requires a restart of the application, causing potential downtime. In a microservices architecture deployed on Kubernetes, this downtime can disrupt service availability. Implementing SSL hot reload ensures that your Spring Boot application seamlessly updates its certificates without restarts, maintaining continuous secure communication.
Prerequisites
Before you start, ensure you have the following:
- A Kubernetes cluster set up (Minikube, EKS, GKE, etc.)
- kubectl configured to interact with your cluster
- Docker installed and configured
- A basic understanding of Spring Boot and Kubernetes
- OpenSSL for generating SSL certificates
Setting Up a Spring Boot Application
First, create a simple Spring Boot application. If you already have one, you can skip this section.
1. Initialize a Spring Boot Project
You can use Spring Initializr to generate a new project or set it up manually. For simplicity, we'll use Spring Initializr.
curl https://start.spring.io/starter.zip \
-d dependencies=web \
-d name=ssl-hot-reload-demo \
-d artifactId=ssl-hot-reload-demo \
-d packageName=com.example.sslhotreloaddemo \
-d javaVersion=11 \
-o ssl-hot-reload-demo.zip
unzip ssl-hot-reload-demo.zip
cd ssl-hot-reload-demo
2. Create a Simple REST Controller
Create a simple REST controller to verify SSL functionality.
package com.example.sslhotreloaddemo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, secure world!";
}
}
Enabling SSL in Spring Boot
Next, configure Spring Boot to use SSL.
1. Generate SSL Certificates
Generate a self-signed certificate using OpenSSL for testing purposes.
mkdir -p src/main/resources/keystore
openssl req -x509 -newkey rsa:4096 -keyout src/main/resources/keystore/private.key -out src/main/resources/keystore/public.crt -days 365 -nodes -subj "/CN=localhost"
openssl pkcs12 -export -in src/main/resources/keystore/public.crt -inkey src/main/resources/keystore/private.key -out src/main/resources/keystore/keystore.p12 -name "ssl-hot-reload" -passout pass:password
2. Configure SSL in application.properties
Update src/main/resources/application.properties
with the following configuration:
server.port=8443
server.ssl.key-store=classpath:keystore/keystore.p12
server.ssl.key-store-password=password
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=ssl-hot-reload
Configuring Kubernetes Secrets
Store the SSL certificates as Kubernetes secrets.
kubectl create secret generic ssl-certs --from-file=src/main/resources/keystore/keystore.p12
Mounting Secrets as Volumes
Modify the Kubernetes deployment manifest to mount the secret as a volume.
1. Create a Deployment Manifest
Create deployment.yaml
with the following content:
apiVersion: apps/v1
kind: Deployment
metadata:
name: ssl-hot-reload-demo
spec:
replicas: 1
selector:
matchLabels:
app: ssl-hot-reload-demo
template:
metadata:
labels:
app: ssl-hot-reload-demo
spec:
containers:
- name: ssl-hot-reload-demo
image: ssl-hot-reload-demo:latest
ports:
- containerPort: 8443
volumeMounts:
- name: ssl-certs
mountPath: /etc/ssl/certs
readOnly: true
volumes:
- name: ssl-certs
secret:
secretName: ssl-certs
Implementing SSL Hot Reload
To enable SSL hot reload, we'll leverage Spring Cloud's Config Watcher and Actuator to trigger a reload.
1. Add Dependencies
Add the necessary dependencies in pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
</dependency>
2. Create a Configuration Watcher
Implement a configuration watcher to detect changes in the mounted volume.
package com.example.sslhotreloaddemo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.restart.RestartEndpoint;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@Component
public class SslConfigWatcher {
@Value("${server.ssl.key-store}")
private String keyStorePath;
private long lastModifiedTime;
private final RestartEndpoint restartEndpoint;
public SslConfigWatcher(RestartEndpoint restartEndpoint) {
this.restartEndpoint = restartEndpoint;
this.lastModifiedTime = getLastModifiedTime();
}
@Scheduled(fixedRate = 10000)
public void checkForChanges() {
long currentModifiedTime = getLastModifiedTime();
if (currentModifiedTime != lastModifiedTime) {
lastModifiedTime = currentModifiedTime;
restartEndpoint.restart();
}
}
private long getLastModifiedTime() {
try {
Path path = Paths.get(keyStorePath.replace("classpath:", ""));
return Files.getLastModifiedTime(path).toMillis();
} catch (Exception e) {
throw new RuntimeException("Failed to get the last modified time", e);
}
}
}
3. Enable Scheduling
Enable scheduling in your main application class:
package com.example.sslhotreloaddemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class EmployeeManagementApplication {
public static void main(String[] args) {
SpringApplication.run(EmployeeManagementApplication.class, args);
}
}
Deploying to Kubernetes
Build and push your Docker image, then deploy the application.
1. Build Docker Image
Create a Dockerfile
:
FROM openjdk:11-jre-slim
VOLUME /tmp
COPY target/ssl-hot-reload-demo-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
Build and push the Docker image:
docker build -t your-dockerhub-username/ssl-hot-reload-demo:latest .
docker push your-dockerhub-username/ssl-hot-reload-demo:latest
2. Apply Kubernetes Manifest
Deploy your application to Kubernetes:
kubectl apply -f deployment.yaml
Testing SSL Hot Reload
To test SSL hot reload, update the SSL certificates and observe the Spring Boot application reload them without downtime.
- Generate new SSL certificates and update the Kubernetes secret:
openssl req -x509 -newkey rsa:4096 -keyout new-private.key -out new-public.crt -days 365 -nodes -subj "/CN=localhost"
openssl pkcs12 -export -in new-public.crt -inkey new-private.key -out new-keystore.p12 -name "ssl-hot-reload" -passout pass:password
kubectl create secret generic ssl-certs --from-file=new-keystore.p12 --dry-run=client -o yaml | kubectl apply -f -
- The Spring Boot application should detect the change and reload the SSL certificates automatically.
Conclusion
Implementing SSL hot reload in a Spring Boot application running on Kubernetes ensures secure and uninterrupted service. By leveraging Kubernetes secrets, Spring Cloud Config Watcher, and Actuator, you can dynamically update SSL certificates without downtime, maintaining the security and availability of your application. This guide provides a
Top comments (0)