Connect via an SSH tunnel
When the database isn't reachable directly from the agent but a bastion host is, the agent can open an SSH channel to the bastion and tunnel the database connection through it. Nothing about the database needs to be exposed to the internet — only SSH to the bastion.
agent ──SSH──▶ bastion ──▶ database (private)
1. Prepare the bastion
-
A host that can reach the database on its port (e.g. 5432) and that the agent can reach on SSH (e.g. 22).
-
A dedicated SSH user for the agent:
sudo useradd -m -s /bin/bash shaft-tunnel sudo -u shaft-tunnel mkdir -p ~shaft-tunnel/.ssh && sudo chmod 700 ~shaft-tunnel/.ssh
2. Create a key pair for the agent
ssh-keygen -t ed25519 -f shaft_tunnel_key -N "" -C "shaft-agent"
Add the public key to the bastion user's authorized keys:
sudo tee -a ~shaft-tunnel/.ssh/authorized_keys < shaft_tunnel_key.pub
sudo chmod 600 ~shaft-tunnel/.ssh/authorized_keys
sudo chown -R shaft-tunnel:shaft-tunnel ~shaft-tunnel/.ssh
Optionally lock the key down to port-forwarding only (no shell) by prefixing the authorized_keys line with:
no-pty,permitopen="DB_HOST:5432",command="/bin/false" ssh-ed25519 AAAA...
3. Give the private key to the agent
Copy the private key onto the agent host, readable only by the agent user:
sudo install -o shaft -g shaft -m 600 shaft_tunnel_key /opt/shaft-agent/tls/ssh_key
4. Configure the connector in the portal
On the connector's Configure page, choose Connection → SSH tunnel and set:
| Field | Value |
|-------|-------|
| SSH host | the bastion's hostname or IP |
| SSH port | usually 22 |
| SSH user | shaft-tunnel |
| SSH private key | /opt/shaft-agent/tls/ssh_key (or an env: reference) |
| Known hosts | how to verify the bastion (see step 5) |
Keep the connector's JDBC URL pointing at the database as seen from the
bastion (e.g. jdbc:postgresql://db.internal:5432/appdb). The agent opens the
tunnel, forwards a local port to that host/port, and connects through it — the
tunnel stays up for the life of the task and is torn down when the task stops.
5. Verify the bastion's host key
The agent checks the bastion against known_hosts and refuses to connect to an
unrecognised host key, so record the key up front. Capture it with ssh-keyscan:
ssh-keyscan -t ed25519 BASTION_HOST
# e.g. bastion.example.com ssh-ed25519 AAAAC3Nza...
Then set the Known hosts field to either:
- a path on the agent host to a known_hosts file, e.g.
/opt/shaft-agent/tls/known_hosts(append thessh-keyscanoutput there); or - the host-key line itself, pasted directly (the agent writes it to a temporary known_hosts for the connection); or
- blank, to use the agent user's
~/.ssh/known_hosts.
Verify the fingerprint out-of-band before trusting it. If no known_hosts entry matches, the tunnel fails closed — the agent never trusts an unknown key.