Skip to content

Secure and simplified secrets management for Spring Boot applications using Doppler.

License

Notifications You must be signed in to change notification settings

DopplerUniversity/doppler-spring-boot

Repository files navigation

Doppler Spring Boot Sample App

Learn how to use Doppler to supply secrets to Spring Boot applications in local development and Kubernetes.

Prerequisites

Setup

Create the sample spring-boot-app Doppler project using the following button:

Import to Doppler

Or the Doppler CLI:

doppler import

Auto-select the project and dev config using the [doppler.yaml](./doppler.yaml] file:

doppler setup --no-interactive

Then verify you can fetch secrets:

doppler secrets

Then open the Project in the doppler dashboard:

doppler open dashboard

Secrets Naming Convention

Doppler secret names are standardized to UPPER_SNAKE_CASE which is compatible with Spring Boot's relaxed binding 2.0.

View the Project in the Doppler dashboard or open the doppler-template.yaml file for examples.

Sample App Overview

Configuration is centralized with an AppConfig.java class using Spring Boot configuration properties to bind secrets injected as environment variables by Doppler.

The configuration values are set by a combination of direct environment variable injection (Redis properties) and using an application.properties file with environment variable placeholders.

Local Development

In local development, the Doppler CLI acts as an application runner, injecting secrets as environment variables into the Spring Boot process:

doppler run -- ./mvnw spring-boot:run --quiet

IDE Debugging

Because the Doppler CLI is required for injecting secrets into the Spring process, running and debugging your application is handled slightly differently.

Using IntelliJ IDEA to demonstrate, create a new Shell Script configuration and use the following as the Script text:

 doppler run -- ./mvnw spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:5005"

Spring Run

We recommend saving the run configuration as a project file so team members don't have to configure this individually.

Now that the server can be run in debug mode, the final step is creating a Remote JVM Debug configuration:

Spring Debug

Running and debugging an application is then as follows.

ScreenFlow.mp4

Usage: Docker

First build the image:

./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=doppler/spring-boot-app

Then use the Doppler CLI to set container environment variables via the --env-file option:

docker run \
  --rm \
  --name doppler-spring-boot \
  --env-file <(doppler secrets download --no-file --format docker) \
  -p $(doppler secrets get SERVER_PORT --plain):$(doppler secrets get SERVER_PORT --plain) \
  doppler-spring-boot

Usage: Kubernetes

Doppler CLI with kubectl

The quickest way to create and sync secrets to Kubernetes is using the Doppler CLI with kubectl.

To create a or update a secret named spring-boot-app-secret:

kubectl create secret generic spring-boot-app-secret \
  	--save-config \
  	--dry-run=client \
  	--from-env-file <(doppler secrets download --no-file --format docker) \
  	-o yaml | \
  	kubectl apply -f -

Then use the handy get-kube-secret.sh script to view the secrets contents:

./bin/get-kube-secret.sh spring-boot-app-secret

This adhoc approach is great for getting started but for production usage to sync secrets at scale, we recommend our Kubernetes Operator.

Kubernetes Operator

The Doppler Kubernetes Operator is a background service that automatically syncs secrets to Kubernetes with (optional) automatic redeployment of services when the secrets they consume are updated.

The Operator uses a DopplerSecret CRD (custom resource definition) which provides the auth token required for fetching secrets as well as the name and namespace the Operator will create

Check out the Operator Secrets Sync Guide for more detailed instructions but to quickly demonstrate, first create a Service Token for the Production environment to grant read-only access:

doppler setup # Select the prd environment

DOPPLER_TOKEN="$(doppler configs tokens create "Doppler Kubernetes Operator" --plain)"

Then create a Kubernetes secret containing the Service Token:

kubectl create secret generic spring-boot-app-doppler-token \
  --namespace doppler-operator-system \
  --from-literal=serviceToken=$DOPPLER_TOKEN

Confirm the secret was created successfully:

./bin/get-kube-secret.sh spring-boot-app-doppler-token --namespace doppler-operator-system

Next, define the DopplerSecret (see ./kubernetes/doppler-secret.yaml):

apiVersion: secrets.doppler.com/v1alpha1
kind: DopplerSecret
metadata:
  # DopplerSecret Name
  name: spring-boot-app-doppler-secret

  # Namespace (only create DopplerSecret resources in the  doppler-operator-system namespace)
  namespace: doppler-operator-system

spec:
  tokenSecret:
    # Doppler token secret reference
    name: spring-boot-app-doppler-token

  managedSecret:
    # Synced secret name
    name: spring-boot-app-secret

    # Synced secret namespace (the namespace of the deployment that will consume this secret)
    namespace: default

Create the DopplerSecret by running:

kubectl apply -f kubernetes/doppler-secret.yaml

Then verify Operator created the secret:

# View secret and Doppler-specific annotations
kubectl describe secret spring-boot-app-secret

# View secrets
./bin/get-kube-secret.sh spring-boot-app-secret

Now that the Kubernetes secret is in place, let's take care of deployment.

You'll notice that the below Deployment spec is pretty standard except for the secrets.doppler.com/reload: 'true' annotation which will trigger a redeploy to update the application with the latest secrets.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: doppler-spring-boot
  annotations:
    # The Operator's real superpower
    secrets.doppler.com/reload: 'true'
spec:
  replicas: 1
  selector:
    matchLabels:
      app: doppler-spring-boot
  template:
    metadata:
      labels:
        app: doppler-spring-boot
    spec:
      containers:
        - name: doppler-spring-boot
          image: doppler/spring-boot-app
          imagePullPolicy: IfNotPresent

          # envFrom injects all secret values as environment variables
          envFrom:
            - secretRef:
                # Operator created secret
                name: spring-boot-app-secret

          ports:
            - name: app
              containerPort: 8080

          resources:
            requests:
              memory: '1024Mi'
              cpu: '250m'
            limits:
              memory: '1024Mi'
              cpu: '500m'

Deploy the application:

kubectl apply -f kubernetes/deployment.yaml

Then tail the deployment logs to verify the secrets were injected successfully:

kubectl logs -f deployment/doppler-spring-boot --tail 50

To test the auto-deployment reload on secrets change, update a secret (e.g APP_APPLICATION_NAME) in the dashboard, then tail the logs again to observe deployment being updated.

If the log tail command is killed, it's because the Pod it was tailing was deleted. Simply re-run the above kubectl logs command.

Help and Support

You can get help and support in our Doppler community forum, find us on Twitter, or Team and Enterprise customers can use our in-product support.

About

Secure and simplified secrets management for Spring Boot applications using Doppler.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published