1

If we want to connect to a host through some server, we can do so using the ProxyJump command in ssh config or directly in terminal via:

ssh -J user@server user@target-host

The manual states that jumping through multiple server is also possible, in case we have a first proxy to jump over and then another subnetwork that is protected from the network we jumped into initially. We can do this simply by supplying multiple jump servers:

ssh -J user@server1,user@server2  user@target-host

...so that we jump to server1 first into the main network and then again over server2 into the protected subnetwork.

However, I was not able to find any information in the manual so far about alternative jump servers in case the main server is down for maintenance, for example.

So let's say we would have a target-host we would like to connect to and there are multiple entries for redundancy reasons, like main-server1, main-server2, main-server3, ... and we could choose any of them for jumping.

In case main-server1 is down for maintenance or other reasons, we can still connect via main-server2, main-server3, ...

Is there any way we could configure this automatically so that ssh tries to connect via main-server1 first but after fail does not cancel the operation but simply goes on to try to connect via the next available server?

1 Answer 1

2

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

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .