feat(sp23): operator scripts (cyclone-init, post-deploy, smoke) + RUNBOOK
cyclone-init.sh generates /etc/cyclone/secrets/{db.key,admin_username,admin_pw} with openssl rand, prints the admin password once. post-deploy.sh installs logrotate.d/cyclone and a 5-minute healthcheck cron. smoke.sh brings up + logs in + parses a sample 837 end-to-end. RUNBOOK.md covers daily/weekly/quarterly/annual ops procedures plus the emergency runbook.
This commit is contained in:
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
# cyclone-init.sh — first-time host bootstrap for a production Cyclone deploy.
|
||||
#
|
||||
# Generates /etc/cyclone/secrets/{db.key,admin_username,admin_pw} with
|
||||
# openssl rand -hex 32, sets ownership + permissions, and prints the
|
||||
# admin password ONCE for the operator to capture.
|
||||
#
|
||||
# Idempotent: refuses to overwrite existing secrets unless --force.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/cyclone-init.sh # generate if missing
|
||||
# bash scripts/cyclone-init.sh --force # overwrite (destroys old data!)
|
||||
set -euo pipefail
|
||||
|
||||
SECRETS_DIR="${CYCLONE_SECRETS_DIR:-/etc/cyclone/secrets}"
|
||||
FORCE=0
|
||||
[[ "${1:-}" == "--force" ]] && FORCE=1
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "ERROR: cyclone-init.sh must run as root (it writes to ${SECRETS_DIR})." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -f "${SECRETS_DIR}/db.key" && $FORCE -eq 0 ]]; then
|
||||
echo "Secrets already exist at ${SECRETS_DIR}. Re-run with --force to overwrite." >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "${SECRETS_DIR}"
|
||||
chmod 700 "${SECRETS_DIR}"
|
||||
|
||||
# 64-hex-char (256-bit) random key for SQLCipher + cookie signing.
|
||||
openssl rand -hex 32 > "${SECRETS_DIR}/db.key"
|
||||
|
||||
# Admin username defaults to "admin" unless CYCLONE_ADMIN_USERNAME is set.
|
||||
ADMIN_USER="${CYCLONE_ADMIN_USERNAME:-admin}"
|
||||
printf '%s' "${ADMIN_USER}" > "${SECRETS_DIR}/admin_username"
|
||||
|
||||
# Memorable-but-random admin password — printed once.
|
||||
ADMIN_PW="$(openssl rand -base64 18 | tr -d '/+=' | head -c 20)Aa1!"
|
||||
printf '%s' "${ADMIN_PW}" > "${SECRETS_DIR}/admin_pw"
|
||||
|
||||
chmod 600 "${SECRETS_DIR}"/*
|
||||
chown -R root:root "${SECRETS_DIR}"
|
||||
|
||||
cat <<EOF
|
||||
================================================================
|
||||
Cyclone secrets generated at ${SECRETS_DIR}.
|
||||
|
||||
db.key SQLCipher key + cookie signing (64 hex chars)
|
||||
admin_username ${ADMIN_USER}
|
||||
admin_pw ${ADMIN_PW} <-- capture this NOW; it won't be shown again.
|
||||
|
||||
Next steps:
|
||||
cd /opt/cyclone
|
||||
docker compose pull # or: docker compose build
|
||||
docker compose up -d
|
||||
bash scripts/post-deploy.sh # logrotate + healthcheck cron
|
||||
bash scripts/smoke.sh # end-to-end smoke test
|
||||
|
||||
Then open http://<lan-ip>:8080/login and log in as '${ADMIN_USER}'.
|
||||
Change the password from /admin/users immediately.
|
||||
================================================================
|
||||
EOF
|
||||
Reference in New Issue
Block a user