SSH - The tool of choice

Everyone who has to administer a server knows ssh, the secure tool for establishing a connection to a (Unix/Linux) server. But the real possibilities of this all-round tool only become apparent when you deal with it in detail. Here are the insights I've gathered so far.

ssh-config

 ssh -p 921 -L 1234:server2:80 -L 3210:server3:3128 -D 3129 username@server1.example.com

This cryptic command does not flow smoothly from everyone's pen. You can get a better understanding if you make the appropriate entries in the .ssh/config file. Let's take a closer look:

 host server1
       HostName server1.example.com
       Port 921
       User username
       DynamicForward 3129
       LocalForward 1234 server2:80
       LocalForward 3210 server:3128

So it looks more readable and the command

 ssh server1

is now sufficient to achieve the same effect. We don't want to try to understand the whole thing in detail just yet, but we'll get an impression of why maintaining a configuration file for ssh calls makes sense. I will describe all other tips for ssh as a command and as an entry in .ssh/config.

PuTTY or openssh

PuTTY is often mentioned as the tool of choice when talking about an ssh client under Windows. Unfortunately, most of the tricks are also possible with PuTTY, but you can't find them on the internet. The search for ssh options looks much better, which then has to be laboriously transferred to PuTTY. PuTTY is a ssh client with terminal emulation, openssh-client is just a ssh client without terminal emulation.
On Windows I only use (oops, there is one exception) Cygwin to use ssh connections. Beyond openssh, Cygwin on Windows allows me to use the oh-so-helpful Unix tools. Of course, Cygwin delivers the terminal emulation free of charge. Since openssh is maintained much better under Cygwin, new functionalities are available to me more quickly.
Result: I am using openssh (the original) and not PuTTY.

Step 1: Login to a server

 ssh -l user server.example.com # or other
 ssh user@server.example.com

Both commands are identical, openssh allows the user „user“ to log in to the server „server.example.com“. The corresponding entry in .ssh/config is

 Host server.example.com
    User user

After entering

 ssh server.example.com

you will be promptly asked for your password.

Step 2: this can also be done without a password

Of course, the user has to identify himself, but this does not necessarily require a password. An SSH key (a kind of ID) is also sufficient, but must first be created. I STRONGLY recommend protecting the key with a password („passphrase“). The SSH key can then only be used once the password has been entered. Such an SSH key is generated with the command:

ssh-keygen -t rsa -b 2048 -f <filename>

If you omit „-f <filename>“, a file called „id_rsa“ is created.

ssh-keygen -t rsa -b 2048 -f /tmp/rsakey
  Generating public/private rsa key pair.
  Enter passphrase (empty for no passphrase):
  Enter same passphrase again:
  Your identification has been saved in /tmp/rsakey.
  Your public key has been saved in /tmp/rsakey.pub.
  The key fingerprint is:
  SHA256:QNdA4hMYyLtz+Z5PZdgxxa2lRZSmygYf1xZQLz8SX1I beckhart@DESKTOP-JMK2FGP
  The key's random art image is:
  +---[RSA 2048]----+
  | . ..o+.+o .o*+.E|
  | o .o + ... Bo |
  | . + o Xo.o|
  | . o.o.o= =".|
  | . . S+++ o o.|
  | o o o= . .|
  | o . .. |
  | .o |
  | .o.. |
  +----[SHA256]-----+

For security, the key consists of two parts, a public part that is used for encryption and a private part that is used for decryption. The above command created two files, „/tmp/rsakey“ (the private part) and /tmp/rsakey.pub (the public part). The two parts are called public key and private key.
In order to authenticate yourself, the public key must be „entered“ on the server and the private key on the client. On the client, the file goes after ~/.ssh/id_rsa. The file must be user-readable, just like the ~/.ssh directory. The public key may be read by anyone (therefore public).

mv /tmp/rsakey* ~/.ssh
ls -ld / /home/ /home/user/ /home/user/.ssh /home/user/.ssh/rsa*
  drwxr-xr-x 32 root system 4096 Jul 17 15:49 /
  drwxr-xr-x 261 am 16384 am Sep 11 00:55 /home
  drwxr-xr-x 14 user group 4096 Sep 18 14:23 /home/user
  drwx------ 3 user group 4096 Sep 08 12:23 /home/user/.ssh
  -rw------- 1 user group 1679 Aug 30 2016 /home/user/.ssh/rsakey
  -rw-r--r-- 1 user group 1679 Aug 30 2016 /home/user/.ssh/rsakey.pub

We have now done everything on the client side and can now pack the public key on the server. The simplest method is the following (see our .ssh/config) command

ssh-copy-id -i /home/user/.ssh/rsakey.pub server.example.com

The password of the user „user“ on the server is queried for the last time. Now we adjust the .ssh/config because our file is not called „id_rsa“ (one of the default values).

host server1
    HostName server1.example.com
    Port 921
    User username
    DynamicForward 3129
    LocalForward 1234 server2:80
    LocalForward 3210 server:3128
    IdentityFile ~/.ssh/rsakey

We have deactivated the server's password query and now have to enter the passphrase of the SSH key. Unfortunately, we have only replaced one password query with another.

Step 3: One password request per day

The openssh developers are apparently pretty lazy fellows. The openssh package also contains an agent that has the task of remembering the SSH keys in RAM and making them available when needed. Of course, the storage in RAM follows all the rules of security. Under Linux (also Cygwin) the agent is used as follows:

