terug naar overzicht

29/04/19

Insight insight

Applicatieontwikkeling Java

Conny van Dijk

+31 35 539 09 09


29/04/19

Secret properties in Spring Boot

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 u003cemu003eapplication.propertiesu003c/emu003e or u003cemu003eapplication.ymlu003c/emu003e 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.rnrnA 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.rnIn 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.rnu003cemu003eFigure1: Setuprnu003cimg class=u0022size-full wp-image-22864 aligncenteru0022 src=u0022https://vxcompany.com/wp-content/uploads/2019/04/Blog-Lie-Cloud-Config-Server@4x.pngu0022 alt=u0022u0022 width=u0022471u0022 height=u0022307u0022 /u003ernu003c/emu003eThe 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:rnu003cimg class=u0022alignnoneu0022 src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-The-setup-of-the-server.pngu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-The-setup-of-the-server.png 104w, https://vxcompany.com/wp-content/uploads/Blog-Lie-The-setup-of-the-server@2x.png 208w, https://vxcompany.com/wp-content/uploads/Blog-Lie-The-setup-of-the-server@4x.png 416wu0022 alt=u0022Blog Lie – The setup of the server@4xu0022 width=u0022416pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-The-setup-of-the-server.png 104w, https://vxcompany.com/wp-content/uploads/Blog-Lie-The-setup-of-the-server@2x.png 208w, https://vxcompany.com/wp-content/uploads/Blog-Lie-The-setup-of-the-server@4x.png 416wu0022 /u003ernrnThe standard Spring Boot main application class needs the u003cemu003eEnableConfigServeru003c/emu003e annotation:rnrnu003cimg src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-EnableConfigServer.pngu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-EnableConfigServer.png 69w, https://vxcompany.com/wp-content/uploads/Blog-Lie-EnableConfigServer@2x.png 139w, https://vxcompany.com/wp-content/uploads/Blog-Lie-EnableConfigServer@4x.png 277wu0022 alt=u0022Blog Lie – EnableConfigServeru0022 width=u0022277pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-EnableConfigServer.png 69w, https://vxcompany.com/wp-content/uploads/Blog-Lie-EnableConfigServer@2x.png 139w, https://vxcompany.com/wp-content/uploads/Blog-Lie-EnableConfigServer@4x.png 277wu0022 /u003ernrnIn addition to the normal application.yml (and application-u0026lt;spring_profileu0026gt;.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 u003cemu003espring.cloud.config.server.encrypt.enabled=false. u003c/emu003ernrnu003cimg src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-spring.cloud_.config.server.encrypt.enabledfalse.pngu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-spring.cloud_.config.server.encrypt.enabledfalse.png 77w, https://vxcompany.com/wp-content/uploads/Blog-Lie-spring.cloud_.config.server.encrypt.enabledfalse@2x.png 155w, https://vxcompany.com/wp-content/uploads/Blog-Lie-spring.cloud_.config.server.encrypt.enabledfalse@4x.png 309wu0022 alt=u0022Blog Lie – spring.cloud.config.server.encrypt.enabled=falseu0022 width=u0022309pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-spring.cloud_.config.server.encrypt.enabledfalse.png 77w, https://vxcompany.com/wp-content/uploads/Blog-Lie-spring.cloud_.config.server.encrypt.enabledfalse@2x.png 155w, https://vxcompany.com/wp-content/uploads/Blog-Lie-spring.cloud_.config.server.encrypt.enabledfalse@4x.png 309wu0022 /u003ernrnThe Server’s context-root and port is defined in the familiar application.yml configuration file, so the server will be available at u003cemu003ehttp://localhost:8888/configserveru003c/emu003e.rnrnu003cimg src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-propeties-in-Spring-Boot.pngu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-propeties-in-Spring-Boot.png 59w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-propeties-in-Spring-Boot@2x.png 118w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-propeties-in-Spring-Boot@4x.png 235wu0022 alt=u0022Blog Lie – Secret properties in Spring Bootu0022 width=u0022235pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-propeties-in-Spring-Boot.png 59w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-propeties-in-Spring-Boot@2x.png 118w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-propeties-in-Spring-Boot@4x.png 235wu0022 /u003ernrnAn 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 u003cemu003e-Dspring.active.profiles=jdbcu003c/emu003e.rnrnu003cimg src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Dspring.active.profilesjdbc.pngu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Dspring.active.profilesjdbc.png 166w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Dspring.active.profilesjdbc@2x.png 332w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Dspring.active.profilesjdbc@4x.png 663wu0022 alt=u0022Blog Lie – -Dspring.active.profiles=jdbcu0022 width=u0022663pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Dspring.active.profilesjdbc.png 166w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Dspring.active.profilesjdbc@2x.png 332w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Dspring.active.profilesjdbc@4x.png 663wu0022 /u003ernrnThe sql query to retrieve client properties from the database is also defined in this file. In the where-clause of this query the field u003cemu003eapplicationu003c/emu003e defines a client application and u003cemu003eprofileu003c/emu003e denotes the spring profile the property belongs to. The u003cemu003elabelu003c/emu003e field in this setup has no specific meaning. Liquibase is used to instantiate the properties table and to insert some values.u003cimg src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Liquibase.pngu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Liquibase.png 131w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Liquibase@2x.png 262w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Liquibase@4x.png 524wu0022 alt=u0022Blog Lie – Liquibaseu0022 width=u0022524pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Liquibase.png 131w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Liquibase@2x.png 262w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Liquibase@4x.png 524wu0022 /u003ernu003cp class=u0022clearfixu0022u003eAn example of an encrypted property value:u003c/pu003ernrnu003cfigure class=u0022clearfixu0022u003eu003cimg src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-encrypted-property-value.pngu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-encrypted-property-value.png 294w, https://vxcompany.com/wp-content/uploads/Blog-Lie-encrypted-property-value@2x.png 588w, https://vxcompany.com/wp-content/uploads/Blog-Lie-encrypted-property-value@4x.png 1176wu0022 alt=u0022Blog Lie – encrypted property valueu0022 width=u00221176pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-encrypted-property-value.png 294w, https://vxcompany.com/wp-content/uploads/Blog-Lie-encrypted-property-value@2x.png 588w, https://vxcompany.com/wp-content/uploads/Blog-Lie-encrypted-property-value@4x.png 1176wu0022 /u003eu003c/figureu003ernu003cp class=u0022clearfixu0022u003eTo acquire an encrypted value, the server exposes an u003cemu003e/encryptu003c/emu003e endpoint which can be called using a tool like curl:u003c/pu003ernrnu003cfigure class=u0022clearfixu0022u003eu003cimg src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-3.jpgu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-3.jpg 173w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-3.jpg 345w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-3.jpg 690wu0022 alt=u0022Blog Lie – Secret properties in Spring Boot – 3u0022 width=u0022690pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-3.jpg 173w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-3.jpg 345w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-3.jpg 690wu0022 /u003eu003c/figureu003ernu003cp class=u0022clearfixu0022u003eIn response to this request the encrypted value of u003cemu003eu0022Some valueu0022u003c/emu003e is returned, which can subsequently be inserted in the properties table.u003c/pu003ernu003cimg src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-4.jpgu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-4.jpg 192w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-4.jpg 384w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-4.jpg 767wu0022 alt=u0022Blog Lie – Secret properties in Spring Boot – 4u0022 width=u0022767pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-4.jpg 192w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-4.jpg 384w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-4.jpg 767wu0022 /u003e

