Skip to content

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 VectorDefense MechanismAction Taken
Credential Stuffing & Brute-ForceIntercepts Backend Error Packet (E) with SQLSTATE 28P01IP banned after max_auth_failures threshold
Connection Starvation AttacksEnforces connection rate limits and burst capsExcess connections throttled or dropped
Insecure Connection ProbesHandles native SSLRequest negotiationPass-through or enforcement based on config
Connection LeaksTransparent full-duplex socket forwardingCleans 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/postgres

Configuration 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: 3

Configuration Options ​

FieldTypeDefaultDescription
listenstring":5432"Local proxy listen address and port.
upstreamstring"127.0.0.1:54320"Target PostgreSQL server address and port.
protocolstring"postgres"Must be set to "postgres" or "postgresql".
max_auth_failuresint3Failed login attempts before the client IP is banned.
ban_durationstring"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 network

Testing & 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

Released under the MIT License.