postgres lane decodes the PostgreSQL v3 frontend/backend protocol: every statement a client sends, and every row the server returns. It is the lane the compose stack demonstrates and the one Running the Sidecar builds step by step.
config.yaml
What the codec reads
Two message types carry SQL, and the codec reads both:
The codec skips everything else by length, so a bulk
COPY stream costs no memory. It reassembles a statement split across TCP segments before classifying it.
The codec splits a multi-statement Q message with PostgreSQL’s own lexical rules (dollar quoting, standard-conforming strings, nested comments) and evaluates each statement on its own. Operation is the statement’s most consequential effect, so a DELETE hidden inside a CTE classifies as delete; see the worked example.
TLS on each leg
pgwire negotiates TLS in-band: the client sends an 8-byteSSLRequest and waits for a one-byte reply. That shapes both ends of the lane.
postgres is one of two protocols that may terminate the client’s TLS at the lane (the other is grpc), because no generic proxy in front can speak the in-band exchange:
config.yaml
PGSSLMODE=require and the gate still reads plaintext, because the lane decrypts what it terminates.
Two upstream details:
- A refusal fails the connection. If the server answers
Nto theSSLRequest, the lane errors out instead of downgrading. You asked for an encrypted hop, and a downgrade would send credentials in the clear without telling you. - The Sidecar strips channel binding. It removes
SCRAM-SHA-256-PLUSfrom the server’s SASL offer, because channel binding ties SCRAM to a single TLS session and a terminating relay has two. PlainSCRAM-SHA-256remains and authenticates the same password against the same verifier, so you change no credential and no server setting.
Masking
Every row and column in a pgwireDataRow is length-prefixed, so the codec re-frames: it rebuilds each message around the rewritten values, and a mask that grows or shrinks a value cannot desynchronize the client. Both rule shapes work:
RowDescription, and wherever the protocol names its values they beat detection.
Denials
A denied statement returns a real pgwireErrorResponse carrying the rule’s message, so the developer reads it in psql instead of watching the socket drop:
FATAL rather than ERROR because the connection closes with the denial; ERROR would leave psql waiting for a ReadyForQuery that never arrives.
The Envoy lane
Envoy has no pgwire parser, so the lane is plaintcp_proxy and the Sidecar sees every byte Envoy could not examine:
envoy.yaml
postgres_proxy filter with a starttls transport socket. Terminating client TLS has the full shape and its caveats.
Try it end to end with the compose stack in deploy/docker-compose/envoy-stack/: its appdb lane runs this protocol with upstream_tls on and masking live.
Next
Running the Sidecar
Builds a Postgres lane from zero, behind Envoy, with the compose stack to prove it.
Guardrail Rules
Every rule type this lane evaluates, including deferring a match to Rego.