How to configure a shortcut for an SSH connection through a SSH tunnel

My company production servers (FOO, BAR...) are located behind two gateway servers (A, B). In order to connect to server FOO, I have to open a ssh connection with server A or B with my username JOHNDOE, then from A (or B) I can access any production server opening a SSH connection with a standard username (let's call it WEBBY).

So, each time I have to do something like:

ssh [email protected]
...
ssh [email protected]
...
# now I can work on the server

As you can imagine, this is a hassle when I need to use scp or if I need to quickly open multiple connections.

I have configured a ssh key and also I'm using .ssh/config for some shortcuts.

I was wondering if I can create some kind of ssh configuration in order to type

ssh foo

and let SSH open/forward all the connections for me. Is it possible?

Edit

womble's answer is exactly what I was looking for but it seems right now I can't use netcat because it's not installed on the gateway server.

weppos:~ weppos$ ssh foo -vv
OpenSSH_5.1p1, OpenSSL 0.9.7l 28 Sep 2006
debug1: Reading configuration data /Users/xyz/.ssh/config
debug1: Applying options for foo
debug1: Reading configuration data /etc/ssh_config
debug2: ssh_connect: needpriv 0
debug1: Executing proxy command: exec ssh a nc -w 3 foo 22
debug1: permanently_drop_suid: 501
debug1: identity file /Users/xyz/.ssh/identity type -1
debug2: key_type_from_name: unknown key type '-----BEGIN'
debug2: key_type_from_name: unknown key type 'Proc-Type:'
debug2: key_type_from_name: unknown key type 'DEK-Info:'
debug2: key_type_from_name: unknown key type '-----END'
debug1: identity file /Users/xyz/.ssh/id_rsa type 1
debug2: key_type_from_name: unknown key type '-----BEGIN'
debug2: key_type_from_name: unknown key type 'Proc-Type:'
debug2: key_type_from_name: unknown key type 'DEK-Info:'
debug2: key_type_from_name: unknown key type '-----END'
debug1: identity file /Users/xyz/.ssh/id_dsa type 2
bash: nc: command not found
ssh_exchange_identification: Connection closed by remote host

Answers 8

  • As a more concrete version of Kyle's answer, what you want to put in your ~/.ssh/config file is:

    host foo
      User webby
      ProxyCommand ssh a nc -w 3 %h %p
    
    host a
      User johndoe
    

    Then, when you run "ssh foo", SSH will attempt to SSH to [email protected], run netcat (nc), then perform an SSH to [email protected] through this tunnel. Magic!

    Of course, in order to do this, netcat needs to be installed on the gateway server; this package is available for every major distribution and OS.


  • You can use the ProxyCommand directive in your ~/.ssh/config file, for example to use netcat as the relay:

    host server2
        ProxyCommand ssh server1 nc server2 22
    

    The you would just use 'ssh server2'. The man page information for this directive is found in 'man ssh_config'


  • I prefer a different approach that maintains a pre-authenticated tunnel to the gateway server. In ~/.ssh/config:

    Host a
        ControlMaster auto
        ControlPath ~/.ssh/control-master/%[email protected]%h:%p
    

    Then in .bashrc:

    s () {
            if ( ssh -O check a 2>&1 > /dev/null 2>&1 )
            then
                    ssh -t a ssh $1
            else
                    if [[ -S ~/.ssh/control-master/[email protected]:22 ]]
                    then
                            echo "Deleting stale socket..."
                            rm ~/.ssh/control-master/[email protected]:22
                    fi
                    echo "Opening master session..."
                    if ssh -Nf a
                    then
                             ssh -t a ssh $1
                    fi
            fi
     }
    

    So to connect to foo:

    s foo
    

    The first time you connect it will authenticate you against "a" and open a persistent, backgrounded ssh tunnel. Subsequent calls to "s" will open almost instantaneously through the pre-authed tunnel.

    Works great.


  • This type of functionality exists in newer versions of OpenSSH and can be used by doing

    ssh -W server2 server1
    

    Where server2 is your intended destination and server1 is your proxy host. You can make this easier by using the ProxyCommand option in your ssh config, something like:

    host = *.example.com
    user = packs
    port = 22
    ProxyCommand ssh -W %h:%p server1
    

  • When netcat is not available on the proxy, try this trick:

    host foo
      User webby      
      ProxyCommand ssh a 'exec 3<>/dev/tcp/foo/22; cat <&3 & cat >&3;kill $!'
    
    host a
      User johndoe
    

    Then you should be able to ssh foo.

    Also, if you have a recent version of ssh on a (i.e., with the -W command for forwarding standard input and output), you may be able to use:

    host foo
      User webby
      ProxyCommand ssh -W foo:%p a
    
    host a
      User johndoe
    

    Finally, just because I found it cool (and not because it will work in your particular case, due to username differences), a friend's blog post points out how to make this kind of thing dynamic and recursively chain SSH proxies (along with some things that don't work well):

    host */*
      ProxyCommand ssh ${$(dirname %h)/\%%/@} nc ${$(basename %h)#*%%} %p
    

    And then ssh machine1/machine2 should give you a shell on machine2, tunneled through machine1.

    I wonder if using custom sed commands instead of dirname and basename might not solve the problem with different user names?



  • Since OpenSSH 7.3 (2016-08-01) the ProxyJump option and corresponding -J command-line flag have been available to allow more simple indirection through a one or more SSH bastions or "jump hosts".

    That removes the dependancy on the external nc command as found in Womble's solution.

    ssh -J [email protected] [email protected] 
    

    will establish an SSH connection from your workstation to the gateway server a as user johndoe and tunnel the SSH session to host foo for user Webby over that.

    To simplify that create host definitions for both in your ~/.ssh/config and the you can simply execute ssh foo

    Host a
        User johndoe
    
    Host foo
        User Webby 
        ProxyJump a
    

  • weppos:~ weppos$ ssh foo -vv
    [..]
    bash: nc: command not found
    

    Netcat isn't installed on a. When you run ssh host "command arg", command is executed on host, not on your local machine.


Related Questions