Security for SSH

SSH is the quintessential tool for server administration. But, most servers and VPS are installed with less than optimal settings for SSH. We don't want root to be able to log in, it's a security vulnerability. We don't want to allow the use of passwords for nobody to log in to our servers/VPS.

Share
Security for SSH
Photo by Marko Slavkovic / Unsplash

SSH Security

  • The first steps to secure a server is to create SSH Keys.
  • Copy these SSH Keys to our Server (later: Server or VPS)
  • Edit the SSH service configuration
    • Then we are blocking root to log in to our Server or a VPS.
      Because of the power of root that would be a security vulnerability.
    • Prohibit password authentication for everyone, we are going to use the SSH Keys.

There is a lot of other hardening to do after that. But, this post concentrates on SSH Keys.

Add a new non-root User

It is best practice to never work on servers as root!
It's better to add a non-root user and add him to the sudo group.

On Debian/Ubuntu: adduser <username> replace <username> with a real name.

You need to supply a password, use a complicated one.

adduser joe

I never fill in all the fields, just accept all blank.

Then we need to make the user part of the sudo group so he can elevate his privileges.

usermod -aG sudo joe

Test the new used

Login with the user and check he can do sudodon't continue before success.

SSH Keys

We will learn to create a key and then send it to our server.
By default, we have the following tools: ssh-keygen, ssh-copy-id and ssh-agent.

Create an SSH Key

The quick one is ssh-keygen -t ed25519. The key is usually stored in the hidden ~/.ssh -directory and this would generate a key pair: id-ed25519 and ed25519.pub.
To remember what it's for, use a comment ssh-keygen -t ed25519 -C "a comment".

You should use a descriptive name instead of the suggested id_ed25519 pair name e.g., truenas-44. This would create the pair truenas-44 and truenas-44.pub. And we added some protection with a passphrase. You will have a lot of SSH Keys.

⚠️
Secure the Private Keys pve-9 – never expose, never send by email...
But, keep safe copies so you don't get locked out.
ℹ️
The Public Keys truenas-44.pub and pve-9.pub, are meant to be public
👉
It is wise to set expiry dates on any key you create.
$ ssh-keygen -t ed25519 -C "Joe@hetzner-123"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/nalle/.ssh/id_ed25519): /home/nalle/.ssh/hetzner-123
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Passphrases do not match.  Try again.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/nalle/.ssh/hetzner-123
Your public key has been saved in /home/nalle/.ssh/hetzner-123.pub
The key fingerprint is:
SHA256:qz2Db87rDnFDuosbfbFYRUElca+Jlo2/E0TkfJGr58o Joe@hetzner-123
The key's randomart image is:
+--[ED25519 256]--+
|         .*=+ .. |
|         . =.... |
|        . ..o o. |
|       o . =.+.  |
|      o S =.+.   |
|     . * * .o .  |
|    . =.+   .+   |
|     o.B+  ....  |
|    o.o*O+  Eo   |
+----[SHA256]-----+
Some newer version might not need the -t flag, they uses ed25519 as default:
ssh-keygen -C "some comment of what it's for"

If you need to change the passphrase:

ssh-keygen -t ed25519 -N new_long_passphrase -C "some comment of what it's for"

Copy the Key to your Server

Copy your key to the new server ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected] now re-login by ssh. If it works you can now lock down the ssh.

ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]

Test the key

If you cal login without a password the key is working

Lock-down the Server

After you have tested that you can log in using just the key, you can start locking down the server for SSH. No root log in, no passwords only keys and only named users.

Who and how can users authenticate

We need to block root and the use of Passwords.
Instead, we use SSH Keys and named users.

On the Server, edit the SSH Configuration

sudo nano /etc/ssh/sshd_config

Essentials to be edited

PermitRootLogin yes → no
PasswordAuthentication yes → no
#PermitEmptyPasswords no → PermitEmptyPasswords no
KbdInteractiveAuthentication no
UsePAM yes → no

Up to you and your use case

X11Forvarding yes → no

Add to the end

AutenticationMethods publickey
AllowedUsers joe

Activate the change

Save and restart the demon sudo systemctl restart sshd

Test for success

  • Can you log in directly without a password – the SSH Key works
  • Try logging in as [email protected] – should not be passible
    • You should get: Permissiom denied (publickey)

Other things to do

Other things we need to do to secure the servers

Use firewalls

Only open ports you need and to address you control. You probably need to (if you don't use tunnels) open WEB (80 and 443) and DROP all others. And your ssh port is only open from inside your home IP (if you have a fixed IP).

Use a VPN or a Tunnel

Use Tailscale or similar to connect to your servers without opening any ports.
Consider a Cloudflare Tunnel for all communication to your servers

Use a Reverse Proxy for Web Services

The Reverse Proxy needs only port 443 open. You will need to have port 80 open for Let's Encrypt to be able to update certificates. You will direct traffic by CNAME to the right service. Minimum exposure from open ports.

Stop Brute Force Attacks

I have Fail2ban is standard in my scripts. You only need to set it up to read the logs with open ports, ssh is activated by default.

HTTPS encryption

Let's Encrypt - A nonprofit Certificate Authority providing TLS certificates to 260 million websites.

Security by obscurity – not a good practice

Security by obscurity is more or less ineffective – only gaining some ms delay.
This is the old practice of setting the SSH port to something other than 22.



References

OpenSSH [1] ED25519 [2] About IPs [3]


  1. OpenSSH homepage, GitHub ↩︎

  2. The key using ED25549 kooding Wikipedia ↩︎

  3. IPv4 Address Blocks for Documentation are by RFC 5737:
    TEST-NET-1 = 192.0.2.0/24, -2 = 198.51.100.0/24, -3 = 203.0.113.0/24 ↩︎