Proof of stake , a small guide on securing login with Secure Shell (SSH)

ADA North Pool
9 min readMay 16, 2022

Example of SSH login to an Ubuntu 22.04 server with a custom made login banner

Secure shell cryptographically protects remote logins and is an important tool to understand for a would be node operator as it will allow you to have relays or even core nodes hosted in datacenters or other locations where you need to login remotely to connect to it. As with any tools for remote login security is paramount as it allows access to the computer you login to for anyone with the correct credentials.

In this article we will look at some of the security settings recommended for an SSH remote connection and end it with a small guide on how to make an SSH failed login dashboard.

This article assumes you have gotten login credentials from a host provider and that you are aware of your remote computers host key. See this article on how to find the host key. It also does not goes into detail of how to login for the first time and create your own user and secure it with a public key and 2 factor security such as using googles autenticator for SSH login. While not discussed in this tutorial at lenght, a SSH client might be preferable to use for SSH login if it is something you often do. You can allways use the command line to SSH into the Linux server but a SSH client is an easy way to manage if you have multiple ssh connections that you want to keep of. In making this guide I used PuTTY https://www.putty.org as a windows SSH client.

Logged into the server you need to edit the SSH config file. On default Ubuntu installs this is in /etc/ssh/sshd_config. Remember to restart the ssh service for the changes to take effect. You can also test it with SSHD -T before committing the change. Here are some recommended settings:

Make sure the access to the configuration file is limited to root or a specific user not group. stat You can run /etc/ssh/sshd_config to make sure this is the case. To make sure it is root: chown root:root /etc/ssh/sshd_config as well as chmod og-rwx /etc/ssh/sshd_config.

Make sure that you are using the latest protocol. To do this add Protocol 2 in the sshd config. A long story short this protocl is slightly more secure and if you want to understand why you can read here.

Protocol 2

Make sure you log ssh events. Add LogLevel INFO to the config file to do this.

LogLevel INFO

Change default port from 22. The main reason to do this is that given it is known this is the default port it is often a port that is used by attackers to try to ssh login and by changing the port you are reducing the number of such attacks. This is a very real thing and testing this with a ssh logger in a matter of minutes there had been multiple tries to login with a default port. Set:

Port #yourportnumber#

Allow only specific users or even specific IPs. By allowing only a specific or a few users to login you are reducing your attack vector even further. If you have a fixed IP, or you want to login through a bastion SSH with a fixed ip you can also add another layer of security. AllowUsers yourusername yoursecondusername sets the allowed users in the config file. For IP address it you can do this by AllowUsers myusername@myipaddress but it is also recommended to add the same IP rules for firewalls so that only these IPs can even connect to the ssh port to try the login.

Reduce MaxAuthTries. After failing more than half of the Authentication tries users will be logged. This is also good to reduce to prevent brute force attacks. MaxAuthTries of 3 could be an example of such setting.

MaxAuthTries 3

Disable X11 forwarding unless needed. Unless you plan to have a desktop graphical environment login type, then disabling X11 forwarding means you can reduce an attack vector of a compromised other users of a x11 server used to login to your SSH. Set:

X11Forwarding no

Have a banner for your SSH login. This can be a way to warn users of the policies regarding connections. Set:

Banner /path/your/banner.

Reduce Login Grace time. An attacker can keep up a lot of unauthorized connections if there is a long grace time so it is recommended to reduce this for example set LoginGraceTime to 20. (20 seconds).

LoginGraceTime 20

