You've already forked ansible-linux-infra
256 lines
7.4 KiB
YAML
256 lines
7.4 KiB
YAML
---
|
|
- name: Include OS-family-specific variables
|
|
ansible.builtin.include_vars: "{{ item }}"
|
|
with_first_found:
|
|
- "{{ ansible_facts['os_family'] }}.yml"
|
|
- "default.yml"
|
|
tags: [cis_hardening, always]
|
|
|
|
- name: Disable unneeded filesystem kernel modules
|
|
ansible.builtin.copy:
|
|
dest: /etc/modprobe.d/cis-disable-filesystems.conf
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
content: |
|
|
# {{ ansible_managed }}
|
|
{% for fs in cis_disable_filesystems %}
|
|
install {{ fs }} /bin/true
|
|
{% endfor %}
|
|
tags: [cis_hardening]
|
|
|
|
- name: Set kernel/network sysctl hardening parameters
|
|
ansible.posix.sysctl:
|
|
name: "{{ item.name }}"
|
|
value: "{{ item.value }}"
|
|
sysctl_set: true
|
|
state: present
|
|
reload: true
|
|
loop:
|
|
- { name: "net.ipv4.ip_forward", value: "0" }
|
|
- { name: "net.ipv4.conf.all.send_redirects", value: "0" }
|
|
- { name: "net.ipv4.conf.all.accept_redirects", value: "0" }
|
|
- { name: "net.ipv4.conf.all.accept_source_route", value: "0" }
|
|
- { name: "net.ipv4.conf.all.log_martians", value: "1" }
|
|
- { name: "net.ipv4.icmp_echo_ignore_broadcasts", value: "1" }
|
|
- { name: "kernel.randomize_va_space", value: "2" }
|
|
- { name: "fs.suid_dumpable", value: "0" }
|
|
tags: [cis_hardening]
|
|
|
|
- name: Enable strict reverse-path filtering (CIS Level 2)
|
|
ansible.posix.sysctl:
|
|
name: "net.ipv4.conf.all.rp_filter"
|
|
value: "1"
|
|
sysctl_set: true
|
|
state: present
|
|
reload: true
|
|
when: cis_level | int >= 2
|
|
tags: [cis_hardening]
|
|
|
|
- name: Harden /tmp mount options (noexec,nosuid,nodev)
|
|
ansible.posix.mount:
|
|
path: /tmp
|
|
src: tmpfs
|
|
fstype: tmpfs
|
|
opts: "defaults,rw,nosuid,nodev,noexec,relatime"
|
|
state: mounted
|
|
tags: [cis_hardening]
|
|
|
|
- name: Bind and harden /var/tmp (CIS Level 2)
|
|
ansible.posix.mount:
|
|
path: /var/tmp
|
|
src: /tmp
|
|
fstype: none
|
|
opts: "bind,nosuid,nodev,noexec"
|
|
state: mounted
|
|
when: cis_level | int >= 2
|
|
tags: [cis_hardening]
|
|
|
|
- name: Disable additional kernel modules (CIS Level 2)
|
|
ansible.builtin.copy:
|
|
dest: /etc/modprobe.d/cis-disable-level2-modules.conf
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
content: |
|
|
# {{ ansible_managed }}
|
|
{% for mod in cis_disable_modules_level2 %}
|
|
install {{ mod }} /bin/true
|
|
{% endfor %}
|
|
when: cis_level | int >= 2
|
|
tags: [cis_hardening]
|
|
|
|
- name: Disable core dumps
|
|
ansible.builtin.copy:
|
|
dest: /etc/security/limits.d/99-cis-disable-coredumps.conf
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
content: |
|
|
# {{ ansible_managed }}
|
|
* hard core 0
|
|
tags: [cis_hardening]
|
|
|
|
- name: Enforce default umask
|
|
ansible.builtin.copy:
|
|
dest: /etc/profile.d/99-cis-umask.sh
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
content: |
|
|
# {{ ansible_managed }}
|
|
umask {{ cis_umask }}
|
|
tags: [cis_hardening]
|
|
|
|
- name: Set shell auto-logout timeout (TMOUT)
|
|
ansible.builtin.copy:
|
|
dest: /etc/profile.d/99-cis-tmout.sh
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
content: |
|
|
# {{ ansible_managed }}
|
|
TMOUT={{ cis_shell_tmout_seconds }}
|
|
readonly TMOUT
|
|
export TMOUT
|
|
tags: [cis_hardening]
|
|
|
|
- name: Mask Ctrl-Alt-Del reboot target
|
|
ansible.builtin.systemd:
|
|
name: ctrl-alt-del.target
|
|
masked: true
|
|
when: cis_disable_ctrl_alt_del | bool
|
|
tags: [cis_hardening]
|
|
|
|
- name: Find world-writable directories missing the sticky bit
|
|
ansible.builtin.shell: >
|
|
set -o pipefail;
|
|
df --local -P | awk '{if (NR!=1) print $6}' |
|
|
xargs -I '{}' find '{}' -xdev -type d \( -perm -0002 -a ! -perm -1000 \) 2>/dev/null
|
|
register: cis_hardening_sticky_bit_dirs
|
|
changed_when: false
|
|
when: cis_sticky_bit_enforce | bool
|
|
tags: [cis_hardening]
|
|
|
|
- name: Apply sticky bit to world-writable directories
|
|
ansible.builtin.file:
|
|
path: "{{ item }}"
|
|
mode: "a+t"
|
|
loop: "{{ cis_hardening_sticky_bit_dirs.stdout_lines | default([]) }}"
|
|
when: cis_sticky_bit_enforce | bool
|
|
tags: [cis_hardening]
|
|
|
|
- name: Configure journald persistent storage and size cap
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/systemd/journald.conf
|
|
regexp: "^#?{{ item.key }}="
|
|
line: "{{ item.key }}={{ item.value }}"
|
|
loop:
|
|
- { key: "Storage", value: "persistent" }
|
|
- { key: "SystemMaxUse", value: "{{ cis_journald_max_use }}" }
|
|
when: cis_journald_persistent | bool
|
|
notify: restart systemd-journald
|
|
tags: [cis_hardening]
|
|
|
|
- name: Schedule weekly report of unowned/ungrouped files
|
|
ansible.builtin.cron:
|
|
name: "Weekly unowned files report"
|
|
weekday: "0"
|
|
hour: "{{ cis_unowned_files_report_cron_hour }}"
|
|
minute: "0"
|
|
job: >-
|
|
/usr/bin/find / -xdev \( -nouser -o -nogroup \) 2>/dev/null |
|
|
/usr/bin/mail -s "Unowned files report {{ inventory_hostname }}" root
|
|
user: root
|
|
when: cis_unowned_files_report_enabled | bool
|
|
tags: [cis_hardening]
|
|
|
|
- name: Harden /boot mount options in fstab (requires manual review and reboot)
|
|
ansible.builtin.replace:
|
|
path: /etc/fstab
|
|
regexp: '^(\S+\s+/boot\s+\S+\s+)(?!.*nodev)(\S+)(\s+.*)$'
|
|
replace: '\1\2,nodev,nosuid\3'
|
|
when: cis_boot_hardening_enabled | bool
|
|
tags: [cis_hardening]
|
|
|
|
- name: Deploy baseline auditd rules (logins, time changes, account changes)
|
|
ansible.builtin.template:
|
|
src: audit-baseline.rules.j2
|
|
dest: /etc/audit/rules.d/10-baseline.rules
|
|
owner: root
|
|
group: root
|
|
mode: "0640"
|
|
notify: reload auditd rules
|
|
tags: [cis_hardening]
|
|
|
|
- name: Deploy extended auditd rules (CIS Level 2)
|
|
ansible.builtin.template:
|
|
src: audit-level2.rules.j2
|
|
dest: /etc/audit/rules.d/20-level2.rules
|
|
owner: root
|
|
group: root
|
|
mode: "0640"
|
|
when: cis_level | int >= 2
|
|
notify: reload auditd rules
|
|
tags: [cis_hardening]
|
|
|
|
- name: Configure auditd log rotation and disk-space handling
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/audit/auditd.conf
|
|
regexp: "^{{ item.key }}\\s*="
|
|
line: "{{ item.key }} = {{ item.value }}"
|
|
loop:
|
|
- { key: "max_log_file", value: "50" }
|
|
- { key: "max_log_file_action", value: "rotate" }
|
|
- { key: "num_logs", value: "10" }
|
|
- { key: "space_left", value: "10%" }
|
|
- { key: "space_left_action", value: "email" }
|
|
- { key: "admin_space_left", value: "5%" }
|
|
- { key: "admin_space_left_action", value: "halt" }
|
|
notify: restart auditd
|
|
tags: [cis_hardening]
|
|
|
|
- name: Set login.defs password aging policy
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/login.defs
|
|
regexp: "^{{ item.key }}"
|
|
line: "{{ item.key }}\t{{ item.value }}"
|
|
loop:
|
|
- { key: "PASS_MAX_DAYS", value: "90" }
|
|
- { key: "PASS_MIN_DAYS", value: "1" }
|
|
- { key: "PASS_WARN_AGE", value: "7" }
|
|
tags: [cis_hardening]
|
|
|
|
- name: Restrict cron/at to authorized users
|
|
ansible.builtin.file:
|
|
path: "{{ item }}"
|
|
state: touch
|
|
owner: root
|
|
group: root
|
|
mode: "0600"
|
|
loop:
|
|
- /etc/cron.allow
|
|
- /etc/at.allow
|
|
tags: [cis_hardening]
|
|
|
|
- name: Configure GRUB bootloader password (pre-generated PBKDF2 hash)
|
|
ansible.builtin.blockinfile:
|
|
path: /etc/grub.d/40_custom
|
|
marker: "# {mark} ANSIBLE MANAGED BLOCK"
|
|
insertafter: "EOF"
|
|
block: |
|
|
set superusers="{{ grub_bootloader_username }}"
|
|
password_pbkdf2 {{ grub_bootloader_username }} {{ grub_bootloader_password_hash }}
|
|
when:
|
|
- cis_grub_password_enabled | bool
|
|
- grub_bootloader_password_hash | length > 0
|
|
notify: regenerate grub config
|
|
tags: [cis_hardening]
|
|
|
|
- name: Enable and start auditd
|
|
ansible.builtin.systemd:
|
|
name: auditd
|
|
enabled: true
|
|
state: started
|
|
tags: [cis_hardening]
|