Linux: SSH

This article is written as note to self. I needed some basic information about SSH to get things working on a CentOS machine.

Secure Shell (SSH) is a cryptographic network protocol for secure data communication, remote command-line login, remote command execution, and other secure network services between two networked computers. It connects, via a secure channel over an insecure network, a server and a client running SSH server and SSH client programs, respectively.

SSH uses public-key cryptography to authenticate the remote computer and allow it to authenticate the user, if necessary. There are several ways to use SSH:

  • Automatically generated public-private key pairs to simply encrypt a network connection, and then use password authentication to log on
  • A manually generated public-private key pair to perform the authentication, allowing users or programs to log in without having to specify a password

When using a public-private key pair, anyone can produce a matching pair of different keys (public and private). The public key is placed on all computers that must allow access to the owner of the matching private key (the owner keeps the private key secret). While authentication is based on the private key, the key itself is never transferred through the network during authentication. SSH only verifies whether the same person offering the public key also owns the matching private key.

In all versions of SSH it is important to verify unknown public keys, i.e. associate the public keys with identities, before accepting them as valid. Accepting an attacker’s public key without validation will authorize an unauthorized attacker as a valid user. Messages encrypted with the public key can be decrypted with the private key. Messages signed with the private key can be verified with the public key.

OpenSSH

OpenSSH is a set of computer programs that provides encrypted communication sessions over a computer network using the SSH protocol. The OpenSSH suite includes the following tools:

  • ssh, a replacement for rlogin, rsh and telnet to allow shell access to a remote machine
  • scp, a replacement for rcp
  • sftp, a replacement for ftp to copy files between computers
  • sshd, the SSH server daemon
  • ssh-keygen a tool to inspect and generate the RSA, DSA and Elliptic Curve keys that are used for user and host authentication
  • ssh-agent and ssh-add, utilities to ease authentication by holding keys ready and avoid the need to enter passphrases every time they are used
  • ssh-keyscan, which scans a list of hosts and collects their public keys
  • ssh-copy-id, a script that uses ssh to log into a remote machine. Ssh-copy-id copies the local-host’s public key to the remote-host’s authorized_keys file. Ssh-copy-id also assigns proper permission to the remote-host’s home, ~/.ssh, and ~/.ssh/authorized_keys.

Normal OpenSSH development produces a very small, secure, and easy to maintain version for the OpenBSD project. The OpenSSH Portability Team takes that pure version and adds portability code so that OpenSSH can run on many other operating systems. Chances are that if you are using a version of Linux that was released after 2002, that you already have OpenSSH installed.

Ssh-agent

ssh-agent is a program that provides a secure way of storing the private key. For private keys that require a passphrase, ssh-agent allows the user to connect multiple times without having to repeatedly type the passphrase. ssh-agent remembers the decrypted private key so that the user does not need to type a passphrase every time he or she wants to connect or send data to the server. To verify that ssh-agent is running on your computer, type the following command in the terminal:

$ echo "$SSH_AUTH_SOCK"
# Print out the SSH_AUTH_SOCK variable
/tmp/launch-kNSlgU/Listeners

Ssh check

There are several ways to check whether SSH is running. The sshd daemon is the process that runs the OpenSSH ssh server:

# This finds the process called sshd (/usr/sbin/sshd)
ps aux | grep sshd
 
# Check if the process sshd is listening on port 22
netstat -plant | grep :22
 
# Check the status of the sshd service
service sshd status [OR]
/etc/init.d/sshd status

The OpenSSH daemon uses the configuration file /etc/ssh/sshd_config. The default configuration file should be sufficient for most purposes.

By default, ssh listens for incoming connections on port 22. For a hacker to determine ssh is running on your machine, he’ll most likely scan port 22 to determine this. An effective method is to run ssh on a non-standard port. Any unused port will do, although one above 1024 is preferable. It’s better to pick some random high port that’s not used for any known services. To make the change, add a line like this to your /etc/ssh/sshd_config file:

# Run ssh on a non-standard port:
Port 2345  #Change me and restart the sshd service

Because ssh is no longer listening for connections on the standard port, you will need to tell your client what port to connect on. Using the ssh client from the command line, we may specify the port using the -p switch. Use -v Verbose mode to print debugging messages about its progress. This is helpful in debugging connection, authentication, and configuration problems. Multiple -v options increases the verbosity. Maximum is 3 (i.e. ssh -vvv):

ssh -p 2345 -vv myserver

It is also possible to set a different port for a specific user and remote address:

Host 192.168.1.0
Port 2345
User git

Authorized_keys

Authorized_keys is a file containing public keys for public key authentication. If none is specified, the default is ~/.ssh/authorized_keys, the home directory of the user that is allowed to log in remotely. This file is respected by ssh only if it is not writable by anything apart from the owner and root. When the public key is present on the remote end and the matching private key is present on the local end, typing in the password is no longer required. However, for additional security the private key itself can be locked with a passphrase.

