Ansible quickstart for secure baselines (idempotent and testable)

Outcome: apply your SSHD/PAM/fail2ban defaults across hosts safely, with check/diff runs and a skeleton for tests.

1) Layout

baseline/
├─ inventory.yaml
├─ site.yaml
└─ roles/
   └─ hardening/
      ├─ tasks/main.yaml
      ├─ templates/sshd_config.j2
      └─ files/sudoers_logging

2) Inventory

# inventory.yaml
all:
  hosts:
    web1.example.com:
    db1.example.com:
  vars:
    ansible_user: admin

3) Playbook

# site.yaml
- hosts: all
  become: true
  roles:
    - hardening

4) Role tasks (extract)

# roles/hardening/tasks/main.yaml
- name: Install packages
  package:
    name: [fail2ban, auditd]
    state: present

- name: SSHD config
  template:
    src: sshd_config.j2
    dest: /etc/ssh/sshd_config
    owner: root
    group: root
    mode: '0644'
  notify: restart ssh

- name: Sudo logging
  copy:
    src: sudoers_logging
    dest: /etc/sudoers.d/logging
    owner: root
    group: root
    mode: '0440'
  notify: validate sudoers

- name: Ensure journald persistent
  file:
    path: /var/log/journal
    state: directory
    owner: root
    group: systemd-journal
    mode: '2755'

handlers:
  - name: restart ssh
    service: { name: ssh, state: reloaded }
  - name: validate sudoers
    command: visudo -c

5) Run modes

# Dry run
ansible-playbook -i inventory.yaml site.yaml --check

# See changes
ansible-playbook -i inventory.yaml site.yaml --diff

# Apply for real
ansible-playbook -i inventory.yaml site.yaml

6) Minimal test (Molecule optional)

At least validate SSH is reachable and password auth is disabled post-run. Add Molecule later if you want full CI.

Want a production-grade baseline role with CI tests? Request a call.