changed to blowfish theme / might change back ...
This commit is contained in:
@@ -0,0 +1,467 @@
|
||||
---
|
||||
title: Securing SSH 🤖
|
||||
date: 2021-12-07T22:41:02Z
|
||||
author: "ahmza"
|
||||
draft: false
|
||||
weight:
|
||||
|
||||
tags: ["HomeLab", "SSH", "RemoteAccess"]
|
||||
description: "Ever wanted to make your SSH connections more secure. Read this"
|
||||
canonicalURL: "https://blog.ahmza.com/Page%28/posts/securing-ssh.md%29"
|
||||
|
||||
cover:
|
||||
image: "/webp/posts/secure-ssh/feature-anim.webp"
|
||||
alt: "ssh-alt image" # alt text
|
||||
caption: "<text>" # display caption under cover
|
||||
relative: false # when using page bundles set this to true
|
||||
showtoc: true
|
||||
searchHidden: false
|
||||
---
|
||||
|
||||
# **Introduction**
|
||||
|
||||
SSH is a widely used protocol to access remote devices. The problem with SSH is
|
||||
at the authentication stage, Brute force attacks are one of the ways an SSH
|
||||
connection is compromised. A malicious actor will constantly hammer the
|
||||
remote host with different passwords until it can gain access. With further
|
||||
configuration of SSH we can make the service a lot more secure.
|
||||
|
||||
# **Configure SSH**
|
||||
|
||||
{{< video label="this is fine" webm="/webm/this-is-fine.webm" >}}
|
||||
|
||||
> **Famous last words:** Configuring SSH like many things in Linux is as simple
|
||||
> as editing a few config files
|
||||
|
||||
Always **create a backup file**, You can end up locking yourself out of a
|
||||
device. Try this on a machine that is not critical.
|
||||
|
||||
## **Create SSH Keys**
|
||||
|
||||
SSH keys use public and private key encryption for authentication.
|
||||
|
||||
To create a set of keys, **on the client do:**
|
||||
|
||||
```bash
|
||||
ssh-keygen -t ecdsa -C <username>@<hostname>
|
||||
```
|
||||
|
||||
- -t ecdsa - sets the key encryption type to _ecdsa_
|
||||
- -C - Comment or name of the _SSH_ key. **Replace content in <>**
|
||||
|
||||
Where you want to save the keys, **I recommend the default location**
|
||||
|
||||
```bash
|
||||
Enter file in which to save the key (/home/user/.ssh/id_rsa):
|
||||
```
|
||||
|
||||
Password for the ssh key, please use a strong password.
|
||||
|
||||
```bash
|
||||
Enter passphrase (empty for no passphrase):
|
||||
```
|
||||
|
||||
Once done you will see a confirmation screen like the one below
|
||||
|
||||
```
|
||||
Output
|
||||
Your identification has been saved in /home/user/.ssh/id_rsa
|
||||
Your public key has been saved in /home/user/.ssh/id_rsa.pub
|
||||
The key fingerprint is:
|
||||
SHA256:tIurljnWJRBc1RnHUJQ5GtND7p9HWKnjV6zjE9AFR1Y user@host
|
||||
The key's randomart image is:
|
||||
+---[RSA 3072]----+
|
||||
| . .....oX=o.oE|
|
||||
| o =oB oo|
|
||||
| . . +.+ o.|
|
||||
| . . .... o+ |
|
||||
| . S .+. +|
|
||||
| .... ..o+.|
|
||||
| +.o. .=o.|
|
||||
| * .. .oo |
|
||||
| o.o. .. |
|
||||
+----[SHA256]-----+
|
||||
```
|
||||
|
||||
## **Copy SSH Keys**
|
||||
|
||||
```bash
|
||||
ssh-copy-id user@host
|
||||
```
|
||||
|
||||
> **Quick note:** user@host is the **username** on the **remeote host** you
|
||||
> would like to copy your public key to.
|
||||
|
||||
**If asked to confirm the connection to the remote host answer yes**, this
|
||||
happens when a new machine with an unknown identity wants to connect.
|
||||
|
||||
```
|
||||
Output
|
||||
The authenticity of host 'host(host)' can't be established.
|
||||
ECDSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx.
|
||||
Are you sure you want to continue connecting (yes/no)? yes
|
||||
```
|
||||
|
||||
**Enter a password** for the user on the remote host
|
||||
|
||||
```
|
||||
Output
|
||||
/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
|
||||
user@host's password:
|
||||
```
|
||||
|
||||
Access the remote device using the SSH key
|
||||
|
||||
To verify this, SSH to the device and **it should ask for the Keys password not
|
||||
the users**
|
||||
|
||||
```bash
|
||||
Enter passphrase for key '/home/user/.ssh/id_rsa':
|
||||
```
|
||||
|
||||
## **Modify SSH Config**
|
||||
|
||||
create a backup
|
||||
|
||||
```bash
|
||||
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
|
||||
```
|
||||
|
||||
open the original file in a text editor
|
||||
|
||||
**NeoVim BTW!!**
|
||||
|
||||
```bash
|
||||
sudo vim /etc/ssh/sshd_config
|
||||
```
|
||||
|
||||
For a new _Linux_ user this might be daunting. Take your time and you will be
|
||||
fine 😊
|
||||
|
||||
{{< video label="thats a big one" webm="/webm/thats-a-big-one.webm" >}}
|
||||
|
||||
**Lines we want to modify**
|
||||
|
||||
> **Note:** uncomment lines as well as add missing lines
|
||||
|
||||
- Protocol 2
|
||||
- Port 2222
|
||||
- PermitRootLogin no
|
||||
- Max Auth Tries 5
|
||||
- PasswordAuthentication no
|
||||
- PermitEmptyPasswords no
|
||||
- AllowUsers <user>
|
||||
- ClientAliveInterval 180
|
||||
|
||||
```
|
||||
# $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $
|
||||
|
||||
# This is the sshd server system-wide configuration file. See
|
||||
# sshd_config(5) for more information.
|
||||
|
||||
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
||||
|
||||
# The strategy used for options in the default sshd_config shipped with
|
||||
# OpenSSH is to specify options with their default value where
|
||||
# possible, but leave them commented. Uncommented options override the
|
||||
# default value.
|
||||
|
||||
Include /etc/ssh/sshd_config.d/*.conf
|
||||
|
||||
Protocol 2
|
||||
|
||||
Port 2222
|
||||
#AddressFamily any
|
||||
#ListenAddress 0.0.0.0
|
||||
#ListenAddress ::
|
||||
|
||||
#HostKey /etc/ssh/ssh_host_rsa_key
|
||||
#HostKey /etc/ssh/ssh_host_ecdsa_key
|
||||
#HostKey /etc/ssh/ssh_host_ed25519_key
|
||||
|
||||
# Ciphers and keying
|
||||
#RekeyLimit default none
|
||||
|
||||
# Logging
|
||||
#SyslogFacility AUTH
|
||||
#LogLevel INFO
|
||||
|
||||
# Authentication:
|
||||
|
||||
#LoginGraceTime 2m
|
||||
PermitRootLogin no
|
||||
#StrictModes yes
|
||||
MaxAuthTries 5
|
||||
#MaxSessions 10
|
||||
|
||||
#PubkeyAuthentication yes
|
||||
|
||||
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
|
||||
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
|
||||
|
||||
#AuthorizedPrincipalsFile none
|
||||
|
||||
#AuthorizedKeysCommand none
|
||||
#AuthorizedKeysCommandUser nobody
|
||||
|
||||
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
|
||||
#HostbasedAuthentication no
|
||||
# Change to yes if you don't trust ~/.ssh/known_hosts for
|
||||
# HostbasedAuthentication
|
||||
#IgnoreUserKnownHosts no
|
||||
# Don't read the user's ~/.rhosts and ~/.shosts files
|
||||
#IgnoreRhosts yes
|
||||
|
||||
# To disable tunneled clear text passwords, change to no here!
|
||||
PasswordAuthentication no
|
||||
PermitEmptyPasswords no
|
||||
|
||||
AllowUsers <user>
|
||||
|
||||
# Change to yes to enable challenge-response passwords (beware issues with
|
||||
# some PAM modules and threads)
|
||||
ChallengeResponseAuthentication no
|
||||
|
||||
# Kerberos options
|
||||
#KerberosAuthentication no
|
||||
#KerberosOrLocalPasswd yes
|
||||
#KerberosTicketCleanup yes
|
||||
#KerberosGetAFSToken no
|
||||
|
||||
# GSSAPI options
|
||||
#GSSAPIAuthentication no
|
||||
#GSSAPICleanupCredentials yes
|
||||
#GSSAPIStrictAcceptorCheck yes
|
||||
#GSSAPIKeyExchange no
|
||||
|
||||
# Set this to 'yes' to enable PAM authentication, account processing,
|
||||
# and session processing. If this is enabled, PAM authentication will
|
||||
# be allowed through the ChallengeResponseAuthentication and
|
||||
# PasswordAuthentication. Depending on your PAM configuration,
|
||||
# PAM authentication via ChallengeResponseAuthentication may bypass
|
||||
# the setting of "PermitRootLogin without-password".
|
||||
# If you just want the PAM account and session checks to run without
|
||||
# PAM authentication, then enable this but set PasswordAuthentication
|
||||
# and ChallengeResponseAuthentication to 'no'.
|
||||
UsePAM yes
|
||||
|
||||
#AllowAgentForwarding yes
|
||||
#AllowTcpForwarding yes
|
||||
#GatewayPorts no
|
||||
X11Forwarding yes
|
||||
#X11DisplayOffset 10
|
||||
#X11UseLocalhost yes
|
||||
#PermitTTY yes
|
||||
PrintMotd no
|
||||
#PrintLastLog yes
|
||||
#TCPKeepAlive yes
|
||||
#PermitUserEnvironment no
|
||||
#Compression delayed
|
||||
ClientAliveInterval 180
|
||||
#ClientAliveCountMax 3
|
||||
#UseDNS no
|
||||
#PidFile /var/run/sshd.pid
|
||||
#MaxStartups 10:30:100
|
||||
#PermitTunnel no
|
||||
#ChrootDirectory none
|
||||
#VersionAddendum none
|
||||
|
||||
# no default banner path
|
||||
#Banner none
|
||||
|
||||
# Allow client to pass locale environment variables
|
||||
AcceptEnv LANG LC_*
|
||||
|
||||
# override default of no subsystems
|
||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||
|
||||
# Example of overriding settings on a per-user basis
|
||||
#Match User anoncvs
|
||||
# X11Forwarding no
|
||||
# AllowTcpForwarding no
|
||||
# PermitTTY no
|
||||
# ForceCommand cvs server
|
||||
```
|
||||
|
||||
{{< video label="not so bad" webm="/webm/wasnt-so-bad.webm" >}}
|
||||
|
||||
**Now lets explain what we just did**
|
||||
|
||||
- **Protocol 2** - released in 2006, SSH2 introduced improved encryption
|
||||
algorithms.
|
||||
- **Port 2222** - The port number can be whatever number you want. Choose
|
||||
something other than 22 this will help hide your device from malicious actors
|
||||
- **PermitRootLogin no** - If the root account gets compromised then the
|
||||
attacker has full control so we stop root from logging in over ssh.
|
||||
- **MaxAuthTries 5** - After 5 failed attempts the remote host blocks requests
|
||||
from that IP for some of time.
|
||||
- **PasswordAuthentication no** - The SSH key is installed, no need to have
|
||||
password authentication.
|
||||
- **PermitEmptyPasswords no** - Don't allow empty passwords
|
||||
- **AllowUsers username** - Add the users you want to connect to the remote
|
||||
host, others will be dropped.
|
||||
- **Client Alive Interval 180** - Drop the connection after 180s of inactivity
|
||||
|
||||
## **Check ability to connect**
|
||||
|
||||
restart sshd service
|
||||
|
||||
```bash
|
||||
sudo systemctl restart sshd
|
||||
```
|
||||
|
||||
**Keep the current SSH connection open** and create a new session.
|
||||
|
||||
If you connect to the remote host then you're set. If not then you still have
|
||||
the initial connection to the remote host to roll back the changes and
|
||||
troubleshoot.
|
||||
|
||||
# **Success**
|
||||
|
||||
{{< video label="clap" webm="/webm/clap.webm" >}}
|
||||
|
||||
# **Setting up** **_Fail2Ban_**
|
||||
|
||||
_Fail2Ban_ is an intrusion prevention tool. Although we slow down attackers with
|
||||
with MaxAuthTries they can still carry on brute forcing. Which is what Fail2Ban
|
||||
does, it actually blocks the connections from that IP.
|
||||
|
||||
## **Install** **_Fail2Ban_**
|
||||
|
||||
**We will install Fail2Ban on the remote host**
|
||||
First upgrade any packages, then **install** **_Fail2Ban_**
|
||||
|
||||
```bash
|
||||
sudo apt update && sudo apt upgrade
|
||||
sudo apt install fail2ban
|
||||
```
|
||||
|
||||
Now we need to enable the service so it starts when the remote host
|
||||
starts
|
||||
|
||||
```bash
|
||||
sudo systemctl enable --now fail2ban
|
||||
```
|
||||
|
||||
## **Configure** **_Fail2Ban_**
|
||||
|
||||
The config file we want to edit is **jail.local** located in **/etc/fail2ban/**
|
||||
open jail.local in your editor of choice
|
||||
|
||||
```bash
|
||||
sudo vim /etc/fail2ban/jail.local
|
||||
```
|
||||
|
||||
The config for _Fail2Ban_ is nice and short
|
||||
|
||||
```
|
||||
[DEFAULT]
|
||||
bantime = 8h
|
||||
ignoreip = 127.0.0.1 <ip addresses to be ignored>
|
||||
ignoreself = true
|
||||
|
||||
[sshd]
|
||||
enabled = true
|
||||
port = 2222
|
||||
filter = sshd
|
||||
logpath = /var/log/auth.log
|
||||
maxretry = 3
|
||||
findtime = 10m
|
||||
```
|
||||
|
||||
**[Default]** - Settings in here apply to all jails
|
||||
|
||||
- **bantime** - how long the ban will last
|
||||
- **ignoreip** - IP addresses to ignore
|
||||
- **ignoreself** - stops from locking itself out
|
||||
|
||||
**[sshd]** - this is the jail for sshd
|
||||
|
||||
- **enabled** - decides weather the jail is active or not
|
||||
- **port** - the port number the service
|
||||
- **filter** - tells the jail which filter to use from /etc/fail2ban/filter.d
|
||||
- **logpath** - where the log you want fail2ban to read is
|
||||
- **maxretry** - Times the client can attempt a login before being banned
|
||||
- **findtime** - An amount of time which maxretry must occur to trigger a ban
|
||||
for example in 10 minutes if 3 login attempts fail ban the IP
|
||||
|
||||
**Restart** **_Fail2Ban_** to load the configuration
|
||||
|
||||
```bash
|
||||
sudo systemctl restart fail2ban
|
||||
```
|
||||
|
||||
## **Testing** **_Fail2Ban_**
|
||||
|
||||
To test Fail2Ban lets create a test user and set a password for the
|
||||
user
|
||||
|
||||
```bash
|
||||
sudo useradd test
|
||||
sudo passwd test
|
||||
```
|
||||
|
||||
**open the sshd config**
|
||||
|
||||
```bash
|
||||
sudo vim /etc/ssh/sshd_config
|
||||
```
|
||||
|
||||
Modify the line **PasswordAuthentication** to say **yes** and add the test user
|
||||
to **AllowUsers**
|
||||
|
||||
```bash
|
||||
PasswordAuthentication yes
|
||||
AllowUsers user test
|
||||
```
|
||||
|
||||
**restart the sshd service**
|
||||
|
||||
```bash
|
||||
sudo systemctl restart sshd
|
||||
```
|
||||
|
||||
Attempt to login to the remote host using the test account using an incorrect
|
||||
password. After 3 failed attempts it should say connection refused.
|
||||
|
||||
```bash
|
||||
ssh test@host -p 2222
|
||||
```
|
||||
|
||||
_Fail2Ban_ should do something along the lines of ...
|
||||
{{< video label="you shall not pass" webm="/webm/you-shall-not-pass.webm" >}}
|
||||
|
||||
log back in as your normal user, remove the test user and restore the sshd
|
||||
config.
|
||||
|
||||
**To remove the user**
|
||||
|
||||
```bash
|
||||
sudo userdel test
|
||||
```
|
||||
|
||||
**restore the /etc/ssh/sshd_config file**
|
||||
|
||||
```bash
|
||||
sudo vim /etc/ssh/sshd_config
|
||||
```
|
||||
|
||||
Set **PasswordAuthentication** back to **no** and remove test from **AllowUsers**
|
||||
|
||||
```bash
|
||||
PasswordAuthentication no
|
||||
AllowUsers user
|
||||
```
|
||||
|
||||
# **Conclusion**
|
||||
|
||||
well done, you managed to make it through all that !! At least now you can be
|
||||
reassured that if them pesky brute-force attackers decide to target your machine
|
||||
they can have a fun time in Jail 🤣 sorry bad joke.
|
||||
|
||||
By now you have managed to setup an ssh key for a client and copy it to
|
||||
a remote host, re-configure the sshd config to lockdown authentication
|
||||
and install and configure Fail2Ban to block pesky attackers.
|
||||
|
||||
{{< video label="proud" webm="/webm/proud.webm" >}}
|
||||
Reference in New Issue
Block a user