Secure Spring Boot Secrets in OpenShift

Learn how to securely manage Spring Boot secrets in OpenShift using Secrets, Service Accounts, RBAC, External Secret Managers, Secret Rotation, and enterprise security best practices.


Introduction

Every enterprise Spring Boot application requires sensitive information to function.

Examples include:

  • Database Passwords
  • API Keys
  • OAuth Client Secrets
  • JWT Signing Keys
  • Kafka Credentials
  • Redis Passwords
  • SSL Certificates
  • Cloud Access Keys

One of the biggest mistakes developers make is storing these secrets inside:

  • application.properties
  • application.yml
  • Git repositories
  • Docker images
  • Source code

This creates significant security risks.

OpenShift provides a secure mechanism using Secrets, enabling applications to consume sensitive data securely at runtime without exposing credentials.


Learning Objectives

By the end of this article, you will understand:

  • Why secret management is important
  • OpenShift Secrets architecture
  • Spring Boot Secret injection
  • Environment variables vs mounted files
  • Secret rotation
  • RBAC protection
  • External Secret Managers
  • Enterprise security best practices

Why Secure Secrets?

Never hardcode secrets.

❌ Bad Example

spring.datasource.password=Admin@123
jwt.secret=my-secret-key
aws.secretKey=AKIAxxxxxxxx

Problems:

  • Visible in Git
  • Stored inside Docker images
  • Easy to leak
  • Difficult to rotate

Enterprise Secret Architecture

flowchart TD
    DEV["Developer"]
    GIT["Git"]
    OCP["OpenShift"]
    SECRET["Secret"]
    POD["Spring Boot Pod"]
    DB["PostgreSQL"]

    DEV --> GIT
    GIT --> OCP
    OCP --> SECRET
    SECRET --> POD
    POD --> DB

Secrets remain outside the application code.


Secret Management Flow

sequenceDiagram

participant Admin

participant OpenShift

participant Secret

participant SpringBoot

Admin->>OpenShift: Create Secret

OpenShift->>Secret: Store Securely

SpringBoot->>Secret: Read Secret

Secret-->>SpringBoot: Credentials

What Should Be Stored as Secrets?

Examples:

Store as Secret Store as ConfigMap
Passwords Database Host
Tokens Logging Level
Certificates Feature Flags
API Keys Kafka Topic
JWT Secret Application Name

Create Secret

apiVersion: v1
kind: Secret

metadata:
  name: payment-secret

type: Opaque

stringData:

  DATABASE_USERNAME: paymentuser

  DATABASE_PASSWORD: StrongPassword@123

  JWT_SECRET: my-super-secret-key

Deploy

oc apply -f payment-secret.yaml

Secret Architecture

flowchart LR
    SECRET["Secret"]
    ENV["Environment Variables"]
    APP["Spring Boot"]
    DB["Database"]

    SECRET --> ENV
    ENV --> APP
    APP --> DB

Inject Secret as Environment Variable

Deployment YAML

env:

- name: DATABASE_USERNAME

  valueFrom:

    secretKeyRef:

      name: payment-secret

      key: DATABASE_USERNAME

- name: DATABASE_PASSWORD

  valueFrom:

    secretKeyRef:

      name: payment-secret

      key: DATABASE_PASSWORD

Spring Boot Configuration

spring.datasource.username=${DATABASE_USERNAME}

spring.datasource.password=${DATABASE_PASSWORD}

Spring Boot automatically resolves the environment variables.


Using @Value

@Value("${DATABASE_USERNAME}")
private String username;

@Value("${DATABASE_PASSWORD}")
private String password;

Using ConfigurationProperties

@ConfigurationProperties(prefix="database")
public class DatabaseProperties {

    private String username;

    private String password;

}

Preferred for enterprise applications.


Mount Secrets as Files

Some applications require certificates or license files.

flowchart LR
    SECRET["Secret"]
    VOLUME["Mounted Volume"]
    APP["Spring Boot"]

    SECRET --> VOLUME
    VOLUME --> APP

Deployment

volumeMounts:

- name: payment-secret

  mountPath: /etc/secrets

volumes:

- name: payment-secret

  secret:

    secretName: payment-secret

Secret Files

Inside the Pod

/etc/secrets

DATABASE_USERNAME

DATABASE_PASSWORD

JWT_SECRET

Read Secret File

String password =
Files.readString(
Path.of("/etc/secrets/DATABASE_PASSWORD"));

Database Connection

flowchart LR
    APP["Spring Boot"]
    SECRET["Secret"]
    DB["PostgreSQL"]

    APP --> SECRET
    SECRET --> DB

Credentials never appear in source code.


JWT Secret

jwt.secret=${JWT_SECRET}

The signing key is securely injected.


TLS Certificates

Store certificates as Secrets.

flowchart TD
    TLS["TLS Certificate"]
    SECRET["Secret"]
    ROUTE["OpenShift Route"]
    BROWSER["Browser"]

    TLS --> SECRET
    SECRET --> ROUTE
    ROUTE --> BROWSER

Verify Secrets

oc get secrets

Describe

