--- 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: "" # 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 @ ``` - -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 - 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 # 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 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" >}}