# PostgreSQL TLS Hardening Runbook This runbook applies to: - PostgreSQL server: `47.117.131.22` (`db.refining.ltd`) - `secrets-mcp` app server: `47.238.146.244` (`secrets.refining.app`) ## 1) Issue certificate for `db.refining.ltd` (Let's Encrypt + Cloudflare DNS-01) Install `acme.sh` on the PostgreSQL server and use a Cloudflare API token with DNS edit permission for the target zone. ```bash curl https://get.acme.sh | sh -s email=ops@refining.ltd export CF_Token="your_cloudflare_dns_token" export CF_Zone_ID="your_zone_id" ~/.acme.sh/acme.sh --issue --dns dns_cf -d db.refining.ltd --keylength ec-256 ``` Install cert/key into a PostgreSQL-readable path: ```bash sudo mkdir -p /etc/postgresql/tls sudo ~/.acme.sh/acme.sh --install-cert -d db.refining.ltd --ecc \ --fullchain-file /etc/postgresql/tls/fullchain.pem \ --key-file /etc/postgresql/tls/privkey.pem \ --reloadcmd "systemctl reload postgresql || systemctl restart postgresql" sudo chown -R postgres:postgres /etc/postgresql/tls sudo chmod 600 /etc/postgresql/tls/privkey.pem sudo chmod 644 /etc/postgresql/tls/fullchain.pem ``` ## 2) Configure PostgreSQL TLS and access rules In `postgresql.conf`: ```conf ssl = on ssl_cert_file = '/etc/postgresql/tls/fullchain.pem' ssl_key_file = '/etc/postgresql/tls/privkey.pem' ``` In `pg_hba.conf`, allow app traffic via TLS only (example): ```conf hostssl secrets-mcp postgres 47.238.146.244/32 scram-sha-256 ``` Keep a safe admin path (`local` socket or restricted source CIDR) before removing old plaintext `host` rules. Reload PostgreSQL: ```bash sudo systemctl reload postgresql ``` ## 3) Verify server-side TLS ```bash openssl s_client -starttls postgres -connect db.refining.ltd:5432 -servername db.refining.ltd ``` The handshake should succeed and the certificate should match `db.refining.ltd`. ## 4) Update `secrets-mcp` app server env Use environment values like: ```bash SECRETS_DATABASE_URL=postgres://postgres:***@db.refining.ltd:5432/secrets-mcp SECRETS_DATABASE_SSL_MODE=verify-full SECRETS_ENV=production ``` If you use private CA instead of public CA, also set: ```bash SECRETS_DATABASE_SSL_ROOT_CERT=/etc/secrets/pg-ca.crt ``` Restart `secrets-mcp` after updating env. ## 5) Verify from app server Run positive and negative checks: - Positive: app starts, migrations pass, dashboard + MCP API work. - Negative: - wrong hostname -> connection fails - wrong CA file -> connection fails - disable TLS on DB -> connection fails This ensures no silent downgrade to weak TLS in production.