QueryProxy

QueryProxy vs a bastion host and shared credentials

Most teams reach production through a jump box, an SSH tunnel and a credential from the password manager. It is cheap, it is already built, and it controls exactly one thing — who reaches the database.

Updated:

At a glance

AspectQueryProxya bastion host
Controls who connectsYes — per-team, per-connection grantsYes, that is what it does well
Controls what runsEvery statement is parsed and approved before executionNo. Once connected, the session is the engineer's
Credential exposureEncrypted server-side; never sent to a browser or a terminalThe password is copied out of a vault and pasted by a person
Second pair of eyesRequired — self-approval is blockedNone, unless someone is watching the screen
PII in resultsMasked in the stream, before results reach diskReturned in full to whoever ran the query
Audit trailRequester, approver, statement, duration, rows — immutableShell history and whatever the database happens to log
Cost to runOne container and a workerAlready built, effectively free

Almost every team starts here, and there is nothing shameful about it: a jump box, an SSH tunnel, and a credential kept in the password manager. It is already built and it costs nothing. It is worth being precise about what it does and does not cover.

What the bastion genuinely does

It controls the network path. Reaching the database means reaching the jump box first, which means an SSH key, which means a person you can name. That is real security and it is not nothing.

Where it stops

The bastion’s job ends the moment the connection is forwarded. After that the session belongs to the engineer, and three things follow:

The credential is now a copy. It was pasted into a terminal. It is in shell history, in a clipboard, possibly in a .pgpass file, and it remains valid until someone rotates it — which, in practice, is when somebody leaves.

Nobody reviews the statement. DELETE FROM orders without a WHERE clause is a well-formed query. The bastion forwards it as readily as a SELECT. The tooling has no opinion, because reading SQL was never its job.

The result comes back whole. Every email address, every card number, every phone number, rendered in a terminal on a laptop, and now in that laptop’s scrollback.

What changes with an approval portal

The credential never leaves the server: QueryProxy holds it AES-256 encrypted and connects on the developer’s behalf, so there is nothing to paste and nothing to leak.

The statement is parsed before it runs. UPDATE and DELETE without a WHERE are rejected outright, a SELECT without a LIMIT gets one injected, and administrative statements are blocked.

Someone else has to agree. The request appears in the DBA queue and as a Slack card with Approve and Reject buttons; nobody can approve their own request.

The result is masked as it streams to storage, so the unmasked version is never written anywhere, and the audit log records who asked, who approved, what ran, how long it took and how many rows it touched — insertable and readable, never updatable.

Keep the break-glass path

None of this argues for deleting the bastion. At three in the morning during an incident, an engineer needs a real terminal, and a submit-and-wait loop is the wrong tool. Keep that path, make it deliberately awkward to use, and alert on it. The goal is not that emergency access becomes impossible — it is that everyday access stops going through the emergency door.

When to choose a bastion host instead

  • Nobody but the DBA ever touches production. If the person with the credential is also the person who would approve, an approval step adds nothing.
  • You need full interactive sessions for incident response — psql at 3am with a real terminal — where a submit-and-wait loop is actively harmful. Keep a break-glass path for this.
  • The team is small enough and the data ordinary enough that the ceremony genuinely costs more than the risk. That is a legitimate answer, and it is worth saying out loud rather than pretending otherwise.

Frequently asked

Is a bastion host not enough?
It is enough for the question it answers — who may reach the database. It cannot answer the other one. A bastion happily forwards a connection to an engineer who then runs an UPDATE with no WHERE clause, and its logs will tell you afterwards that a connection was opened, not what was destroyed.
Do I have to remove the bastion to use QueryProxy?
No. Most teams keep it as the break-glass path for genuine emergencies and route everyday access through QueryProxy, so that the bastion becomes the exception rather than the routine — and its use is conspicuous when it happens.
What about credentials in a password manager?
A vault controls distribution, not use. Once the credential is pasted into a terminal it is on a laptop, in a shell history and in a clipboard, and it stays valid. QueryProxy never hands the credential over — it holds it encrypted and runs the query on the developer's behalf.
Is this not just added bureaucracy?
It is a second pair of eyes on statements that touch production, which is bureaucracy in the same sense that code review is. The cost is a wait; approvals arrive as a Slack card with two buttons, so in practice that wait is usually short.

Arrow keys to move, Enter to open.