ssh agent
  SSH_AUTH_SOCK=/tmp/ssh-YYMhp1JPZkWu/agent.25166028; export SSH_AUTH_SOCK;
  SSH_AGENT_PID=10682402; export SSH_AGENT_PID;
  echo Agent pid 10682402;

The agent is now started and the commands that enable use are issued. The agent stays active until the next reboot, so we can write the commands to a file and then run them in the current shell. Let's name the file ~/ssh-agent-vars.sh and fill it with content. Then we run it in the current shell.

SSH_AUTH_SOCK=/tmp/ssh-YYMhp1JPZkWu/agent.25166028; export SSH_AUTH_SOCK;
SSH_AGENT_PID=10682402; export SSH_AGENT_PID;
echo Agent pid 10682402;

And now the execution, the dot at the beginning signals that the script is executed in the current shell:

. ~/ssh-agent-vars.sh

After the agent has been started and the use has been set up, we now have to provide the agent with the private key

ssh-add ~/.ssh/rsakey

The agent asks us to enter the passphrase and can now take over the task of providing the private key if required. The registration can now be made without any password query.

ssh server.example.com

Made it. from now on it is no longer necessary to enter a password. We only have to remember to start the agent again after a reboot and write the issued commands to the ~/ssh-agent-vars.sh file. The private key must also be reloaded once.
Of course, if we start a new shell, ~/ssh-agent-vars.sh must also be executed in the current shell. You can store this in ~/.bashrc.

Note: if you use PuTTY and openssh under Cygwin in parallel, you should look at using PAGEANT (PuTTY) and working with ssh-pageant (openssh under Cygwin). Here is a link to get started

Step 4: Use the SSH key also from server.example.com

Often you will find a whole server landscape on which you can register. Once you have deposited the public part of the SSH key on all servers, you can log on to any server from the client without an additional password. But if you now want to jump from one server to the other, you will be asked for the password again, because the agent only runs on our client. It is now an unforgivable sin to copy the private key to the servers in the example.com domain.
A private key must NEVER leave the client.
Of course, openssh has a solution here, because the ssh-agent can do even more. The private key can be used in a whole chain of consecutive SSH sessions. The „-A“ switch ensures that the private key is passed on through all ssh instances:

client: ssh -A server.example.com
server.example.com: ssh server2.example.com

The ssh command sent to „server.example.com“ also does not require a password, the ssh-agent satisfies the request for the private key without any problems, provided the public key was provided on server2.example.com using „ssh-copy-id“. The equivalent in the .ssh/config is

host *
  ForwardAgent yes

And learned something again, you can use wildcards („*“ and „?“) for the definitions in the .ssh/config. But be careful: All definitions in all groups to which the wildcards apply are used.

Step 5: Use non-public services locally

What do you mean with that? A web server runs on server.example.com, which cannot be reached from the Internet, but which we want to address on our client. A web server is addressed on port 80 (unencrypted) or 443 (encrypted). However, this port is blocked by a firewall. The solution is: port forwarding, which is not a problem with openssh.

ssh -L 1234:localhost:443 server.example.com

What is the poet trying to tell us? The SSH session is persuaded to open port 1234 on the client and forward all traffic on that port to port 443 on server.example.com („localhost“, from his point of view). Entering in the browser is now sufficient

https://localhost:1234

to reach the web server.

The entry in the .ssh/config is

LocalForward 1234 localhost:443

Confusing? This is due to the dual use of „localhost“. This computer name „localhost“ always refers to the computer on which it is interpreted. In the SSH command, „localhost“ is interpreted from the point of view of „server.example.com“, in the browser, which runs on the client, it is of course interpreted as „client“.
But in the server landscape behind server.example.com there are several web servers running, and setting up port forwarding for each one is probably a bit time-consuming. But of course openssh has everything at hand. We simply set up a socks proxy, which we enter in the browser and all web servers are available with a single entry in the SSH command.

ssh -D 3128 server.example.com

As always, that's it. Just set the proxy settings in the browser and all web servers that can reach server.example.com are available. The behavior is unpleasant if you use names instead of IP addresses. Normally we address websites according to the scheme <hostname>.<domain> (e.g. www.google.de). The DNS does the work for us to translate names into IP addresses. Since the DNS protocol is based on UDP, but ssh only provides TCP, the names must either be resolvable in public DNS or maintained in the local hosts file.
Oh yes, what does the entry in .ssh/config look like?

DynamicForward 3128

Conclusion: Example of a .ssh/config

# First of all the settings that should apply to all computers
hosting *
  # ssh-agent should provide the private keys
  ForwardAgent yes
  # If there are any inconsistencies with host keys, we want to be asked
  StrictHostKeyChecking ask
  # We want to carry the value of some variables with us, here those
  # related to the locale
  SendEnv LANG LC_*
  # Where is our private key again?
  IdentityFile ~/.ssh/rsakey
# Now to Server.example.com
# Since the settings that apply to all hosts are also valid here, we only need
# indicate what changes or what is added
Host Server.example.com
  # what is our username
  User user
  # our nice Socks 5 proxy
  DynamicForward 3128
  # The local forward to reach the web server on server.example.com
  # is actually unnecessary, because we have a dynamic forward
  LocalForward 1234 localhost:443
# Here is an example for multiple servers
Host *.example.com
  User user

The basics have been laid and most questions have been answered. Further HowTo's for SSH will follow….