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