The usual ways to query a database that is not on the internet all open something. An SSH tunnel (ssh -L 5432:localhost:5432) needs port 22 open and a key on every laptop. A bastion is a server whose only job is to be attacked. A VPN puts every laptop on the network the database lives on. And all three end with the database password in somebody’s .pgpass.
The connection goes the other way
In Subnomic, a small agent runs on a machine that can already reach the database, often the database host itself. It opens one outbound TLS connection to Subnomic and listens on nothing. When you open the database console, the query travels down that connection and the agent connects to 127.0.0.1:5432 on your behalf. Port 5432 stays closed to the internet; so does 22.
Two kinds of agent can carry it:
- Host agent: a systemd service that also gives you a terminal and the host’s metrics.
- Tunnel agent: the same tunnel with no shell and no metrics, for when a database is all it should reach. It refuses to dial anything outside its allowlist, which defaults to private address ranges.
Nobody needs the password
You register the database once: the engine (PostgreSQL, MySQL, Redis or MongoDB), the agent that can reach it, the address, and a username and password. The credentials are encrypted at rest and never returned by the API, so the people who query the database never see them, and offboarding someone does not mean rotating them.
Reads and writes are different permissions
Every statement is classified before it runs. SELECT, SHOW and EXPLAIN, Redis’s GET family and Mongo’s find and aggregate need database.query_read; anything else counts as a write and needs database.query_write. A role for analysts can read production without being able to change it, enforced by the server, not by a read-only user someone forgot to create.
On Team and Enterprise, guardrails go further: a regular expression on the statement, checked before it runs. A rule that denies DELETE or UPDATE without a WHERE is two lines in the rule list. Sessions are recorded: the query text with obvious secrets redacted, the timing and the row count, never the rows themselves.
What it looks like
Open the database in the console and type a query; ⌘/Ctrl + Enter runs it, and results come back as a grid of up to 1,000 rows. The same access works for Runa: an agent access with database.query_read lets it explore schemas and run read-only SQL against the databases that access names, each query shown with its text.
What it is not
- It is not yet a way to point psql or DBeaver at your database: a local proxy client is planned, and until it ships, the console and Runa are the clients.
- It does not make the database public. The agent must be able to reach the database, and nothing else can.
- It starts on Pro, where your own servers start; guardrails and recording come with Team.
Setting it up takes the agent install and one form: see Agents and Databases. Why the agent dials out in the first place is in SSH without a single open port.