Ansible Logo

This blog post is going to be about hardening your SSH config with Ansible. This guide will be built upon my earlier post about Updating your Homelab with Ansible and Configuring Linux users and SSH keys with Ansible. This post is mainly focused on Ubuntu/Debian systems. For another distro’s the path to the sshd config might be different.

The playbook

With every Ansible configuration, we start with the playbook. All these playbooks can be found on my GitHub as well.

---
 - hosts: ubuntu
   gather_facts: yes
   become: true
   become_method: su
   become_user: root
   tasks:
   - name: Hardening sshd
     block:
       - name: Editing sshd config
         lineinfile:
           dest: "/etc/ssh/sshd_config"
           regexp: "{{ item.regexp | default(omit) }}"
           line: "{{ item.line }}"
           state: "{{ item.state | default('present') }}"
           validate: "sshd -t -f %s"
         with_items:
           - line: "Protocol 2"
           - line: "Protocol 1"
             state: "absent"
           - line: "RSAAuthentication yes"
             state: "absent"
           - regexp: "^Port\ "
             line: "Port {{ ssh_port }}"
           - regexp: "^PermitRootLogin\ "
             line: "PermitRootLogin no"
           - regexp: "^PasswordAuthentication\ "
             line: "PasswordAuthentication no"
           - regexp: "^PermitEmptyPasswords\ "
             line: "PermitEmptyPasswords no"
           - regexp: "^StrictModes\ "
             line: "StrictModes yes"
           - regexp: "^IgnoreRhosts\ "
             line: "IgnoreRhosts yes"
           - regexp: "^RhostsAuthentication\ "
             line: "RhostsAuthentication no"
           - regexp: "^RhostsRSAAuthentication\ "
             line: "RhostsRSAAuthentication no"
           - regexp: "^ClientAliveInterval\ "
             line: "ClientAliveInterval 300"
           - regexp: "^ClientAliveCountMax\ "
             line: "ClientAliveCountMax 0"
           - regexp: "^AllowTcpForwarding\ "
             line: "AllowTcpForwarding no"
           - regexp: "^X11Forwarding\ "
             line: "X11Forwarding no"
           - regexp: "^KexAlgorithms\ "
             line: "KexAlgorithms [email protected],ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256"
           - regexp: "^Ciphers\ "
             line: "Ciphers [email protected],[email protected],[email protected],aes256-ctr,aes192-ctr,aes128-ctr"
           - regexp: "^MACs\ "
             line: "MACs [email protected],[email protected],[email protected],hmac-sha2-512,hmac-sha2-256,[email protected]"

       - name: Reload sshd
         service:
           name: sshd
           state: reloaded

This playbook uses the lineinfile module with Ansible variables loaded in from the with_items. It parses through every line in the with_items section and changes the value in the sshd_config according to the regular expression. The last step reloads the sshd daemon to finalize the settings.

The settings used are:

  • Change protocol version to 2 to allow better cipher suites.
  • Removes RSAAuthentication, which is deprecated.
  • Changes the SSH port to the set variable.
  • Sets PermitRootLogin to no. This disables direct root login via SSH.
  • Sets PasswordAuthentication to no. This only allows key-based logins.
  • Sets PermitEmptyPasswords to no. This disables to use of empty passwords.
  • Enables Strictmode. This enables checks on the daemon before starting up SSH. For example, file permissions. If the settings are wrong. The SSH services do not start.
  • Disables multiple RHosts settings. This disables the use of .rchosts file to connect.
  • Sets ClientAlive settings. Drops idle connections after a set time.
  • Sets AllowTcpForwarding to no. This disables the use of TCP forwarding via SSH.
  • Sets X11Forwarding to no. This disables to use of X11 forwarding via SSH.
  • Sets optimal cipher suites to use for the connection.

Conclusion

Feel free to leave a comment.