security: rotate local deployment secrets safely
This commit is contained in:
parent
7a0138fffd
commit
bd448f5afd
|
|
@ -33,7 +33,7 @@ SMTP_PASSWORD=
|
|||
SMTP_AUTH=never
|
||||
SMTP_TLS=never
|
||||
SMTP_SSL=false
|
||||
EMAIL_FROM_NAME=Who Need Help
|
||||
EMAIL_FROM_NAME="Who Need Help"
|
||||
EMAIL_FROM_ADDRESS=contact@example.com
|
||||
|
||||
CODEX_SESSION_ID=copy-the-main-local-codex-session-id
|
||||
|
|
|
|||
11
README.md
11
README.md
|
|
@ -80,6 +80,17 @@ set `app.host`, `app.scheme`, and `app.urlPort` to the public URL used in email
|
|||
links, and must set `app.mapTileUrl` to a tile service whose policy and capacity
|
||||
fit the deployment.
|
||||
|
||||
Rotate all local application secrets and the existing local PostgreSQL role
|
||||
without printing the generated values:
|
||||
|
||||
```bash
|
||||
./scripts/rotate-local-secrets.sh
|
||||
docker compose up -d --wait
|
||||
```
|
||||
|
||||
This preserves the named PostgreSQL volume, but invalidates existing browser
|
||||
sessions and changes handover codes for active local requests.
|
||||
|
||||
## Tests
|
||||
|
||||
The reproducible test command builds a dedicated test target and uses the
|
||||
|
|
|
|||
73
scripts/rotate-local-secrets.sh
Executable file
73
scripts/rotate-local-secrets.sh
Executable file
|
|
@ -0,0 +1,73 @@
|
|||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
ENV_FILE="$ROOT/.env"
|
||||
TEST_IMAGE="${TEST_IMAGE:-who-need-help:test}"
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "Missing $ENV_FILE. Copy .env.example to .env first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for command in docker openssl perl; do
|
||||
if ! command -v "$command" >/dev/null 2>&1; then
|
||||
echo "Required command is unavailable: $command" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
set -a
|
||||
. "$ENV_FILE"
|
||||
set +a
|
||||
|
||||
: "${POSTGRES_USER:?POSTGRES_USER is missing from .env}"
|
||||
: "${POSTGRES_DB:?POSTGRES_DB is missing from .env}"
|
||||
|
||||
case "$POSTGRES_USER" in
|
||||
*[!A-Za-z0-9_]* | "") echo "POSTGRES_USER contains unsupported characters." >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
case "$POSTGRES_DB" in
|
||||
*[!A-Za-z0-9_]* | "") echo "POSTGRES_DB contains unsupported characters." >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
generate_phoenix_secret() {
|
||||
docker run --rm "$TEST_IMAGE" mix phx.gen.secret
|
||||
}
|
||||
|
||||
new_secret_key_base=$(generate_phoenix_secret)
|
||||
new_handover_secret=$(generate_phoenix_secret)
|
||||
new_release_cookie=$(generate_phoenix_secret)
|
||||
new_postgres_password=$(openssl rand -hex 32)
|
||||
new_database_url="ecto://${POSTGRES_USER}:${new_postgres_password}@db/${POSTGRES_DB}"
|
||||
|
||||
tmp_env=$(mktemp "${ENV_FILE}.rotate.XXXXXX")
|
||||
trap 'rm -f "$tmp_env"' EXIT HUP INT TERM
|
||||
chmod 600 "$tmp_env"
|
||||
|
||||
NEW_SECRET_KEY_BASE=$new_secret_key_base \
|
||||
NEW_HANDOVER_SECRET=$new_handover_secret \
|
||||
NEW_RELEASE_COOKIE=$new_release_cookie \
|
||||
NEW_POSTGRES_PASSWORD=$new_postgres_password \
|
||||
NEW_DATABASE_URL=$new_database_url \
|
||||
perl -pe '
|
||||
s/^SECRET_KEY_BASE=.*/SECRET_KEY_BASE=$ENV{NEW_SECRET_KEY_BASE}/;
|
||||
s/^HANDOVER_SECRET=.*/HANDOVER_SECRET=$ENV{NEW_HANDOVER_SECRET}/;
|
||||
s/^RELEASE_COOKIE=.*/RELEASE_COOKIE=$ENV{NEW_RELEASE_COOKIE}/;
|
||||
s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$ENV{NEW_POSTGRES_PASSWORD}/;
|
||||
s/^DATABASE_URL=.*/DATABASE_URL=$ENV{NEW_DATABASE_URL}/;
|
||||
' "$ENV_FILE" >"$tmp_env"
|
||||
|
||||
printf "ALTER ROLE \"%s\" WITH PASSWORD '%s';\n" \
|
||||
"$POSTGRES_USER" "$new_postgres_password" |
|
||||
docker compose --project-directory "$ROOT" exec -T db \
|
||||
psql --set ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" \
|
||||
>/dev/null
|
||||
|
||||
mv "$tmp_env" "$ENV_FILE"
|
||||
chmod 600 "$ENV_FILE"
|
||||
trap - EXIT HUP INT TERM
|
||||
|
||||
echo "Local application and PostgreSQL secrets rotated without printing their values."
|
||||
echo "Run docker compose up -d --wait to apply the new application environment."
|
||||
Loading…
Reference in New Issue
Block a user