Each line of the file contains one key (empty lines and lines starting with a `#’ are ignored as comments).

Note: the private key can also be looked for in standard places, and its full path can be specified as a command line setting (the option -i for ssh). The ssh-keygen utility produces the public and private keys, always in pairs.

You might have some users (or scheduled automatisms) that you don’t want to be able to log on to that machine at all, but who should be permitted to execute only a given command. In order to achieve this, you can configure key-based authentication. Once this has been done, the key can be prefixed with a number of configuration options. Using one of these options, it is possible to enforce execution of a given command when this key is used for authentication.

In this example from ~/.ssh/authorized_keys, the user wants to look at the process list, so we set the command to ‘ps -ef’:

command="/bin/ps -ef"

Using this, when the user tries to log in, or tries to execute an arbitrary command, ‘/bin/ps -ef’ is executed instead and the SSH session terminates.

In addition to enforcing a command, it is advisable to disable a number of advanced SSH features, such as TCP and X11 forwarding. Assignment of a pseudo terminal to the user’s SSH session may also be suppressed, by adding a number of additional configuration options next to the forced command:

command="/bin/ps -ef",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa [public key]
 
# An example to let SVN work; use '-r /opt/svn' to set the root directory of the repositories
command="/usr/bin/svnserve -t  -r /opt/svn",no-port-forwarding,no-pty,no-agent-forwarding,no-X11-forwarding [public key]

Host Key

Much like how the authorized_keys file is used to authenticate users the known_hosts file is used to authenticate servers. To prevent man-in-the-middle attacks, each SSH server has a unique identifying code, called a host key. These keys prevent a server from forging another server’s key. If you connect to a server for the first time or if the server presets a different key then previously you will be prompted to verify (accept) the host key. Each time you connect, the client uses the cached SSH host public key (stored in ~/.ssh/known_hosts) to authenticate that the server it is connecting to is the same server it connected to the first time.

The /etc/ssh/ssh_known_hosts and ~/.ssh/known_hosts files contain host public keys for all known hosts. The global file should be prepared by the administrator (optional), and the per-user file is maintained automatically: whenever the user connects from an unknown host, its key is added to the per-user file.

Lines starting with ‘#’ and empty lines are ignored as comments. Each line in these files contains the following fields: markers (optional), hostnames, bits, exponent, modulus, comment. The fields are separated by spaces.

Note that the lines in these files are typically hundreds of characters long, and you definitely don’t want to type in the host keys by hand. Rather, generate them by a script, ssh-keyscan or by taking /etc/ssh/ssh_host_key.pub and adding the host names at the front. Ssh-keygen also offers some basic automated editing for ~/.ssh/known_hosts including removing hosts matching a host name and converting all host names to their hashed representations.

Note that the host key is randomly generated when the SSH server is set up. The host key might change when recompiling or upgrading SSH, rebuilding the server, or just using a different address to get to the same host.

Sometimes you may see a “known_hosts2” file in place of or in addition to “known_hosts”. If both are there then “known_hosts2” is usually the file being used when you make a connection.

schema

Use shared keys for authentication

Shared Keys consist of a Public and Private key and allow a remote machine to authenticate a machine trying to connect it. The Private key resides on your machine and is used to identify you against the public key which resides on the machine you are trying to login to. You might think of it as a handshake.

Using encrypted keys for authentication offers two main benefits:

  • it is convenient as you no longer need to enter a password (unless you encrypt your keys with password protection) if you use public/private keys.
  • once public / private key pair authentication has been set up on the server, you can disable password authentication completely meaning that without an authorized key you can’t gain access – so no more password cracking attempts

The verification to the server is based on challenge-response authentication. Ssh connects to the server with a user name and the request for a key. The ssh daemon gets the request and sends back a challenge based on the public key stored in the authentication file. Ssh uses the private key to construct a key response, and sends it to the waiting sshd on the other end of the connection. It does not send the private key itself. The ssh daemon validates the key response, and if valid, grants access to the system. Ssh-agent simplifies this by creating a socket that listens for SSH connections. The user simply starts ssh-agent, telling it how to find their keys (if they are not in the default location), enters the passphrase for each key to be used, on a one-time basis, and then ssh-agent handles the rest every time the user connects to a remote server.

It’s a relatively simple process to create a public / private key pair and install them for use on your ssh server.

First, create a public / private key pair on the client that you will use to connect to the server (you will need to do this from each client machine from which you connect). Be sure to login with the user who is used to connect to the remote server.

ssh-keygen -t rsa

If you don’t want to still be asked for a passphrase (which is basically a password to unlock a given public key) each time you connect, just press enter when asked for a passphrase when creating the key pair.

This will create two files in your ~/.ssh directory called: id_rsa (private key) and id_rsa.pub (public key). Public keys are stored by default in ~/.ssh , one key per line (a user may have multiple keys). Encrypting the key adds additional security at the expense of eliminating the need for entering a password for the ssh server only to be replaced with entering a passphrase for the use of the key. This may be further simplified by the use of the ssh_agent program as mentioned above.

Ssh keys can not be ‘world readable’ otherwise you will see an error message. Permissions must be 400 or 600. The option StrictModes specifies whether ssh should check user’s permissions in their home directory and rhosts files before accepting login. This option must always be set to yes because sometimes users may accidentally leave their directory or files world-writable. So, set permissions on your private key:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
chmod 600 ~/.ssh/config (optional)
chmod 600 ~/.ssh/authorized_keys (optional)

If you do not have the ssh-copy-id program available, then you must use a manual method for installing your ssh key on the remote host. Copy the public key (id_rsa.pub) to the server and install it to the authorized_keys list. Once you’ve imported the public key, you can delete it from the server.

# It will prompt you for your password on the remote host and take care of the rest
ssh-copy-id username@host [OR]
ssh-copy-id username@host -p port_nr
 
# If authorized_keys is not created on your remote server, you can do this manually
cat your_public_key.pub >> ~/.ssh/authorized_keys

If you add your SSH key to an authorised_keys file on server running SELinux, but for some reason you still can’t connect with your key, then it may be because the SELinux contexts have not been correctly set on the .ssh folder and authorized keys file. Ensure the correct SELinux contexts are set:

# Determine whether SELinux is enabled
getenforce [OR]
sestatus
 
restorecon -Rv ~/.ssh

Dedicated user
Use a locked dedicated user on each client to let scripts access the remote server using SSH:

# Script will be executed with this user
adduser git
# Lock this account
sudo usermod -L git

Use a password protected dedicated user on the server to let scripts access the remote server using SSH:

# Script will be executed with this user
adduser git

Leave a Reply