28

I was trying to set the password from secrets but it wasn't picking it up. Docker Server verions is 17.06.2-ce. I used the below command to set the secret:

echo "abcd" | docker secret create password -

My docker compose yml file looks like this

version: '3.1'
...
 build:
  context: ./test
  dockerfile: Dockerfile
environment:
  user_name: admin
  eureka_password: /run/secrets/password
secrets:
  - password

I also have root secrets tag:

secrets:
  password:
     external: true

When I hardcode the password in environment it works but when I try via the secrets it doesn't pick up. I tried to change the compose version to 3.2 but with no luck. Any pointers are highly appreciated!

mohan08p
  • 5,002
  • 1
  • 28
  • 36
raj
  • 471
  • 1
  • 5
  • 12
  • 1
    I think this can help you: https://stackoverflow.com/questions/42139605/how-do-you-manage-secret-values-with-docker-compose-v3-1 – lvthillo Jan 04 '18 at 12:11
  • thanks lvthillo. This post was one of the post which I had referred. Only difference seems to be I want the secret to be injected into containers environment. I'm using docker stack deploy as mentioned here: https://docs.docker.com/engine/swarm/secrets/#use-secrets-in-compose . But for some reason it is not working as expected. I did read some post where they suggested to use command/entrypoint script to pick from /run/secrets/ and put in environment variable. Not sure if that is the only way. – raj Jan 04 '18 at 15:47

6 Answers6

17

To elaborate on the original accepted answer, just change your docker-compose.yml file so that it contains this as your entrypoint:

version: "3.7"
  services:
    server:
      image: alpine:latest
      secrets:
        - test
      entrypoint: [ '/bin/sh', '-c', 'export TEST=$$(cat /var/run/secrets/test) ; source /entrypoint.sh' ]
    
secrets:
  test:
    external: true

That way you don't need any additional files!

Griff
  • 68
  • 5
Griff
  • 171
  • 1
  • 4
12

You need modify docker compose to read the secret env file from /run/secrets. If you want to set environment variables via bash, you can overwrite your docker-compose.yaml file as displayed below.

You can save the following code as entrypoint_overwrited.sh:

