Skip to content
Fondazione ITS INCOM

Examples · Cloud & Cybersecurity

Harden SSH with Ansible

Qwen3-Coder writes an Ansible playbook that turns off password logins over SSH. Then you check it, and run it on a lab VM without locking yourself out.

Advanced · 60 min

Why

On a server reachable from the internet, SSH should accept keys only: no passwords, no root. With password logins, such a server receives thousands of guessing attempts a day. Doing it by hand on one server is easy; on fifty, you use Ansible.

What you need

A Linux virtual machine for the lab (Ubuntu 24.04), your SSH key already working on it, and Ansible on your computer: pip install ansible.

The model

Qwen3-Coder 30B (qwen3-coder-30b). You can use the chat: no code is needed to ask.

The request

Write an Ansible playbook for Ubuntu 24.04 that hardens SSH: no password login, no root login, only the members of the group ssh-users may log in, at most 3 authentication attempts. Add the user {{ ansible_user }} to the group first. Put the settings in a drop-in file in /etc/ssh/sshd_config.d/, validate it with sshd -t before it is applied, and restart ssh with a handler. It must be idempotent.

Read the answer line by line before you run anything: you are about to change how you log in to that machine.

Check it against this one

A correct playbook looks like this:

- name: Harden SSH
  hosts: lab
  become: true
  tasks:
    - name: Group allowed to log in over SSH
      ansible.builtin.group:
        name: ssh-users
        state: present

    - name: Add the current user to it
      ansible.builtin.user:
        name: "{{ ansible_user }}"
        groups: ssh-users
        append: true

    - name: Hardening settings, checked by sshd before they are put in place
      ansible.builtin.copy:
        dest: /etc/ssh/sshd_config.d/10-hardening.conf
        owner: root
        group: root
        mode: "0644"
        content: |
          PasswordAuthentication no
          KbdInteractiveAuthentication no
          PermitRootLogin no
          AllowGroups ssh-users
          MaxAuthTries 3
        validate: /usr/sbin/sshd -t -f %s
      notify: Restart ssh

  handlers:
    - name: Restart ssh
      ansible.builtin.service:
        name: ssh
        state: restarted

Why 10-: in sshd_config the first value wins, and on many cloud images a file called 50-cloud-init.conf turns password logins back on. Files are read in alphabetical order, so 10- comes first.

Run it

inventory.ini:

[lab]
lab-vm ansible_host=192.168.56.10 ansible_user=student

First a dry run, which changes nothing and shows the differences:

ansible-playbook -i inventory.ini harden-ssh.yml --check --diff

Then, with a second SSH session open on the VM in case something goes wrong:

ansible-playbook -i inventory.ini harden-ssh.yml

Prove it

ssh -o PubkeyAuthentication=no student@192.168.56.10

must answer Permission denied (publickey). On the VM, sudo sshd -T | grep -Ei 'passwordauth|permitroot|allowgroups|maxauthtries' shows the values in force.

Exercise

All examples