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
| Aspect | QueryProxy | a bastion host |
|---|---|---|
| Controls who connects | Yes — per-team, per-connection grants | Yes, that is what it does well |
| Controls what runs | Every statement is parsed and approved before execution | No. Once connected, the session is the engineer's |
| Credential exposure | Encrypted server-side; never sent to a browser or a terminal | The password is copied out of a vault and pasted by a person |
| Second pair of eyes | Required — self-approval is blocked | None, unless someone is watching the screen |
| PII in results | Masked in the stream, before results reach disk | Returned in full to whoever ran the query |
| Audit trail | Requester, approver, statement, duration, rows — immutable | Shell history and whatever the database happens to log |
| Cost to run | One container and a worker | Already 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.