From 63c073e31e2c89d239a152ef6dc18894adbfd4f5 Mon Sep 17 00:00:00 2001 From: iosabi Date: Thu, 15 May 2025 19:58:40 +0900 Subject: [PATCH] feat: Support loading passwords from docker secrets Docker secrets are exposed as files in `/run/secrets/` inside the container instead of as environment variables. To support deployments where the passwords are stored in secrets, this patch adds support for loading the `SMTP_PASSWORD`, `SECRET_KEY` and the database password from files, using the `__FILE` suffix convention found in many docker images. The database password is part of the `DATABASE_URL` environment variable, if a password is used at all. To support injecting the password into the DATABASE_URL without having to use the whole URL as the secret, the `start.sh` replaces the string `${DATABASE_PASSWORD}` in the `DATABASE_URL` environment variable by the contents of the `DATABASE_PASSWORD` variable, which can now also be loaded from the corresponding file passed in `DATABASE_PASSWORD__FILE`. These changes are backwards compatible since they only load the `__FILE` suffix version if the original variable was not set the `__FILE` one is set. Added comments in docker-compose.yml with examples for discoverability of the feature. Tested this on top of 2.0.0-rc.2. --- docker-compose.yml | 9 +++++++++ server/start.sh | 28 +++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 038ee4f1..78d4ca99 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,15 @@ services: environment: - BASE_URL=http://localhost:3000 - DATABASE_URL=postgresql://postgres@postgres/planka + # Optionally store the database password in secrets: + # - DATABASE_URL=postgresql://postgres:$${DATABASE_PASSWORD}@postgres/planka + # - DATABASE_PASSWORD__FILE=/run/secrets/planka_database_password + # ... and add the following to the service: + # secrets: + # - planka_database_password + - SECRET_KEY=notsecretkey + # If not set, it is loaded from the file SECRET_KEY__FILE on start. # - LOG_LEVEL=warn @@ -69,6 +77,7 @@ services: # - SMTP_SECURE=true # - SMTP_USER= # - SMTP_PASSWORD= + # If not set, SMTP_PASSWORD is loaded from the file SMTP_PASSWORD__FILE on start. # - SMTP_FROM="Demo Demo" # - SMTP_TLS_REJECT_UNAUTHORIZED=false diff --git a/server/start.sh b/server/start.sh index 440950cc..9b931743 100755 --- a/server/start.sh +++ b/server/start.sh @@ -1,2 +1,28 @@ #!/bin/bash -export NODE_ENV=production && set -e && node db/init.js && node app.js --prod + +set -eu + +# Load secrets from files if needed. Only the first line, not including the \n, +# is loaded. +if [[ -z "${SECRET_KEY:-}" && -e "${SECRET_KEY__FILE:-}" ]]; then + read SECRET_KEY <"${SECRET_KEY__FILE}" + export SECRET_KEY +fi +if [[ -z "${SMTP_PASSWORD:-}" && -e "${SMTP_PASSWORD__FILE:-}" ]]; then + read SMTP_PASSWORD <"${SMTP_PASSWORD__FILE}" + export SMTP_PASSWORD +fi +if [[ -z "${DATABASE_PASSWORD:-}" && -e "${DATABASE_PASSWORD__FILE:-}" ]]; then + read DATABASE_PASSWORD <"${DATABASE_PASSWORD__FILE}" + # No need to export DATABASE_PASSWORD, it is only used below. +fi +# Replace the exact "${DATABASE_PASSWORD}" string in the DATABASE_URL +# environment variable with the contents of DATABASE_PASSWORD. +if [[ -n "${DATABASE_PASSWORD:-}" && -n "${DATABASE_URL}" ]]; then + export DATABASE_URL="${DATABASE_URL/\$\{DATABASE_PASSWORD\}/${DATABASE_PASSWORD}}" +fi + +export NODE_ENV=production + +node db/init.js +exec node app.js --prod