Remote login and file transfer with OpenSSH

From WikiGagneLague
Jump to: navigation, search


Contents

Introduction

OpenSSH (used in GNU/Linux and other operating systems) is a port of OpenBSD's free SSH. SSH (which stands for Secure SHell) is a protocol for remote login and file transfer. Using an SSH client, you can open a session on a remote computer running an SSH server as though you were sitting in front of a terminal (screen, keyboard, mouse...) plugged into the remote host. The session can be command-line-based or graphical (using an X11 server instance on the local machine to display the graphical session running on the remote host). Command-line sessions can be run in the Linux console or inside a terminal program running in a graphical session. You can also start remote graphical applications that will be displayed by the currently running X11 server on the local machine. SSH encrypts all transmitted data, which means your connexions with remote servers cannot be spied upon; this makes SSH particularly well-suited for communicating over insecure networks such as the Internet.

OpenSSH also allows you to transfer files between two computers using SFTP (Secure File Transfer Protocol). Files can be transfered to and from a local computer and a remote machine, or between two distant computers. Many applications can open and save remote files transparently using SFTP, which allows you to work with remote files as though they were located on your computer. File managers allow you to browse and modify remote directories and files graphically and transparently. The SHFS (secure SHell FileSystem) module for the Linux kernel goes a step further and allows you to mount remote directories on a local computer. You can then work on the contained files as though they were on your computer, using any program.

This guide presents the basics of remote logging and file transfer, including the mounting of remote filesystems. It also touches the topics of client configuration and private key identification. The section on SSH tunnelling shows how to take advantage of SSH to encrypt connexions that use other (potentially insecure) protocols and to forward ports to access machines located behind a firewall. A final section shows how to setup an SSH server, and suggests modifications to the default OpenSSH configuration that improve security. Whilst this guide is written for Gentoo Linux users, it should be fairly easy to adapt the instructions to other operating systems.

Remote login

OpenSSH is a basic component of any Linux operating system, so it is certainly already installed on your Gentoo Linux system. To log into a remote computer, use the ssh (secure shell) program, specifying your user name on the remote system and its hostname or IP address:

$ ssh alice@wonderland.net
$ ssh alice@133.250.12.18

Once the connection is established, the remote host will ask for your password to open a remote session. You can then use your shell as usual. The connection will be closed when you exit your shell (usually by typing Ctrl+D or exit).

If you use the same username on both the local and distant machines, you need not specify it on the command line. For instance, if you were logged into the alice user account, the above commands could be simplified into:

$ ssh wonderland.net
$ ssh 133.250.12.18

Usually, SSH servers listen for connections on port 22. By default, the SSH client tries to connect on this port. If you need to connect to a server on a different port, use the -p option:

$ ssh -p 2222 dodo@wonderland.net

Sometimes, you wish to execute a single command on a remote host and then immediately close the connection. To do this, just append the command to execute to the command line:

$ ssh wonderland.net hostname -i

This will connect to the remote host, execute the command hostname -i, then close the connection.

If you wish to regain control of your (local) terminal while executing a lenghty command on a remote host, you can use the -f option. The SSH client will then put itself in the background immediately after authentication. The following command would execute updatedb remotely, and keep control of the terminal where the command was typed:

$ ssh -f wonderland.net updatedb 

X forwarding

If you try to launch a graphical application from a remote shell opened using one of the above commands, you will encounter an error such as Cannot connect to X server. This is because the X application (X client) executed in the remote session is not aware of your local graphical display (X server). The application therefore has no idea where it should display its window(s). To use remote grahical applications, you must instruct the remote host to use your local X server as the display. This is known as X forwarding. When passing the -X option to ssh, the necessary setup will be done automatically on the remote host so that graphical applications are displayed locally:

$ ssh -X eucaryote.net
$ xclock

