In the previous six instalments we looked in detail at how TCP/IP networks tick. In these instalments we worked our way up from the bottom of the four-layer TCP/IP network model to the top, finishing off with a look at two protocols in the Application Layer at the top of the stack. Those two protocols, DHCP & DNS exist in the top layer, but are different to most other top layer protools in that they can reasonably be described as forming part of the infrastructure of the internet. The email and web protocols may site within the same network layer, but they still rely on DNS to function.

For the remainder of the networking section in this series we’ve moving away from infrastructure-like protocols, and focusing on the user-facing Application Layer protocols. The first of these we’ll be looking at is the Secure Shell, or SSH. This protocol is one of the absolute work-horses of the internet, and a vital tool for all Linux, Unix, and OS X sysadmins.

At it’s simplest level SSH allows you to execute commands on a remote computer, but because it was designed around the concept of a secure tunnel between two systems, SSH has expanded to allow all kinds of advanced features. The least-generous description of this could be that SSH has become a kind of sysadmins fridgeoven. But I don’t buy that, I prefer the alternative interpretation – it simply makes sense not to re-invent the wheel, and to allow as much information as possible to flow throw the secure connection SSH provides between the two end-points.

Today we’re just going to start with the basics, but in future instalments we’ll move on to the more advanced features.

Listen Along: Taming the Terminal Podcast Episode 29

Introducing SSH

The SSH protocol allows one computer running an SSH client to securely connect to another running an SSH server. In other words, SSH is a client-server protocol. The computer initiating the connection is referred to as the client, and the computer being connected to as the server.

SSH operates over TCP, and while SSH servers can listen on any TCP port, by default SSH servers listen on port 22. As its name suggests, security is integral to the Secure Shell, and all SSH traffic is encrypted by default.

SSH is often described as the secure replacement for the older insecure Telnet protocol. It’s certainly true that SSH provides a secure replacement for Telnet, but it’s much more than that, providing additional features Telnet never did.

The first version of SSH dates back to 1995, which sounds old in IT terms, but bear in mind that Telnet dates back to 1968! The first version of the SSH protocol had some security shortcomings, so a new version of the protocol, SSH 2, was released in 2006, and this is what we use today.

Some Preliminaries

To play along with this segment you’ll need two computers with SSH installed the SSH service enabled on at least one of those computers, and TCP/IP network connectivity between them. The two computers can be a mix of OS X, Linux, and Unix.

OS X comes with SSH installed by default, but remote logins over SSH are disabled by default, i.e. the SSH service is not running by default. This means that a Mac can always act as an SSH client, but can only act as an SSH server it has been configured to do so.

To enable the SSH service on a Mac, open the Sharing preference pane and enable the ‘Remote Login’ option. This interface will allow you to limit SSH access to just some of the user accounts on your Mac, or to allow all users connect to your Mac over SSH.

OS X Enable SSH Service

Linux machines usually have SSH installed and enabled by default. Instructions for installation and activation vary from one Linux distribution to the next, so I’ll have to leave it as an exercise for the reader to find instructions for specific Linux distros as needed.

With SSH installed and enabled on two computers, pick one to be the client, and one the server, i.e. one to connect from, and one to connect to. You’ll need to know the IP address (or DNS name) of the one you choose to act as the server. In the examples below I’ll be connecting to my file server, a Linux server on my LAN with the private IP address 192.168.10.20.

Using SSH to Run a Command on Another Computer

The simplest thing you can do with SSH is use it to execute a single command on a remote computer. This can be done using the SSH command in the following way:

For example, the following command returns a list of all running processes on my file server:

Note that when you are asked for a password, you should enter the password for the remote user, not your password on the local computer.

Note that if your username is the same on the machine you are SSHing from and the one your are SSHing to, you can leave out the username, so since I log in to both computers as the user bart, I could simplify the above command to:

SSH Security

If you’ve never used SSH before on a computer, the chances are very high that when you tried to play along with the previous section you encountered a strange notification that may have looked like an error, asking you to enter yes or no. It probably looked something like:

Firstly, it’s safe to hit yes if you are connecting to a server for the first time.

