Harden PostgreSQL security and add nginx basic auth for screenshots
- PostgreSQL: roles, passwords, pg_hba.conf, listen_addresses configured - nginx: basic auth on /screenshots/ with htpasswd - warden-zfs: fix snapshot naming convention, clarify dry-run scope - .env: add password generation pattern for all credentials Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9abcc9754d
commit
a2f3cbf28b
4 changed files with 85 additions and 13 deletions
|
|
@ -51,9 +51,42 @@ This skill does not replace:
|
|||
nginx-ssl.html # Nginx + SSL guide
|
||||
stripe-agents.html # Stripe agents guide
|
||||
tailscale-vpn.html # Tailscale VPN guide
|
||||
screenshots/ # Diagnostic screenshots (basic auth protected)
|
||||
clawdie-eng-v1.md # English content source
|
||||
```
|
||||
|
||||
## Protected paths
|
||||
|
||||
| Path | Auth | htpasswd file | Credentials |
|
||||
| --- | --- | --- | --- |
|
||||
| `/screenshots/` | basic auth | `/usr/local/etc/nginx/screenshots.htpasswd` | in `.env` (`SCREENSHOTS_USER`, `SCREENSHOTS_PASSWORD`) |
|
||||
|
||||
### Adding basic auth to a new path
|
||||
|
||||
```sh
|
||||
# 1. generate password hash
|
||||
openssl passwd -apr1 'your-password'
|
||||
|
||||
# 2. write htpasswd file
|
||||
sudo sh -c 'cat > /usr/local/etc/nginx/newpath.htpasswd << EOF
|
||||
username:$apr1$hash...
|
||||
EOF'
|
||||
sudo chmod 640 /usr/local/etc/nginx/newpath.htpasswd
|
||||
sudo chown root:www /usr/local/etc/nginx/newpath.htpasswd
|
||||
|
||||
# 3. add location block to vhost
|
||||
# location /newpath/ {
|
||||
# auth_basic "Description";
|
||||
# auth_basic_user_file /usr/local/etc/nginx/newpath.htpasswd;
|
||||
# try_files $uri $uri/ =404;
|
||||
# }
|
||||
|
||||
# 4. test and reload
|
||||
sudo nginx -t && sudo service nginx reload
|
||||
```
|
||||
|
||||
Store credentials in `/home/clawdie/clawdie-ai/.env`. Never in skill files.
|
||||
|
||||
## Safe defaults
|
||||
|
||||
- Always run `nginx -t` before reloading
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ Never expose this role to remote connections.
|
|||
Set a password anyway as defense in depth:
|
||||
|
||||
```sh
|
||||
sudo jexec db su - postgres -c "psql -c \"ALTER USER postgres WITH PASSWORD 'secure-admin-password';\""
|
||||
. /home/clawdie/clawdie-ai/.env
|
||||
sudo jexec db su - postgres -c "psql -c \"ALTER USER postgres WITH PASSWORD '$POSTGRES_ADMIN_PASSWORD';\""
|
||||
```
|
||||
|
||||
### Role: clawdie_app (Clawdie memory)
|
||||
|
|
@ -29,8 +30,9 @@ sudo jexec db su - postgres -c "psql -c \"ALTER USER postgres WITH PASSWORD 'sec
|
|||
For the Clawdie agent memory database:
|
||||
|
||||
```sh
|
||||
. /home/clawdie/clawdie-ai/.env
|
||||
sudo jexec db su - postgres -c "createuser clawdie_app"
|
||||
sudo jexec db su - postgres -c "psql -c \"ALTER USER clawdie_app WITH PASSWORD 'secure-clawdie-password';\""
|
||||
sudo jexec db su - postgres -c "psql -c \"ALTER USER clawdie_app WITH PASSWORD '$CLAWDIE_DB_PASSWORD';\""
|
||||
sudo jexec db su - postgres -c "createdb -O clawdie_app clawdie_memory"
|
||||
```
|
||||
|
||||
|
|
@ -39,8 +41,9 @@ sudo jexec db su - postgres -c "createdb -O clawdie_app clawdie_memory"
|
|||
For the Strapi content management database:
|
||||
|
||||
```sh
|
||||
. /home/clawdie/clawdie-ai/.env
|
||||
sudo jexec db su - postgres -c "createuser strapi_user"
|
||||
sudo jexec db su - postgres -c "psql -c \"ALTER USER strapi_user WITH PASSWORD 'secure-strapi-password';\""
|
||||
sudo jexec db su - postgres -c "psql -c \"ALTER USER strapi_user WITH PASSWORD '$STRAPI_DB_PASSWORD';\""
|
||||
sudo jexec db su - postgres -c "createdb -O strapi_user strapi_cms"
|
||||
```
|
||||
|
||||
|
|
@ -147,10 +150,21 @@ Should fail with: `FATAL: pg_hba.conf rejects connection`
|
|||
|
||||
## Password storage
|
||||
|
||||
Store database passwords in `.env` files inside the respective jails:
|
||||
All database passwords live in `/home/clawdie/clawdie-ai/.env`:
|
||||
|
||||
- controlplane: `/home/clawdie/clawdie-ai/.env` → `DATABASE_PASSWORD=...`
|
||||
- cms: `/home/clawdie/strapi/.env` → `DATABASE_PASSWORD=...`
|
||||
```
|
||||
POSTGRES_ADMIN_PASSWORD=<generated>
|
||||
CLAWDIE_DB_PASSWORD=<generated>
|
||||
STRAPI_DB_PASSWORD=<generated>
|
||||
```
|
||||
|
||||
Generate with: `python3 -c "import secrets; print(secrets.token_urlsafe(24))"`
|
||||
|
||||
Source before running setup commands: `. /home/clawdie/clawdie-ai/.env`
|
||||
|
||||
When jails need their own `.env`, copy only the relevant variable:
|
||||
- controlplane: `CLAWDIE_DB_PASSWORD`
|
||||
- cms: `STRAPI_DB_PASSWORD`
|
||||
|
||||
Never commit passwords to git. Never store them in skill files.
|
||||
|
||||
|
|
@ -171,11 +185,9 @@ Never commit passwords to git. Never store them in skill files.
|
|||
## ZFS snapshots
|
||||
|
||||
```sh
|
||||
# before security changes — dry-run first
|
||||
sudo zfs snapshot -nv zroot/clawdie-runtime/jails/db@pre-security-DD-mon-YYYY
|
||||
sudo zfs snapshot zroot/clawdie-runtime/jails/db@pre-security-DD-mon-YYYY
|
||||
# before security changes (snapshots are non-destructive, no dry-run needed)
|
||||
sudo zfs snapshot zroot/clawdie-runtime/jails/db@pre-security_YYYY-MM-DD_HH:MM:SS
|
||||
|
||||
# after successful setup
|
||||
sudo zfs snapshot -nv zroot/clawdie-runtime/jails/db@security-configured-DD-mon-YYYY
|
||||
sudo zfs snapshot zroot/clawdie-runtime/jails/db@security-configured-DD-mon-YYYY
|
||||
sudo zfs snapshot zroot/clawdie-runtime/jails/db@security-configured_YYYY-MM-DD_HH:MM:SS
|
||||
```
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@ namespace.
|
|||
|
||||
## Dry-run rule (mandatory)
|
||||
|
||||
**Every destructive or mutating ZFS command MUST be run with `-n` (dry-run) first.** This applies to `zfs destroy`, `zfs send`, `zfs rollback`, `zpool create`, and `zpool destroy`. Only after reviewing the dry-run output and confirming it is correct should the real command be executed.
|
||||
**Every destructive ZFS command MUST be run with `-n` (dry-run) first.** This applies to `zfs destroy`, `zfs rollback`, `zfs send`, `zpool destroy`, and `zpool create`. Only after reviewing the dry-run output and confirming it is correct should the real command be executed.
|
||||
|
||||
Note: `zfs snapshot` does NOT support `-n` because snapshots are non-destructive (instant, zero-cost). Just run `zfs snapshot` directly.
|
||||
|
||||
Workflow:
|
||||
1. Run the command with `-nv` (dry-run + verbose) to preview what will happen
|
||||
|
|
@ -58,9 +60,24 @@ Commands that are read-only (`zfs list`, `zfs get`, `zpool status`) do not need
|
|||
- keep Bastille on `zroot`
|
||||
- keep Bastille prefix `clawdie-runtime`
|
||||
- snapshot before risky jail changes
|
||||
- use day-first snapshot names with fixed month abbreviations
|
||||
- do not handcraft parallel jail dataset trees outside Bastille
|
||||
|
||||
## Snapshot naming
|
||||
|
||||
Sanoid automated snapshots follow: `autosnap_YYYY-MM-DD_HH:MM:SS_<policy>`
|
||||
|
||||
Operator-requested snapshots follow: `<description>_YYYY-MM-DD_HH:MM:SS`
|
||||
|
||||
Examples:
|
||||
```
|
||||
autosnap_2026-03-08_18:46:47_hourly # sanoid
|
||||
pre-security_2026-03-08_21:30:00 # operator request
|
||||
postgres-ready_2026-03-08_19:00:00 # operator milestone
|
||||
```
|
||||
|
||||
Do not use day-first or month-abbreviation formats (e.g., `08-mar-2026`).
|
||||
Stick to ISO-style `YYYY-MM-DD` for consistent sorting and Sanoid compatibility.
|
||||
|
||||
## Expected operator outcomes
|
||||
|
||||
- Bastille datasets exist under `zroot/clawdie-runtime`
|
||||
|
|
|
|||
10
.env.example
10
.env.example
|
|
@ -17,3 +17,13 @@ OPENROUTER_API_KEY=
|
|||
|
||||
# Channels
|
||||
TELEGRAM_BOT_TOKEN=
|
||||
|
||||
# PostgreSQL (db jail at 192.168.100.2)
|
||||
# Generate with: python3 -c "import secrets; print(secrets.token_urlsafe(24))"
|
||||
POSTGRES_ADMIN_PASSWORD=
|
||||
CLAWDIE_DB_PASSWORD=
|
||||
STRAPI_DB_PASSWORD=
|
||||
|
||||
# Nginx basic auth (clawdie.si/screenshots/)
|
||||
SCREENSHOTS_USER=clawdie
|
||||
SCREENSHOTS_PASSWORD=
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue