How to get HostName from executable script in SSH config file?

10

3

I frequently need to ssh into an arbitrary computer from a particular cluster (all machines in the cluster are identical). However, the set of available machines in the cluster changes frequently, so I have a script that returns an arbitrary hostname from the cluster that is available and matches my requirements (e.g., online and running the correct OS).

Note also, that I'm using Kerberos (GSSAPIAuthentication) credential forwarding for authentication.

Right now, I ssh in using ssh `get_host`. I would like to instead execute ssh cluster. With a known hostname, this is easy with the following in /ssh/config:

Host cluster
    HostName static_host.cluster.domain.tld
    GSSAPIAuthentication yes
    GSSAPIDelegateCredentials yes

How can I select the HostName dynamically, using my script? (Or does SSH have a different method to support my desired function?) I would like to do something like the following, but it does not work:

Host cluster
    HostName `get_host`   # This does not work
    ...

Grawity showed that the ProxyCommandcan be a script that gets the hostname and forwards the ssh connection to it using netcat or socat. However, this isn't forwarding the Kerberos credentials. Help with this is appreciated as well.

EDIT:

You can't do this with Kerberos as I would like (see comments in the accepted answer). So, I'm using this script, ssh-wrapper, as an ssh alias to do dynamic rewriting on the ssh command-line argument. It's not robust, but it works for me.

#!/bin/bash

# Mapping between host aliases and dynamically-generated hostname
declare -A MAP
MAP[cluster]=`gethost`

# Find and replace on all positional args
args=$*
for key in ${!MAP[@]}; do
    replace=${MAP[$key]}
    args=`echo ${args} | sed "s/\(^\|[[:space:]]\)${key}\(\$\|[[:space:]]\)/${replace}/"`
done

# Execute using called-name if not this script
if [ "ssh-wrapper" != "`basename $0`" ]; then
    exec $0 ${args}
# Otherwise, assume ssh and execute
else
    exec ssh ${args}
fi

David B.

Posted 2011-09-21T18:24:24.663

Reputation: 245

Related question on Server Fault.

– Michael - Where's Clay Shirky – 2019-03-28T19:43:15.890

Answers

6

~/.ssh/config:

Host cluster
    ProxyCommand ~/bin/cluster-connect

~/bin/cluster-connect:

#!/bin/bash
socat stdio tcp:$(get_host):22

user1686

Posted 2011-09-21T18:24:24.663

Reputation: 283 655

Thanks. This (or netcat $(get_host) 22) works great for the connection. But, it doesn't seem to pass my kerberos credentials. I've got GSSAPIAuthentication yes and GSSAPIDelegateCredentials yes under Host cluster in my .ssh/config file, and they work if the HostName is given explicity, but not if I route through the ProxyCommand. Thoughts? I'll amend the question as well. – David B. – 2011-09-21T19:20:16.947

I don't think you can achieve that -- ssh must know the target hostname to get the correct ticket, and there's just no way to provide it dynamically (short of using a wrapper that simply runs ssh $(get_host) "$@", which as I understood you don't want). It may work if all servers in the cluster have the same Kerberos principal, but I don't think anyone ever does that. – user1686 – 2011-09-21T19:30:05.597

Unfortunate, but makes sens. I wrote a quick wrapper to do a dynamic find/replace (added to the question). It'll break in some scenarios, but works for me. – David B. – 2011-09-21T21:00:36.213

Dynamic find/replace?... – user1686 – 2011-09-21T21:03:47.850

Just a sed substituion on the commandline arguments to ssh, from a host-alise to host-generation-script mapping stored in the script. – David B. – 2011-09-21T21:05:33.337

That was epic! – g33kz0r – 2013-06-29T17:52:21.183