Configure Spring Boot with Docker Secrets

Prerequisites

You should have a reasonable well understanding of Docker before we continue here. Also you are not afraid of using a command line and have a basic understanding of Spring Boot, Maven or Java development in general.

The Problem

As consultants we’re quite often exposed to new code bases across various clients. And quite often, we find code like this in the very first repository we’re cloning:

production.properties

Ok, this alone usually won’t allow me to go to the production DB and create havoc – in a serious setup this is also well hidden inside its own network zone which is normally not accessible by each and every developer. Still leaving production passwords in plain sight is simply wrong.

While there are various solutions around for this problem, here is one outlined which is very easy to integrate when working with Docker (who isn’t nowadays?). Docker introduced the swarm concept with version 1.12 (and in case you have not heard about swarm, you might definitely have a look at the documentation also to have the terminology for further reading), and with swarm in Docker 1.13 you can use Docker secrets. Yes, secrets currently can’t be used with “standalone” Docker – but if you run in a productive Docker environment without swarm, you really might want to consider it. Oh if you follow this blog further, there will actually be some hands on opportunity with swarm… Anyway, the main goal here is to show a convenient way on how to leverage Docker secrets with a Spring Boot microservice.

Docker secrets allow you to manage sensitive configuration values across a whole Docker cluster – Docker encrypts those values, distributes them in the swarm and allows you to grant your containers access to those values. Production passwords won’t have to show up ever again in your Git repo!

The drawback: Your Docker image has to support secrets. There are many developers already catching up with secrets (e.g. PostgreSQL or MySQL, see the “Docker Secrets” chapters for both) so you should not be limited to your own Docker images. Spring Boot might support this in the future natively, but for now I show you an alternative quick way to integrate this seamlessly into your microservice deployments.

Docker Swarm Setup

Action speaks louder than words! I have prepared a small demo where you can get your hands dirty. Please head over to our GitHub account and clone the demo repository. The demo is based on Vagrant and VirtualBox as it’s a simple way to create a multi-host Docker swarm without charging your credit card for a cloud provider. So after you’ve cloned the repo, spin up your favorite shell, cd into the cloned directory and run the demo environment with

This takes while as you probably first download the Vagrant base image and install a good bunch of software on it. Let’s quickly look at the Vagrantfile to see what we just got:

This results in:

  • A single node named swarm1 on IP 192.168.99.201 (created in the # Swarm nodes section)
  • The node(s) have the latest Docker version installed, plus a JDK and Apache Maven. This is done in the shell scripts referenced in the vm.provision config.
  • The files in the stacks folder (docker-compose resp. Swarm stacks files) and the spring-boot directory (obviously our Spring Boot sources) have been copied over to the VM. See the vm.synced_folder entries for this.

From Single Node to Cluster

A single node swarm cluster? Yes, how boring! Feel free to add more nodes by just increasing the (1..1) to (1..x) – each node gets 2 GB of RAM, so make sure not to go over you machine’s limit. Also make sure to read the notes for multiple nodes in the post.

Credits to Wes Higbee for this swarm setup, you can find the base Vagrant setup I used on GitHub. He has also an excellent course on Docker swarm on Pluralsight.

We are using sdkman to install the JDK and Maven. If you read this in the far future and this breaks, it might be that the currently used JDK 8 disappeared from the options list. Please just update the provision/tools.sh file in this case.

Accessing the Box

Let’s login to the provisioned Vagrant box and start our Docker swarm:

If you have provisioned more nodes, log into those nodes and follow the instructions that just got printed out on the console. Swarm distinguishes between manager and worker nodes – some functionality will only be available on manager nodes, but a proper productive Swarm setup is beyond the scope of this post.

Let’s quickly visualize what’s going on in the swarm by jumping back into our Vagrant box. We’ll first deploy a so called stack to our swarm which is very simple using a compose file:

Pointing your browser to http://192.168.99.201:10080 will show you an overview of your swarm (given the REPLICAS is really it 1/1, otherwise wait a little more until the container is started – image download first time might need a little time):

The Microservice

Let’s head over to our Spring Boot sources. We’re just exposing one REST endpoint:

We get a secret value injected and expose this over the REST endpoint. Yes, there are definitely smarter usages for secrets than just echoing it on a public REST service! In our local dev environment, the value comes out of the application.properties in our src/main/resources directory:

Spinning up the container for a test run is as simple as

and we get our REST endpoint content (in a new shell) with

The Secret

Let’s put our secret into the Docker swarm. We create a secret called “secret” (we injected this name in our Spring Boot code above) and put in the value “Docker Secrets!”. All that’s needed is a command like:

We can now authorize a swarm service to get access to this secret and exposing it under /run/secrets/[secret name] on the container file system. But how can we use this in our Spring Boot microservice in a transparent way (after all we don’t want custom code in our microservice to read this)?

Spring Boot supports reading an application.properties from the file system, which takes precedence over values defined in a classpath application.properties. We can use this mechanism and simply have a shell script converting any available secrets to be written into a custom application.properties. This is reflected in the src/main/docker/create_properties.sh script:

This adds a key-value pair in application.properties for each secret we received from swarm (secret name=secret value). We want to run this before our service so we need to combine this in a container entrypoint:

Combining all the parts into a Dockerfile looks like

Note that the CMD is passed as argument to the ENTRYPOINT. In order to use ENV variables, we have to run this over a sh shell command.

The Service

In order to put all the pieces together now, we have to create a Docker image of our microservice. We have a Dockerfile so let’s use our Maven build to create the image:

Docker Image: Check. Let’s deploy this as a service in our Docker swarm. Simply done (as before) with a compose file. We also grant the container(s) access to the secret:

As you see, we define the secret as external as we have already created it. Now we just spin up this stack executing

Did it work? Let’s see:

Service running: Check!

Secret picked up: Check!

Running on multiple nodes? Note that you created your image locally. In order to test this setup on multiple nodes, you need to publish the image to a registry (or build it on all other nodes, which is not very convenient). But then you can simply scale your service across multiple nodes with something like

You can watch the results on the visualizer.

Conclusion

This might look like a rather long description but overall we spent a good part setting up Swarm and our environment. This drills down to a simple modification on your Docker image, update the way you launch your service and add a secret to your swarm. Even better, the integration into the service workes transparently and does not impact your development process by adding a dependency on a specific technology.

Given this fits into your infrastructure this seems like a small price to pay to get rid of passwords in your version control system.

Stay up to date with our articles, job postings and events by subscribing to “Snapshot”, our monthly newsletter!

Summary
Configure Spring Boot with Docker Secrets
Article Name
Configure Spring Boot with Docker Secrets
Description
Learn how to keep your source repository free of production passwords using Docker Secrets and configure them with Spring Boot and Docker Swarm.
Author
Publisher Name
Atos Consulting CH
Publisher Logo

Tom Hug

Senior Technology Specialist at Atos Consulting
Tech nerd, OSS contributor and JVM aficionado. Coder at day, gamer at night. The rest of my time belongs to my family.

I have more than 15 years experience building distributed systems, and also know how to deploy and run them. Fluent in Java, and currently polishing again my language skills in Kotlin, C#, JavaScript and Python (in that order of preference).

Leave a Reply

Your email address will not be published. Required fields are marked *