166

I want to access a computer, say machine A which is based in my university's network. However, this computer is only accessible via the internal network of the university, so I can not use SSH to this computer from home directly.

Here's what I do now:

  1. Log in to a different university machine, say machine B

    (This machine B is accessible via SSH from my home computer.)

  2. Use SSH on B to connect to A.

Is there a way to do that faster? Using only one ssh command.

gertvdijk
  • 69,427
nikosdi
  • 1,852

8 Answers8

136

Using ProxyCommand in your SSH config.

Create an SSH configuration file in your home directory (unless you want to make this system-wide), ~/.ssh/config:

Host unibroker          # Machine B definition (the broker)
Hostname 12.34.45.56    # Change this IP address to the address of the broker
User myusername         # Change this default user accordingly 
                        # (`user@unibroker` can overwrite it)

Host internalmachine    # Machine A definition (the target host)
ProxyCommand ssh -q unibroker nc hostname.or.IP.address.internal.machine 22

Now you can reach Machine A directly using

ssh user@internalmachine

Also note that now you have a single SSH host target name for it, you can use this in other applications as well. E.g.:

  • SCP to copy files.

    scp somefile user@internalmachine:~/
    
  • In your GUI applications:

    use sftp://user@internalmachine/ as the location to browse on the machine.

    KDE-based (Dolphin): use fish://user@internalmachine/

Notes

Change hostname.or.IP.address.internal.machine and the port (22) to the machine you like to reach as if you would from the unibroker machine.

Depending on netcat versions on the unibroker host, the -q0 option must be omitted. Regarding authentication; you're basically setting up two SSH connections from your workstation. This means both the unibroker host and the internalmachine host are verified/authenticated against one after another (for both keypair/password and host key verification).

Explanation

This approach of the use of ProxyCommand and 'netcat' is just one way to do it. I like this, because my SSH client talks directly to the target machine so that I can verify the host key from my client and I can use my public key authentication without using another key on the broker.

Each Host defines the start of a new host section. Hostname is the target hostname or IP address of that host. User is what you would provide as the user part in ssh user@hostname.

ProxyCommand will be used as the pipe to the target machine. By using SSH to the first machine and directly setting up a simple 'netcat' (nc) to the target from there, this is basically just a plaintext forward to the internal machine from the broker between those. The -q options are to silence any output (just a personal preference).

Make sure you have netcat installed on the broker (usually available by default on Ubuntu) - either netcat-openbsd Install netcat-openbsd or netcat-traditional Install netcat-traditional.

Note that you're still using SSH with encryption twice here. While the netcat channel is plaintext, your SSH client on your PC will set up another encrypted channel with the final target machine.

gertvdijk
  • 69,427
91

You could use the -J command line option:

ssh -J user@machineB user@machineA

From man ssh:

-J [user@]host[:port]
     Connect to the target host by first making a ssh connection to
     the jump host and then establishing a TCP forwarding to the
     ultimate destination from there.  Multiple jump hops may be
     specified separated by comma characters.  This is a shortcut to
     specify a ProxyJump configuration directive.

It was introduced in OpenSSH version 7.3 (released in August 2016). It is available in Ubuntu 16.10 and later.

muru
  • 207,228
69

Hop in one go

An obvious alternative to the ProxyCommand approach I provided in my other answer would be 'hopping' directly to the target machine:

ssh -t user@machineB ssh user@machineA

Note the -t on the first ssh command. Without it, it will fail:

Pseudo-terminal will not be allocated because stdin is not a terminal.
ssh_askpass: exec(/usr/bin/ssh-askpass): No such file or directory
Permission denied, please try again.
[...]

It will force a real TTY to be allocated

Downside of this is that now all configuration, verification and authentication takes place at Machine B, which I really don't like in my situation for security reasons. I like my keypair on my own PC and authenticate and verify the final target machine from my own PC. Additionally, you can only use the interactive shell for SSH, so this won't deal with other tools like SCP or using your GUI file manager.

For all the aforementioned reasons I strongly recommend the ProxyCommand approach, but for a quick connect this works fine.

gertvdijk
  • 69,427
19

Try using

