Files, tunnels, and jumps

Use jump hosts without spreading keys

Reach a private host through a bastion while keeping authentication end to end where possible.

Many setups have one server with a public address and others that only have private ones. The public one is the bastion, or jump host. To reach 10.0.0.12 you first have to go through 203.0.113.10.

The naive approach is to SSH into the bastion, then SSH again from there. For that second hop to work you need a private key on the bastion. So people copy their key there. Now a shared, internet-facing machine holds a credential that opens every private server. That is exactly the file we spent module two keeping on one laptop.

ProxyJump

-J tells your client to reach the target through another host, without a shell or a key on the middle machine:

ssh -J notes-server [email protected]

Your client opens an SSH connection to the bastion and asks it to forward a raw TCP stream to 10.0.0.12:22. Then your client runs a second, complete SSH handshake through that stream, straight to the private server. The bastion only sees encrypted bytes.

Watch it in verbose mode:

ssh -v -J notes-server [email protected]
debug1: Setting implicit ProxyCommand from ProxyJump: ssh -v -W '[%h]:%p' notes-server
debug1: Server host key: ssh-ed25519 SHA256:pR4tK8m...   <- bastion
debug1: Server host key: ssh-ed25519 SHA256:zX9cV2b...   <- private host
debug1: Offering public key: /Users/flavio/.ssh/notes_server_ed25519 ...
debug1: Offering public key: /Users/flavio/.ssh/notes_server_ed25519 ...

Two host keys, both verified against your local known_hosts. Two user authentications, both signed by the key on your laptop. Nothing was copied anywhere. The first time you do this, the private host’s fingerprint prompt appears too, and you verify it from the console exactly like any other server.

Put it in config

Host notes-db
  HostName 10.0.0.12
  User deploy
  ProxyJump notes-server
  IdentityFile ~/.ssh/notes_server_ed25519
  IdentitiesOnly yes

Now ssh notes-db, scp file notes-db:/tmp/, and ssh -L 5433:127.0.0.1:5432 notes-db all work. The jump is invisible to the tools on top.

Prove the bastion has no key

Log in to the bastion itself and look:

ssh notes-server 'ls -la ~/.ssh'
drwx------ 2 deploy deploy 4096 Sep  8 09:30 .
-rw------- 1 deploy deploy   99 Sep  8 09:30 authorized_keys

Only authorized_keys, no private key. Then try to hop the old way from there:

ssh notes-server 'ssh [email protected] hostname'
[email protected]: Permission denied (publickey).

Good. The bastion cannot reach the private server on its own. Only you can, from your laptop, through it.

When people reach for agent forwarding

ssh -A would make that second hop work by lending the bastion your agent. It solves the same problem, but anyone with root on the bastion can use your agent while you are connected. ProxyJump needs no such trust. My default is always ProxyJump, and I only consider -A when a tool on the middle host itself must authenticate as me, and I have looked at who else has root there.

Lesson completed