6

I am currently creating a Java program that uses a MongoDB database and I am storing the connection information in a properties file.

But my project is opensource on GitHub and I cannot store the connection information in the properties file.

And so I wanted to ask you if it is possible to give the login information from docker run.

example : docker run registry/image -args db.password=psw db.username=user

I have seen solutions in stackoverflow but all solutions use Spring features, but my project does not use Spring framework.

ThrowsError
  • 1,169
  • 1
  • 11
  • 43
  • 6
    We can - of course - read them from the `args`-array of our `main`-method. Antoher common way would be to pass the parameter as system parameters, e.g. `java ... -Ddb.password=pwd -Ddb.username=user ...` and evaluate them through [`System::getProperty`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/System.html#getProperty(java.lang.String)). A third possibility would be to use environment variables and evaluate them through [`System::getenv`](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/System.html#getenv(java.lang.String)) – Turing85 Jan 01 '22 at 21:38
  • 4
    There's always the simple possibility of not putting those lines in the properties file on github. Maybe have two properties files, one of which contains 'sensitive' info and which you don't post. – passer-by Jan 01 '22 at 21:47
  • 2
    @Turing85 Thank you for your answer, and with this solution, we can execute `docker run -Dbb.password=pwd -Ddb.username=user` rigth ? – ThrowsError Jan 01 '22 at 21:48
  • 3
    I do not know the base image, hence I do not know its entrypoint definition. In essence, we would have to pass the environment arguments to the VM. This is done through `java -Dname=value`. However, I would highly advice to use the 2nd approach (environment varialbes) as this is the [3rd factor of a 12 factor app](https://12factor.net/config). In this case, we would use the [`-e` parameter of `docker run`](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file) to set the environment variable for the container. – Turing85 Jan 01 '22 at 21:53
  • 2
    @Turing85 The base image is [*azul/zulu-openjdk:17-jre*](https://hub.docker.com/layers/azul/zulu-openjdk/17-jre/images/sha256-dcde329b10e55ed2ae5bdc21ddc04c7908cf960c839c572a4eb4e26f540228fd?context=explore) and I am using the [*JIB*](https://github.com/GoogleContainerTools/jib) build pack to create a docker image. If we use the `-e` parameter in Docker so in Java we have to use `System::getenv`? – ThrowsError Jan 01 '22 at 22:09
  • 3
    Yes, that is correct. – Turing85 Jan 01 '22 at 22:33
  • 3
    1. for environment variables (discouraged, even in docker): `System.getenv(...)`, 2. for "-D" properties (good!): `System.getProperty(...)` 3. `main (String... args)` – xerx593 Jan 01 '22 at 22:43
  • 3
    [here](https://github.com/carsdotcom/docker-secrets-java) is a nice (oss, 2 classes only (depend or copy&paste), jdk libs only) "docker secret reader". – xerx593 Jan 01 '22 at 22:50
  • 3
    @xerx593 Thanks for your sharing, secret docker is a good solution, but I like `-e` because it is easier to run a container than it is to create a secret docker, connect that file to the docker container and run it. – ThrowsError Jan 01 '22 at 23:15

3 Answers3

8

We have multiple solutions for this:

Secret Docker

Create a file with the properties syntax:

//secret-file.txt
db.password=psw
db.username=user

With this file create a docker secret in your docker :

$ docker secret create test-secret secret-file.txt

And use this with the java library docker-secrets in your java program :

Map<String, String> secrets = DockerSecrets.loadFromFile("test-secret");
System.out.println(secrets.get("db.password")) // readonly

For more example, look here.


Environment variables

Set the environment variables in the docker with -e argument :

$ docker run -e DB_PASSWORD=pwd -e DB_USERNAME=user registry/image:tag

And use these variables with System::getenv in your java program :

System.out.println(System.getenv("DB_PASSWORD"))

VM Arguments

This solution depends on your base image that was used to create your Docker container.

Give VM Arguments to the docker run command :

$ docker run -e JAVA_OPTS="-Ddb.password=pwd -Ddb.username=user" registry/image:tag

And use these variables with System::getProperty in your java program :

System.out.println(System.getProperty("db.password"))

Program arguments

Give arguments to docker run command :

It is important to give the arguments after declaring the image.

$ docker run registry/image:tag pwd user

And use these arguments with main method in your java program :

public static void main(String[] args) {
    System.out.println("The password: " + args[0]);
    System.out.println("The username: " + args[1]);
}

For better handling of arguments, you can use the Apache's commons-cli java library or use a another library.

ThrowsError
  • 1,169
  • 1
  • 11
  • 43
0

if you are hosting this application on AWS an option is using Secrets Manager which has an integration start project for Spring - How to integrate AWS Secret Manager with Spring Boot Application

Edwin M. Cruz
  • 362
  • 1
  • 8
  • 1
    This question concerns projects that do not use Spring frameworks. – ThrowsError Jan 08 '22 at 08:48
  • 1
    Sorry above example assume spring - here is a plain java example - https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/secretsmanager/src/main/java/com/example/secrets/GetSecretValue.java – Edwin M. Cruz Jan 08 '22 at 21:06
0

You can:

  • Use a .properties file for your properties

  • Add it to .gitignore so that you don't push it to GitHub

  • Add a .properties_example file that contains placeholders for others to override in their local repo, e.g:

    db.password=<password>
    db.username=<username>
    
Mor Blau
  • 420
  • 3
  • 15