10

I have to administer a whole pile of hosts over ssh. However I can only access them through a certain gateway ssh server.

I have the following in my ~/.ssh/config:

Host mygateway-www
Hostname www
IdentityFile ~/.ssh/id_rsa
ProxyCommand ssh mygateway nc %h 22

However I have to connect to lots of these machines. Instead of putting dozens of entries in my ~/.ssh/config, is there anyway I can have something like this:

Host mygateway-*
Hostname ???WHAT GOES HERE????
IdentityFile ~/.ssh/id_rsa
ProxyCommand ssh mygateway nc %h 22

I know you can use %h in the Hostname argument, but that would be the hostname. What I really need is some sort of string substitution, like bash's ${VAR%thingie}. Is this possible?

6 Answers 6

27

This can be done with the following SSH config file:

Host *
  ServerAliveInterval 120

Host gateway.somewhere.com
  User jdoe

Host gateway+*
  User jdoe
  ProxyCommand ssh -T -a $(echo %h |cut -d+ -f1).somewhere.com nc $(echo %h |cut -d+ -f2) %p 2>/dev/null
  ControlMaster auto
  ControlPath ~/.ssh/ssh-control_%r@%h:%p

You then access your internal hosts like so:

ssh gateway+internalhost01.somewhere.com
ssh gateway+internalhost02.somewhere.com

The name you choose for the right half should be resolvable by the jump host.

The User parameter is specified in case you need to manually map to different users on the different classes of hosts. ControlMaster and ControlPath are specified to allow SSH connection re-use.

7

You shouldn't need to manually specify HostName as it will come from the command line.

Simply try:

Host *.domain  
  IdentityFile ~/.ssh/id_rsa  
  ProxyCommand ssh mygateway /usr/bin/nc %h 22
3
  • The problem with that approach is that the Hostname is quite generic (eg db1, www, mail2), whereas I want them prefixed with the project aswell, since I may need to ssh to a different machine called 'db2'. Hence the prefix in Host Jun 16, 2009 at 10:00
  • 2
    So you actually want to reconfigure your DNS. The simplest (but most cumbersome solution) is to modify your hosts file. You could on the other hand always add a local DNS server to your workstation with a .invalid domain and use the hostnames you prefer. Jun 16, 2009 at 10:09
  • +1 the previous. Create a subdomain for each project. DNS is there to make your life easier ;)
    – Dan Carley
    Jun 16, 2009 at 10:26
3

Ignore specifying overriding the hostname directly via the Hostname declaration and instead determine it at runtime. Do this by evaluating it as part of the ProxyCommand, using %h to reference it in the command (also use %p instead of hardcoding port as 22) i.e.

Host mygateway-*
   #Hostname ???WHAT GOES HERE????
   IdentityFile ~/.ssh/id_rsa
   ProxyCommand ssh mygateway nc $(echo %h|sed 's/^mygateway-//') %p

One could even have a more generic stanza, whereby you can specify any host without a - to just be treated as is, or as per another matching stanza(s), but have a generic - approach to specify any <gateway>-<target>:

Host *-*
   # Assume LHS of "-" is GW and RHS of "-" is target host
   IdentityFile ~/.ssh/id_rsa
   ProxyCommand ssh $(echo %h|cut -d - -f1) nc $(echo %h|cut -d - -f2-) %p

Additionally, newer versions of the SSH client support the [-W host:port] option to directly perform the same function as nc (netcat). As such, we can use the modified:

Host *-*
   # Assume LHS of "-" is GW and RHS of "-" is target host
   IdentityFile ~/.ssh/id_rsa
   ProxyCommand ssh -W $(echo %h|cut -d - -f2-):%p $(echo %h|cut -d - -f1)

Of course, if you did have a finite list of hosts, you could always do:

Host host1 host2 host3 hostN
   IdentityFile ~/.ssh/id_rsa
   ProxyCommand ssh mygateway nc %h %p

Hope this helps!

1
  • 1
    Note for anyone using this answer with newer ProxyJump directive, which is meant to be replacement for ProxyCommand (see this answer) - echo works in both ProxyJump and ProxyCommand, but sed/awk only works in ProxyCommand.
    – Bojan P.
    Nov 16, 2020 at 11:01
1

I had a similar problem and ended up writing a script that generated all the boilerplate for me. I no longer change ~/ssh/config, I change ~/ssh/config.in and rerun my script.

5
  • 1
    Care to share your script? I've thought of doing this, but it seems that a robust and generic solution might take a lot of work to get right. Even if your solution is not yet that, it would be useful to know what you think it gets right, and what you would do differently if you were to do it over.
    – iconoclast
    Aug 2, 2015 at 17:10
  • My thought was to have .ssh/config.d with a file for each template, where each template would generate one or more entries in the final ~/.ssh/config. There would also be a file with universal variables, but each template could have its own variables which would take precedence over globals, listed at the top. The ~/.ssh/config file could be generated on demand or on a schedule—it wouldn't matter—as long as you never made direct edits to it that you wanted to preserve.
    – iconoclast
    Aug 2, 2015 at 17:11
  • My script is totally undocumented and I don't think it would be comprehensible without documentation or examples, which I don't have time to create. Aug 2, 2015 at 17:29
  • Understandable. Any feedback on the approach I outlined would be appreciated, especially if I'm overlooking either some important need or use case, or else some big (or small) obstacles.
    – iconoclast
    Aug 2, 2015 at 17:35
  • 1
    I think that's a fine approach, probably a little less confusing than the approach I used. I read a number of Host declarations into memory, then a number of non-host declarations. The non-host declarations are applied to each Host in the current group until there's another Host. I also allow Hosts to be declared multiple times in the file, including using globbing. At the end I write out all of what I have been building in memory. Aug 2, 2015 at 17:48
0

It looks like there isn't any way to do this.

1
  • This can't be the correct answer. I see at least two other answers meeting your criteria. Aug 17, 2023 at 15:22
0

I had a client with the same setup and I used DSSH to solve my problem.
DSSH among other things allows you to transparently login to remote hosts via a gateway host.

Use cases

  • Collect configuration parameters from Cisco routers which require "ena" login
  • Log in to servers, which have PermitRootLogin disabled directly as root (by typing su - and password automatically), while preserving exit status
  • Add custom logic such as advanced logging
  • tunnel through several connections to get to target server
3
  • 7
    I'd rather not start using some random third party ssh client that uses java, for things that I can do in ~/.ssh/config. Jun 16, 2009 at 10:41
  • 2
    the link is dead
    – iconoclast
    Aug 2, 2015 at 17:13
  • The software source can be found on Github: github.com/digmia/dssh
    – Guest
    Dec 7, 2016 at 17:07

You must log in to answer this question.

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