RSA Key file based SSH on Debian Linux.

RSA Key file based SSH on Debian Linux.

Hi again world!
One of the best things I ever did since i first time played with an Amazon EC2 Debian instance, was to copy the SSH login procedure it came with to any other production system I take care of.
Nothing, even changing listening port, has ever made more significant difference in terms of reduction of hostile SSH activity on production servers.
As you probably know, I'm talking about the mandatory usage of an RSA key pem file to gain SSH access to non-root user server account.

I have had since those times, kept my written note at my office desk, with the routine set commands to apply that recipe, to any Debian SSH default install.
Clearly deteriorated over the years, the time has come to move that note into one of my blog posts...so here go!

Creating a login user

The first thing we need is to ensure we do have a non-root user account ready on our remote server to log in as it.
The idea is to enforce security so, beyond RSA file authentication, the user account our key file will automatically log in as, will be a non-root user... that way, we do still keep a last line of defense (the root password) in case our key file is somehow compromised.
Normally, I create a login-only-purpose dedicated user account, apart from any other on the system

If you do not have a candidate account already created on the remote server, you could create an user as usual.
Here's an example by using the adduser Debianist script :

root@remoteserver:~# adduser ssh-access
Adding user `ssh-access' ...
Adding new group `ssh-access' (1003) ...
Adding new user `ssh-access' (1002) with group `ssh-access' ...
Creating home directory `/home/ssh-access' ...
Copying files from `/etc/skel' ...
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully
Changing the user information for ssh-access
Enter the new value, or press ENTER for the default
        Full Name []: SSH Remote Access user account
	    Room Number []: 
	    Work Phone []: 
	    Home Phone []: 
	    Other []: 
Is the information correct? [Y/n] Y
root@remoteserver:~#

 

Generating the key files

Now, at your desktop or system management computer, issue the following command:

ssh-keygen -t rsa -b 2048 -v

 
This will prompt you for a file name, so, choose an appropriate name for the keyfile pair that will be generated (a public key, and a private key).
After the file naming, you will be prompted for a key encrypt password, just press ENTER so the key will be not encrypted (this will grant passwordless usage, but remember, keep your key files always secure!!!!).

a console example will look somehow like this:

alex@localmachine:~$ ssh-keygen -t rsa -b 2048 -v
Generating public/private rsa key pair.
Enter file in which to save the key (/home/alex/.ssh/id_rsa): remoteserver
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in monitoring.
Your public key has been saved in monitoring.pub.
The key fingerprint is:
SHA256:+1/sdgfwrfg76gsgheeejfdeqhfkhjsrwqldjdfn9435 alex@localmachine
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|                 |
|           .     |
|            +    |
|        S. o .  .|
|        ..+ = ...|
|       ..= o Xo .|
|      . oo+=OAX.o|
|       F..+O%@CCC|
+----[SHA256]-----+
alex@localmachine:~$

 
At this stage, there will be two files: a private key file and a public key file (easily identifiable by its .pub extension).
In this example, a remoteserver file and remoteserver.pub file are generated...
Eventualy, at the end of the process, we will add the distinctive .pem extension to the private key file after installing its public pair... this is next step!

Installing public key on remote server

The next step is to install the public key into remote access user at remote server.
There is no need to access to the remote server to do so, instead, the ssh-copy-id command will do all the work from the very same place where key files are.
We will need to provide the command the path of the public key file to install, and the remote target user account and hostname or Ip address:

ssh-copy-id -i ./XXXXXXX.pub target_user@target_host_or_IP

 
On the process, we will be asked for the remote access user password, in order to effectively log in and install pertinent files at its profile... Once they are in place, the private key will work, and grant passwordless ssh access to the server.

A console example of the process looks like follows:

alex@localmachine:~$ ssh-copy-id -i ./remoteserver.pub ssh-access@remoteserver
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "./remoteserver.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
ssh-access@remoteserver's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'ssh-access@remoteserver'"
and check to make sure that only the key(s) you wanted were added.

 
Now you could rename your extensionless private key file to something more tasty... I like to add to it the .pem extension, but you could use anything such as .priv or .key extension.

