754 lines
26 KiB
YAML
754 lines
26 KiB
YAML
---
|
||
- name: Verify
|
||
hosts: all
|
||
any_errors_fatal: true
|
||
|
||
tasks:
|
||
- name: Reboot host
|
||
become: true
|
||
ansible.builtin.reboot:
|
||
|
||
- name: Wait for the host and reconnect
|
||
ansible.builtin.wait_for:
|
||
port: 22
|
||
host: '{{ (ansible_ssh_host | default(ansible_host)) | default(inventory_hostname) }}'
|
||
delay: 10
|
||
timeout: 120
|
||
|
||
- name: Include default vars
|
||
ansible.builtin.include_vars:
|
||
dir: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/defaults/"
|
||
extensions:
|
||
- 'yml'
|
||
|
||
- name: Include host vars
|
||
ansible.builtin.include_vars:
|
||
file: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/inventory/host_vars/{{ ansible_hostname }}"
|
||
|
||
- name: Set sysctl configuration directory as fact
|
||
tags:
|
||
- fact
|
||
- sysctl
|
||
block:
|
||
- name: Stat /usr/lib/sysctl.d/ exists
|
||
ansible.builtin.stat:
|
||
path: "/usr/lib/sysctl.d/"
|
||
register: usr_lib_sysctl_d
|
||
|
||
- name: Set sysctl fact
|
||
ansible.builtin.set_fact:
|
||
sysctl_conf_dir: "{{ '/usr/lib/sysctl.d' if usr_lib_sysctl_d.stat.exists else '/etc/sysctl.d' }}"
|
||
|
||
- name: Debug sysctl
|
||
ansible.builtin.debug:
|
||
msg: "{{ sysctl_conf_dir }}"
|
||
|
||
- name: Get installed ssh version
|
||
ansible.builtin.command:
|
||
cmd: ssh -V
|
||
changed_when: false
|
||
failed_when: false
|
||
register: ssh_version
|
||
tags:
|
||
- sshd
|
||
- sshd_config
|
||
|
||
- name: Set ssh version as fact
|
||
ansible.builtin.set_fact:
|
||
ssh_installed_version: "{{ ssh_version.stderr | regex_search('^OpenSSH_([0-9+].[0-9]+)', '\\1') | join('.') | float }}" # noqa jinja[spacing]
|
||
tags:
|
||
- sshd
|
||
- sshd_config
|
||
|
||
- name: Stat IPv6 status
|
||
become: true
|
||
ansible.builtin.stat:
|
||
path: /proc/sys/net/ipv6
|
||
register: stat_ipv6
|
||
|
||
- name: Set IPv6 fact
|
||
ansible.builtin.set_fact:
|
||
system_has_ipv6: "{{ stat_ipv6.stat.exists }}"
|
||
|
||
- name: Update current facts
|
||
ansible.builtin.setup: ~
|
||
|
||
- name: Verify auditd configuration
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
dest: /etc/audit/auditd.conf
|
||
line: "{{ item }}"
|
||
state: present
|
||
check_mode: true
|
||
register: auditd_conf
|
||
failed_when: auditd_conf is changed
|
||
with_items:
|
||
- action_mail_acct = {{ auditd_action_mail_acct }}
|
||
- admin_space_left_action = {{ auditd_admin_space_left_action }}
|
||
- disk_error_action = {{ auditd_disk_error_action }}
|
||
- disk_full_action = {{ auditd_disk_full_action }}
|
||
- max_log_file = {{ auditd_max_log_file }}
|
||
- max_log_file_action = {{ auditd_max_log_file_action }}
|
||
- name_format = hostname
|
||
- num_logs = {{ auditd_num_logs }}
|
||
- space_left = {{ auditd_space_left }}
|
||
- space_left_action = {{ auditd_space_left_action }}
|
||
|
||
- name: Verify systemd system.conf
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
dest: /etc/systemd/system.conf
|
||
line: "{{ item }}"
|
||
state: present
|
||
check_mode: true
|
||
register: systemd_system_conf
|
||
failed_when: systemd_system_conf is changed
|
||
with_items:
|
||
- DumpCore=no
|
||
- CrashShell=no
|
||
- CtrlAltDelBurstAction=none
|
||
- DefaultLimitCORE=0
|
||
- DefaultLimitNOFILE={{ limit_nofile_hard }}
|
||
- DefaultLimitNPROC={{ limit_nproc_hard }}
|
||
|
||
- name: Verify systemd user.conf
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
dest: /etc/systemd/user.conf
|
||
line: "{{ item }}"
|
||
state: present
|
||
check_mode: true
|
||
register: systemd_user_conf
|
||
failed_when: systemd_user_conf is changed
|
||
with_items:
|
||
- DefaultLimitCORE=0
|
||
- DefaultLimitNOFILE={{ limit_nofile_hard }}
|
||
- DefaultLimitNPROC={{ limit_nproc_hard }}
|
||
|
||
- name: Verify postfix configuration
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
dest: /etc/postfix/main.cf
|
||
line: "{{ item }}"
|
||
state: present
|
||
check_mode: true
|
||
register: postfix_conf
|
||
failed_when: postfix_conf is changed
|
||
with_items:
|
||
- disable_vrfy_command = yes
|
||
- inet_interfaces = loopback-only
|
||
- smtpd_banner = \$myhostname - ESMTP
|
||
- smtpd_client_restrictions = permit_mynetworks,reject
|
||
|
||
- name: Stat /etc/ssh/sshd_config
|
||
ansible.builtin.stat:
|
||
path: '/etc/ssh/sshd_config'
|
||
register: sshd_config_file
|
||
|
||
- name: Stat /etc/ssh/ssh_config
|
||
ansible.builtin.stat:
|
||
path: '/etc/ssh/ssh_config'
|
||
register: ssh_config_file
|
||
|
||
- name: Stat /etc/ssh/sshd_config.d/01-hardening.conf
|
||
become: true
|
||
ansible.builtin.stat:
|
||
path: '/etc/ssh/sshd_config.d/01-hardening.conf'
|
||
register: sshd_config_directory
|
||
|
||
- name: Assert /etc/ssh/ssh_config permissions
|
||
ansible.builtin.assert:
|
||
that:
|
||
- ssh_config_file.stat.mode == "0644"
|
||
success_msg: "{{ ssh_config_file.stat.path }} has correct permissions: {{ ssh_config_file.stat.mode }}"
|
||
fail_msg: "{{ ssh_config_file.stat.path }} permissions are incorrect: {{ ssh_config_file.stat.mode }}"
|
||
|
||
- name: Assert /etc/ssh/sshd_config permissions
|
||
ansible.builtin.assert:
|
||
that:
|
||
- sshd_config_file.stat.mode == "0600"
|
||
success_msg: "{{ sshd_config_file.stat.path }} has correct permissions: {{ sshd_config_file.stat.mode }}"
|
||
fail_msg: "{{ sshd_config_file.stat.path }} permissions are incorrect: {{ sshd_config_file.stat.mode }}"
|
||
|
||
- name: Assert /etc/ssh/sshd_config.d/01-hardening.conf permissions
|
||
ansible.builtin.assert:
|
||
that:
|
||
- sshd_config_directory.stat.mode == "0600"
|
||
success_msg: "{{ sshd_config_directory.stat.path }} has correct permissions: {{ sshd_config_directory.stat.mode }}"
|
||
fail_msg: "{{ sshd_config_directory.stat.path }} permissions are incorrect: {{ sshd_config_directory.stat.mode }}"
|
||
when: sshd_config_directory.stat.exists
|
||
|
||
- name: Verify sshd_config PermitRootLogin configuration
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
dest: /etc/ssh/sshd_config
|
||
line: "PermitRootLogin yes"
|
||
state: absent
|
||
check_mode: true
|
||
register: sshd_config
|
||
failed_when: sshd_config is changed
|
||
|
||
- name: Verify sshd_config.d PermitRootLogin configuration
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
dest: /etc/ssh/sshd_config.d/01-hardening.conf
|
||
line: "PermitRootLogin yes"
|
||
state: absent
|
||
check_mode: true
|
||
register: sshd_config_d
|
||
failed_when: sshd_config_d is changed
|
||
when: sshd_config_directory.stat.exists
|
||
|
||
- name: Verify sshd_config configuration
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
dest: /etc/ssh/sshd_config
|
||
line: "{{ item }}"
|
||
state: present
|
||
check_mode: true
|
||
register: sshd_config
|
||
failed_when: sshd_config is changed
|
||
with_items:
|
||
- AllowGroups vagrant sudo
|
||
- AllowAgentForwarding {{ sshd_allow_agent_forwarding }}
|
||
- AllowTcpForwarding {{ sshd_allow_tcp_forwarding }}
|
||
- AuthenticationMethods {{ sshd_authentication_methods }}
|
||
- Banner {{ sshd_banner }}
|
||
- ChallengeResponseAuthentication {{ sshd_challenge_response_authentication }}
|
||
- Ciphers {{ sshd_ciphers }}
|
||
- ClientAliveCountMax {{ sshd_client_alive_count_max | int }}
|
||
- ClientAliveInterval {{ sshd_client_alive_interval | int }}
|
||
- Compression {{ sshd_compression }}
|
||
- GSSAPIAuthentication {{ sshd_gssapi_authentication }}
|
||
- HostbasedAuthentication {{ sshd_hostbased_authentication }}
|
||
- IgnoreUserKnownHosts {{ sshd_ignore_user_known_hosts }}
|
||
- KerberosAuthentication {{ sshd_kerberos_authentication }}
|
||
- HostKeyAlgorithms {{ sshd_host_key_algorithms }}
|
||
- KexAlgorithms {{ sshd_kex_algorithms }}
|
||
- LogLevel {{ sshd_log_level }}
|
||
- LoginGraceTime {{ sshd_login_grace_time | int }}
|
||
- Macs {{ sshd_macs }}
|
||
- MaxAuthTries {{ sshd_max_auth_tries | int }}
|
||
- MaxSessions {{ sshd_max_sessions | int }}
|
||
- MaxStartups {{ sshd_max_startups }}
|
||
- PasswordAuthentication {{ sshd_password_authentication }}
|
||
- PermitEmptyPasswords {{ sshd_permit_empty_passwords }}
|
||
- PermitRootLogin {{ sshd_permit_root_login }}
|
||
- PermitUserEnvironment {{ sshd_permit_user_environment }}
|
||
- Port {{ sshd_port | int }}
|
||
- PrintLastLog {{ sshd_print_last_log }}
|
||
- PrintMotd {{ sshd_print_motd }}
|
||
- RekeyLimit {{ sshd_rekey_limit }}
|
||
- StrictModes {{ sshd_strict_modes }}
|
||
- TCPKeepAlive {{ sshd_tcp_keep_alive }}
|
||
- UseDNS {{ sshd_use_dns }}
|
||
- UsePAM {{ sshd_use_pam }}
|
||
- X11Forwarding {{ sshd_x11_forwarding }}
|
||
when: not sshd_config_directory.stat.exists
|
||
|
||
- name: Verify sshd_config.d configuration
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
dest: /etc/ssh/sshd_config.d/01-hardening.conf
|
||
line: "{{ item }}"
|
||
state: present
|
||
check_mode: true
|
||
register: sshd_config
|
||
failed_when: sshd_config is changed
|
||
with_items:
|
||
- AllowGroups vagrant sudo
|
||
- AllowAgentForwarding {{ sshd_allow_agent_forwarding }}
|
||
- AllowTcpForwarding {{ sshd_allow_tcp_forwarding }}
|
||
- AuthenticationMethods {{ sshd_authentication_methods }}
|
||
- Banner {{ sshd_banner }}
|
||
- ChallengeResponseAuthentication {{ sshd_challenge_response_authentication }}
|
||
- Ciphers {{ sshd_ciphers }}
|
||
- ClientAliveCountMax {{ sshd_client_alive_count_max | int }}
|
||
- ClientAliveInterval {{ sshd_client_alive_interval | int }}
|
||
- Compression {{ sshd_compression }}
|
||
- GSSAPIAuthentication {{ sshd_gssapi_authentication }}
|
||
- HostbasedAuthentication {{ sshd_hostbased_authentication }}
|
||
- IgnoreUserKnownHosts {{ sshd_ignore_user_known_hosts }}
|
||
- KerberosAuthentication {{ sshd_kerberos_authentication }}
|
||
- HostKeyAlgorithms {{ sshd_host_key_algorithms }}
|
||
- KexAlgorithms {{ sshd_kex_algorithms }}
|
||
- LogLevel {{ sshd_log_level }}
|
||
- LoginGraceTime {{ sshd_login_grace_time | int }}
|
||
- Macs {{ sshd_macs }}
|
||
- MaxAuthTries {{ sshd_max_auth_tries | int }}
|
||
- MaxSessions {{ sshd_max_sessions | int }}
|
||
- MaxStartups {{ sshd_max_startups }}
|
||
- PasswordAuthentication {{ sshd_password_authentication }}
|
||
- PermitEmptyPasswords {{ sshd_permit_empty_passwords }}
|
||
- PermitRootLogin {{ sshd_permit_root_login }}
|
||
- PermitUserEnvironment {{ sshd_permit_user_environment }}
|
||
- Port {{ sshd_port | int }}
|
||
- PrintLastLog {{ sshd_print_last_log }}
|
||
- PrintMotd {{ sshd_print_motd }}
|
||
- RekeyLimit {{ sshd_rekey_limit }}
|
||
- StrictModes {{ sshd_strict_modes }}
|
||
- Subsystem {{ sshd_subsystem }}
|
||
- TCPKeepAlive {{ sshd_tcp_keep_alive }}
|
||
- UseDNS {{ sshd_use_dns }}
|
||
- UsePAM {{ sshd_use_pam }}
|
||
- X11Forwarding {{ sshd_x11_forwarding }}
|
||
when: sshd_config_directory.stat.exists
|
||
|
||
- name: Verify sshd RequiredRSASize
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
dest: /etc/ssh/sshd_config.d/01-hardening.conf
|
||
line: "RequiredRSASize {{ sshd_required_rsa_size }}"
|
||
state: present
|
||
check_mode: true
|
||
register: sshd_config_rsasize
|
||
failed_when: sshd_config_rsasize is changed
|
||
when: sshd_config_directory.stat.exists and ssh_installed_version is version('9.1', '>')
|
||
|
||
- name: Verify sshd runtime configuration
|
||
become: true
|
||
environment:
|
||
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||
ansible.builtin.command: sshd -T
|
||
register: sshd_config
|
||
changed_when: false
|
||
failed_when: item not in sshd_config.stdout_lines
|
||
with_items:
|
||
- allowgroups sudo
|
||
- allowgroups vagrant
|
||
- allowagentforwarding {{ sshd_allow_agent_forwarding }}
|
||
- allowtcpforwarding {{ sshd_allow_tcp_forwarding }}
|
||
- authenticationmethods {{ sshd_authentication_methods }}
|
||
- banner {{ sshd_banner }}
|
||
- clientalivecountmax {{ sshd_client_alive_count_max | int }}
|
||
- clientaliveinterval {{ sshd_client_alive_interval | int }}
|
||
- compression {{ sshd_compression }}
|
||
- logingracetime {{ sshd_login_grace_time | int }}
|
||
- macs {{ sshd_macs }}
|
||
- maxauthtries {{ sshd_max_auth_tries | int }}
|
||
- maxsessions {{ sshd_max_sessions | int }}
|
||
- maxstartups {{ sshd_max_startups }}
|
||
- permitrootlogin {{ sshd_permit_root_login }}
|
||
- port {{ sshd_port | int }}
|
||
- subsystem {{ sshd_subsystem }}
|
||
- usedns {{ sshd_use_dns }}
|
||
- usepam {{ sshd_use_pam }}
|
||
- x11forwarding {{ sshd_x11_forwarding }}
|
||
|
||
- name: Verify ssh_config configuration
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
dest: /etc/ssh/ssh_config
|
||
line: " {{ item }}"
|
||
state: present
|
||
check_mode: true
|
||
register: ssh_config
|
||
failed_when: ssh_config is changed
|
||
with_items:
|
||
- Ciphers {{ sshd_ciphers }}
|
||
- GSSAPIAuthentication {{ sshd_gssapi_authentication }}
|
||
- HashKnownHosts yes
|
||
- HostKeyAlgorithms {{ sshd_host_key_algorithms }}
|
||
- KexAlgorithms {{ sshd_kex_algorithms }}
|
||
- MACs {{ sshd_macs }}
|
||
- RekeyLimit {{ sshd_rekey_limit }}
|
||
|
||
- name: Merge sysctl settings
|
||
ansible.builtin.set_fact:
|
||
sysctl_settings: "{{ generic_sysctl_settings | combine(ipv4_sysctl_settings) }}"
|
||
|
||
- name: Verify sysctl configuration
|
||
become: true
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
grep -R "^{{ item.key }}.*{{ item.value | int }}$" "{{ sysctl_conf_dir }}/"
|
||
args:
|
||
executable: /bin/bash
|
||
with_dict: "{{ sysctl_settings | dict2items | rejectattr('key', 'search', 'nf_conntrack') | items2dict }}"
|
||
register: sysctl_file_config
|
||
failed_when: sysctl_file_config.rc != 0
|
||
changed_when: sysctl_file_config.rc != 0
|
||
|
||
- name: Verify sysctl runtime configuration
|
||
become: true
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
sysctl -a | grep "^{{ item.key }}.*{{ item.value | int }}$"
|
||
args:
|
||
executable: /bin/bash
|
||
with_dict: "{{ sysctl_settings | dict2items | rejectattr('key', 'search', 'nf_conntrack') | items2dict }}"
|
||
register: sysctl_runtime_config
|
||
failed_when: sysctl_runtime_config.rc != 0
|
||
changed_when: sysctl_runtime_config.rc != 0
|
||
|
||
- name: Stat crypto-policies config
|
||
become: true
|
||
ansible.builtin.stat:
|
||
path: /etc/crypto-policies/config
|
||
register: crypto_policies_config
|
||
|
||
- name: Get crypto-policies value
|
||
environment:
|
||
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||
ansible.builtin.shell: grep "^{{ crypto_policy | upper }}$" /etc/crypto-policies/config
|
||
register: crypto_policy_set
|
||
when: crypto_policies_config.stat.exists
|
||
failed_when: crypto_policy_set.rc != 0
|
||
changed_when: crypto_policy_set.rc != 0
|
||
|
||
- name: Verify noexec /dev/shm
|
||
ansible.builtin.shell: grep '^tmpfs\s/dev/shm.*noexec' /proc/mounts
|
||
register: dev_shm_noexec
|
||
failed_when: dev_shm_noexec.rc != 0
|
||
changed_when: dev_shm_noexec.rc != 0
|
||
|
||
- name: Verify /proc
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
grep -E '^proc\s/proc proc rw,nosuid,nodev,noexec,relatime.*hidepid=({{ hide_pid }}|invisible)' /proc/mounts
|
||
args:
|
||
executable: /bin/bash
|
||
register: proc_opts
|
||
failed_when: proc_opts.rc != 0
|
||
changed_when: proc_opts.rc != 0
|
||
tags:
|
||
- skip_ansible_lint
|
||
|
||
- name: Verify tmp.mount
|
||
become: true
|
||
ansible.builtin.systemd:
|
||
name: tmp.mount
|
||
register: tmp_mount
|
||
failed_when: not 'nosuid,nodev,noexec' in tmp_mount.status.Options
|
||
changed_when: not 'nosuid,nodev,noexec' in tmp_mount.status.Options
|
||
|
||
- name: Verify /tmp
|
||
become: true
|
||
ansible.builtin.shell: grep '^tmpfs\s/tmp\s.*nosuid,nodev,noexec' /proc/mounts
|
||
register: mounts_tmp
|
||
failed_when: mounts_tmp.rc != 0
|
||
changed_when: mounts_tmp.rc != 0
|
||
|
||
- name: Verify login.defs settings
|
||
become: true
|
||
ansible.builtin.shell: grep "^{{ item }}$" /etc/login.defs
|
||
register: login_defs
|
||
failed_when: login_defs.rc != 0
|
||
changed_when: login_defs.rc != 0
|
||
with_items:
|
||
- ENCRYPT_METHOD SHA512
|
||
- FAILLOG_ENAB yes
|
||
- LOG_OK_LOGINS yes
|
||
- PASS_MAX_DAYS 60
|
||
- PASS_MIN_DAYS 1
|
||
- PASS_WARN_AGE 7
|
||
- SHA_CRYPT_MAX_ROUNDS 65536
|
||
- SHA_CRYPT_MIN_ROUNDS 10000
|
||
- SU_NAME su
|
||
- SYSLOG_SG_ENAB yes
|
||
- SYSLOG_SU_ENAB yes
|
||
- UMASK {{ umask_value }}
|
||
|
||
- name: Verify pwquality.conf settings
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
path: /etc/security/pwquality.conf
|
||
line: "{{ item.key }} = {{ item.value }}"
|
||
state: present
|
||
mode: "0644"
|
||
owner: root
|
||
group: root
|
||
check_mode: true
|
||
register: pwquality_conf
|
||
failed_when: pwquality_conf is changed
|
||
with_dict: "{{ pwquality_config }}"
|
||
|
||
- name: Verify RedHat GRUB audit settings
|
||
become: true
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
grubby --info="/boot/vmlinuz-$(uname -r)" | grep "^args.*{{ grub_audit_cmdline }} {{ grub_audit_backlog_cmdline }}"
|
||
register: audit_grubenv
|
||
failed_when: audit_grubenv.rc != 0
|
||
changed_when: audit_grubenv.rc != 0
|
||
when: ansible_os_family == "RedHat"
|
||
|
||
- name: Verify Debian audit GRUB settings
|
||
become: true
|
||
ansible.builtin.shell: grep "linux.*{{ grub_audit_cmdline }} {{ grub_audit_backlog_cmdline }}" /boot/grub/grub.cfg
|
||
register: audit_grub_cfg
|
||
failed_when: audit_grub_cfg.rc != 0
|
||
changed_when: audit_grub_cfg.rc != 0
|
||
when: ansible_os_family == "Debian"
|
||
|
||
- name: Verify RedHat GRUB IPv6 settings
|
||
become: true
|
||
ansible.builtin.shell:
|
||
cmd: |
|
||
set -o pipefail
|
||
grubby --info="/boot/vmlinuz-$(uname -r)" | grep "ipv6.disable=1"
|
||
register: audit_grubenv
|
||
failed_when: audit_grubenv.rc != 0
|
||
changed_when: audit_grubenv.rc != 0
|
||
when: ansible_os_family == "RedHat" and disable_ipv6
|
||
|
||
- name: Verify Debian GRUB IPv6 settings
|
||
become: true
|
||
ansible.builtin.shell:
|
||
cmd: grep "linux.*ipv6.disable=1" /boot/grub/grub.cfg
|
||
register: audit_grub_cfg
|
||
failed_when: audit_grub_cfg.rc != 0
|
||
changed_when: audit_grub_cfg.rc != 0
|
||
when: ansible_os_family == "Debian" and disable_ipv6
|
||
|
||
- name: Verify IPv6 sysctl configuration
|
||
become: true
|
||
ansible.builtin.shell: grep -R "^{{ item }}$" /etc/sysctl.* /usr/lib/sysctl.d/*
|
||
register: sysctl_ipv6_config
|
||
failed_when: sysctl_ipv6_config.rc != 0
|
||
changed_when: sysctl_ipv6_config.rc != 0
|
||
with_items:
|
||
- net.ipv6.conf.all.disable_ipv6=1
|
||
- net.ipv6.conf.default.disable_ipv6=1
|
||
when: disable_ipv6
|
||
|
||
- name: Verify IPv6 sysctl runtime configuration
|
||
environment:
|
||
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||
become: true
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
sysctl -a | grep "^{{ item.key }}.*{{ item.value | int }}$"
|
||
args:
|
||
executable: /bin/bash
|
||
with_dict: "{{ ipv6_disable_sysctl_settings }}"
|
||
register: sysctl_ipv6
|
||
changed_when: sysctl_ipv6.rc != 0
|
||
failed_when: sysctl_ipv6.rc != 0
|
||
when: system_has_ipv6 and disable_ipv6
|
||
|
||
- name: Find GRUB config files
|
||
become: true
|
||
ansible.builtin.find:
|
||
paths: /boot
|
||
patterns: "*.cfg,grubenv"
|
||
recurse: true
|
||
register: perm_grub_cfg
|
||
|
||
- name: Verify GRUB config files permission
|
||
become: true
|
||
ansible.builtin.stat:
|
||
path: "{{ item.path }}"
|
||
changed_when: item.mode | int > 644
|
||
failed_when: item.mode | int > 644
|
||
with_items:
|
||
- "{{ perm_grub_cfg.files | reject('search', '/boot/efi/EFI/ubuntu/grub.cfg') | list }}"
|
||
loop_control:
|
||
label: "{{ item.path }}"
|
||
|
||
- name: Verify systemd resolved.conf
|
||
become: true
|
||
ansible.builtin.shell: grep "^{{ item }}$" /etc/systemd/resolved.conf
|
||
register: systemd_resolved_conf
|
||
failed_when: systemd_resolved_conf.rc != 0
|
||
changed_when: systemd_resolved_conf.rc != 0
|
||
with_items:
|
||
- DNS={{ dns }}
|
||
- FallbackDNS={{ fallback_dns }}
|
||
- DNSSEC={{ dnssec }}
|
||
- DNSOverTLS={{ dns_over_tls }}
|
||
|
||
- name: Verify systemd timesyncd.conf
|
||
become: true
|
||
ansible.builtin.shell: grep "^{{ item }}$" /etc/systemd/timesyncd.conf
|
||
register: systemd_timesyncd_conf
|
||
failed_when: systemd_timesyncd_conf.rc != 0
|
||
changed_when: systemd_timesyncd_conf.rc != 0
|
||
with_items:
|
||
- NTP={{ ntp }}
|
||
- FallbackNTP={{ fallback_ntp }}
|
||
|
||
- name: Stat /etc/default/motd-news
|
||
ansible.builtin.stat:
|
||
path: /etc/default/motd-news
|
||
register: motd_news
|
||
|
||
- name: Verify masked motdnews service
|
||
become: true
|
||
ansible.builtin.systemd:
|
||
name: motd-news.service
|
||
masked: true
|
||
enabled: false
|
||
state: stopped
|
||
check_mode: true
|
||
register: motdnews_service
|
||
failed_when: motdnews_service is changed
|
||
when: ansible_os_family == "Debian" and motd_news.stat.exists
|
||
|
||
- name: Stat /usr/bin/pro
|
||
ansible.builtin.stat:
|
||
path: /usr/bin/pro
|
||
register: ubuntu_advantage_pro
|
||
when: ansible_os_family == "Debian"
|
||
|
||
- name: Verify that apt_news is disabled
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
pro config show | grep '^apt_news.*False'
|
||
args:
|
||
executable: /bin/bash
|
||
register: ubuntu_advantage_pro_state
|
||
changed_when: ubuntu_advantage_pro_state.rc != 0
|
||
failed_when: ubuntu_advantage_pro_state.rc != 0
|
||
when: ansible_os_family == "Debian" and ubuntu_advantage_pro.stat.exists
|
||
|
||
- name: Efi fact
|
||
ansible.builtin.set_fact:
|
||
booted_with_efi: "{{ ansible_mounts | selectattr('mount', 'equalto', '/boot/efi') | list | length > 0 }}"
|
||
|
||
- name: Verify cracklib password list
|
||
environment:
|
||
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
grep '/usr/share/dict/passwords' /var/cache/cracklib/src-dicts
|
||
args:
|
||
executable: /bin/bash
|
||
register: cracklib_passwords
|
||
failed_when: cracklib_passwords.rc != 0
|
||
changed_when: cracklib_passwords.rc != 0
|
||
when: ansible_os_family == "Debian"
|
||
|
||
- name: Index blacklisted kernel modules
|
||
environment:
|
||
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
modprobe -c | grep -o '^blacklist .*' | awk '{print $2}'
|
||
args:
|
||
executable: /bin/bash
|
||
changed_when: false
|
||
failed_when: modprobe_blacklist.rc != 0
|
||
register: modprobe_blacklist
|
||
when: block_blacklisted | bool
|
||
|
||
- name: Verify blocked blacklisted kernel modules
|
||
environment:
|
||
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
grep 'install {{ item }} /bin/true' /etc/modprobe.d/blockblacklisted.conf
|
||
args:
|
||
executable: /bin/bash
|
||
register: modprobe_blockblacklisted
|
||
failed_when: modprobe_blockblacklisted.rc != 0
|
||
changed_when: modprobe_blockblacklisted.rc != 0
|
||
with_items:
|
||
- "{{ modprobe_blacklist.stdout_lines | sort }}"
|
||
when: block_blacklisted | bool
|
||
|
||
- name: Verify sudo settings
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
sudo -l | grep "{{ item }}"
|
||
register: sudo_settings
|
||
failed_when: sudo_settings.rc != 0
|
||
changed_when: sudo_settings.rc != 0
|
||
args:
|
||
executable: /bin/bash
|
||
with_items:
|
||
- 'use_pty'
|
||
- 'logfile="/var/log/sudo.log"'
|
||
- '!pwfeedback'
|
||
- '!visiblepw'
|
||
- 'passwd_timeout=1'
|
||
- 'timestamp_timeout=5'
|
||
- 'timestamp_type=tty'
|
||
- "!rootpw"
|
||
- "!runaspw"
|
||
- "!targetpw"
|
||
|
||
- name: Stat faillock.conf
|
||
become: true
|
||
ansible.builtin.stat:
|
||
path: /etc/security/faillock.conf
|
||
register: faillockconf
|
||
|
||
- name: Verify faillock.conf
|
||
become: true
|
||
ansible.builtin.lineinfile:
|
||
dest: /etc/security/faillock.conf
|
||
mode: "0644"
|
||
state: present
|
||
line: "{{ item }}"
|
||
check_mode: true
|
||
register: verify_faillock
|
||
failed_when: verify_faillock is changed
|
||
with_items:
|
||
- "audit"
|
||
- "local_users_only"
|
||
- "deny = 5"
|
||
- "fail_interval = 900"
|
||
when: faillockconf.stat.exists
|
||
|
||
- name: Verify wireless state
|
||
environment:
|
||
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||
ansible.builtin.command: nmcli -t radio
|
||
register: wireless_state
|
||
changed_when: not 'disabled' in wireless_state.stdout
|
||
failed_when: not 'disabled' in wireless_state.stdout
|
||
when: disable_wireless
|
||
|
||
- name: Stat firewall rules when UFW is enabled
|
||
become: true
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
ufw show added | grep '^ufw' | grep -v "'ansible\smanaged'" | sed 's/ufw //g'
|
||
args:
|
||
executable: /bin/bash
|
||
failed_when: ufw_not_managed.rc > 1
|
||
changed_when: false
|
||
register: ufw_not_managed
|
||
when: ufw_enable
|
||
|
||
- name: Stat firewall rules when UFW is disabled
|
||
become: true
|
||
ansible.builtin.shell: |
|
||
set -o pipefail
|
||
ufw show added | grep '^ufw' | grep "'ansible\smanaged'" | sed 's/ufw //g'
|
||
args:
|
||
executable: /bin/bash
|
||
failed_when: ufw_not_managed.rc > 1
|
||
changed_when: false
|
||
register: ufw_not_managed
|
||
when: not ufw_enable
|
||
|
||
- name: Create test user
|
||
become: true
|
||
ansible.builtin.user:
|
||
name: roletestuser
|
||
password: "{{ 'Ansible Role Test User' | password_hash('sha512') }}"
|
||
state: present
|
||
shell: /bin/bash
|
||
|
||
- name: Create test user salt
|
||
ansible.builtin.set_fact:
|
||
test_user_salt: "{{ lookup('password', '/dev/null chars=ascii_lowercase,ascii_uppercase,digits length=16') }}"
|
||
|
||
- name: Change test user password
|
||
become: true
|
||
ansible.builtin.user:
|
||
name: roletestuser
|
||
password: "{{ 'roletestuser' | password_hash('sha512', test_user_salt, rounds=656000) }}"
|
||
register: test_user_pass
|
||
|
||
- name: Debug test user salt
|
||
ansible.builtin.debug:
|
||
msg: "{{ test_user_salt }}"
|
||
|
||
- name: Debug test user password
|
||
ansible.builtin.debug:
|
||
msg: "{{ test_user_pass }}"
|
||
...
|