SSH
SSH has become the de-facto standard for accessing *nix based systems, even Window$ in some setups. It’s used for administration, file transfer and tcp connection tunneling among other things. It is a valuable endpoint that needs protection behind the perimeter. VPN setups can add unnecessary complexity, a bastion is enough, even better if the UX is transparent.
Bastion
A common practice in cloud setups is to utilize a bastion host, a minimal VM that lives on two network segments. Both on the public internet and on the internal application network. Access to the bastion may have more or less complex authentication requirements, but access to protected resources from a public endpoint is the common thread.
Using a bastion in its most basic form, is not user friendly. Consider the following login flow:
[Client] --(login)--> [Bastion] --(login)--> [Protected Resource]
It ain’t much, but its hone… Logging in twice may not seem like much work, but what about when you need to transfer a file? Or forward a tcp port? Have fun.
Enter ProxyJump
Provided that authentication is setup properly on both the bastion and target endpoint, IdentityFile, GSSAPI or otherwise. The following configuration should be sufficient:
Host bastion.example.com
User bastionUser
Port 22 || non-standard
IdentityFile ssh_key.priv
Host behind.bastion.example.com
User appUser
Port 22
IdentityFile ssh_key.priv
ProxyJump bastion.example.com <-----
That’s it, now you can treat behind.bastion.example.com
as any other ssh endpoint from your client.
ssh behind.bastion.example.com
scp behind.bastion.example.com
sftp behind.bastion.example.com
ssh -L 8080:localhost:80 behind.bastion.example.com -N
etc
Side-note
Another nice feature with this setup is that it somewhat applies system wide (at least in my experience, running Linux and macOS since 2006…)
Meaning that whether you are ssh:ing through the terminal, running an Ansible playbook or browsing with Cyberduck. The configuration should apply.