Updated
This commit is contained in:
Executable
+85
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# generate-env.sh: copy .env.example to .env and fill in every secret.
|
||||
#
|
||||
# Fills POSTGRES_PASSWORD, JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY,
|
||||
# SECRET_KEY_BASE, SECRETS_ENCRYPTION_KEY and CRON_SECRET. ANON_KEY and
|
||||
# SERVICE_ROLE_KEY are HS256 JWTs signed with the generated JWT_SECRET.
|
||||
#
|
||||
# Usage: scripts/generate-env.sh [--output FILE] [--yes]
|
||||
# --output FILE write here instead of .env
|
||||
# --yes, --force skip the confirmation prompt (required when stdin is not a
|
||||
# terminal)
|
||||
#
|
||||
# Always asks before writing; the default answer is N.
|
||||
#
|
||||
# The default target is .env (git-ignored), not .env.example, because
|
||||
# .env.example is committed and must never hold real secrets.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
TEMPLATE="$ROOT/.env.example"
|
||||
OUT="$ROOT/.env"
|
||||
FORCE=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--output) OUT="$2"; shift 2 ;;
|
||||
--yes|--force) FORCE=1; shift ;;
|
||||
-h|--help) sed -n '2,18p' "${BASH_SOURCE[0]}"; exit 0 ;;
|
||||
*) echo "error: unknown argument: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
command -v openssl >/dev/null || { echo "error: openssl is required" >&2; exit 1; }
|
||||
[[ -f "$TEMPLATE" ]] || { echo "error: $TEMPLATE not found" >&2; exit 1; }
|
||||
if [[ $FORCE -ne 1 ]]; then
|
||||
if [[ ! -t 0 ]]; then
|
||||
echo "error: not a terminal; pass --yes to run non-interactively" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -e "$OUT" ]]; then
|
||||
echo "$OUT already exists. Continuing replaces it and rotates every secret."
|
||||
else
|
||||
echo "This will create $OUT with newly generated secrets."
|
||||
fi
|
||||
read -r -p "Continue? [y/N] " answer
|
||||
case "$answer" in
|
||||
y|Y|yes|YES) ;;
|
||||
*) echo "aborted"; exit 1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; }
|
||||
|
||||
# sign_jwt ROLE SECRET -> HS256 JWT valid for 10 years
|
||||
sign_jwt() {
|
||||
local role="$1" secret="$2" iat header payload sig
|
||||
iat="$(date +%s)"
|
||||
header="$(printf '{"alg":"HS256","typ":"JWT"}' | b64url)"
|
||||
payload="$(printf '{"role":"%s","iss":"supabase","iat":%d,"exp":%d}' \
|
||||
"$role" "$iat" "$((iat + 315360000))" | b64url)"
|
||||
sig="$(printf '%s.%s' "$header" "$payload" \
|
||||
| openssl dgst -sha256 -hmac "$secret" -binary | b64url)"
|
||||
printf '%s.%s.%s' "$header" "$payload" "$sig"
|
||||
}
|
||||
|
||||
POSTGRES_PASSWORD="$(openssl rand -hex 24)"
|
||||
JWT_SECRET="$(openssl rand -hex 32)"
|
||||
ANON_KEY="$(sign_jwt anon "$JWT_SECRET")"
|
||||
SERVICE_ROLE_KEY="$(sign_jwt service_role "$JWT_SECRET")"
|
||||
SECRET_KEY_BASE="$(openssl rand -hex 32)"
|
||||
SECRETS_ENCRYPTION_KEY="$(openssl rand -hex 32)"
|
||||
CRON_SECRET="$(openssl rand -hex 32)"
|
||||
|
||||
umask 077
|
||||
cp "$TEMPLATE" "$OUT"
|
||||
for name in POSTGRES_PASSWORD JWT_SECRET ANON_KEY SERVICE_ROLE_KEY \
|
||||
SECRET_KEY_BASE SECRETS_ENCRYPTION_KEY CRON_SECRET; do
|
||||
# Values are hex or base64url, so they contain no sed-special characters.
|
||||
sed -i "s|^${name}=.*|${name}=${!name}|" "$OUT"
|
||||
done
|
||||
chmod 600 "$OUT"
|
||||
|
||||
echo "wrote $OUT"
|
||||
Reference in New Issue
Block a user