Host <visible hostname alias>
        Controlmaster auto
        User <user>
        hostname <visible hostname>
        port <port>
        IdentityFile ~/.ssh/<id file>

Host <private LAN hostname alias>
     ProxyCommand ssh -q -W <private LAN hostname>:<private LAN port> <visible hostname alias>

in your ~/.ssh/config and do it all in one shot with keys only residing on your computer.

ElefantPhace
  • 3,281
SSH Help
  • 191
9

machineA is the final target. machineB is the broker.

We want to do home -- machineB -- machineA easily via ssh.

In OpenSSH version 7.3 (released in August 2016) or later, you can do one of the following:

.ssh/config approach:

Add the following lines to your .ssh/config:

Host machineB
    Hostname 12.12.12.12           # IP of machineB (w.r.t. home)
    User usernameB                 # username on machineB

Host machineA Hostname 34.34.34.34 # IP of machineA (w.r.t. machineB) ProxyJump usernameB@machineB # PROXY MAGIC! User usernameA # username on machineA

Then type ssh machineA. Also compatible with scp. You can augment the above config to also force specific key usage via https://unix.stackexchange.com/a/494485.

-J flag option:

Just type ssh -J usernameB@machineB usernameA@machineA.

Final notes

This answer combines gertvdijk and Erik Sjölund answers with the guide at https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Proxies_and_Jump_Hosts#cite_note-ProxyJump-1.

2

This is a very helpful suggestion. After messing about for hours, I found this note, & confirmed this works exactly as documented. To connect thru MachineA to MachineB, from remote machineC:

eg: [xuser@machineC ~] ssh -t MachineA ssh MachineB

The "-t" is critical, ssh fails if it is not present. You will get prompted twice, first for password on MachineA, then second time for MachineB. Also, note that this assumes you have user "xuser" defined on all three machines. If not, just use the ssh syntax: "yuser@MachineA ...". Also note that you can use dotted quad raw IP#s, if you want to. This is useful if you are linking thru a private local net which is using IPs not exposed to the world - ie. not in your local host file, or any DNS. To get a file from MachineB, to remote machineC, you can scp from MachineB to MachineA, then from MachineA to remote machineC. (Eg. the remote machineC can ping MachineA, but not MachineB.) Caveat: I tested with Fedora and WindowsXP, MachineA is an XP-box running ICS (Internet Connection Sharing), while MachineB and remote machineC are Fedora-Linux boxes. This suggestion solved a key problem for me - ie. restricted, monitored remote access to my remote site lan. Note also, when you "logout" from MachineB, you should see two "Connection to xxx.xxx.xxx.xxx closed." messages.

Mcl
  • 31
1

You mean you need several jumpers:)

Recently,I met this problem with jumper1 jumper2 and my final machine,as for my sol

local script:

#!/bin/bash
sshpass -p jumper1Passwd ssh -t jumper1@jumper1IP ./Y00.sh

then on the 1st jumper (which is my router), I placed a script named Y00.sh:

ssh -tt jumper2@jumper2 -i ~/.ssh/id_rsa sshpass -p finalPassWord ssh -tt final@final

You can replace these with your IP and passwords, good luck!

Y00
  • 121
1

ProxyCommand is a clean solution for a case when you allow shell access in both the systems. We wanted to give remote users access to an internal machine (A) through a broker (B), but without allowing the user a shell access to B for improved security. This worked:

Replace the login shell

Replace the login shell (use chsh) for extuser on the broker with the following script (stored in a file):

#!/bin/sh   # this is essential to avoid Exec format error
ssh internaluser@A

Provided no password login has been set up in extuser@B for the remote user and in internaluser@A for extuser@B, then executing the following command will directly take the remote user to A

ssh extuser@B

Tip: Create the necessary no password login authorized_keys setup in extuser@B before changing to the custom login shell. After the change, since this account is inaccessible to anybody through a shell, only a sudoer@B can make changes to the file authorized_keys by editing it directly.

sudo vi ~extuser/.ssh/authorized_keys
sudo touch ~extuser/.hushlogin

The last line is to supress the login banner display from B, so the remote user has a transparent access to A.

Sunthar
  • 111