Spring Boot SSL Hot Reload on Kubernetes: A Detailed Guide

javafullstackdev

JavaFullStackDev.in

Posted on August 2, 2024

Spring Boot SSL Hot Reload on Kubernetes: A Detailed Guide

Image description
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

  1. Introduction
  2. Prerequisites
  3. Setting Up a Spring Boot Application
  4. Enabling SSL in Spring Boot
  5. Configuring Kubernetes Secrets
  6. Mounting Secrets as Volumes
  7. Implementing SSL Hot Reload
  8. Deploying to Kubernetes
  9. Testing SSL Hot Reload
  10. 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


Enter fullscreen mode Exit fullscreen mode

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!";
    }
}


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

Configuring Kubernetes Secrets

Store the SSL certificates as Kubernetes secrets.



kubectl create secret generic ssl-certs --from-file=src/main/resources/keystore/keystore.p12


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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>


Enter fullscreen mode Exit fullscreen mode

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);
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

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);
    }
}


Enter fullscreen mode Exit fullscreen mode

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"]


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

2. Apply Kubernetes Manifest

Deploy your application to Kubernetes:



kubectl apply -f deployment.yaml


Enter fullscreen mode Exit fullscreen mode

Testing SSL Hot Reload

To test SSL hot reload, update the SSL certificates and observe the Spring Boot application reload them without downtime.

  1. 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 -


Enter fullscreen mode Exit fullscreen mode
  1. 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

💖 💪 🙅 🚩
javafullstackdev
JavaFullStackDev.in

Posted on August 2, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related