Secret properties in Spring Boot

Door Lie Zeilstra In Java

Spring Boot is a popular framework used to create (microservice) applications in Java.
It has a flat learning curve and yet is very versatile, which goes a long way explaining its popularity.
As with all Spring frameworks, Spring Boot sports a ‘convention over configuration’ approach to discovering beans, services and also properties. In practice this means working with Spring Boot can largely be done intuitively.
This is also true for the configuration properties

The Problem

The standard way to provide a Spring Boot application with its properties is to include an application.properties or application.yml file containing key-value pairs in the codebase of the application. When working with different Spring profiles, in an OTAP setting, the property files for all profiles are typically included.
The problem here is that there are production-settings that a company does not wish to be clearly visible to every developer.
Even if the property files are not in the codebase, the fact that the application needs access to them makes it hard to hide production-settings from unauthorized eyes.

Encrypting the properties

One solution to the problem is to encrypt the application properties.
This can be done using the Jasypt library, which uses a secret key to encrypt and decrypt configuration values. The secret key needs to be available to the application at runtime, which makes it hard to hide it from a developer. The library works fine for properties injected into custom made Spring components and services, but it is difficult to use decrypted values in Spring Framework provided beans like datasources etc.
The same limitations apply to any custom encryption/decryption technique.

Config server

Spring Cloud Config Server offers an HTTP API for external configuration.
The application properties do not reside in the codebase but are provided by the config server.
Cloud config server also offers the possibility to encrypt the property values.
This encryption can be symmetric (using a shared secret key) or asymmetric using a public/private keypair. One instance of Cloud Config Server can be used to provide multiple client applications with their properties, each encrypted by using their individual public key.
A client application uses its private key to decrypt the values.
Although it is possible to store the application private keys at the Config Server to decrypt there and send unencrypted values to the client, this, imho, defeats the purpose.
A client application should keep its private key private and sending encrypted values over http makes sniffing for secrets much harder.
In the default setup, Cloud Config Server reads the properties it exposes from files stored in a Git repository, but in this instance a database is used to store the encrypted values.

Cloud Config Server using Asymmetric encryption and a database

In figure 1 the setup of the implementation is given.
Figure1: Setup

Blog Lie – Cloud Config Server

The Config Server stores the properties of each client application, encrypted using their public key, in a central database. On demand each client application gets its encrypted configuration values served over http and decrypts them locally using its private key.
This way custom made beans as well as Spring Framework beans can be instantiated and have their configuration properties provided.

The setup of the server is mostly done by configuration

This is the key dependency in the server pom.xml:Blog Lie – The setup of the server@4x

The standard Spring Boot main application class needs the EnableConfigServer annotation:Blog Lie – EnableConfigServer

In addition to the normal application.yml (and application-<spring_profile>.yml), the server relies on a bootstrap.yml to store the definition of its local keystore.
Server-side decryption of encrypted values is disabled by the somewhat cryptic property
spring.cloud.config.server.encrypt.enabled=false.
Blog Lie – spring.cloud.config.server.encrypt.enabled=false

The Server’s context-root and port is defined in the familiar application.yml configuration file, so the server will be available at http://localhost:8888/configserver.
Blog Lie – Secret properties in Spring Boot

An additional application-jdbc.yml contains the settings for the use of an in-memory H2 database for the storage of the encrypted client configuration values. To activate this, run the server with the JVM argument -Dspring.active.profiles=jdbc.Blog Lie – -Dspring.active.profiles=jdbc

The sql query to retrieve client properties from the database is also defined in this file.
In the where-clause of this query the field application defines a client application and profile denotes the spring profile the property belongs to. The label field in this setup has no specific meaning.

Liquibase is used to instantiate the properties table and to insert some values.Blog Lie – Liquibase

An example of an encrypted property value:

Blog Lie – encrypted property value

To acquire an encrypted value, the server exposes an /encrypt endpoint which can be called using a tool like curl:

Blog Lie – Secret properties in Spring Boot – 3

In response to this request the encrypted value of “Some value” is returned, which can subsequently be inserted in the properties table.

Blog Lie – Secret properties in Spring Boot – 4

The client configuration to connect to the Config Server

The spring cloud starter dependency needs to be added to the pom.xml:Blog Lie – The spring cloud

The client also will need a bootstrap file where the predicates for the server’s query are defined, as well as the basic authentication to connect to the server.Blog Lie – Secret properties in Spring Boot

The location of and credentials for the keystore containing the public and private key-pair are also defined in the bootstrap.yml configuration file.

The bean classes of the client need the RefreshScope annotation.
This, together with the information in the bootstrap file, is enough to make the client use the config server as it’s source of property values.
Blog Lie – RefreshScope annotation

Here, a REST controller is resolving the value of the property app.message by retrieving it from the config server.

For illustration purposes, the decrypted value is returned upon a get request to the client’s /message endpoint.

The complete code for this example can be viewed and downloaded from:
https://github.com/Civilis317/cloud-config-server/tree/asymmetric-encryption 

Sources

https://cloud.spring.io/spring-cloud-config/multi/multi_spring-cloud-config.html
https://cloud.spring.io/spring-cloud-config/multi/multi__spring_cloud_config_server.html
https://spring.io/guides/gs/centralized-configuration/
https://stackoverflow.com/questions/37404703/spring-boot-how-to-hide-passwords-in-properties-file
https://www.baeldung.com/spring-cloud-configuration
http://www.jasypt.org/

 

Meer informatie

Lie Zeilstra

Lie Zeilstra

Java Architect

Stuur Lie een e-mail

Reacties

Er zijn nog geen reacties op dit bericht.

Plaats een reactie

Dit veld is verplicht.

Vul een geldig e-mailadres in.

Dit veld is verplicht.