Ansible Security Hardening

Hardening means reducing the ways a system can be attacked. A new server ships with extra services, loose settings, and default accounts. Each one adds risk. Doing the work by hand across fifty servers invites mistakes, and Ansible applies the same safe settings everywhere in minutes. Imagine locking every door and window in an apartment block with a single master checklist: nothing gets skipped, and the result is easy to verify.

Two Security Jobs

Security with Ansible covers two areas. The first area protects the automation itself, including keys, passwords, and access. The second area uses Ansible to harden the servers it manages.

Diagram: Layers of Protection

  ┌────────────────────────────────────────────┐
  │ Layer 4: Monitoring and audit              │
  │  ┌──────────────────────────────────────┐  │
  │  │ Layer 3: Services and firewall       │  │
  │  │  ┌────────────────────────────────┐  │  │
  │  │  │ Layer 2: SSH and user accounts │  │  │
  │  │  │  ┌──────────────────────────┐  │  │  │
  │  │  │  │ Layer 1: OS updates      │  │  │  │
  │  │  │  └──────────────────────────┘  │  │  │
  │  │  └────────────────────────────────┘  │  │
  │  └──────────────────────────────────────┘  │
  └────────────────────────────────────────────┘

Protect the Automation

  • Encrypt passwords and tokens with Ansible Vault
  • Use SSH keys with a passphrase and an agent instead of passwords
  • Create a dedicated automation account with limited sudo rights
  • Add no_log: true to tasks that handle secrets so output hides sensitive values
  • Keep vault password files out of version control
- name: Set the database password
  community.mysql.mysql_user:
    name: shop
    password: "{{ vault_db_password }}"
  no_log: true

Harden SSH

- name: Apply safe SSH settings
  hosts: all
  become: true
  tasks:
    - name: Apply sshd options
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        regexp: "^#?{{ item.key }}"
        line: "{{ item.key }} {{ item.value }}"
        validate: /usr/sbin/sshd -t -f %s
      loop:
        - { key: PermitRootLogin, value: "no" }
        - { key: PasswordAuthentication, value: "no" }
        - { key: MaxAuthTries, value: "3" }
        - { key: X11Forwarding, value: "no" }
      notify: Restart sshd

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

The validate option tests the new file before Ansible saves it. A syntax mistake never locks administrators out. Keep a second terminal session open during the first rollout as a safety net.

Configure a Firewall

- name: Allow only needed ports
  community.general.ufw:
    rule: allow
    port: "{{ item }}"
    proto: tcp
  loop: ['22', '80', '443']

- name: Deny everything else
  community.general.ufw:
    state: enabled
    default: deny
    direction: incoming

Order matters. Add the SSH allow rule before enabling the deny default, or the connection drops.

Manage Accounts and Updates

- name: Lock an unused account
  ansible.builtin.user:
    name: olduser
    password_lock: true
    shell: /usr/sbin/nologin

- name: Enable automatic security updates
  ansible.builtin.package:
    name: unattended-upgrades
    state: present

Remove Risky Software

- name: Remove legacy network tools
  ansible.builtin.package:
    name:
      - telnet
      - rsh-server
    state: absent

Common Hardening Targets

AreaAction
LoginDisable root and password logins over SSH
NetworkOpen only required ports
SoftwareRemove unused packages and services
FilesSet strict permissions on sensitive folders
KernelTune sysctl network settings
AuditEnable logging with auditd

Use Published Hardening Roles

The community maintains roles that follow benchmarks such as CIS and DISA STIG. Search Ansible Galaxy for hardening and review the role code before use. Run the role in check mode against a test machine to preview every change.

ansible-playbook harden.yml --check --diff

Try This

Write a playbook that disables root SSH login on a lab VM with the validate option. Run the playbook in check mode and read the diff. Run the playbook for real and confirm that sshd -T | grep permitrootlogin reports no.

Summary

Security hardening with Ansible covers the automation setup and the managed servers. Vault, SSH keys, limited sudo, and no_log protect secrets. Playbooks apply safe SSH settings, firewall rules, account controls, and software removal in a repeatable way. Check mode, validation, and test machines reduce the risk of a lockout.