Consider not allowing SSH connections to be alive if idle. Depending on if other uses can access your computer and how you will use the SSH connection having a time limit on how long an SSH connection is kept alive could be a good idea. You can set this with ClientAliveInterval 120 (120 seconds) and ClientAliveCountMax 0 (How many times to check if idle with the interval in this case 120 seconds. Set:

ClientAliveCountMax 0
ClientALiveInterval 120

Remove unsafe Message Autentication Code (MAC) algorithms. MD5 and 96-bit SHA1 are considered unsafe according to this article. Set:

MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256

Use good Ciphers. This as well as this article gives some recommondations on Ciphers to use. There is a weakness in some of the Ciphers used that allows up to 32 bits of plaintext from a block of ciphertext that was encrypted with the Cipher Block Chaning (CBD) method according to this article. Set:

Ciphers aes256-ctr,aes192-ctr,aes128-ctr

Disable user environment for SSH. By disabling this you can make it harder to for example add a trojan to the execution path of SSH. Set:

PermitUserEnvironment no

Disable root login. It is good operation security practices to operate as a non-privileged user and use sudo to escelate privileges when needed. Set:

PermitRootLogin no

Disable password authentication as well as not permitting empty passwords. In general it is good practice to not use passwords as it encourages you to use more secure (from brute force) methods of autentication such as private keys and 2 factor authentication. It will also help with logs of attacks as it avoids a lot of the brute force attempts on password login. Set:

PasswordAuthentication no
PermitEmptyPasswords no

Consider disabling Host based authentication methods. See this article on what host based authentication is. In general allowing one host to authenticate for many users is not a good thing from a security perspective unless needed and should be disabled. Set:

HostbasedAuthentication no
IgnoreRhosts yes
RhostsRSAAuthentication no

Disable additional authentication methods not needed. If you are not using Challenge Responce Authentication, Kerberos Authentication or GSSAPI Authentication you should disable them to reduce your attack surface.

ChallengeResponseAuthentication no
KerberosAuthentication no
GSSAPIAuthentication no

Install fail2ban. Fail2ban blocks ips from addresses that fails to authenticate according to configured settings. Install with:

sudo apt-get install fail2ban -y

Edit the /etc/fail2ban/jail.local file with an editor such as nano or nice editor. Find the [SSHD] section and enable and configure it:

[SSHD]
enabled = true
Port = #yourportnumber_for_ssh
filter= sshd
logpath = /var/log/auth.log
maxretry = #same_as_maxauthtries
#whitelisted IP addresses
ignoreip = <if you have a static ip you use to connect to ssh you can whitelist it so you do not risk banning yourself out of the server>

After configuring restart fail2ban with:

sudo systemctl restart fail2ban

Bonus: Tunneling local port through PuTTY to show a dashboard in Grafana of failed SSH attempts.

Consider tunneling any ports from localhost of remote computer to your local computer instead of opening ports if it is only needed for yourself to access. In this example we will install a docker with grafana having metrics of SSH logins and telling us of any failed attempts. In this example we use https://github.com/acouvreur/ssh-log-to-influx (always check the docker images you use are from a trusted source and it is the correct images you are pulling to use on your local computer). You should have docker installed on your server, you can follow this guide to do so for Ubuntu 22.04 as well as this guide for the docker-compose. (And please do not enable any web rest api or other attack vectors for your docker containers).

Get the raw docker compose configuration file from the page do:

wget https://raw.githubusercontent.com/acouvreur/ssh-log-to-influx/master/docker-compose.standalone.yml

Run the compose with this command (down to close the docker images): (add sudo if you have not added your own user to the docker usergroup)

docker-compose -f docker-compose.standalone.yml up

You can make this run in the background by doing ctrl + z

Now comes the cool part you can tunnel Grafana from the localhost to your own computer for example through PuTTY:

Source port is 3000 by default for grafana and destination should be localhost:3000. Add remote ports do the same since we are using SSH-2. If you want to do it through command line use ssh -N -f youruser@remoteserver -L localpcport:remoteserver:remoteport. See this for more examples.

You can now access grafana through your local webbrowser for as long as the ssh connection is up. Basically you are tunneling the port throguh SSH with its encryption. Default login is admin pw admin. Change password. Then import a dashboard:

You can get the raw JSON of the dashboard https://raw.githubusercontent.com/acouvreur/ssh-log-to-influx/master/grafana/dashboards/geossh.json and paste that into “import via panel.json”. Then select import. Currently the dashboard will look empty as we need to fix the datasources.

First thing we add login to pass to the docker image by editing /etc/rsyslog.conf as per the guide on https://github.com/acouvreur/ssh-log-to-influx, in my case I use Publickey for authentication so add that segment and to the pottom of my rsyslog.conf I add:

template(name="OnlyMsg" type="string" string="%msg:::drop-last-lf%\n")
if $programname == 'sshd' then {
if $msg startswith ' Failed' then {
action(type="omfwd" target="127.0.0.1" port="7070" protocol="tcp" template="OnlyMsg")
}
}
template(name="OnlyMsg" type="string" string="%msg:::drop-last-lf%\n")
if $programname == 'sshd' then {
if $msg startswith ' Invalid' then {
action(type="omfwd" target="127.0.0.1" port="7070" protocol="tcp" template="OnlyMsg")
} else if $msg startswith ' Disconnected from authenticating' then {
action(type="omfwd" target="127.0.0.1" port="7070" protocol="tcp" template="OnlyMsg")
}
}

Then next we need to set the datasource in Grafana to the influx database used for the error logs. You need to find the name of your docker container with docker ps. This will default to your directory+_grafana_1 in my case sshlog_influxdb_1 by running docker ps:

Now in Grafana you go to configuration datasources and add influx:

user root password root, database telegraf and url is http://#nameofyourinfluxcontainer:8086

You now have a working dashboard that we can test by adding an error message to the docker container handling the errors and passing them to the influx database in the terminal of our ssh remote connection:

netcat localhost 7070
Failed password for username from 206.253.167.10 port 11111 ssh2
(then ctrl + c to get out of netcat to the localhost)

Voila we now have an attack shown on our dashboard

And there you have it a simple guide to securing SSH with a bonus on Tunneling a Grafana SSH failed attempt login. This guide is not ment to be an exhaustive list of all the security aspects of SSH login but ment as some example of common security measurements.

If this guide was usefull and you hold ADA in the Cardano blockchain, I Hope you will consider delegating to the staking pool I run for NBX called ADA North Pool, with ticker ANP. See this guide for how to delegate.

--

--

ADA North Pool

http://adanorthpool.com 0100000101000100010000010010000001001110010011110101001001010100010010000010000001010000010011110100111101001100