oc describe secret payment-secret

View Secret

oc get secret payment-secret -o yaml

Data is Base64 encoded.


Decode Secret

echo "YWRtaW4=" | base64 --decode

Remember:

Base64 is encoding, not encryption.


RBAC Protection

Only authorized Service Accounts should access Secrets.

flowchart LR
    APP["Spring Boot"]
    SA["Service Account"]
    RBAC["RBAC"]
    SECRET["Secret"]

    APP --> SA
    SA --> RBAC
    RBAC --> SECRET

Banking Example

flowchart TD
    PAYMENT["Payment Service"]

    PAY_SECRET["Payment Secret"]
    JWT_SECRET["JWT Secret"]
    KAFKA_SECRET["Kafka Secret"]

    DB["Oracle Database"]

    PAYMENT --> PAY_SECRET
    PAY_SECRET --> DB

    PAYMENT --> JWT_SECRET
    PAYMENT --> KAFKA_SECRET

Each microservice has its own Secrets.


Secret Rotation

Passwords should be rotated regularly.

flowchart LR
    OLD["Old Secret"]
    NEW["New Secret"]
    RESTART["Restart Pods"]
    APP["Spring Boot"]

    OLD --> NEW
    NEW --> RESTART
    RESTART --> APP

Benefits

  • Better security
  • Compliance
  • Reduced credential exposure

External Secret Managers

Many enterprises don't store Secrets directly inside OpenShift.

Common solutions:

  • HashiCorp Vault
  • AWS Secrets Manager
  • Azure Key Vault
  • Google Secret Manager
  • CyberArk

Enterprise Architecture

flowchart TD
    APP["Spring Boot"]
    SA["Service Account"]
    ESO["External Secrets Operator"]
    VAULT["HashiCorp Vault"]

    DB["Database Password"]
    API["API Keys"]
    CERT["Certificates"]

    APP --> SA
    SA --> ESO
    ESO --> VAULT

    VAULT --> DB
    VAULT --> API
    VAULT --> CERT

Applications never directly store credentials.


AWS Secrets Manager Example

flowchart LR
    APP["Spring Boot"]
    ESO["External Secrets"]
    ASM["AWS Secrets Manager"]
    DB["PostgreSQL"]

    APP --> ESO
    ESO --> ASM
    ASM --> DB

Secret Synchronization

flowchart LR
    VAULT["HashiCorp Vault"]
    ESO["External Secrets Operator"]
    SECRET["OpenShift Secret"]
    APP["Spring Boot"]

    VAULT --> ESO
    ESO --> SECRET
    SECRET --> APP

Secrets stay synchronized automatically.


Verify Environment Variables

oc rsh payment-api
env

Verify:

DATABASE_USERNAME

DATABASE_PASSWORD

Common Problems

Secret Not Found

oc get secrets

Wrong Secret Name

Verify

secretKeyRef:

  name: payment-secret

Permission Denied

Verify Service Account permissions.

oc auth can-i get secrets

Pod Cannot Start

Possible causes:

  • Missing Secret
  • Wrong key
  • Incorrect mount path

Useful Commands

Create Secret

oc apply -f secret.yaml

List Secrets

oc get secrets

Describe Secret

oc describe secret payment-secret

Delete Secret

oc delete secret payment-secret

Production Best Practices

  • Never hardcode secrets.
  • Use one Secret per application.
  • Protect Secrets with RBAC.
  • Rotate passwords regularly.
  • Use Service Accounts.
  • Use TLS everywhere.
  • Store certificates as Secrets.
  • Audit Secret access.
  • Integrate with enterprise secret managers.
  • Never expose secrets in application logs.

Common Mistakes

❌ Storing passwords in Git.

❌ Hardcoding JWT keys.

❌ Sharing one Secret across multiple applications.

❌ Logging passwords.

❌ Giving all Pods permission to read Secrets.

❌ Assuming Base64 provides encryption.


Advantages

  • Secure credential management
  • Centralized secret storage
  • Easy rotation
  • Better compliance
  • Cloud-native security
  • Enterprise ready
  • Spring Boot integration
  • Zero hardcoded credentials

Summary

Secure secret management is a critical part of deploying Spring Boot applications on OpenShift.

Key takeaways:

  • Store all sensitive information in OpenShift Secrets.
  • Inject secrets using environment variables or mounted volumes.
  • Protect access with Service Accounts and RBAC.
  • Rotate credentials regularly.
  • Integrate with external secret management solutions such as Vault for enterprise environments.
  • Never hardcode credentials in source code, configuration files, or container images.

Interview Questions

  1. What is an OpenShift Secret?
  2. Why shouldn't passwords be stored in application.properties?
  3. What is the difference between ConfigMaps and Secrets?
  4. How do Spring Boot applications consume Secrets?
  5. How can Secrets be mounted as files?
  6. Why is Base64 encoding not considered encryption?
  7. What is Secret rotation?
  8. How do Service Accounts and RBAC secure Secret access?
  9. What are the benefits of using HashiCorp Vault or AWS Secrets Manager?
  10. What are the best practices for managing secrets in OpenShift?