About keys, tunneling, and more
Generating a key
- Install SSH
- Create key pairs:
    $ ssh-keygen -t dsa -b 4096 -C "" -N ""
- By default, the files named id_dsa.pubandid_dsaare created, the later one is the private key
- Copy the public key to the remote server as ~/.ssh/authorized_keys2(for SSHv2, if for SSHv1, it isauthorized_keys)
- Please make sure that the directory ~/.sshand your home directory is in mode 0755 (i.e. only writable by the owner) and owned by the home owner
Using SSH agent
- Just a command, then it will spawn a shell for you
    $ ssh-agent /bin/bash -c 'ssh-add < /dev/null && /bin/bash'
- In the spawned shell, do your work and you will get passed on SSH without passphase
Tunneling
Assume the network looks like this:
[192.168.0.0/24] -- [MachineA]--[internet]--[MachineB]--[172.16.0.0/24]
The game is as follows:
User at MachineA accessing 172.16.0.1
A user using MachineA want to connect to 172.16.0.1 directly. As the Internet
would not route for such IP, we set up a tunnel between MachineA and MachineB
for that. The result is, SSH listen on port 3210 of MachineA. For whatever
connection established to that port, it is tunneled over the Internet and, from
MachineB, forwarded to 172.16.0.1:4321
This is called local binding:
MachineA$ ssh -L 3210:172.16.0.1:4321 MachineB
then, MachineA’s 127.0.0.1:3210 is listened. Users on MachineA can connect to
127.0.0.1:3210 to mean to connect to 172.16.0.1:4321
If, on MachineA, 0.0.0.0:3210 shall be listened instead of 127.0.0.1:3210, use option -g:
MachineA$ ssh -g -L 3210:172.16.0.1:4321 MachineB
User at MachineB allows users at MachineA accessing 172.16.0.1
Same problem, but this time, a user at MachineB creates the tunnel instead of a
user at MachineA:
MachineB$ ssh -R 3210:172.16.0.1:4321 MachineA
This is the remote binding. Like the case above, 127.0.0.1:3210 is listened on
MachineA. And also likewise, use option -g to listen on 0.0.0.0:3210 instead.
Creating a SOCKS server
The local binding or remote binding creates an explicit tunnel for a specific
IP:port pair. To make the tunnel generally usable for all IP:port instead of
just one, we have to use a proxy server.
SSH supports SOCKS4 and SOCKS5. It is similar to local binding except no destination IP and port number needed:
MachineA$ ssh -D 3210 MachineB
This command creates a SOCKS server at 127.0.0.1:3210 at MachineA. A client
shall speak SOCKS protocol to this port to request a connection to some port at
a machine in 172.16.0.0/24. Such connection will then delivered over the SSH to
MachineB, i.e. encrypted. MachineB will create such connection on behalf of the
client.
Multihop SSH tunneling
In SSH, there is a feature named ProxyCommand. What this means is that, when you want to connect to a host, instead of directly setting up a socket to that host, you do it over another command. A common use is the following:
localhost <--> mediate1 <--> mediate2 <--> remotehost
Then you can do a SSH login from losthost to remotehost by using ProxyCommand
constructs. A convenient way is to set up the following in ~/.ssh/config in
localhost (another way is to use -oproxycommand in command line)
Host remotehost
  user remotelogin
  port 22
  hostname remotehost.domain
  ProxyCommand ssh mediate2 nc %h %p
Host mediate2
  user mediate2login
  port 22
  hostname mediate2.domain
  ProxyCommand ssh mediate1 nc %h %p
Host mediate1
  user mediate1login
  port 22
  hostname mediate1.domain
Afterwards, in localhost, we can login to remotehost using account remotelogin
by simply invoking:
$ ssh remotehost
New in OpenSSH 5.4: Instead of using netcat externally, we can use -W option to
do the same thing, now the ProxyCommand line becomes
ProxyCommand ssh -W %h:%p mediate2
Reference
- Ed Cashin’s intriguing papers page
- “HOWTO: set up ssh keys” by Paul Keck
- OpenSSH key management, Parts 1-3, by Daniel Robbins, IBM developerWorks article