If it is still opened at that time, the X application will be terminated when you close your session. If you only wish to launch a remote graphical application without keeping an opened shell, you should use the -f option and specify the application on the command line. As explained above, this will put the SSH client in the background after authentication:

$ ssh -Xf eucaryote.net xclock

Be aware that not all SSH servers allow X forwarding, as it is a potential security risk. In its default configuration, the OpenSSH server disallows X forwarding.

Remote graphical sessions with XDMCP

XDMCP (X Display Manager Control Protocol) provides a way of executing a graphical session on a remote computer and to control it from a terminal on a local machine. This differs from X forwarding (described above), in which a single graphical application is run remotely and displayed locally. XDMCP sessions can (and usually should) be tunnelled through SSH connexions to secure them. To learn about setting up XDMCP and securing it via SSH, I suggest reading the Linux XDMCP HOWTO.

File transfer

To copy files between two computers using OpenSSH, use the scp (secure copy) program. As with the standard cp command, general usage is:

$ scp source destination

For instance, the following command would first copy the local file 1btl.pdb to the remote host eucaryote.net using the ribosome user account:

$ scp 1btl.pdb ribosome@eucaryote.net:

The ":" character is mandatory; it is used by scp to determine whether the argument refers to a local or remote path. In the above command, file 1btl.pdb would be copied to the user's home directory on the remote host (for instance /home/ribosome/1btl.pdb). You can specify a subdirectory or filename in your home directory or an absolute path, as shown in the following examples:

$ scp 1btl.pdb ribosome@eucaryote.net:structures/
$ scp 1btl.pdb ribosome@eucaryote.net:structures/1btl-edited.pdb
$ scp 1btl.pdb ribosome@eucaryote.net:/home/shared/
$ scp 1btl.pdb ribosome@eucaryote.net:/home/shared/1btl-edited.pdb

As with the ssh command, the user account need not be mentioned if it is the same on both hosts. For example, the first command in this section could be simplified into:

$ scp 1btl.pdb eucaryote.net:

Files names containing blank or special characters should be quoted twice (or the relevant characters escaped twice). The first pair of quotes (outer) avoid interpretation by the local shell, whilst the second (inner) avoids interpretation by the remote shell. Two different quote characters (single and double) must be used. For instance:

$ scp 1btl.pdb eucaryote.net:'"My Structures/"'

You can copy a file from your home directory on a remote host to the current working directory on your local computer by using a command such as:

$ scp eucaryote.net:1btl.pdb .

Absolute paths and paths relative to your remote home directory can also be used as discussed above.

Files can be copied between two remote hosts:

$ scp ribosome@eucaryote.net:1btl.pdb pilus@procaryote.com:

To recursively copy directories, use the -r option:

$ scp -r structures/ eucaryote:

To preserve modification times (highly recommended), access times, and modes from the original file

$ scp -p structures/ eucaryote:

To use a non-standard port, use the -P option:

$ scp -P 2222 -r structures/ eucaryote:

I also find scp handy for copying files between two user accounts on the same computer. For example, if user ribosome asked me to send him the file 1btl.pdb, I could do so by typing the following command, then ask him to type in his password at the prompt.

$ scp 1btl.pdb ribosome@localhost:

Finally, the sftp program is an interactive file transfer program that uses SSH. You can use it to connect to a remote host, then list the available files, and transfer to and from your local computer. To learn how to use it, read its man page.

Transparent file tranfer in SSH-aware applications

Many programs support operations on remote files through SSH. KDE applications are examples of this. Anyplace in KDE where you can type an URL (Konqueror browser and file manager windows, file open/save dialogs, etc.), you can access remote hosts using SSH by typing URLs such as:

sftp://eucaryote
sftp://ribosome@eucaryote
sftp://ribosome@eucaryote:22
sftp://eycaryote/home/ribosome/structures

As shown in these example commands, user name and port are optional, and a remote directory can be specified (but must be given as an absolute path). If necessary, you will be prompted for a password.

