Skip to content

Postgres

Postgres mode intercepts the PostgreSQL wire protocol. For each incoming connection, Waypoint:

  1. Authenticates the caller via Tailscale.
  2. Reads the requested database from the startup message. TestReadWriteStartupMessage internal/pgwire/startup_test.go:22
  3. Provisions a temporary backend role with the permissions described by the ACL grant. TestIntegration_EnsureUser_CreatesRole internal/provision/provision_integration_test.go:95 TestIntegration_EnsureUser_CanLogin internal/provision/provision_integration_test.go:114
  4. Authenticates as that role against the backend (supporting SCRAM, MD5, and cleartext upstream auth) TestHandleUpstreamAuth_SCRAM internal/pgwire/auth_test.go:115 TestHandleUpstreamAuth_MD5Password internal/pgwire/auth_test.go:73 TestHandleUpstreamAuth_CleartextPassword internal/pgwire/auth_test.go:33 and proxies the rest of the session. TestIntegration_Proxy_SelectAllowed internal/proxy/proxy_integration_test.go:397
[[listeners]]
name = "pg-main"
listen = ":5432"
mode = "postgres"
backend = "10.0.1.10:5432"
tls_mode = "optional"
use_tailscale_tls = true
[listeners.postgres]
admin_user = "waypoint_admin"
admin_password = "${PG_ADMIN_PASSWORD}"
admin_database = "postgres"
user_prefix = "wp_"
user_ttl = "24h"
FieldPurpose
admin_user / admin_passwordBackend credentials Waypoint uses to create roles. Needs CREATEROLE plus CONNECT on each target database.
admin_databaseDatabase to connect to for admin operations (usually postgres).
user_prefixAll provisioned roles begin with this string. Default wp_. TestFormatUsername_DefaultPrefix internal/provision/provision_test.go:123 TestFormatUsername_CustomPrefix internal/provision/provision_test.go:131
user_ttlHow long a role stays in the database after last use before cleanup eligibility. TestPostgresAdmin_UserTTLDefault internal/config/config_test.go:325 TestPostgresAdmin_UserTTLCustom internal/config/config_test.go:332

Roles are deterministically named from the caller’s identity and target database, e.g. wp_alice_laptop_appdb. TestFormatUsername_Basic internal/provision/provision_test.go:33 Names longer than Postgres’s 63-byte identifier limit are deterministically truncated with a hash suffix, so the same caller always resolves to the same role. TestFormatUsername_TruncationDeterministic internal/provision/provision_test.go:76 This means the same user reconnecting reuses the same role (and its password is rotated each time), keeping the role count bounded.

Postgres clients can request a lower effective preset for one connection via the waypoint_presets query parameter:

postgres://ignored:ignored@waypoint-db/myapp?sslmode=require&waypoint_presets=readonly

Values are readonly, readwrite, or admin. Comma-separated values are accepted; the strongest listed is treated as the maximum. TestPostgresPresetLimitFromStartup internal/proxy/preset_limit_test.go:10 The override cannot elevate beyond the ACL grant — a readonly grant stays read-only even if the client asks for admin. TestLimitDBPermissionsToPostgresPreset internal/proxy/preset_limit_test.go:83

When set, Waypoint provisions a scoped backend role for that effective preset and skips raw-SQL grants for that connection. TestIntegration_Proxy_PresetQueryParamLimitsReadwriteGrant internal/proxy/proxy_integration_test.go:474

Postgres clients negotiate TLS via SSLRequest. Waypoint serves the certificate that matches the requested server name. See TLS for the full certificate-selection logic. Use tls_mode = "require" to reject plaintext clients entirely. TestReadStartupMessage_TLSRequireRejectsPlaintext internal/pgwire/startup_test.go:247

Waypoint auto-detects CockroachDB backends and adjusts role-lifecycle behavior accordingly. See CockroachDB for the differences.