Spring Boot how to hide passwords in properties file

JavaSpringSpring Boot

Java Problem Overview


Spring Boot uses the properties file, and at least by default, the passwords are in plain text. Is it possible to somehow hide/decrypt these?

Java Solutions


Solution 1 - Java

You can use Jasypt to encrypt properties, so you could have your property like this:

db.password=ENC(XcBjfjDDjxeyFBoaEPhG14wEzc6Ja+Xx+hNPrJyQT88=)

Jasypt allows you to encrypt your properties using different algorithms, once you get the encrypted property you put inside the ENC(...). For instance, you can encrypt this way through Jasypt using the terminal:

encrypted-pwd$ java -cp ~/.m2/repository/org/jasypt/jasypt/1.9.2/jasypt-1.9.2.jar  org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="contactspassword" password=supersecretz algorithm=PBEWithMD5AndDES

----ENVIRONMENT-----------------

Runtime: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 24.45-b08



----ARGUMENTS-------------------

algorithm: PBEWithMD5AndDES
input: contactspassword
password: supersecretz



----OUTPUT----------------------

XcBjfjDDjxeyFBoaEPhG14wEzc6Ja+Xx+hNPrJyQT88=

To easily configure it with Spring Boot you can use its starter jasypt-spring-boot-starter with group ID com.github.ulisesbocchio

Keep in mind, that you will need to start your application using the same password you used to encrypt the properties. So, you can start your app this way:

mvn -Djasypt.encryptor.password=supersecretz spring-boot:run

Or using the environment variable (thanks to spring boot relaxed binding):

export JASYPT_ENCRYPTOR_PASSWORD=supersecretz
mvn spring-boot:run

You can check below link for more details:

https://www.ricston.com/blog/encrypting-properties-in-spring-boot-with-jasypt-spring-boot/

To use your encrypted properties in your app just use it as usual, use either method you like (Spring Boot wires the magic, anyway the property must be of course in the classpath):

Using @Value annotation

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

Or using Environment

@Autowired
private Environment environment;

public void doSomething(Environment env) {
    System.out.println(env.getProperty("db.password"));
}

Update: for production environment, to avoid exposing the password in the command line, since you can query the processes with ps, previous commands with history, etc etc. You could:

  • Create a script like this: touch setEnv.sh
  • Edit setEnv.sh to export the JASYPT_ENCRYPTOR_PASSWORD variable >#!/bin/bash > >export JASYPT_ENCRYPTOR_PASSWORD=supersecretz
  • Execute the file with . setEnv.sh
  • Run the app in background with mvn spring-boot:run &
  • Delete the file setEnv.sh
  • Unset the previous environment variable with: unset JASYPT_ENCRYPTOR_PASSWORD

Solution 2 - Java

UPDATE: I noticed folks down-voting this, so I have to say that although this is not an ideal solution, but this works and acceptable in some use-cases. Cloudfoundry uses Environment variables to inject credentials when a Service is binded to an application. More info https://docs.cloudfoundry.org/devguide/services/application-binding.html

And also if your system is not shared, then for local development this is also acceptable. Of course, the more safe and secure way is explained in Answer by @J-Alex.

Answer:

If you want to hide your passwords then the easiest solution is to use Environment variables in application.properties file or directly in your code.

In application.properties:

mypassword=${password}

Then in your configuration class:

@Autowired
private Environment environment;

[...]//Inside a method
System.out.println(environment.getProperty("mypassword"));

In your configuration class:

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

[...]//Inside a method
System.out.println(herokuPath);

Note: You might have to restart after setting the environment variable. For windows:

In Windows

Refer this Documentation for more info.

Solution 3 - Java

To the already proposed solutions I can add an option to configure an external Secrets Manager such as Vault.

  1. Configure Vault Server vault server -dev (Only for DEV and not for PROD)
  2. Write secrets vault write secret/somename key1=value1 key2=value2
  3. Verify secrets vault read secret/somename

Add the following dependency to your SpringBoot project:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>

Add Vault config properties:

spring.cloud.vault.host=localhost
spring.cloud.vault.port=8200
spring.cloud.vault.scheme=http
spring.cloud.vault.authentication=token
spring.cloud.vault.token=${VAULT_TOKEN}

Pass VAULT_TOKEN as an environment variable.

Refer to the documentation here.

There is a Spring Vault project which is also can be used for accessing, storing and revoking secrets.

Dependency:

<dependency>
    <groupId>org.springframework.vault</groupId>
    <artifactId>spring-vault-core</artifactId>
</dependency>

Configuring Vault Template:

@Configuration
class VaultConfiguration extends AbstractVaultConfiguration {

  @Override
  public VaultEndpoint vaultEndpoint() {
    return new VaultEndpoint();
  }

  @Override
  public ClientAuthentication clientAuthentication() {
    return new TokenAuthentication("…");
  }
}

Inject and use VaultTemplate:

public class Example {

  @Autowired
  private VaultOperations operations;

  public void writeSecrets(String userId, String password) {
      Map<String, String> data = new HashMap<String, String>();
      data.put("password", password);
      operations.write(userId, data);
  }

  public Person readSecrets(String userId) {
      VaultResponseSupport<Person> response = operations.read(userId, Person.class);
      return response.getBody();
  }
}

Use Vault PropertySource:

@VaultPropertySource(value = "aws/creds/s3",
  propertyNamePrefix = "aws."
  renewal = Renewal.RENEW)
public class Config {

}

Usage example:

public class S3Client {

  // inject the actual values
  @Value("${aws.access_key}")
  private String awsAccessKey;
  @Value("${aws.secret_key}")
  private String awsSecretKey;

  public InputStream getFileFromS3(String filenname) {
    // …
  }
}

Solution 4 - Java

Spring Cloud Config Server will allow this type of behavior. Using JCE you can setup a key on the server and use it to cipher the apps properties.

http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html

Solution 5 - Java

In additional to the popular K8s, jasypt or vault solutions, there's also Karmahostage. It enables you to do:

@EncryptedValue("${application.secret}")
private String application;

It works the same way jasypt does, but encryption happens on a dedicated saas solution, with a more fine-grained ACL model attached to it.

Solution 6 - Java

In case you are using quite popular in Spring Boot environment Kubernetes (K8S) or OpenShift, there's a possibility to store and retrieve application properties on runtime. This technique called secrets. In your configuration yaml file for Kubernetes or OpenShift you declare variable and placeholder for it, and on K8S\OpenShift side declare actual value which corresponds to this placeholder. For implementation details, see: K8S: https://kubernetes.io/docs/concepts/configuration/secret/ OpenShift: https://docs.openshift.com/container-platform/3.11/dev_guide/secrets.html

Solution 7 - Java

My solution to hiding a DB-Password in Spring Boot App's application.properties does implemented here.

Scenario: some fake password already reading and saved from application.properties on start, in global Spring object ConfigurableEnvironment will be, in Run-Time replaced programmaticaly, by real DB-Password. The real password will be reading from another config file, saved in safe, project-outer place.

Don't forget: call the the Bean from main class with:

@Autowired
private SchedUtilility utl;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1340582View Question on Stackoverflow
Solution 1 - JavaFederico PiazzaView Answer on Stackoverflow
Solution 2 - JavaSanjay RawatView Answer on Stackoverflow
Solution 3 - JavaJ-AlexView Answer on Stackoverflow
Solution 4 - JavacodeView Answer on Stackoverflow
Solution 5 - JavaQkyrieView Answer on Stackoverflow
Solution 6 - JavastingerView Answer on Stackoverflow
Solution 7 - JavaIakov SenatovView Answer on Stackoverflow