Reputation: 4366
I am using Spring JPA to access my database but the username and password for the database is provided to me in the form of two files (username.txt and password.txt). The security guideline is that we are not supposed to paste password or any form of password (encrypted) in the config files.
I am trying to figure out ways to do something like this:
spring.datasource:
url: <db url>
username: "file:/path/username.txt"
password: "file:/path/password.txt"
Does anyone have any idea on how to achieve something very similar to this?
PS. I want to keep the environment-specific credential file paths in this spring properties file. There are ways to pass in the file content as environment variable java -Dusername=${cat /path/username} but I want to avoid putting my config outside the the spring properties file.
EDIT: The username and password are stored as plaintext in separate files.
Upvotes: 5
Views: 8548
Reputation: 13820
Spring Boot 2.4 introduced the ability to read configuration values from files where the name of the directory and file is the property name and the file content is the property value. For example, given the directory structure
path/
spring/
datasource/
username
password
and the application.yaml
file contains
spring.config.import: configtree:/path/
then the Environment will contain properties named spring.datasource.username
and spring.datasource.password
.
Upvotes: 5
Reputation: 13261
When we serach for "spring-boot secrets", still this (2016) article pops up first:
Some modern approaches (here) with docker-secrets:
But "pragmatically" and with the "latest rce's${;}", i would propose something like:
@Value("#{T(java.nio.file.Files).readString(T(java.nio.file.Path).of('/path/username.txt'))}")
String username;
// or having the path in a property (named db.password.file):
@Value("#{T(java.nio.file.Files).readString(T(java.nio.file.Path).of('${db.password.file}'))}")
String password;
Thx to:
Upvotes: 2
Reputation: 1
Though I can't say, this is a good idea, but you can read file content to field. But you'll have to do 3 steps
password.file=/Users/user/work/pass.txt
For example
public static String readPassword(String filePath) throws IOException {
return FileUtils.readFileToString(new File(filePath), Charset.defaultCharset());
}
@Value("#{T (com.github.TestComponent).readPassword(\"${password.file}\")}")
private String password;
While startup, Spring will invoke this method and put the result to password field.
Class may look like
package com.github;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class TestComponent {
@Value("#{T (com.github.TestComponent).readPassword(\"${password.file}\")}")
private String password;
public void showPassword() {
System.out.println(password);
}
public static String readPassword(String filePath) throws IOException {
return FileUtils.readFileToString(new File(filePath), Charset.defaultCharset());
}
}
Upvotes: 0
Reputation: 24528
You can’t read the contents of a file from Spring application properties file. But you can certainly configure the data source programmatically, and in code, read the files.
@Configuration
public class DataSourceConfig {
@Bean
public DataSource getDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName("org.h2.Driver");
dataSourceBuilder.url("jdbc:h2:mem:test");
dataSourceBuilder.username("SA");
dataSourceBuilder.password("");
return dataSourceBuilder.build();
}
}
See this article for details. I’m assuming you know how to read a file using Spring Boot, if not, you can see this article.
Upvotes: 3
Reputation: 2365
There are multiple ways how you can load another config file containing your secrets (see documentation)
One idea is to create a environment specific application.yaml (e.g. application-prod.yaml
containing only the prod config next to your application config (you dont need to pack that in your jar, you can simple put it next to you jar only in your production environment.
Another idea is to load additional config using -Dspring.config.additional-location=...
Upvotes: 1