[java] Spring Boot how to hide passwords in properties file

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?

This question is related to java spring spring-boot

The answer is


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.


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


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


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) {
    // …
  }
}

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;

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.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to spring

Are all Spring Framework Java Configuration injection examples buggy? Two Page Login with Spring Security 3.2.x Access blocked by CORS policy: Response to preflight request doesn't pass access control check Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified Spring Data JPA findOne() change to Optional how to use this? After Spring Boot 2.0 migration: jdbcUrl is required with driverClassName The type WebMvcConfigurerAdapter is deprecated No converter found capable of converting from type to type

Examples related to spring-boot

Access blocked by CORS policy: Response to preflight request doesn't pass access control check Why am I getting Unknown error in line 1 of pom.xml? Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured How to resolve Unable to load authentication plugin 'caching_sha2_password' issue ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified After Spring Boot 2.0 migration: jdbcUrl is required with driverClassName ERROR Source option 1.5 is no longer supported. Use 1.6 or later How to start up spring-boot application via command line? JSON parse error: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value