chore(security): remove committed secrets/dumps, .env-based config, hardened deploy webhook
- Delete backups/*.dump and all real credentials from README/docs
(prod MinIO creds, Casdoor passwords, server IP, admin password)
- All stack secrets now come from git-ignored .env (.env.example added);
docker-compose.prod.yml refuses to boot without them (${VAR:?})
- seed_casdoor.py: bcrypt password hashing, generated console/client secrets
- Harden infra/deploy-webhook: HMAC-verified Gitea webhook receiver
+ systemd unit + README (replaces unauthenticated deploy endpoint)
- docs/SECRET-MANAGEMENT.md: secret inventory + rotation checklist
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Secret management & rotation
|
||||
|
||||
**Policy (short):** real credentials live only in git-ignored `.env` files —
|
||||
the server-side `/srv/erp/.env` (used by the deploy webhook and compose) and
|
||||
local dev `.env` copies. Nothing secret goes into git: not in the README,
|
||||
not in dumps, not in docs. The repo is (or was) **public** — assume anything
|
||||
ever committed is compromised and rotate.
|
||||
|
||||
`docker-compose.prod.yml` declares every production secret as
|
||||
`${VAR:?set in .env}` so the stack **refuses to boot** on defaults.
|
||||
|
||||
## Where each secret lives
|
||||
|
||||
| Secret | Used by | Defined in |
|
||||
|---|---|---|
|
||||
| `POSTGRES_PASSWORD` | postgres, api | server `.env` |
|
||||
| `MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD` | minio, minio-init, api | server `.env` |
|
||||
| `CASDOOR_CLIENT_SECRET` | Casdoor application record, api | server `.env` (must match the app in the Casdoor console) |
|
||||
| `CASDOOR_ADMIN_PASSWORD` | Casdoor console admin, api (`/users/sync`) | server `.env` (rotate in the Casdoor console too) |
|
||||
| `CORS_ORIGINS`, `*_HOST`, `TRAEFIK_ACME_EMAIL` | compose / Traefik | server `.env` |
|
||||
| `GITEA_WEBHOOK_SECRET` | deploy-webhook receiver (port 9000) | server `.env` + Gitea webhook config |
|
||||
| Monitoring DSNs/keys | OpenPanel, GlitchTip, Grafana | `monitoring/.env` (server-side) |
|
||||
|
||||
## Rotation checklist — run after any leak suspicion
|
||||
|
||||
The production branch history contained real credentials (MinIO admin,
|
||||
Casdoor passwords, server IP, DB dumps). All of the following must be
|
||||
rotated once, on the VPS:
|
||||
|
||||
```bash
|
||||
cd /srv/erp
|
||||
|
||||
# 1) MinIO root — then update MINIO_ROOT_* in /srv/erp/.env
|
||||
mc alias set local http://127.0.0.1:9000 <old-user> '<old-pass>'
|
||||
mc admin user add local <new-user> '<new-pass>' # then:
|
||||
mc admin policy attach local consoleAdmin --user <new-user>
|
||||
mc admin user remove local <old-user>
|
||||
# (simplest equivalent: mc admin user svcacct or change root via env +
|
||||
# `docker compose up -d minio` — MinIO persists root creds from env)
|
||||
|
||||
# 2) PostgreSQL — then update POSTGRES_PASSWORD in .env
|
||||
docker exec -it procurement-postgres psql -U postgres -c \
|
||||
"ALTER USER postgres PASSWORD '<new-strong-password>';"
|
||||
docker compose up -d api # api re-reads the DSN from .env
|
||||
|
||||
# 3) Casdoor console admin (console → Identity → users → admin → reset
|
||||
# password) — then update CASDOOR_ADMIN_PASSWORD in .env
|
||||
# 4) Casdoor application client secret (console → Applications →
|
||||
# inventory-app → edit secret) — then update CASDOOR_CLIENT_SECRET in .env
|
||||
# 5) Seeded human users: reset each password in the Casdoor console.
|
||||
# 6) Gitea webhook secret (Gitea → repo → Settings → Webhooks) — then update
|
||||
# GITEA_WEBHOOK_SECRET in .env and restart the receiver (systemctl restart erp-deploy-webhook)
|
||||
|
||||
# 7) Apply everything:
|
||||
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||
```
|
||||
|
||||
- **SSH**: disable password login (`PasswordAuthentication no` in
|
||||
`/etc/ssh/sshd_config`), use keys only, and prefer a non-root user with
|
||||
sudo over `root` direct login.
|
||||
- **Repo hygiene**: keep the repo private until the git history is either
|
||||
purged (BFG / `git filter-repo` on the README + `backups/` blobs) or every
|
||||
leaked value is rotated. Deleting a file in a later commit does **not**
|
||||
remove it from history.
|
||||
- **Verify**: after rotation, `docker compose logs api | grep -i error`,
|
||||
log into the app, upload + download one attachment, and confirm the
|
||||
webhook deploy still works with a test push.
|
||||
Reference in New Issue
Block a user