Contents of the remote directory will be displayed graphically. You can copy, paste, drag and drop files and directories in the same way you operate on local files. You can transfer files between your local machine and the remote host, and even between two remote hosts (using a split view in Konqueror, or two side-by-side Konqueror windows, for instance).

You can open a remote file in an editing program (a text file in Kate or a graphic file in KolourPaint, for instance). When you save your modifications, the updated file is automatically uploaded to the remote host to replace the previous version.

Mounting remote filesystems using SSHFS

Accessing remote files transparently in KDE applications as described above is a useful but limited feature. What about non-KDE applications and command-line tools? Would it not be a lot better if transparent SSH transfers were integrated directly into the operating system rather than tied to a specific graphical environment? Fortunately, the tool to do just that exists. The Filesystem in Userspace (FUSE) project allows virtual filesystems to be built for Linux and other UNIX systems using userspace applications (as opposed to implementing filesystems as kernel modules). SSHFS is a filesystem based on FUSE and the SSH transfer protocol. With SSHFS, you can mount a directory located on a remote machine and manipulate its contents as though the files and directories were local. To use SSHFS, first make sure support for FUSE is built into your kernel (directly or as a module). In your kernel config file, you should have:

CONFIG_FUSE_FS=y

Next, install SSHFS. On a Gentoo system, use:

# emerge --ask sshfs-fuse

You can mount and unmount SSH shares (as a normal user) using sshfs and fusermount, respectively:

$ sshfs mammouth: /mnt/mammouth
$ fusermount -u /mnt/mammouth

You can also add entries such as the following to your /etc/fstab file:

sshfs#mammouth: /mnt/mammouth fuse noauto,user,cache=no,ServerAliveInterval=15 0 0

The cache option makes sure that your view of remote files and directories is updated whenever they change. The ServerAliveInterval option avoids timeouts. The user option makes it possible for any user to mount the directory. With the noauto option, the filesystem is not automatically mounted at boot time. When you want to mount the remote share, use:

$ mount /mnt/mammouth

For more information, see the SSHFS page on the FUSE home page.

Client configuration

The file ~/.ssh/config can be used to configure the behavior of the ssh client program. The file is divided into two parts. The first contains global options that apply to all hosts SSH connects to. The second contains host-specific instructions. Here is an example config file. See the man page (man ssh_config) for more options.

# Empty lines and lines beggining with # are ignored.

# This is the first part of the file, containing directives
# that apply to all hosts.

# Enable X11 forwarding by default. (Same as using the -X
# option.)
ForwardX11

# This is the second part of the file, containing host-specific
# directives.

# Specify a non-standard port to use with procaryote.com.
Host procaryote.com
Port 2222

# Specify a user name for all subdomains of ratrace.com.
Host *.ratrace.com
User fatcat

# Use glurs as an alias for host glutamyltrnasynthetase.net
# and specify the user name.
Host glurs
HostName glutamyltrnasynthetase.net
User aars

Static lookup table

The /etc/hosts file is the static lookup table for host names. It is used by all applications (including SSH programs) to resolve the I.P. address associated with a given hostname. It is better to define hosts in this file rather than make aliases in the SSH configuration file, as definitions in /etc/hosts apply to all programs.

As an example, adding the following entry to your /etc/hosts file would allow you to simplify SSH commands.

132.203.160.175 gorfou.rsvs.ulaval.ca gorfou

The following:

$ ssh 132.203.160.175

Could be written:

$ ssh gorfou.rsvs.ulaval.ca

Or simply:

$ ssh gorfou

Public key authentication