The client configuration to connect to the Config Server

The spring cloud starter dependency needs to be added to the pom.xml:rnrnu003cimg src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-The-spring-cloud.pngu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-The-spring-cloud.png 102w, https://vxcompany.com/wp-content/uploads/Blog-Lie-The-spring-cloud@2x.png 204w, https://vxcompany.com/wp-content/uploads/Blog-Lie-The-spring-cloud@4x.png 407wu0022 alt=u0022Blog Lie – The spring cloudu0022 width=u0022407pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-The-spring-cloud.png 102w, https://vxcompany.com/wp-content/uploads/Blog-Lie-The-spring-cloud@2x.png 204w, https://vxcompany.com/wp-content/uploads/Blog-Lie-The-spring-cloud@4x.png 407wu0022 /u003ernrnThe 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.u003cimg src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-2.pngu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-2.png 81w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-2@2x.png 162w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-2@4x.png 323wu0022 alt=u0022Blog Lie – Secret properties in Spring Bootu0022 width=u0022323pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-2.png 81w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-2@2x.png 162w, https://vxcompany.com/wp-content/uploads/Blog-Lie-Secret-properties-in-Spring-Boot-2@4x.png 323wu0022 /u003ernrnThe 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.rnrnu003cimg src=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-RefreshScope-annotation.pngu0022 srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-RefreshScope-annotation.png 74w, https://vxcompany.com/wp-content/uploads/Blog-Lie-RefreshScope-annotation@2x.png 148w, https://vxcompany.com/wp-content/uploads/Blog-Lie-RefreshScope-annotation@4x.png 295wu0022 alt=u0022Blog Lie – RefreshScope annotationu0022 width=u0022295pxu0022 height=u0022autou0022 data-srcset=u0022https://vxcompany.com/wp-content/uploads/Blog-Lie-RefreshScope-annotation.png 74w, https://vxcompany.com/wp-content/uploads/Blog-Lie-RefreshScope-annotation@2x.png 148w, https://vxcompany.com/wp-content/uploads/Blog-Lie-RefreshScope-annotation@4x.png 295wu0022 /u003ernrnHere, a REST controller is resolving the value of the property u003cemu003eapp.messageu003c/emu003e by retrieving it from the config server. For illustration purposes, the decrypted value is returned upon a get request to the client’s u003cemu003e/messageu003c/emu003e endpoint. The complete code for this example can be viewed and downloaded from: u003ca href=u0022https://github.com/Civilis317/cloud-config-server/tree/asymmetric-encryptionu0022u003ehttps://github.com/Civilis317/cloud-config-server/tree/asymmetric-encryption u003c/au003e

Sources

u003ca href=u0022https://cloud.spring.io/spring-cloud-config/multi/multi_spring-cloud-config.htmlu0022u003ehttps://cloud.spring.io/spring-cloud-config/multi/multi_spring-cloud-config.htmlu003c/au003e u003ca href=u0022https://cloud.spring.io/spring-cloud-config/multi/multi__spring_cloud_config_server.htmlu0022u003ehttps://cloud.spring.io/spring-cloud-config/multi/multi__spring_cloud_config_server.htmlu003c/au003e u003ca href=u0022https://spring.io/guides/gs/centralized-configuration/u0022u003ehttps://spring.io/guides/gs/centralized-configuration/u003c/au003e u003ca href=u0022https://stackoverflow.com/questions/37404703/spring-boot-how-to-hide-passwords-in-properties-fileu0022u003ehttps://stackoverflow.com/questions/37404703/spring-boot-how-to-hide-passwords-in-properties-fileu003c/au003e u003ca href=u0022https://www.baeldung.com/spring-cloud-configurationu0022u003ehttps://www.baeldung.com/spring-cloud-configurationu003c/au003e u003ca href=u0022http://www.jasypt.org/u0022u003ehttp://www.jasypt.org/u003c/au003e

Delen