A bit about SSH

SSH is a protocol used (1) for remote logins, and (2) to secure networking services on an insecure network (Neveth et al., 2018). SSH uses cryptography for client/server connections.

In this short post, we will follow along the steps to connect two machines via SSH. In here, the opposition client/server will in some way be similar to the local/remote opposition, and a bit less but still to the user/admin.

Classic SSH connection

If the client trusts the server, the fingerprint is appended to the file ~/.ssh/known_hosts on their local machine.

This way, if the public key of the server changes, the client will be warned (potential identity theft), else no question about trusting the server will be asked for future connections.

As public key authentication is the most common authentication method, with great benefit regarding security1 and conveniance (Nemeth et al., 2018), we will suppose that it is the one our fictive client wants to use.

Public key authentication

The client needs a pair of keys: the public and the private.

The public key is meant to be public, we can share it with anyone. It is derived from the private key, but the private key cannot be derived from the public key! The private key is meant to stay private (really!).

If the client does not possess any SSH key pair, he can use ssh-keygen to generate some.

ssh-keygen

When asked for "which file to save the key", we can specify a name for our keypair (e.g. ~/.ssh/debian-server), because we may someday have multiple keys, one for each different servers we are going to connect to. We then can pass the corresponding key in the ssh command when we ask for a specific server. For example:

ssh -i ~/.ssh/server-X-key username@server-X.org

The configuration file ~/.ssh/config can store informations so we don't have to be that explicit every time we want to connect:

Host server-X.org Port 22 IdentityFile ~/.ssh/server-X-key User username

This would allow us to use ssh server-X.org instead of ssh -i ~/.ssh/server-X-key username@server-X.org.

Note that the public key in ~/.ssh has the .pub extension. Not the private.

Ok, let's close this parenthesis here. Consider the client already has a private and a public SSH keys.

If the server does not possess the client's public key before the client asks to connect, it will not recognize the client, and won't accept the public key authentication method.

For the server to possess the client's public key prior to the connection, the user must send their public key to the administrator (sometimes it is the same person, making it even easier). To do that, here are two methods: a simple mail (remember the public key can be public), or with ssh-copy-id.

To add an SSH public key for a specific user, the administrator must add the client's public key to /home/username/.ssh/authorized_keys (file with permissions 0600, folder .ssh with permissions 0700), where username is the username of the client on the server.

Another method, if the client can connect to the server with a password, is to use ssh-copy-id. The client authentifies thanks to their password, copy their public key to their remote ~/.ssh/ directory before using only the public key authentication method. Locally:

ssh-copy-id -i ~/.ssh/server-X-key username@server-X.org

End of digression.

Let's say the client's public key is already stored on the server.

https://www.ibm.com/support/pages/system/files/inline-images/public_private_keys.png

Some other stuff

Launch command

ssh example-server.com "command"

Connect via ssh, launch "command" on server, then exit. No interactive shell session.

Permissions

  • ~/.ssh : 0700
  • ssh_priv_key : 0600
  • ssh_pub_key : 0644
  • Key forwarding

    On a local machine having multiple keys to reach different servers, if we want to use a remote server as a proxy (more of a jump server) to reach other machines (for which we have keys) even if this server doesn't have any key to other machines, we must use key forwarding. (Better draw here...)

    First we load our keys to the ssh-agent daemon of our local machine with ssh-add, then we connect to our first server (from which we are going to jump to another machine) with ssh -A.

    ssh-add ~/.ssh/second_machine ssh-add -l # show the current loaded private keys ssh -A user@first_machine # now on the first machine (the jump server) ssh user@second_machine # you are now on the second machine, from the first one

    Use with caution. You need to fully trust the first machine, because even if the private key remains unreadable to it, someone on that server could use it to connect to your secondary machines.

    Sockets for connection multiplexing

    Authention to servers necessitates to establish a TCP connection. That takes time. Creating a socket (locally) that will be reused when connecting back to the server will help decrease connection latency by using the first TCP connection instead of creating another one.

    # in ~/.ssh/config Host Server-X ... ControlMaster auto # enable multiplexing ControlPath ~/.ssh/multiplex_sockets/%r@%h:%p # local dir for sockets ControlPersist 10m # life duration of a socket

    Sockets are created at the first connection to the server. This connection process at "normal" speed as the TCP connection cannot be bypassed.

    Here are tests results to a local server based on the OpenSSH Cookbook method to measure the processing speed of the true program, whether multiplexing is used or not:

    # First connection time ssh username@server-x.org true ssh pi@raspi true 0.10s user 0.00s system 12% cpu 0.838 total # Now that the sockets is created (check ~/.ssh/multiplex_sockets/) time ssh username@server-x.org true ssh pi@raspi true 0.00s user 0.00s system 12% cpu 0.037 total

    From 0.838s to 0.037s, that is 20x faster.

    Port forwarding

    If a firewall forbids connections on specific ports to a server (firewalled-server.org), for example port 80, an SSH connection can tunnel TCP connections through other allowed ports to reach the 80 port on the machine behind that firewall.

    This example is from the UNIX and Linux System Administration Handbook, with minor modifications:

    ssh -L 8000:user-machine:80 firewalled-server.org

    In this example the firewall obviously allows port 22 for SSH connections.

    The user (physically logged on user-machine) forwards it's own port 8000 to the firewalled-server.org on port 80, via firewalled-server.org SSH server on port 22. (The SSH service on the server redirects port 22 to its own port 80.)

    Again, drawing could be better here...

    Servers host keys

    When asked to trust the fingerprint of a server we usually blindly say yes.

    That can be considered a security risk. To solve this, SSHFP offers to bind servers public keys to a DNS. With VerifyHostKeyDNS=yes in sshd_config, issue solved.


    TLDR;

    Steps to connect a client to SSH server with public key authentication.

    Resources

  • Nemeth, E., Snyder, G., Hein, T. R., Whaley, B., & Mackin, D. (2018). UNIX and Linux system administration handbook. (pp.940-951)

  • SSH RFCs : https://datatracker.ietf.org/doc/html/rfc4253

  • https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing

  • The Cyber Plumber's Handbook : https://github.com/opsdisk/the_cyber_plumbers_handbook

  • Linux From Scratch (OpenSSH) : https://www.linuxfromscratch.org/blfs/view/stable/postlfs/openssh.html
  • chessgitxmppbookswallet