SSH supports public key authentication as an alternative to login passwords. To use it, you must first create a pair of keys. The first is the "public" key. It contains no sensitive information, and should be copied to all computers you want to log to using key-based authentication. The second is the "private" key, which must be kept secret. To remain secure, the private key is encrypted and can only be unlocked by providing a secret passphrase. The process of key-based authentication goes as follows:

  1. Using SSH, you try to connect to a remote host. The user name you wish to use is transmitted to the server, along with a request to use a key for authentication.
  2. The server verifies that the key you specified is authorised.
  3. The server uses the authorised public key to construct a challenge, and sends it back to the connecting client.
  4. The SSH client receives the challenge and finds the corresponding private key. Since that key is encrypted, it asks you for the passphrase to unlock the key.
  5. Using the unlocked private key, the SSH client constructs a response to the authentication challenge and sends it to the server.
  6. The server verifies that the response is valid and grants access to the system.

From the user's point of view, not much has changed. Instead of being asked for a password to log into the system, you are asked for a passphrase to unlock a private key. However, public key authentication requires you to remember only one passphrase (to unlock the key), as opposed to a variety of passwords to log into different computers.

To set up key-based authentication using OpenSSH, first create your key pair:

$ ssh-keygen -t dsa

Accept the default values and use a strong passphrase. Your private key is ~/.ssh/id_dsa, your public one ~/.ssh/id_dsa.pub. Now, copy the public (and only the public) key to the server, and add it to your personal list of authorised keys:

$ scp ~/.ssh/id_dsa.pub user@server:
$ ssh user@server "cat ~/id_dsa.pub >> ~/.ssh/authorized_keys"

Key-based authentication is now setup. If the server supports it, you can start using it by simply connecting to the remote host in the usual manner:

$ ssh user@server

Rather than the usual request for a password, you should be asked for the passphrase to your private key. After providing that passphrase, you should be granted access to the server.

If you use multiple key pairs, you can configure the identity to use in an host-based manner in the SSH configuration file:

# Specify the identity to use with a given host.
Host ratrace.com
IdentityFile ~/.ssh/id_dsa-ratrace

Public key authentication provides increased security since a potential attacker must both have your private key and know your passphrase to gain access to your account. (This, however, is only true if the server is set up to use only key-based authentication.) Another benefit, as stated above, is the convenience of having only one passphrase to remember as opposed to many passwords.

Passphraseless private keys

Key pairs do not have to be encrypted and protected by a passphrase. Passphraseless keys can be used for authentication in secure networks instead of UNIX passwords.

Unfortunately, many people abuse this functionnality to achieve convenient, passwordless, interactive logins. Even system administrators do it frequently, and many a guide on the Internet suggests creating "passwordless DSA keys" for convenient SSH usage. However, using a passphraseless key over an insecure network is an important security risk. What would you think about keeping your UNIX password in a unencrypted text file in your home directory, and naming that file my_password.txt? Using a passphraseless key is akin to that; once an attacker steals your private key (which he knows is likely to reside in ~/.ssh/id_dsa), he automatically gains access to all your accounts configured for authentication with that key. Do you have backup copies of your home directory? Maybe in a few places? Anyone with access to one of these could steal your key and impersonate you.

Even worse, some people copy their private key to the remote hosts they log into. They either believe that the server needs their private key for authentication, or they appreciate being able to make further passwordless logins from that host, perhaps to circumvent a firewall. For all practical purposes, this is just like using the same password for all your logins, and keeping that password unencrypted in an obvious place on all these computers...

Passphraseless keys are never necessary for interactive logins, and should never be used for that purpose. Private keys should be kept on as few computers as possible. (Only the ones you use as terminals to work and log into other computers.) Convenient, passwordless logins can be achieved securely using ssh-agent and keychain; ssh allows authentication credentials kept by ssh-agent to be forwarded to remote hosts for further logins; firewall-protected machines can be accessed using SSH tunnelling. All these features are covered in the following sections.

Key management with ssh-agent and keychain

