PostgreSQL Protocol Guard (postgres)
The PostgreSQL Protocol Guard plugin inspects native PostgreSQL frontend/backend wire protocol traffic (PostgreSQL 3.0 protocol). It parses frontend startup packets, transparently negotiates SSL handshakes (SSLRequest), and inspects backend error responses for SQLSTATE 28P01 (password authentication failed) to automatically ban credential stuffing bots before they saturate database connection pools.
Capabilities & Threat Defense
| Threat / Attack Vector | Defense Mechanism | Action Taken |
|---|---|---|
| Credential Stuffing & Brute-Force | Intercepts Backend Error Packet (E) with SQLSTATE 28P01 | IP banned after max_auth_failures threshold |
| Connection Starvation Attacks | Enforces connection rate limits and burst caps | Excess connections throttled or dropped |
| Insecure Connection Probes | Handles native SSLRequest negotiation | Pass-through or enforcement based on config |
| Connection Leaks | Transparent full-duplex socket forwarding | Cleans up socket handles immediately on termination |
Installation
Install the plugin via CLI or declaratively:
# Install using short nametcp-warden plugins install postgres# Or install via Git repository URLtcp-warden plugins install https://github.com/routewarden/plugins/postgresConfiguration Reference
Add a PostgreSQL guard service to tcp-warden.yaml:
services: pg_bastion: listen: ":5432" upstream: "127.0.0.1:54320" protocol: "postgres" rate_limit: connections_per_minute: 60 burst: 15 max_auth_failures: 3 ban_after_failures: 3 ban_duration: "4h" plugin_config: max_auth_failures: 3Configuration Options
| Field | Type | Default | Description |
|---|---|---|---|
listen | string | ":5432" | Local proxy listen address and port. |
upstream | string | "127.0.0.1:54320" | Target PostgreSQL server address and port. |
protocol | string | "postgres" | Must be set to "postgres" or "postgresql". |
max_auth_failures | int | 3 | Failed login attempts before the client IP is banned. |
ban_duration | string | "4h" | Ban duration for abusive client IPs ("1h", "4h", "24h"). |
Network & Deployment Architecture
Because PostgreSQL operates on an unprivileged port (5432), firewall redirects (nftables/iptables) are unnecessary. You can deploy RouteWarden as a direct reverse proxy or via container networking:
Option A: Direct Reverse Proxy (Bare-Metal / VM)
Bind RouteWarden directly to standard port 5432, and run PostgreSQL on an internal loopback port or private subnet IP:
# tcp-warden.yaml — RouteWarden binds to standard port 5432services: pg_bastion: listen: ":5432" upstream: "127.0.0.1:54320" # Or private backend "10.0.0.15:5432" protocol: "postgres"Option B: Docker Compose Bridge Network
In containerized stacks, expose only RouteWarden on the host, keeping the PostgreSQL container private within the internal Docker bridge network:
services: routewarden: image: ghcr.io/routewarden/tcp-warden:latest ports: - "5432:5432" - "9091:9091" volumes: - ./tcp-warden.yaml:/etc/routewarden/tcp-warden.yaml:ro depends_on: - db db: image: postgres:16-alpine environment: POSTGRES_PASSWORD: supersecretpassword # Do NOT publish host ports; keep internal to bridge networkTesting & Verification
Verify query execution, credential failure detection, and API ban status:
# Test valid database connection through RouteWardenpsql -h 127.0.0.1 -p 5432 -U postgres -d postgres