0

I have an artifact repository (set up on GitLab) for which downloading artifacts is protected by a secret token. When I try and build my project, which relies on downloading artifacts, in a Docker image it cannot download them because it does not have a settings file with the secret token to access the repository server.

My Setup

The server in my personal, local maven settings.xml

    <server>
      <id>my-gitlab-maven-registry</id>
      <configuration>
        <httpHeaders>
          <property>
            <name>Deploy-Token</name>
            <value>fake-deploy-token-value</value>
          </property>
        </httpHeaders>
      </configuration>
    </server>

The repository in my project's pom.xml

    <repository>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
      <id>my-gitlab-maven-registry</id>
      <name>Main Maven Repository</name>
      <url>https://gitlab.com/api/v4/projects/1234567/packages/maven</url>
    </repository>

My project's (simplified) Dockerfile (fails when it runs mvn package)

FROM maven:3.6.3-openjdk-15-slim AS build

COPY src /home/app/src
COPY pom.xml /home/app

RUN mvn -f /home/app/pom.xml clean package -DskipTests

My project's (simplified) docker-compose.yml

version: "3"
services:
  my-app:
    container_name: my-app
    build: .
    ports:
      - 8080:8080

I know a possible solution is to copy my local settings (with an absolute path) into the Docker image, but considering I want this project to be used by multiple people on multiple computers, I want a way to generalize passing the settings or the secret token to the docker image; so I basically want anyone who has the secret token to be able to do some sort of simple configuration to be able to build the Docker image -- I want to avoid the simplest solution of actually uploading the secret token to version control.

My Question

So what are some possible ways I might accomplish a general solution to passing a user's maven settings or the secret token to a docker image?

My Thoughts on Solutions

One potential option would be to use an environment variable to hold the secret token, similar to what's used for GitLab CI:

<!-- This environment variable is used in GitLab CI, but I could use a different name for the variable. -->
<value>${env.CI_JOB_TOKEN}</value>

But then using an environment variable, I'm not really sure how to pass an environment variable to a service when running docker-compose up without actually hardcoding the environment variable within the docker-compose.yml.

Austin Brown
  • 830
  • 12
  • 24
  • 1
    The safest way is to mount an in-memory file system with the relevant credentials stored as a file within it. Now that you're at this level of complexity, you'd be much better moving to kubernetes, as this is way beyond the capabilities of docker-compose to manage well. Compose is meant for developers desktops, not enterprise quality production releases. – Software Engineer Apr 07 '21 at 16:17
  • Yeah, I definitely have my sights set on kubernetes eventually. And while I want my project to be worked on by multiple developers, I'm definitely not at an enterprise level yet. There are just a handful of us working on the project in our freetime. I definitely want to use kubernetes eventually, but I'm not sure now is the best time since the project is still in its infancy. – Austin Brown Apr 07 '21 at 18:39
  • 1
    If it's just development, and you'll improve it later, you can use local env-files (https://docs.docker.com/compose/environment-variables/#the-env-file) that you keep in your .gitignore. But, for prod that's not secure because anyone with access to the server can see the values of the env that docker is using. Personally, I think you'll waste more time trying to get things working not using k8s. k8s is hard, but it's easier than everything else. When you mature even more, you'll want to start using hashicorp vault with k8s, then secrets get even easier. – Software Engineer Apr 07 '21 at 19:22
  • Yup, you're right. I'll definitely need to be using secrets and k8s eventually even if it means a little extra work at the moment if I don't. Thanks for pointing out that the secrets will exist in the image, that's good to know. But yeah, I'm thinking adding an ignored env file and @KeKru's answer is what I'm going to go with for now until I get to k8s. – Austin Brown Apr 07 '21 at 19:56

1 Answers1

1

I would go with the env variable, as you already said

<value>${env.YOUR_TOKEN}</value>

In your Dockerfile

ARG YOUR_TOKEN
RUN mvn package

Then in your docker-compose.yml

version: "3"
services:
  my-app:
    container_name: my-app
    build:
      context: .
      args:
        YOUR_TOKEN: $YOUR_TOKEN
    ports:
      - 8080:8080

Now this should work

export YOUR_TOKEN=abc123
docker-compose build

BUT You should not upload this build image, as it contains the token in its history.
If you have a multistage build and the maven step is your build step, which will be thrown away, it's ok.


A more elegant solution would be buildkit secrets. But I don't know if they already work with docker compose. See https://docs.docker.com/develop/develop-images/build_enhancements/ and How do you use Docker build secrets with Docker Compose?


If you need the variable at runtime (docker-compose up) and not buildtime (docker-compose build) you can do it like this:

version: "3"
services:
  my-app:
    environment:
      YOUR_TOKEN: $YOUR_TOKEN
    ports:
      - 8080:8080

Then

export YOUR_TOKEN=abc123
docker-compose up
KeKru
  • 444
  • 3
  • 13
  • Ah, this worked for me! As I was trying to work on this before your answer, a lot of my problem was that I need the variable at buildtime, but I was supplying it at runtime. So I was supplying it via `environment` and not in the build `args`. So thanks for elaborating on the difference of buildtime and runtime variables here. – Austin Brown Apr 07 '21 at 19:52
  • Also thanks for pointing out that the secret will be in the image history. Currently I'm not deploying these images anywhere (they're just for local development atm) but definitely good to know before I get to that point. – Austin Brown Apr 07 '21 at 19:57