How would I set "spring.datasource.password" using a docker secret?
Asked Answered
A

2

6

Currently I have the following in a datasource.properties file to connect to the datasource locally...

//datasource.properties
spring.datasource.password=${DB_PASSWORD}

This worked great for local but now I am trying to create a docker image. To store the data I would rather use a secret than an environment variable (Or maybe even the secret then the env var where not found). I have the secret currently set up in my local docker image but I can't figure out how to set the spring.datasource.password using code instead of the properties.

How would I set "spring.datasource.password" using a docker secret?

Adcock answered 3/10, 2018 at 15:16 Comment(0)
A
3

With the help of a customized implementation of the EnvironmentPostProcessor interface, the "spring.datasource.password" can be set as following in application.yml

   spring:
     datasource:
       password: ${docker-secret-my-db-passwd}

The docker secrets bind within the container are presented as files under the /run/secrets folder. The EnvironmentPostProcessor implementation load these file as the environment properties.

The idea has also been introduced in Spring boot reference - Encrypted Properties

Adur answered 6/4, 2019 at 19:42 Comment(0)
O
0

I solved the Problem with a custom PropertySource that loads values from Files.

So your .properties file would look like this:

spring.datasource.password=${file(/run/secrets/db-password)}

or it is also possible to load the file url from an environment variable like this:

spring.datasource.password=${file(${SPRING_DATASOURCE_PASSWORD_FILE})}

To resolve the ${file(...)} placeholder you need a custom PropertySource: (Kotlin)

class FilePropertySource : PropertySource<File>("file") {

    override fun getProperty(value: String): Any? =
        Regex("file\\(([^\\s]*)\\)").matchEntire(value)
            ?.let { Files.newBufferedReader(Path.of(it.groupValues[1])).use(BufferedReader::readLine) }
}

(Java)

public class FilePropertySource extends PropertySource<File> {

    private static final Log logger = LogFactory.getLog(FilePropertySource.class);

    public FilePropertySource() { super("file"); }

    @Override
    public Object getProperty(String value) {
        Matcher m = Pattern.compile("^file\\(([^\\s]*)\\)$").matcher(value);
        if (!m.matches()) return null;
        String path = m.toMatchResult().group(1);
        try (BufferedReader br = Files.newBufferedReader(Path.of(path))) {
            return br.readLine();
        } catch (IOException e) {
            logger.trace("Failed to read file for property: " + value);
        }
        return null;
    }
}

And to activate this custom PropertySource it needs to be registered in the main method. (Kotlin)

fun main(args: Array<String>) {
    runApplication<Application>(*args) {
        addInitializers({
            it.environment.propertySources.addLast(FilePropertySource())
        })
    }
}

(Java)

public class Application {
    public static void main(String[] args) {
        SpringApplication sa = new SpringApplication(Application.class);
        sa.addInitializers((ConfigurableApplicationContext applicationContext) -> {
            applicationContext.getEnvironment().getPropertySources().addLast(new FilePropertySource());
        });
        sa.run(args);
    }
}
Overtop answered 25/9, 2022 at 12:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.