It’s still important that we understand what the message meant, and why it’s OK to say yes on your first connection to a server.

When SSHing to a remote computer, your computer tries its best to authenticate the remote computer in order to protect you from man-in-the-middle attacks.

Web servers solve this problem using Certificates signed by Certificate Authorities and validated by trust anchors installed in our computers. If SSH had been designed the same way, we would need to apply for a certificate for each computer we wanted to SSH to. This would create a major barrier to the adoption of SSH, so thankfully the SSH protocol solves the man-in-the-middle problem in a very different way. The solution SSH has chosen works without the need for any central authorities like the CAs that underpin security on the web, but the price we pay for that convenience is that we have to deal with prompts like the one above. Because there are no central authorities to rely on, the end user has to take responsibility for their own security.

When the SSH service is installed on a computer, a random asymmetric key-pair is generated. One half of that pair is designated the server’s private key, and the other the server’s public key.

The first time a client connects to a server via SSH, the client saves the server’s public key in a special file, along with the server’s IP address and DNS name (if the client connected by DNS name rather than IP).

When the client re-connects with a server on an IP address or at a DNS name it has saved details for, it uses the saved public key to validate the server. A man-in-the-middle will not have the server’s private key, and so will not be able to pass the client’s security check.

Once you understand this process, the message you get when you first connect to a server makes more sense. You are being asked if you want to trust a server for which there is no saved public key, and hence who’s identity cannot be confirmed. When you say yes a second message will pop up, telling you the key has been saved, it will look something like:

On future connections to the server you should not see any more messages, because they key will be saved, and the server should pass validation by the client.

The database of public keys is stored in a plain text file, ~/.ssh/known_hosts, one entry per line. You can view the content of this file with the command:

If for some reason the server validation fails, you’ll see an error message something like:

This could mean there is a man-in-the-middle attack in progress. But before you assume the worst, remember that there are legitimate reasons a server’s public and private keys could change.

Firstly, if you re-install the OS on a computer, a new set of SSH keys will be generated, so the server will legitimately change identity.

Secondly, if you regularly connect to multiple servers on a network that has dynamically assigned IPs, then sooner or later you’ll get this error because you once saw one computer at this IP, and now a different one has randomly been assigned it. It’s largely to avoid problems like this that I like to set static DHCP leases for all my computers on my home network.

Once you have satisfied yourself that the warning message is innocent, the solution is to edit ~/.ssh/known_hosts with your favourite text editor and remove the line containing the old key. Conveniently, the line number is given in the error message, it’s the number after the :, so in the example above, the offending key is on line 14, so that’s the line I need to delete.

Update: an alternative to manually editing the file is to use the ssh-keygen command to delete the offending key for you. You do this using the -R flag (R for remove) to pass the IP or hostname who’s key you need to remove:

Thanks to Twitter user @adrianluff for the tip!

Remote Command Shells

If you need to run more than one command on a remote computer, it’s more convenient to get a full remote command shell, which you can easily do by leaving off the final argument (the command to execute remotely). So, the general form would be:

Again, the username can be omitted if it’s the same on both computers, so for me I can get a remote shell on my file server with:

Once you ssh to a remote computer in this way you get a full remote shell, so it really is as if you were typing in a terminal window on that computer.

As mentioned previously, SSH defaults to using TCP port 22, but, an SSH service can in theory be run on any port number. Some hosting providers add a little extra security by running SSH on a non-standard port. This will not protect from targeted attacks, but it will stop automated scans of the internet from finding your SSH server. If the SSH server you are connecting to is not running on port 22, you need to use the -p flag to specify the port number, e.g. if I were to move the SSH service on my file store to port 2222 the two example commands above would become:

Conclusions

In this instalment we’ve covered the basics of SSH. We can now use it to execute single commands on a remote computer, and to get an interactive command shell on a remote computer. This is enough to replace the old insecure Telnet protocol with a secure alternative, and, enough to get by in most scenarios.

while what we’ve learned in this instalment is usually sufficient, there are advantages to learning about some of SSH’s more advanced features, which is what we’ll be doing in the next instalment.