Typing the same passphrase over and over again gets tedious, and considerably limits usability. (It is impossible to make unattended automated scripts that connect to remote hosts, amongst others.) Fortunately, the OpenSSH suite provides the ssh-agent program, which can store an unlocked private key in memory and use it to establish connexions with SSH servers. ssh-agent provides both the security of public key authentication, and the convenience of passwordless logins. You need only unlock your key once (using your passphrase) at the start of your session.

You can start ssh-agent using the following command (replace -s by -c if you use a csh-style shell):

$ eval "$(/usr/bin/ssh-agent -s)"

ssh-agent puts itself in the background and prints environment variable definitions that are evaluated by your shell. (These variables set the PID of the agent so that SSH can query it later on.) Next, you need to unlock your private key:

$ ssh-add

You will be prompted for your passphrase. After that, you can connect to remote servers and execute automated scripts without ever entering your passphrase again.

As you will quickly notice, however, ssh-agent really works only from the session it was started in. If you open another session (in a terminal application or virtual console), SSH will not find the running agent and will ask for your passphrase again. The reason is that the environment variables giving the PID of the agent are, of course, missing from the new sessions. There are a number of ways to share an agent between sessions. In my opinion, the best one is the keychain tool. To use it, you first need to install it. On Gentoo systems, use:

# emerge --ask keychain

Then, ensure that the keychain script is run at the start of your sessions by adding the following to your .bashrc:

if grep -q i <<< ${-}; then
    eval $(keychain --eval --quiet id_dsa)
else
    eval $(keychain --eval --quiet --noask)
fi

(If you use a different shell, modify as required.)

The script will automatically set the necessary environment variables for sharing the existing agent, or will set up the agent if it is not running already.

The next time you open a command-line session (in a terminal application or virtual console), you will prompted for your passphrase to unlock your private key. Afterwards, you can SSH passwordlessly from any session. Typically, you will have to unlock your key only once in the morning when you open your first terminal. This setup is extremely convenient, and also reasonably secure.

Agent forwarding

There is still one last drop of convenience we can squeeze out of OpenSSH. Once connected to an SSH server, you will still have to type in your password if you try to open an outbound connexion to another SSH server (to open an SSH session within an SSH session). Using public key authentication would not solve the problem, as you would still have to unlock your private key on the first server to connect to the second. (Furthermore, you would need to copy your private key on the first server, which is not a good idea security-wise.)

The solution is to use agent forwarding. Agent forwarding allows chains of SSH connexions to query the agent running on the first machine in the connexion chain to allow authentication. Let us take the above example of running an SSH session within another SSH session. When you connect to the second server from the session running in the first server, the authentication challenge is passed to your local machine, where your unlocked private key is kept in memory by the SSH agent. The agent constructs the answer to the challenge, and passes it back to the first server, which can use it to open a connexion on the second server. All this happens without you needing to type in your passphrase or copy your private key to the first server. This process can be repeated to extend the SSH connexion chain to more than three machines.

To enable agent forwarding, use the -A option with ssh:

$ ssh -A ribosome@eucaryote

You can also enable agent forwarding (either globally or on a per-host basis) in your SSH configuration file, using the instruction:

ForwardAgent yes

SSH tunnelling

In addition to providing secure logins, SSH can be used to create encrypted communication tunnels between hosts. These tunnels can be used to secure unencrypted communication protocols. For example, the POP protocol, used for fetching mail from a server, is extremely insecure, as the passwords are sent unencrypted (in plain text) over the network. Anyone using a network sniffer program can intercept the communication and obtain your password. Wrapping POP communications inside an SSH session using tunnelling (also called port forwarding) makes them as secure as a conventional SSH session. To open an SSH tunnel, use a command such as:

$ ssh -fN eucaryote -L 9001:eucaryote:110

The -f option (discussed before) puts ssh in the background after authentication. -N instructs ssh not to execute any command. (It will only open an SSH tunnel.) The -L option enables local port forwarding: port 9001 on the local host will be forwarded to port 110 on the remote server eucaryote. Once the tunnel is established, you can use it to establish an encrypted connexion with the remote host:

