postgres-hardeninglisted
Install: claude install-skill GoldenWing-360/claude-security-skills
# PostgreSQL Hardening
A practical baseline for a single Postgres instance (self-hosted or managed) that backs a web app. Skews toward small-team realities — not a regulated-environment DBA's playbook.
## When to invoke
- New Postgres provisioned (Docker, package, RDS, Supabase, Neon — same threat model)
- Inheriting an existing Postgres with no documented hardening
- Adding a new application or service that connects to an existing Postgres
- After a Postgres security advisory
- Reviewing a multi-tenant schema where one tenant should not see another's data
- Planning a major-version upgrade (14 → 15 → 16 → 17)
## Step 1 — Network reachability
Postgres listening on `0.0.0.0:5432` open to the internet is one of the most common misconfigurations in shared/cloud environments.
```bash
# What is the listener bound to?
sudo ss -tlnp | grep 5432
# From outside the VPS — can the world reach it? (this should fail)
nc -zv <vps-ip> 5432
```
Acceptable bindings:
- `127.0.0.1` only — app on same host, no remote access (best for single-VPS deployments)
- VPC-internal IP only — apps in same private network
- Public IP **only with TLS-required + IP allowlist at firewall** — last resort, document why
In `postgresql.conf`:
```
listen_addresses = 'localhost' # or 'localhost,10.0.0.5' for private LAN
port = 5432
```
Restart Postgres after change.
## Step 2 — `pg_hba.conf` (host-based auth)
This file is the primary access-control surface. Order matters: the first matching rule