mv remoteserver remoteserver.pem

 

Testing your key file access

OK... now it is time to test your private key file. To do so, we need to use the '-i' modifier at the ssh command to add the keyfile path along with the usual username and remote host:

ssh -i ./XXXXXXX.pem target_user@target_host_or_IP

 
If everything is correct, the login is passwordless, just like this:

alex@localmachine:~$ ssh -i ./remoteserver.pem ssh-access@remoteserver

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
ssh-access@remoteserver:~$

 
IF and only IF that worked, you could proceed to the next step: disabling string password authentication on the remote server!
That is, of course, what will drastically increase security.
In any case, before proceeding any further, su to root at the SSH testing session, and keep it open and untouched (if something goes wrong, that root session would allow you to go backwards. Without it, a mistake in SSH config could render your remote server inaccessible!!!!)

Force key file SSH access on the remote server

Read carefully this step procedure... it is a piece of cake, very very easy, and I've done it dozens of times without any issue ever, like any other routine, but remember: A mistake in SSH server config may render a remote server inaccessible!!!!

Launch a new SSH session to your remote server, either directly as root or as any other user, and gain root prompt (you could use sudo, of course).

Now with your favorite editor, we will edit the SSH server config file /etc/ssh/sshd_config.
The objective is to find out, and set to 'no' the PermitRootLogin parameter that enable root user direct ssh access (if it is not already disabled)
Also to 'no' the one that enables the usual string password authentication method PasswordAuthentication (you'll have to comment it out, and set to 'no').
That way, only the usage of a valid RSA key file remains as valid authentication method (confirm that RSAAuthentication and PubkeyAuthentication parameters are set to 'yes').

So, Modify the file at involved parameters so they look like this excerpt:

...
PermitRootLogin no
...
RSAAuthentication yes
PubkeyAuthentication yes
...
# Change to no to disable tunnelled clear text passwords
PasswordAuthentication no

 
Now it is time to RELOAD the SSH server... DO NOT 'restart' it!!!, but instead 'reload' it... That way, by reloading, the new config will be applied, but your emergency SSH session will not be killed... a server restarting would kill opened SSH sessions, so, if a typo or mistake in the config has been done, our emergency SSH session will be useless in case of trouble!!!

So, reload the ssh service:

service ssh reload

 
Now, check SSH access again using your key file... it should work!!!
If it did (as surely did), you got the job done. Now you can close any SSH opened sessions, your server is proven to be still accessible.
It would be a good idea now to test that 'classic' SSH access methods have stopped to work.

Now, maybe you realize how awkward is to SSH to your server by using a keyfile all the times!!! so... wouldn't it be great if we could add some exceptions to that setup? I do not like to access my server that way!!! ... well, in fact there is, we will see how we can add exceptions to some IPs or subnets that will be able to SSH to the server the 'classic' way while the rest of the world is denied password access.

Creating SSH config exceptions

Ok... now lets imagine that we do connect to our servers through their LAN interface, on a secured network, or through a VPN connection, and we do want to create exception to the above config to certain IPs or subnets.

Edit /etc/ssh/sshd_config again, go to the end of the file and add sections, as many as you need, with the following pattern

Match Address aaa.bbb.ccc.ddd
        PasswordAuthentication yes
	    PermitRootLogin yes

 
As you see, what happens here is that we are applying a different config to that of the default one written above in the same file, but to matched clients (in this case, by using the Address criteria).
The example bellow shows how the final idea may look:

...
# This section Adds security Exceptions to main setup!

# LAN connections are considered safe
Match Address 192.168.1.0/24
        PasswordAuthentication yes
        PermitRootLogin yes

# VPN client IP address is considered safe
Match Address 10.0.0.2
        PasswordAuthentication yes
        PermitRootLogin yes
...

 
Now, to apply the changes, reload the SSH service again.
In theory, you will be able to ssh to root account using root password normally from safe environments.

So... that's all folks!
Till the next time!