10th June, 2020 – Day 1
Hi people, today we are learning something quite detailed about SSH and the way it works. I had problems understanding SSH, how it works, what is that tunnel everyone talks about, how other machine knows the key is right, how to configure those configuration files, what do they do actually? All these questions will be answered and hopefully you will understand what this actually is and how simple SSH is.
I challenge you to read the whole thing, as I am sure you will better understand how SSH works. Let’s go.
What is SSH actually?
The SSH is encrypted communication protocol that sends traffic between two end points and those two points (client/server) can be connected and administered remotely from outside the network (over the Internet) or locally (from within the LAN network). SSH is powerful, and today we are going to learn tons of stuff about it, so buckle up folks.
In order for two machines to connect to each other using SSH, there must be one machine that serves as a server, and other that serves as a client. The machine we are connecting to, acts as server, while the machine we are connecting from, acts as a client. Similar to client/server communication HTTP protocol works on. Now, to connect to another remote end-point (SSH server) we can use two methods: passwords or keys – third does not exist.
For example, consider two Linux machines sitting on a LAN network: 192.168.100.101/24 (centos1) and 192.168.100.102/24 (centos2). These two machines are on the same network, same subnet, and can ping each other – great. We are centos1 and want to remotely administer centos2, which sits somewhere in the data center. To remotely connect to it, as we said, we use password, or key-pairs. Depending on how the SSH on centos2 is configured, it may allow only connections with key-pairs, or only by password, or both. For now, just imagine we have those two machines in our network, and we will use them throughout this post.
What is asymmetric cryptography
As we said, SSH uses key-pairs to establish a client connection with the server, and server with the client. Now, what are those keys, how to make them, are they safe, what if one of them is missing? All of these questions will be answered, let’s do it.
The term asymmetric cryptography means that keys used for encryption or decryption are different. Well, this is our SSH example in which we have two key-pairs. Both are different and this is how it works. One mathematical formula spits two keys that are not identical and wola, we have two brand new keys to share. Private key stays private, on our machine, while the public key can be shared with anyone we want to establish connection. One key can encrypt data and the other key can decrypt it, same happens vice verca. So only those two key-pairs (private and public) can be used to decrypt/encrypt traffic coming from/to them. We dont care how it works, it just works. Someone who is smarter than you and me figured this out, and now it is used world wide. Yes, it is secure and no one can break those keys as they use very long hashes and it would take centuries to break them.
Let’s say centos1 wants to remotely administer centos2. We don’t care what, he just wants to connect to it using SSH. What we must do? We need to generate those keys using centos1. Centos1 will generate public and private key. Private key stays with centos1, and is kept private. Public key can be shared with all machines we want to connect to. Once the centos2 has our public key (we simply send the key to it), we can connect to the centos2 since the public key centos2 has, matches our private key combination. In this way, centos1 knows that centos2 has legit key and can connect to it. Simple, right?
Generating RSA keys
By using ssh-keygen tool on Linux, we will create those two keys we talked about.
# ssh-keygen -b 4096 -C "Our new RSA Key"
We just created a new key-pairs. Let’s digest the command used and the image above. First, ssh-keygen is a tool that creates those keys for us. The -b argument specifies key length, and the more lengthy key the more secure it is. The -C argument adds simple description at the end of our key. It is not that important but can help if our system has several keys and we use -C option to describe each key in a meaningful way. Also, output instructs to enter new passphrase. The passphrase is similar to password and we would use that passphrase when we establish a connection with the centos2. Centos2 would ask us to enter this passphrase (just additional security layer, it could be blank if we want). If you want to change passphrase but don’t want to generate new keys, use -p argument.
Let’s see how our private and public keys look:
This is our private key id_rsa. Everything is key starting from BEGIN RSA PRIVATE KEY all down to the END RSA PRIVATE KEY. Since we specified -b 4096 key length, this is the result. Note that image contains <SNIP> as the key is much longer. Now, let’s take a look at his brother, public key. The public key is much shorter, and it is the key we place on remote machines.
Copying public RSA key to remote machine
# ssh-copy-id 192.168.100.102
We just copied public key to the centos2. The ssh-copy is another tool in our arsenal that helps us with the copying. Also, we could manually copy the public key but ssh-copy-id saves us some time. What now happened on centos2 is that a new file is made called authorized_keys. In this file, we can find all public keys that centos2 accepts. With the right combination, private and public keys will establish a connection.
Connecting to remote machine with RSA private key
# ssh 192.168.100.102
Since we use keys to establish connection, centos2 will ask for a passphrase that we previously set. Without passphrase, SSH connection would be invalid.
Generating ed25519 SSH key-pair
The key we just made was RSA key. The ed25519 (weird name) is another type of key. This key is superior security to RSA. Generated keys will be stored in user’s home directory, under the directory .ssh
# ssh-keygen -t ed25519 -C "This is ed25519 key"
Like before, we use ssh-keygen tool that will generate key-pair for us. Now, we will use another key – ed25519. Same stuff like before, it will generate private and public keys. Private stays on our machine, public one is shared among other machines.
Copying public ed25519 key to remote machine
# ssh-copy-id -i ~/.ssh/id_ed25519.pub 192.168.100.102
Using ssh-copy-id, we send public key. Location of key is specified using absolute path with -i argument. At the end, we specify IP address of remote machine. That is it, we sent public ed25519.pub key file to remote machine.
Connecting to remote machine with ed25519 private key
# ssh firstname.lastname@example.org -i ~/.ssh/id_ed25519
To SSH to 192.168.100.102, we issue the command with -i argument that specifies which private key to use during this connection (note that we specify id_ed25519 and not id_ed25519.pub). Note this, instead of using IP address, we used email@example.com, this will login as specific user on remote machine.
When we connect to a remote host, centos2 in our example, SSH validates the private key from centos1 and compares it to the all keys contained in authorized_keys file on centos2. Basically, that is the main goal of the author
Intermediate Guide for SSH
To this part, we have learned basic things about SSH. We mentioned private and public keys, asymmetric keys, how private and public keys look, what is their role, what passphrase is, and how important are authorized_keys files.
Now, we will talk about different ways of connecting to remote machine, for example connecting with IPv6, with port numbers, editing and modifying configuration files, preventing others from connecting to our machine, allowing only specific IPv4 addresses to connect to us, denying all IPv6 connections, etc.
Configuring client-side SSH configuration file
In this chapter, we want to personalize our client-side SSH configuration file. This file is located in /etc/ssh/. To create our personalized client-side config, go to /home/username/.ssh/ and create brand new empty file called config
# cd /home/themozak/.ssh/ # nano config ------------------------ Host * !centos-v6 IdentityFile ~/.ssh/id_ed25519 Port 22 #NOTE: Global configuration, allow all except centos-v6 if he tries id_ed25519 connection. Host centos2-v4 Hostname 192.168.100.102 User root #NOTE: $ssh centos2-v6 would be equivalent to $ssh firstname.lastname@example.org Host centos2-v6 Hostname 192.168.100.102 User root Port 22 IdentityFile ~/.ssh/id_rsa #NOTE: centos2-v6 would be equivalent to $ssh email@example.com -p 22 -i ~/.ssh/id_rsa Host centos2-Hostname Hostname centos2 User root #NOTE: $ssh centos2-Hostname would be equivalent to $ssh root@centos2 (SSH works with DNS too)
Entries inside config files are self explanatory. We made variables called centos2-v4, centos2-v6, centos2-Hostname, that will be used when connecting to remote machine. Such variables store information so we don’t have to type them every time.
Modifying the server-side SSH configuration file
The modification of server-side SSH config file can be daunting at first, but I will try to explain it as much as I can. So, to begin with, we need to locate sshd_config file and open it
# nano /etc/ssh/sshd_config
Change the listening port number
When inside file, find Port 22 and change to 2222 or whatever port number you want. On this port, SSH will listen for incoming connection requests. Save and exit the file.
# yum install -y policycoreutils-python-utils
By installing this package, we would be able to modify SELinux using semanage package.
Everything should be fine by now. We installed semanage package that will let us modify SELinux configuration and change the port to 2222. Restart the sshd daemon and try to connect to centos2 on port 2222.
# semanage port -a -t ssh_port_t -p tcp 2222 # systemctl restart sshd
# ssh 192.168.100.102 -p 2222
The connection should be successful. Also, try to connect with default port 22 and you should not allowed to connect.
Changing the listen address
By default, SSH is listening on all IPv4 and IPv6 addresses. This is quite bad for our security and we want to change it so that SSH server only listens for our IP address. To do so, go back to the sshd_config file and modify it as follows:
# nano /etc/ssh/sshd_config #Find this part #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: #And change to this #AddressFamily inet #ListenAddress 192.168.100.101 #ListenAddress ::
Save the file and restart sshd daemon
# systemctl restart sshd
Now, ssh-server listens only for our IP address, on specific interface and other addresses will be blocked.
Change the daemon logging level
There are several levels that SSH can log entries, wrong passwords, etc. They are dictated by LogLevel setting inside sshd_config file. Supported options are QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG1, DEBUG2, DEBUG3. However, DEBUG settings are not recommended to be used.
# nano /etc/ssh/sshd_config #SyslogFacility AUTH #SyslogFacility AUTHPRIV #LogLevel INFO #Change it to #SyslogFacility AUTH SyslogFacility AUTHPRIV LogLevel INFO
We can analyze entries from /var/log/secure using grep to find specific words we are interested in.
Disallowing root login
Some Linux distributions deny root login which is good idea. Ideally, you should not let someone to login to remote machine as root that easily.
# nano /etc/ssh/sshd_config #LoginGraceTime 2m #PermitRootLogin no #StrictModes yes #Change it to: #LoginGraceTime 2m PermitRootLogin no #StrictModes yes
# systemctl restart sshd
In the beginning of this post, we talked that SSH establishes connections using key-pairs or passwords. We will learn how to disable passwords and enforce using keys and passphrase.
# nano /etc/ssh/sshd_config #PermitEmptyPasswords no PasswordAuthentication no
# systemctl restart sshd
Setting a message of the day (MOTD)
MOTD is used to create custom made banners or messages that are shown when attempting to connect to certain machine.
# nano /etc/ssh/sshd_config #PermitTTY yes PrintMotd yes #PrintLastLog yes
# systemctl restart sshd
Setting is used when we want to allow only specific users to connect. For that, we will use AllowUsers setting. If you cannot find this setting in sshd_config file, append it on the bottom.
# nano /etc/ssh_sshd_config #PermitTTY no #ForceCommand cvs server AllowUsers themozak
To deny certain user from connecting to our server SSH, we use DenyUsers setting
# nano /etc/ssh_sshd_config #PermitTTY no #ForceCommand cvs server DenyUsers themozak
AllowGroups and DenyGroups
Same as AllowUser and DenyUser, AllowGroups will allow only specified groups and DenyGroups will deny them.
# nano /etc/ssh_sshd_config #PermitTTY no #ForceCommand cvs server AllowGroups themozak