I stumbled upon this blog-post from Austin W. Milne where he is detailing how he implemented an automatic fallback behavior in his SSH Config, following recommandations are based on his post, for more information feel free to refer to it or comment here
Concept
Using SSH Config's Match
directive, you can run a command before connecting to a specific host, from SSH config man page:
Match Restricts the following declarations (up to the next Host
or Match keyword) to be used only when the conditions
following the Match keyword are satisfied. Match
You could use it to check for a running service on a specific IP, like:
Match host mycomputer exec "nc -G 1 -z 192.168.1.11 %p"
Match host mycomputer exec "ping 192.168.1.11"
And then be able to connect to mycomputer
only when the specified command succeeds
In your case you could implement a two configuration blocks:
- one that matches if your
target-server
is reachable, directly connecting to it
- one that matches if your
target-server
is unreachable, with a proxy to your jumphost
One issue here would be that if another server with similar is available on your current network, but isn't the expect target-server
then script would fail as you would attempt direct connection to an unknown server (including potential risk if this is a malicious actor)
Going further
To ensure identity of target-server
before attempting to connect, you can make use of the host key, and compare it with the one you expect in a Match
statement
Upon connection you could check if the expected server has a compliant host key
- If it does, then this is your
target-server
and you can attempt a direct connection
- If it doesn't, then the fallback connection using a jumphost will be used
Example
Match
only accepts a one-line command, to improve readability, we will use a shell script and run it from the Match
command:
Script to add in ~/.ssh/scripts/check-host-fingerprints.sh
for example:
#!/bin/bash
tmpfile=$(mktemp /tmp/check-host-fingerprints.tmp.XXXXXX)
ssh-keyscan $1 2>/dev/null > $tmpfile
fingerprints=$(ssh-keygen -lf $tmpfile | awk '{print $2}')
for fingerprint in $fingerprints
do
if [ "$fingerprint" == "$2" ];
then
exit 0
fi
done
exit 1
Note: In his blog-post Austin also provides script and config for Windows
You will then need the IP address from your target-server
(note it) and run this command:
ssh -v <target-server>
And take not of the HOST_KEY as follows: debug1: Server host key ssh-xxxxxx <HOST_KEY(SHA256:.*)>
You now have everything to implement automatic failover in your SSH config by adding these lines in ~/.ssh/config
:
Match host auto-failover exec "/bin/bash %d/.ssh/scripts/check-host-fingerprint.sh <TARGET-SERVER-IP> <TARGET-SERVER-HOST-KEY>"
<DIRECT-CONFIG>
Host auto-failover
<JUMPHOST-CONFIG>
Replace <TARGET-SERVER-IP>
and <TARGET-SERVER-HOST-KEY>
with values you previously gathered
DIRECT-CONFIG
would be the configuration you use to connect directly to your host (i.e. when a direct connection between your local machine and target-server
is available)
JUMPHOST-CONFIG
would be the configuration you are using when you need to connect through a jumphost to reach you target-server
If this doesn't suit your use case, feel free to provide more details