OpenSSH
OpenSSH is a free implementation of Secure Shell. It is probably the most useful utility I know of. I have helped a great many people with SSH so I thought I would write down some of the more important topics as an easy reference for those people.
Contents
Key based authentication
The whole idea of SSH, apart from being able to connect to remote computers, is to be secure. So it should be no surprise that SSH supports many different security mechanisms to prevent unauthorized access. The most basic form of protection is the password, but since SSH provides much more secure methods than passwords you shouldn't be using passwords (by themsleves) with SSH. So how to use something better?
SSH relies on public-key cryptography to secure all of it's communications. You can either borrow the host computer's key to do this (which is how it works if you only use a password) or you can make your own personal key instead. The advantage to using your own key is that in order to gain access to the server you have to:
- use something you know (your password)
- use something you have (your key).
If someone were able to force you to tell them your password they would not be able to gain access to your remote computers unless they were also able to get access to your key. Also they cannot get access with your key unless they also know your password. It's double the security (more than that actually).
Creating a private/public key pair
There are three things to consider before making your private/public key pair:
- Do you want your key password protected or not? (You definitely want this unless you are on a completely private network)
- What encryption type do you want, RSA or DSA? (Typically you want RSA as there are some security issues with DSA)
- What size to make the key? The larger the better, but it makes communication (especially the initial connection) slower. 4096 or 8192 bits is a good balance of security/performance on modern hardware.
To create the key run:
ssh-keygen -b 8192 -t rsa
It will ask you where to save the file, choose the default (usually /home/username/.ssh/id_rsa). Next it will ask you for a password. Try to make it as complex and as tedious to type as possible (With key based authentication you only have to type your password at most once per day so it pays off to make it a complex one).
Distribute your public key
Your public key is stored by default in /home/username/.ssh/id_rsa.pub. This file should be distibuted to all the computers you wish to access. The contents of the file is a single line. Copy this line to a file on the destination server called .ssh/authorized_keys. If that file doesn't exist, create it. If it does exist, just put the line at the bottom of the file. You can create multiple keys, one for each computer you wish to connect to, but it's much easier to just use one key for all your accounts.
If you don't adminster the machine you need access to, you can also email or instant message your public key to the administrators of machines you need access to. Because the public key is only half of the private/public key pair, even if someone intercepts your public key, it's useless to them.
Your private key is in /home/username/.ssh/id_rsa (no .pub on the end). GUARD THIS FILE WITH YOUR LIFE. As long as you chose a strong password when you created the keypair, this file is relatively safe, but you still don't want to give anyone access to this file. If you suspect someone of stealing this file from you, remove your public key out of all the computers .ssh/authorized_keys files and create a new key.
Using your key
Once you have your key setup, when you log into remote machines it will favor your keyfile over your account password. You'll see something like the following:
ryan@insurgent:~$ ssh vorta Enter passphrase for key '/home/ryan/.ssh/id_rsa':
Instead of typing your account password, type in the password that you used to create your key.
Turning off password authentication
Once you're used to using keys instead of passwords it should make sense to turn off password based access into your machine. This has the small inconvenience that you'll need to keep your SSH keys with you wherever you go (USB keychains are good for this) but the added security benefit is tremendous. With password authentication turned on, I literally get thousands of probes from China, Italy, Brazil etc trying to hack into my box. With password authentication turned off, all of these probes stop dead in their tracks. Just modify one line in /etc/ssh/sshd_config:
PasswordAuthentication no
and restart the server:
sudo /etc/init.d/ssh restart
SSH-Agent
Unless you really like typing in your password everytime you connect, SSH-Agent is a real time saver. SSH-Agent acts as a memory for your key(s) password. Once you let SSH-Agent know your password, it decrypts your keyfile and keeps that decrypted version in memory for as long as you want or until you log out on your local machine. SSH-Agent is enabled on most distributions by default, so the only thing left for you to do is to type this command ONCE per session:
ryan@insurgent:~$ ssh-add Enter passphrase for /home/ryan/.ssh/id_rsa:
Type your key password at the prompt and from that point on SSH-Agent will remember your password (in reality just your decrypted key). Any computers that have your public key (in your .ssh/authorized_keys file on that machine) will let you in without you having to type your password.
Extra Functionality
SSH is great as a remote shell login, but there is so much more to it. Here are a few extra features:
Port forwarding
You may have heard of the word "tunnel" or VPN (virtual private network). SSH can fill both of these roles. Basically speaking, you can tunnel any sort of normal network traffic through SSH and gain in the security that SSH provides. You can turn an insecure networking application into secure one with no modification to that program!
Note: In the examples below I use ports like 8080 and 2525. You can choose whatever ports you want, but remember that unless you are root, you must choose ports that are greater than 1024.
Local Forward
A local forward allows you to access a service on a remote machine through an encrypted channel. For instance, say you want to run a private web server for yourself and a couple of friends that live around the world, but you don't want to make it available to the internet at large. You can use SSH to provide this service. The following example shows how you would provide access to a web server but really it will work with any TCP/IP based server.
Run a webserver application on port 80, but don't enable outside access, leave it firewalled.
- Make sure everyone that needs access to the webserver can ssh into the machine normally.
- Have each user that needs access run the following command:
ssh -L 8080:localhost:80 name_of_server
This will connect you to the machine as normal, but in addition you'll have access to the webserver for as long as you leave that connection open. Point your web browser to http://localhost:8080 and you should see the private webserver. Let's break down the command:
- The -L tells SSH you want to perform a local forward
The 8080 is the local TCP port you want to use for access
The localhost part is not your localhost but rather it's the remote machine's localhost. This is confusing at first but what it is doing is SSH is asking the remote machine to access the webserver on that remote machine residing on port 80. So, when doing a local forward, this field is the domain as seen by the remote host.
What if the server you want to access is on a private network, not accessible from the internet? If you have another machine on that local network that DOES have internet access you could use "ssh -L 8080:name_of_private_server:80 name_of_public_server" and gain access to the private server through the public server.
Remote Forward
A remote forward operates in the opposite direction that a local forward does. For instance, if you have a local webserver running on port 80 on your computer and you want to show someone else that server without letting the whole world see it, you can give that person access through SSH:
ssh -R 15000:localhost:80 remote_machine
After you have connected, tell the person on the other end that you have done so, and they will be able to access your server via a web browser by going to http://localhost:15000
Permenant Forwarding
If you do port forwarding to the same machines on a regular basis, you can configure SSH to perform the forwarding automatically everytime you connect. Edit (create it if nessecary) the file /home/username/.ssh/config and put in the following:
Host name_of_computer
Username remote_username
LocalForward localport remote_host:remote_port
RemoteForward remoteport local_host:local_port
For instance, if I wanted to access a private web server on my friends computer (asimov) running on port 80, and at the same time I wanted to give him access to my SMTP mail server (insurgent) running on port 25, I would make the following configuration file:
Host asimov
Username ryan
LocalForward 8080 asimov:80
RemoteForward 2525 insurgent:25
After I connect to asimov, My friend will be able to access my mail server at localhost port 2525 and I will be able to access his webserver at localhost port 8080.
True VPN
In the previous section I covered port forwarding, which is superb for allowing access to individual remote services. However, if you need access to a lot of services it can get tedious to set up port forwardings for every single one of them. Wouldn't it be nice if you could forward all the ports of a machine to your local box? It's a little bit more involved, but OpenSSH has a solution: tun based VPN.
The Universal TUN/TAP driver is a virtual point to point network device for the Linux (or FreeBSD or Solaris) kernel. The driver is probably already installed if you're running a preconfigured kernel, but if you've compiled your own be sure to enable it:
Device Drivers-->
Network Device support -->
<M> Universal TUN/TAP device driver support
The machine you want to connect to has to have the following enabled in their /etc/ssh/sshd_config:
PermitTunnel yes PermitRootLogin yes
To establish the virtual link you connect this way:
ssh -w 0:0 remote_machine
The 0:0 part is telling which tun device to use on both the local side as well as the remote side. You're probably not using a tun device yet so just use 0 for both. You can also specify "any:any" and it will use whatever device number is available.
If you run 'ifconfig tun0' now on your local as well as your remote box you should see something like the following:
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00
POINTOPOINT NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
You'll need to give both machines IP addresses for the new devices. If the remote network's subnet is unique (ie you're not using the same one locally) then use that one. Otherwise, you'll have to come up with a new subnet. You're probably not using 10.10.0.0, so we'll use 10.10.0.1 for the remote machine and 10.10.0.2 for your local machine:
On the remote side:
ifconfig tun0 10.10.0.1 pointopoint 10.10.0.2
On your local machine:
ifconfig tun0 10.10.0.2 pointopoint 10.10.0.1
And you should now be able to ping the remote box and get a response:
# ping 10.10.0.1 PING 10.10.0.1 (10.10.0.1) 56(84) bytes of data. 64 bytes from 10.10.0.1: icmp_seq=1 ttl=64 time=74.8 ms 64 bytes from 10.10.0.1: icmp_seq=2 ttl=64 time=73.6 ms 64 bytes from 10.10.0.1: icmp_seq=3 ttl=64 time=74.3 ms
That's all you need to do to connect to that one machine. However, if there are multiple machines on the remote end that you want to connect to through the VPN there are still a few more steps to perform.
Setup a route on the local machine:
route add -net 10.10.0.0 netmask 255.255.255.0 gw 10.10.0.1 tun0
Setup an Arp entry on the remote machine:
arp -sD 10.10.0.2 eth0 pub
Note: To access additional machines on the remote network, they need to have IP addresses in the same network that you set up the route for (in the example 10.10.0.0). That's the reason why it's nice if you can have two unique subnets on the local and remote side.
I've written a python tool to help set this up if you're doing this a lot. Read the instructions in the top of the file for more information.
SOCKS proxy
I have to admit, this is one my favorite things about SSH. SSH supports protocol specific dynamic forwarding. That's a fancy name for the fact that SSH provides for plugins. The only plugin that has yet been written (that I know of) is a SOCKS server. SOCKS is proxy server protocol. Proxies allow you to access websites (and a few other types of servers too) through another server. Once a proxy has been configured, the proxy will fetch site content on your behalf and then deliver it to you. If the proxy is configured to be an anonymous proxy, then the end server will never even know that you accessed the server, just that the proxy did.
You can easily setup an anonymous proxy using SSH. Just connect to your server like so:
ssh -D 8080 your_server
Then configure your web browser for a SOCKS based proxy (either version 4 or 5) on port 8080. To test that it works, go to http://www.whatismyip.com. You will see the IP address of the proxy machine and not your own.
Note: Although web servers will no longer be able to identify you based on your IP address, be warned that even with this type of proxy your webbrowser can still send out other types of revealing information.
Persistent connections
Do your SSH connections die if you leave them idle for only a few minutes? Most likely, this is not the fault of SSH but rather a dumb network router that kills any connection that isn't used after a while. Don't let it get you down, SSH has a solution. Just put this in your .ssh/config:
Host * Protocol 2 ServerAliveInterval 120
This only works for SSH servers that support protocol 2 (these days, most do). The ServerAliveInterval option will ping the server sending a small amount of information every two minutes. This should keep your connection alive indefinitely. If you get diced before two minutes (man I pity your net connection
) you can change the timeout value to any number of seconds you want.
Connection sharing
When you make a connection to a remote machine it takes a while to negotiate keys etc. Throughout any given day, I probably establish and disconnect from the same machines about 100 times each day. If you add up all the time spent just negotiating keys, it's probably substantial. SSH has a solution for this scenario that lets you re-utilize existing connections when you make a subsequent connection to the same machine. It's called a master connection.
To make use of master connections add the following to your .ssh/config:
Host *
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p
Now whenever you make a connection to a machine that you already are connected to, it will reutilize that same connection. Try it out, the secondary connection should only take a fraction of the time it normally takes to connect.
One thing to be watchful of is that the first connection you make is the master connection. If you make a second connection and then decide later on to close the first connection, it'll close the second connection too. Fortunately, if the master connection is a normal login session, and you quit the session, it will hang until the second connection closes too.
Like I said before, I make multiple connections to the same machines all the time, I can't honestly be expected to remember which connection is the master connection, and I don't want to accidentally close it while I am doing something important in a secondary connection. To prevent this I make sure to start a terminal-less connection in the background before I make any other connection into the machine I want to connect to:
ssh computer_name -N -Y &
Note: Only put the -Y if you want X11 forwarding enabled.
This starts a terminal-less connection in the background. You won't see any output, but give it a few seconds to make sure it connects before closing the window that you issued that command in. Now open up a new window and connect in.. it should be fast to connect and when you exit that session you'll see the message:
Connection to master closed.
If you see that, you'll know it's working.
User comments
Click here to leave your comments
Leave your comments below
Have you ever encountered the problem that, when using a master connection, children connecting to the master cannot create channels for port forwarding but just get interactive shells? I looked into the OpenSSH code for an hour now but haven't found any hint that this is even implemented... Any idea?