# get your envs files and export envars
export $(egrep  -v '^#'  /run/secrets/* | xargs) 
# if you need some specific file, where password is the secret name 
# export $(egrep  -v '^#'  /run/secrets/password| xargs) 
# call the dockerfile's entrypoint
source /docker-entrypoint.sh

In your docker-compose.yaml overwrite the dockerfile and entrypoint keys:

version: '3.1'
#...
build:
  context: ./test
  dockerfile: Dockerfile
entrypoint: source /data/entrypoint_overwrited.sh
tmpfs:
  - /run/secrets
volumes:
  - /path/your/data/where/is/the/script/:/data/
environment:  
  user_name: admin
  eureka_password: /run/secrets/password
secrets:
  - password

Using the snippets above, the environment variables user_name or eureka_password will be overwritten. If your secret env file defines the same env vars, the same will happen if you define in your service some env_file.

Dov Benyomin Sohacheski
  • 7,133
  • 7
  • 38
  • 64
Alejandro Molina
  • 170
  • 2
  • 13
2

I found this neat extension to Alejandro's approach: make your custom entrypoint load from ENV_FILE variables to ENV ones:

environment:
  MYSQL_PASSWORD_FILE: /run/secrets/my_password_secret
entrypoint: /entrypoint.sh

and then in your entrypoint.sh:

#!/usr/bin/env bash

set -e

file_env() {
   local var="$1"
   local fileVar="${var}_FILE"
   local def="${2:-}"

   if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
      echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
      exit 1
   fi
   local val="$def"
   if [ "${!var:-}" ]; then
      val="${!var}"
   elif [ "${!fileVar:-}" ]; then
      val="$(< "${!fileVar}")"
   fi
   export "$var"="$val"
   unset "$fileVar"
}

file_env "MYSQL_PASSWORD"

Then, when the upstream image changes adds support for _FILE variables, you can drop the custom entrypoint without making changes to your compose file.

3wordchant
  • 197
  • 1
  • 5
  • dude, this is a copy of code from https://medium.com/@adrian.gheorghe.dev/using-docker-secrets-in-your-environment-variables-7a0609659aab – NorrPL Aug 22 '23 at 09:58
  • @NorrPL that page is... literally linked in the first sentence of my answer? (also, not a "dude", try again) – 3wordchant Aug 24 '23 at 19:37
1

One option is to map your secret directly before you run your command:

entrypoint: "/bin/sh -c 'eureka_password=`cat /run/secrets/password` && echo $eureka_password'"

For example MYSQL password for node:

version: "3.7"
services:
  app:
    image: xxx
    entrypoint: "/bin/sh -c 'MYSQL_PASSWORD=`cat /run/secrets/sql-pass` npm run start'"
    secrets:
      - sql-pass  
secrets:
   sql-pass:
     external: true
BorutT
  • 503
  • 4
  • 5
1

Here's a similar approach to the accepted answer, just from the other side: "If you want a secret to be in the environment, just append '.env' to its name". POSIX-compliant, so will work with every /bin/sh, not just bash:

# ############################################################
# secrets2env.sh
#
# Set environment variables from secret files
#
# For every secret file ending in ".env",
# set an environment variable with the same name
# but without the ".env" suffix, and the contents
# of the file as its value.
# Then call all positional parameters (=original entrypoint).
#
# This is meant to be used in docker compose when you don't have control
# over the docker image which requires secrets in environment variables.
# Simply inject this script as a new entrypoint and name your file
# secrets as required:
#
# ------------------------------------------------------------
# docker-compose.yml
# ------------------------------------------------------------
# services:
#   app:
#     entrypoint: ["/run/secrets/secrets2env.sh", "/original-entrypoint-if-any"]
#     secrets:
#       - ADMIN_PASSWORD.env
#       - source: secrets2env.sh
#         target: /run/secrets/secrets2env.sh
#         mode: 0777
#
# secrets:
#  ADMIN_PASSWORD.env:
#    file: ./secrets/ADMIN_PASSWORD.env
#  secrets2env.sh:
#    file: ./secrets/secrets2env.sh
# ------------------------------------------------------------
# (adding the script itself as a secret seems fitting, you may prefer it
# as a config, or even just a bind mount)
# (the file in /run/secrets/ will be named ADMIN_PASSWORD.env
# because that's the name of the secret - your original local file could
# be named differently - I'm just trying to keep it simple)
#
# The container will get an environment variable
# "ADMIN_PASSWORD" with the value being the contents
# of your file ./secrets/ADMIN_PASSWORD_ENV.env
# (in the container, the file /run/secrets/ADMIN_PASSWORD.env
# will also still exist, it is just read into the variable)
#
# Unfortunately, it's not possible to "inherit" the original
# entrypoint and command of the image. Even worse, if you set
# a new entrypoint then the original command is nulled out and needs
# to be set again. See https://stackoverflow.com/a/47063296
#
# Use docker inspect to look them both up, e.g. `docker inspect postgres:13`
# will show you in "Config" that "Cmd": ["postgres"] and
# "Entrypoint": ["docker-entrypoint.sh"] so you set
# entrypoint: ["/run/secrets/secrets2env.sh", "docker-entrypoint.sh"]
# command: postgres
# You may want to copy it to /secrets2env.sh to make the call shorter
# but I prefer it in the same directory as the secret files.
# ############################################################

for secret_file in $(find /run/secrets -name '*.env'); do
    export "$(basename "${secret_file%.env}")"="$(cat "$secret_file")"
done

# Chain with existing entrypoint (if any)
exec "$@"

Setting the file mode to make it executable requires the long notation which makes it a bit of a mouthful. If several services need this you can add to the top of your docker-compose.yml

x-secrets2env: &secrets2env
  source: secrets2env.sh
  target: /run/secrets/secrets2env.sh
  mode: 0777

and then just refer to that whenever you have one or more "env secrets":

services:
  app:
    entrypoint: ["/run/secrets/secrets2env.sh", "/entrypoint.sh"]
    secrets:
      - ADMIN_PASSWD.env
      - DB_PASSWORD.env
      - *secrets2env
Danny W. Adair
  • 12,498
  • 4
  • 43
  • 49
-2

Because you are initialising the eureka_password with a file instead of value.

vishy dewangan
  • 1,061
  • 7
  • 9