$ telnet localhost 9001

This would open a telnet session on your local system, on port 9001, which is forwarded (with concomitant encryption) to the remote host (on port 110).

You could use an SSH server on a machine other than the mail server to establish the tunnel:

$ ssh -fN ssh_server -L 9001:mail_server:110

This would establish an encrypted tunnel between your computer and the remote SSH server. Data would first travel unencrypted from the mail server to the SSH server; it would then be encrypted and sent to your computer.

Accessing firewall-protected hosts

A practical application of SSH port forwarding is to access firewall-protected hosts. Suppose you are working from home on your laptop, and need to access a remote host at your workplace. However, this remote host is located behind a firewall, and the only way to access it is through another machine that serves as an entry point for connexions made from outside the workplace. For remote login, you could simply use an SSH session within another SSH session. However, file transfers are more problematic, as you need to copy files from the remote host to the network entry point, and then from the entry point to your local machine. To avoid this, you could open direct SHH connexions (for remote login or file transfer) from your local machine to the remote host, tunnelling them through the entry point computer using local SSH port forwarding.

A simple command will do the trick:

$ ssh -fN entrypoint -L 1901:remote:22

This will connect to the network entry point computer, and establish an SSH tunnel between your local system and the remote computer you wish to access, by forwarding port 1901 on your local machine to port 22 on the remote host (22 is the default SSH port). Once the tunnel is established, you can connect to the remote host using:

$ ssh -p 1901 localhost

You can define tunnel and tunnelled connexion aliases using your SSH configuration file:

Host ssh_tunnel
HostName entrypoint
LocalForward 9001 remote:22

Host tunnelled_host
HostName localhost
HostKeyAlias remote
Port 9001

You can then open the tunnel with:

$ ssh -fN ssh_tunnel

And log into the remote host with:

$ ssh tunnelled_host

The HostKeyAlias option makes sure that the remote host key fingerprint is compared to the correct entry in the known_hosts file. This is particularily handy if you reuse the same port to open SSH tunnels to different hosts.

Accessing blocked ports

Sometimes, a firewall will selectively block ports you can connect to on a remote machine. For instance, only port 22 (SSH) is accessible from outside the campus on most our lab's computers. Forwarding can be used to access other ports through an SSH tunnel. The following command will make an HTTP proxy service listening at port 8079 (blocked) on a remote computer accessible through an SSH tunnel:

$ ssh -fN pelican -L 1902:pelican:8079

You could then connect to your own computer (on port 1902) to access the service listening at port 8079 on the remote machine. Data will pass through port 22 on the remote host before reaching its final destination (port 8079). (Your Web browser should be configured to use localhost on port 1902 as the proxy server.)

The following entry could be put in your SSH config file:

Host proxy_tunnel
HostName pelican
LocalForward 1902 pelican:8079

Opening the tunnel would then be as simple as:

$ ssh -fN proxy_tunnel

Server configuration

To start an SSH server on a Gentoo Linux system, use the following command:

/etc/init.d/sshd start

To have the server automatically start at boot time, add the server daemon to the default runlevel:

rc-update add sshd default

To augment the security of your SSH server, make sure the following options are set in your server configuration file (/etc/ssh/sshd_config):

# Only enable protocol version 2.
Protocol 2

# Disable root login. Users must use "su" to open a session as root.
PermitRootLogin no

# Enable public key authentication. Make sure users do not use passphraseless keys.
# It is better to turn off this option than allow passphraseless keys.
PubkeyAuthentication yes

To further secure your server, you can elect to use only public key authentication. This requires all users to have a public/private key pair, and is only secure if you enforce the use of passphrase-protected keys.

# Enable public key authentication.
PubkeyAuthentication yes
# Disable .rhost and normal password authentication.
HostbasedAuthentication no
PasswordAuthentication no
PermitEmptyPasswords no

Resources