├── .gitignore ├── LICENSE ├── README.md ├── docs ├── controls_list.md └── controls_list_win.md ├── galaxy.yml ├── meta └── runtime.yml └── roles └── cis_security ├── README.md ├── defaults └── main.yml ├── files ├── banner ├── duplicate_groups.sh ├── duplicate_guids.sh ├── duplicate_uids.sh ├── duplicate_users.sh ├── issue ├── non_existant_homedirs.sh ├── path_check.sh ├── rsyslog.conf └── undefined_groups.sh ├── handlers └── main.yml ├── meta └── main.yml ├── tasks ├── CIS-CentOS-7.yml ├── CIS-CentOS-8.yml ├── CIS-Fedora-31.yml ├── CIS-Fedora-32.yml ├── CIS-Microsoft Windows 10 Pro.yml ├── CIS-Oracle-7.yml ├── CIS-OracleLinux-8.yml ├── CIS-RedHat-7.yml ├── CIS-RedHat-8.yml ├── CIS-RedHat-9.yml ├── CIS-SLES-15.yml ├── CIS-Ubuntu-18.yml ├── CIS-Ubuntu-20.yml ├── CIS-Ubuntu-22.yml ├── main.yml └── type-files │ ├── MS-Server-type.yml │ ├── SLES-addons.yml │ ├── redhat-7-type.yml │ ├── redhat-8-type.yml │ ├── redhat-9-type.yml │ ├── ubuntu-18-type.yml │ └── ubuntu-22-type.yml ├── templates ├── aidecheck.service ├── aidecheck.timer ├── audit_rules │ ├── MAC-policy.rules │ ├── bad-file-access.rules │ ├── chacl.rules │ ├── chcon.rules │ ├── dac.rules │ ├── datetime.rules │ ├── delete.rules │ ├── file-system-mounts.rules │ ├── login.rules │ ├── modules.rules │ ├── network.rules │ ├── sessions.rules │ ├── setfacl.rules │ ├── sudolog.rules │ ├── user-group-info.rules │ ├── user_emulation.rules │ └── usermod.rules ├── chrony.conf ├── chronyd ├── chronyd.ubuntu ├── ntp.conf ├── ntpd └── timesyncd.conf └── vars └── main.yml /.gitignore: -------------------------------------------------------------------------------- 1 | vault* 2 | *.retry 3 | *.gz 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | License for CIS Controls: 3 | 4 | Creative Commons License 5 | 6 | This work is licensed under a Creative Commons Attribution-NonCommercial-No Derivatives 4.0 International 7 | Public License (the link can be found at https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode. 8 | To further clarify the Creative Commons license related to the CIS Controls® content, you are authorized to 9 | copy and redistribute the content as a framework for use by you, within your organization and outside of your 10 | organization, for non-commercial purposes only, provided that (i) appropriate credit is given to CIS, and (ii) 11 | a link to the license is provided. Additionally, if you remix, transform, or build upon the CIS Controls, you may 12 | not distribute the modified materials. Users of the CIS Controls framework are also required to refer to (http:// 13 | www.cisecurity.org/controls/) when referring to the CIS Controls in order to ensure that users are employing 14 | the most up-to-date guidance. Commercial use of the CIS Controls is subject to the prior approval of the 15 | Center for Internet Security, Inc. (CIS®). -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cis_security 2 | 3 | A role to implement Center for Internet Security (CIS) controls for RHEL (7-9) and RHEL clones (Oracle, CentOS), recent Fedora (31-32), SLES 15, and Ubuntu \[18-22\].04 LTS and certain Windows servers. 4 | 5 | ## Introduction 6 | 7 | The [Center for Internet Security](https://www.cisecurity.org/) provides a set of 8 | security benchmarks for operating systems designed to decrease the vulnerability vectors of a system. 9 | 10 | These benchmarks are published in PDFs for non-commercial use. This role is an implementation of 11 | those controls for various Operating Systems per the list below. The controls themselves are not published here and 12 | you should visit CIS for a copy of the PDF. These automations are provided as a resposne and a tool to 13 | help systems administrators secure machines based off those recommendations. This collection is not 14 | endorsed by the Center for Internet Security in any way. 15 | 16 | This collection contains a role that is designed to layer under other Ansible roles that install software packages, users, etc. It should be idempotent and can be run at any time. As usual with Ansible, make sure that later playbooks don't modify 17 | files that are modified in this role. 18 | 19 | Benchmark Versions: 20 | | Operating System | OS Benchmark version | 21 | | -----------------|--------------------- | 22 | | RHEL 7 | v2.2.0 | 23 | | RHEL 8 | v2.0.1 | 24 | | RHEL 9 | V1.0.0 | 25 | | CentOS 7 | v2.2.0 | 26 | | CentOS 8 | v1.0.0 | 27 | | Fedora 31 | \(Fedora 28\) v1.1.0 | 28 | | Fedora 32 | \(Fedora 28\) v1.1.0 | 29 | | Oracle Linux 7 | v2.2.0 | 30 | | Oracle Linux 8 | v1.0.0 | 31 | | SUSE Linux Enterprise 15 SP1 | \(SUSE Linux Enterprise 12\) v2.1.0 | 32 | | Ubuntu 18.04 LTS | v2.0.1 | 33 | | Ubuntu 20.04 LTS | \(Ubuntu 18.04 LTS\) v2.0.1 | 34 | | Ubuntu 22.04 LTS | v1.0.0 | 35 | | Windows Server 2019 | v1.8.1 | 36 | | Windows 10 | \(Windows Server 2019\) v1.8.1 | 37 | 38 | - Some distributions use older CIS benchmarks that were the most recent at the time of creation. Efforts have 39 | been made to update the controls to work with the newer operating systems. Older versions of the benchmarks are listed in parenthesis. 40 | - SUSE Linux Enterprise 15 SP1 uses the RHEL 7 task file since their controls are so similar. If you want to exclude a SUSE tag, make sure you use the associated RHEL 7 tag number if they are different. Tags can be found in the appropriate controls_list file found in the docs directory. 41 | 42 | ## Requirements 43 | 44 | To implement the collection correctly, you will require the following 45 | 46 | Control machine: 47 | 48 | - Ansible 2.11+ 49 | - Machine connected to a package repository source (Satellite or yum repo) 50 | 51 | Target machine: 52 | 53 | - SSH connection with prviiledge escalation on Linux machines. 54 | - Python interpreter 55 | - WinRM connection with user with admin priviledge for Windows. Alternatively you can use an SSH connection. 56 | - PowerShell v3 or higher 57 | 58 | Some of the Ansible modules that are used require Ansible 2.7 and newer. 59 | 60 | For most of the collection to work, you will need to have a package repo where you can install packages for 61 | the target machine. Registering with Satellite, a package repository, SCM, or a local package collection is recommended before using this, unless you exclude any tags that install packages. 62 | 63 | ## Use and Care 64 | 65 | The collection is designed to run on the machines in the chart above. It may run on other Red Hat and Ubuntu deriviatives, but it has not been tested on them. Upon initiation, the collection will automatically detect the OS and run the appropriate task list. 66 | 67 | As the role runs, you will see an output listing the control number and a brief description of the 68 | task being performed (or skipped): 69 | 70 | ```bash 71 | TASK [security-rollup : 1.7.1.3 - Set SELinux policy to targeted] ****************************** 72 | ok: [192.168.122.252] 73 | ``` 74 | 75 | The controls are implemented as Ansible tags. By default all tags are run on a given system. To 76 | disable a tag from running, run the playbook with the tag excluded (--skip-tags "x.y.z"): 77 | 78 | ```bash 79 | ansible-playbook -i --skip-tags "x.y.z" 80 | ``` 81 | 82 | Multiple tags can be listed, separated by commas: 83 | 84 | ```bash 85 | ansible-playbook -i --skip-tags "x.y.z,a.b.c" 86 | ``` 87 | 88 | Note: Some automation tasks handle multiple controls. In the role you may see something like this: 89 | 90 | ```yaml 91 | - name: 6.1.[2,4] - Ensure permissions on /etc/passwd /etc/group 92 | file: 93 | path: /etc/{{item}} 94 | owner: root 95 | group: root 96 | mode: 0644 97 | loop: 98 | - passwd 99 | - group 100 | tags: 101 | - 6.1.2 102 | - 6.1.4 103 | ``` 104 | 105 | - In this control, two tags are being processed, '6.1.2' and '6.1.4' if you want this control to not 106 | run, you must exclude both tags: 107 | 108 | ```bash 109 | ansible-playbook -i --skip-tags "6.1.2,6.1.4" 110 | ``` 111 | 112 | Some controls are surrouned by Ansible blocks that themselves have tags. Excluding the tag that applies 113 | to the block will exclude all of the tasks inside of the block. If the block's tag is **not** excluded, 114 | then individual tasks inside of the block can be excluded by excluding their tags. 115 | 116 | The list of tags and their associated crontol descriptions are listed in the [controls_list](./docs/controls_list.md) file for Linux and [control_list_win](./docs/controls_list_win.md_ file for Windows) 117 | in the docs directory. 118 | 119 | In addition to tags, there are a number of variables that can be set which will enable or disable 120 | tasks, or set values. These are explained and given default values in the **roles/cis-security/defaults/main.yml** 121 | file. Do not set these values in that file, but create and include your own variable file to override the 122 | defaults or set them as host variables. 123 | 124 | ## Idempotency 125 | 126 | Every effort has been made to make the controls idempotent, however some Ansible modules do not have the ability 127 | to measure every need as currently written and shell or command has been utilized to implement controls. This 128 | has the effect of bringing down the quality score on Ansible Galaxy, but the roles can be run multiple times 129 | without fear of breaking. 130 | 131 | ## Learning Tool 132 | 133 | A secondary purpose of this collection is to show numerous ways that Ansible can be used to 134 | manage systems with various modules. The first time a module is used it is commented on many times 135 | to explain what the module is doing. Other times you may see something like the following: 136 | 137 | ```yaml 138 | - name: 5.4.4 - Ensure umask is set 139 | replace: 140 | path: "{{ item }}" 141 | replace: " umask {{ default_umask }}" 142 | regexp: '^\s*umask\s*022' 143 | loop: 144 | - /etc/bashrc 145 | - /etc/profile 146 | when: ansible_distribution != "SLES" 147 | tags: 148 | - 5.4.4 149 | 150 | - name: 5.4.5 - Ensure shell timeout is {{ shell_timeout }} seconds or less 151 | blockinfile: 152 | path: "{{ item }}" 153 | block: "TMOUT={{ shell_timeout }}" 154 | marker: "# {mark} Ansible Managed CIS Timeout" 155 | loop: 156 | - /etc/bashrc 157 | - /etc/profile 158 | when: ansible_distribution != "SLES" 159 | tags: 160 | - 5.4.5 161 | ``` 162 | 163 | Both of these tasks manipulate the same file in the same way. They could have been written 164 | with the same module, even in the same task with a loop, but here it illustrates different 165 | ways files can be manipuldated with modules. 166 | 167 | ## Change Log 168 | 169 | - 1/20/2020 - dsglaser@gmail.com - Initial creation 170 | - 1/22/2020 - dsglaser@gmail.com - Added enhanced selinux controls 171 | - 2/18/2020 - dsglaser@gmail.com - Added support for Ubuntu 18.04 LTS, added RHEL clone links 172 | - 2/20/2020 - dsglaser@gmail.com - Fixed numerous tests and rearranged network controls 173 | - 2/25/2020 - dsglaser@gmail.com - Added SLES 15 SP 1 support 174 | - 3/17/2020 - dsglaser@gmail.com - Added Windows 2019 support 175 | - 7/28/2022 - dsglaser@gmail.com - Adapted as a collection. Support for Ubuntu 20.04 and Windows 10 176 | - 7/28/2022 - dsglaser@gmail.com - Fixed formatting 177 | -------------------------------------------------------------------------------- /docs/controls_list.md: -------------------------------------------------------------------------------- 1 | # CIS Security 2 | 3 | ## Below are the tags used in the CIS roles on Linux Machines 4 | 5 | | RHEL 9 | RHEL 8 / Fedora 31 / CentOS 8 / Oracle 8 | RHEL 7 / Centos 7 / Oracle 7 / SLES 15 | Ubuntu 22.04 | Ubuntu 18.04 / 20.04 | Control Description | Notes | 6 | | ----------------- | -----------------|--------------------- | -----------------|--------------------- | --------------------- | --------------| 7 | | | 1.1.1.1 | 1.1.1.1 | 1.1.1.1 | 1.1.1.1 | Remove cramfs | 8 | | | | 1.1.1.2 | | 1.1.1.2 | Remove freevxfs 9 | | | | 1.1.1.3 | | 1.1.1.3 | Remove jffs2 10 | | | | 1.1.1.4 | | 1.1.1.4 | Remove hfs 11 | | | | 1.1.1.5 | | 1.1.1.5 | Remove hfsplus 12 | | | 1.1.1.2 | 1.1.1.8 | | 1.1.1.8 | Remove vfat 13 | | 1.1.1.1 | 1.1.1.3 | 1.1.1.6 | 1.1.1.2 | 1.1.1.6 | Remove squashfs 14 | | 1.1.1.2 | 1.1.1.4 | 1.1.1.7 | 1.1.1.3 | 1.1.1.7 | Remove udf 15 | | 1.1.2 | 1.1.2 | | 1.1.2 | 1.1.2 | Ensure tmpfs is configured 16 | | 1.1.2.1 | | 1.1.2 | 1.1.2.1 | | Report if /tmp is not on a separate partition | a) If report comes back saying partitions are not separate, the no\[dev,suid,exec\] checks aren't run b) On a failed control, simply prints a notification to the user | 17 | | 1.1.2.2 | 1.1.3 | 1.1.4 | 1.1.2.2 | 1.1.3 | Ensure nodev option on /tmp partition 18 | | 1.1.2.3 | 1.1.4 | 1.1.5 | 1.1.2.4 | 1.1.4 | Ensure nosuid option set on /tmp partition 19 | | 1.1.2.4 | 1.1.5 | 1.1.3 | 1.1.2.3 | 1.1.5 | Ensure noexec option set on /tmp partition 20 | | 1.1.3 | 1.1.3 | | 1.1.3 | | Configure /var (includes all the /var partition controls) 21 | | 1.1.3.1 | 1.1.3.1 | 1.1.10 | 1.1.3.1 | 1.1.6 | Report if /var is not on a separate partition 22 | | 1.1.3.2 | 1.1.3.2 | | 1.1.3.2 | | Report if /var is missing nodev option 23 | | 1.1.3.3 | 1.1.3.3 | | 1.1.3.3 | | Report if /var is missing noexec option 24 | | 1.1.4 | 1.1.4 | | 1.1.4 | | Configure /var/tmp 25 | | 1.1.4.1 | 1.1.4.1 | 1.1.11 | 1.1.4.1 | 1.1.7 | Report if /var/tmp is not on a separate partition a) If report comes back saying partitions are not separate, the no\[dev,suid,exec\] checks aren't run b) On a failed control, simply prints a notification to the user | 26 | | 1.1.4.2 | 1.1.4.2 | 1.1.13 | 1.1.4.4 | 1.1.8 | Ensure nodev option on /var/tmp partition 27 | | 1.1.4.3 | 1.1.4.3 | 1.1.14 | 1.1.4.3 | 1.1.9 | Ensure nosuid option set on /var/tmp partition 28 | | 1.1.4.4 | 1.1.4.4 | 1.1.12 | 1.1.4.2 | 1.1.10 | Ensure noexec option set on /var/tmp partition 29 | | 1.1.5 | 1.1.5 | | 1.1.5 | | Configure /var/log 30 | | 1.1.5.1 | 1.1.5.1 | 1.1.15 | 1.1.5.1 | 1.1.11 | Report if /var/log is not on a separate partition | On a failed control, simply prints a notification to the user | 31 | | 1.1.5.2 | 1.1.5.2 | | 1.1.5.2 | | Ensure nodev option on /var/log partition 32 | | 1.1.5.3 | 1.1.5.3 | | 1.1.5.4 | | Ensure nosuid option set on /var/log partition 33 | | 1.1.5.4 | 1.1.5.4 | | 1.1.5.3 | | Ensure noexec option set on /var/log partition 34 | | 1.1.6 | 1.1.6 | | 1.1.6 | | Configure /var/log/audit 35 | | 1.1.6.1 | 1.1.6.1 | 1.1.16 | 1.1.6.1 | 1.1.12 | Report if /var/log/audit is not on a separate partition | On a failed control, simply prints a notification to the user | 36 | | 1.1.6.2 | 1.1.6.2 | | 1.1.6.3 | | Ensure nodev option on /var/log/audit partition 37 | | 1.1.6.3 | 1.1.6.3 | | 1.1.6.4 | | Ensure nosuid option set on /var/log/audit partition 38 | | 1.1.6.4 | 1.1.6.4 | | 1.1.6.2 | | Ensure noexec option set on /var/log/audit partition 39 | | 1.1.7 | 1.1.7 | | 1.1.7 | | Configure /home 40 | | 1.1.7.1 | 1.1.7.1 | 1.1.17 | 1.1.7.1 | 1.1.13 | Report if /home is not on a separate partition | On a failed control, simply prints a notification to the user | 41 | | 1.1.7.2 | 1.1.7.2 | | 1.1.7.2 | | Ensure nodev option on /home partition 42 | | 1.1.7.3 | 1.1.7.3 | | 1.1.7.3 | | Ensure nosuid option set on /home partition 43 | | 1.1.8.2 | 1.1.8.2 | 1.1.8 | 1.1.8.1 | 1.1.15 | Report if /dev/shm does not have nodev set 44 | | | | | 1.1.8.2 | | Report if /dev/shm does not have noexec set 45 | | 1.1.8.2 | 1.1.8.3 | 1.1.9 | 1.1.8.3 | 1.1.16 | Report if /dev/shm does not have nosuid set 46 | | 1.1.8.4 | 1.1.8.4 | 1.1.20 | | 1.1.18 | Ensure nodev option set on removable media | skipped: environment dependent| 47 | | | 1.1.22 | 1.1.23 | 1.1.9 | 1.1.22 | Disable automounting 48 | | | 1.1.23 | 1.1.24 | 1.1.10 | 1.1.23 | Disable USB storage module 49 | | 1.2.0 | 1.2.0 | | 1.9.0 | | Update System to latest 50 | | | 1.2.1 | 1.2.2 | 1.2.1 | 1.2.1 | Ensure system is configured for updates |skipped: environment dependent| 51 | | | 1.2.2 | 1.2.5 | | | Disable the rhnsd Daemon | RHEL control only | 52 | | 1.2.1 | 1.2.3 | 1.2.1,3 | 1.2.2 | 1.2.2 | Ensure gpg keys are configured | gpgcheck set to yes. 1.2.2 on SLES 15, but skipped | 53 | | 1.2.2 | 1.2.4 | 1.2.2 | 1.2.2 | 1.2.2 | Ensure gpgcheck is globally activated. Missing on SLES 15 benchmark 54 | | 1.2.3 | 1.2.5 | 1.2.4 | | | Ensure machine is registerd with Red Hat |skipped: environment dependent| 55 | | 5.3.1 | 5.3.1 | | 5.3.1 | 1.3.1 | Ensure sudo is installed 56 | | 5.3.2 | 5.3.2 | | 5.3.2 | 1.3.2 | Ensure sudo commands use pty 57 | | 5.3.3 | 5.3.3 | | 5.3.3 | 1.3.3 | Ensure sudo log file exists 58 | | 1.3.0 | 1.3.0 | 1.3.0 | 1.3.0 | 1.4.0 | Install and configure filesystem integrity checking w/AIDE 59 | | 1.3.1 | 1.3.1 | 1.3.1 | 1.3.1 | 1.4.1 | Ensure aide is installed 60 | | 1.3.2 | 1.3.2 | 1.3.2 | 1.3.2 | 1.4.2 | Ensure File integrity is regularly checked 61 | | 1.4.1 | 1.4.1 | 1.4.1 | 1.4.1 | 1.5.2 | Ensure bootloader password is set |skipped: environment dependent| 62 | | 1.4.2 | 1.4.2 | 1.4.2 | 1.4.2 | 1.5.1 | Set permissions on grub bootloader files 63 | | | | 1.4.3 | 1.4.3 | 1.5.3 | Set single user password | if root password is not set, sets root password before setting up secure single user mode. Uses root_password variable. See [Using vaults with playbooks](https://docs.ansible.com/ansible/latest/user_guide/playbooks_vault.html#playbooks-vault) for information on how to secure it| 64 | | 1.5.1 | 1.5.1 | 1.5.1 | 1.5.4 | 1.6.4 | Ensure core dumps are restricted 65 | | 1.5.2 | 1.5.2 | | | | Ensure core dump backtraces are disabled 66 | | | | 1.5.2 | | 1.6.1 | Ensure XD/NX support is enabled 67 | | 1.5.3 | 1.5.3 | 1.5.3 | 1.5.1 | 1.6.2 | Ensure address space layout reandomization (ASLR) is enabled 68 | | | | 1.5.4 | 1.5.2 | | Ensure prelink is not installed 69 | | | | | 1.5.3 | | Ensure Apport Error Reporting Service is disabled 70 | | 1.6.0 | 1.6.0 | 1.6.0 \(SLES: skipped\) | | | Configure SELinux | SLES supports SELinux, but does not provide a policy, so enabling it will crash the system, so we are skipping it on SLES) 71 | | 1.6.1.1 | 1.6.1.1 | 1.6.1.1 | | | Ensure SELinux is installed 72 | | 1.6.1.2 | 1.6.1.2 | 1.6.1.2 | | | Ensure SELinux is not disabled in bootloader configuration 73 | | 1.6.1.3 | 1.6.1.3 | 1.6.1.3 | | | Set SELinux policy 74 | | 1.6.1.4 | 1.6.1.4 | 1.6.1.2 | | | Set SELinux to not disabled 75 | | 1.6.1.5 | 1.6.1.5 | 1.6.1.2 | | | Set SELinux state to enforcing 76 | | 1.6.1.6 | 1.6.1.5 | 1.6.1.6 | | | Ensure no unconfined services exist 77 | | 1.6.1.7 | 1.6.1.7 | 1.6.1.7 | | | Remove setroubleshoot 78 | | 1.6.1.8 | 1.6.1.8 | 1.6.1.8 | | | Remove MCS Translation Service 79 | | | | | 1.6.1.0 | 1.7.0 | Install and Configure AppArmor 80 | | | | | 1.6.1.1 | 1.7.1.1 | Ensure AppArmor is installed 81 | | | | | 1.6.1.2 | 1.7.1.2 | Ensure AppArmor is not disabled in bootloader configuration 82 | | | | | 1.6.1.3 | 1.7.1.3 | Ensure AppArmor profiles are in enforce or complain mode 83 | | | | \(SLES 1.|6.2.2\) | 1.6.1.4 | 1.7.1.4 | Ensure AppArmor profiles are enforcing | SLES only control in the RHEL 7 file, use 1.6.2.2 for the tag number 84 | | | | \(SLES 1.6.3\) | | | Ensure SELinux or AppArmor are installed | SLES only control in the RHEL 7 file, use 1.6.3 for the tag number 85 | | 1.7.1 | 1.7.1 | 1.7.1.1 | 1.7.1 | 1.8.1.1 | Install motd banners 86 | | 1.7.2 | 1.7.2 | 1.7.2 | 1.7.2 | 1.8.1.2 | Install issue banners 87 | | 1.7.3 | 1.7.3 | 1.7.3 | 1.7.3 | 1.8.1.3 | Install issue.net banners 88 | | 1.7.4 | 1.7.4 | 1.7.4 | 1.7.4 | 1.8.1.4 | Ensure permissions on /etc/motd are configured 89 | | 1.7.5 | 1.7.5 | 1.7.5 | 1.7.5 | 1.8.1.5 | Ensure permissions on /etc/issue are configured 90 | | 1.7.6 | 1.7.6 | 1.7.6 | 1.7.6 | 1.8.1.6 | Ensure permissions on /etc/issue.net are configured 91 | | 1.8.1 | 1.8.1 | 1.8.1 | 1.8.1 | | Ensure GNOME Display Manager is removed 92 | | 1.8.2 | 1.8.2 | 1.8.2 | 1.8.2 | 1.8.2 | Ensure GDM banner set up 93 | | 1.8.3 | | 1.8.3 | 1.8.3 | | Ensure last logged in user display is disabled 94 | | 1.8.4 | | | 1.8.4 | | Ensure GDM screen locks when user is idle 95 | | 1.9.0 | 1.9.0 | | 1.9.0 | 1.9.0 | Ensure updated system | First control to be run chronologically in order to make sure things are in the same state for the rest of the play 96 | | 1.10.0 | 1.10.0 | | | | Ensure crypto policy is not legacy | set to what the crypto_policy variable is set to| 97 | | | 2.1.1 | 2.1.7 \(SL ES 2.1.11 || 2.1.1 | Remove xinetd service 98 | | | | 2.1.1 | | | Ensure chagen services are not enabled 99 | | 2.2.1 | 2.2.2 | | | | Ensure xorg-x11-server-common is not installed 100 | | | | 2.1.2 | | | Ensure daytime services are not enabled 101 | | | | | | 2.1.2 | Ensure openbsd-inetd is not installed 102 | | | | 2.1.3 | | | Ensure discard services are not enabled 103 | | | | 2.1.4 | | | Ensure echo services are not enabled 104 | | | | 2.1.5 | | | Ensure time services are not enabled 105 | | 2.2.7 | 2.2.9 | 2.1.6 | | | Ensure tftp server is not enabled 106 | | 2.1.1 | 2.1.1 | 2.2.1.1 | 2.1.1 | 2.2.1.1 | Verify Time synchronization is in use 107 | | | | | 2.1.1.1 | | Ensure a single time synchronization daemon is in use 108 | | 2.1.2 | 2.1.2 | 2.2.1.3 | 2.1.2 | 2.2.1.3 | Configure chrony 109 | | | | | 2.1.2.2 | | Ensure chrony is running as user _chrony (configurable via variable) 110 | | | | | 2.1.2.3 | | Ensure chrony is enabled and running 111 | | | | | 2.1.3 | 2.2.1.2 | Configure systemd-timesyncd 112 | | | | | 2.1.3.2 | | Ensure systemd_tiemsyncd is enbled and running 113 | | | | 2.2.1.2 | | | Configure ntp (skipped on ubuntu as not recommended ) 114 | | | | 2.2.2 | 2.2.1 | 2.2.2 | Disable display manager 115 | | 2.2.18 | 2.2.20 | 2.2.21 \(SLES 2.2.18\) | 2.2.16 | 2.2.16 | Remove rsync 116 | | 2.2.2 | 2.2.3 | 2.2.3 | 2.2.2 | 2.2.3 | Remove avahi 117 | | 2.2.12 | 2.2.14 | 2.2.14 | 2.2.13 | 2.2.14 | Remove snmp 118 | | 2.2.11 | 2.2.13 | 2.2.13 | 2.2.12 | 2.2.13 | Remove Web proxy 119 | | 2.2.10 | 2.2.12 | 2.2.12 | 2.2.11 | 2.2.12 | Remove Samba server 120 | | 2.2.9 | 2.2.11 | 2.2.11 | 2.2.15 | 2.2.11 | Remove Mail Relay Server 121 | | 2.2.8 | 2.2.10 | 2.2.10 | 2.2.9 | 2.2.10 | Remove http Server 122 | | 2.2.6 | 2.2.\[7,8\] | 2.2.9 | 2.2.8 | 2.2.9 | Remove FTP Server 123 | | 2.2.5 | 2.2.6 | 2.2.8 | 2.2.7 | 2.2.8 | Remove DNS server 124 | | 2.2.\[12,16\] | 2.2.18 | 2.2.7 | 2.2.6 | 2.2.7 | Remove nfs server 125 | | 2.2.16 | 2.2.19 | 2.2.7 | 2.2.6 | 2.2.7 | Remove rpcbind 126 | | | 2.2.14 | 2.2.6 | 2.2.5 | 2.2.6 | Remove LDAP server |skipped in RHEL 8 as it is part of SSSD| 127 | | 2.2.4 | 2.2.5 | 2.2.5 | 2.2.4 | 2.2.5 | Remove DHCP server 128 | | | | 2.2.17 | 2.3.2 | 2.3.2 | Remove rsh Server/Client 129 | | | | 2.2.18 | 2.3.3 | 2.3.3 | Remove talk 130 | | 2.3.3 | 2.2.9 | 2.2.20 \(SLES 2.2.17\) | | | Remove tftp client 131 | | 2.3.4 | | | | | Remove ftp client 132 | | 2.2.3 | 2.2.16 | 2.2.4 | 2.2.3 | 2.2.4 | Disable cups as we my not be able to uninstall it 133 | | | 2.2.15 | 2.2.16 | 2.2.14 | 2.2.17 | Remove NIS Server 134 | | | 2.2.16 | | | | Remove telnet-server 135 | | 2.2.15 | 2.2.17 | 2.2.15 | 2.2.15 | 2.2.15 | Configure mail MTA agent for local-only mode 136 | | | 2.3.1 | | 2.3.1 | 2.3.1 | Remove NIS Client 137 | | 2.3.3 | | | | | Remove NFS Client 138 | | 2.3.1 | 2.3.2 | 2.2.19 \(SLES 2.2.8\) | 2.3.4 | 2.3.4 | Remove telnet client 139 | | 2.3.2 | 2.3.3 | | 2.3.5 | 2.3.5 | Remove openldap-clients 140 | | | | | 3.2.0 | 3.1.0 | Set host network parameters | host with single interface, or multiple interfaces but not routing between them 141 | | 3.2.1 | 3.1.1 | 3.1.1 | 3.2.2 | 3.1.2 | Ensure IP forwarding is disabled | included in 3.1.0 142 | | 3.2.2 | 3.1.2 | 3.1.2 | 3.2.1 | 3.1.1 | Ensure packet redirect sending is disabled | included in 3.1.0 143 | | | | | | 3.2.0 | Set host with router network parameters | to be used when using 3.1.0 above as well as hosts with two interfaces configured to perform routing between them 144 | | 3.3.1 | 3.2.1 | 3.2.1 | 3.3.1 | 3.2.1 | Ensure source routed packets are not accepted | included in 3.2.0 145 | | 3.3.2 | 3.2.2 | 3.2.2,3.3.2 | 3.3.2 | 3.2.2 | Ensure ICMP redirects are not accepted | included in 3.2.0 146 | | 3.3.3 | 3.2.3 | 3.2.3 | 3.3.3 | 3.2.3 | Ensure secure ICMP redirects are not accepted | included in 3.2.0 147 | | 3.3.4 | 3.2.4 | 3.2.4 | 3.3.4 | 3.2.4 | Ensure suspicious packets are logged | included in 3.2.0 148 | | 3.3.5 | 3.2.5 | 3.2.5 | 3.3.5 | 3.2.5 | Ensure broadcast ICMP requests are ignored | included in 3.2.0 149 | | 3.3.6 | 3.2.6 | 3.2.6 | 3.3.6 | 3.2.6 | Ensure bogus ICMP responses are ignored | included in 3.2.0 150 | | 3.3.7 | 3.2.7 | 3.2.7 | 3.3.7 | 3.2.7 | Ensure Reverse Path Filtering is enabled | included in 3.2.0 151 | | 3.3.8 | 3.2.8 | 3.2.8 | 3.3.8 | 3.2.8 | Ensure TCP SYN Cookies is enabled | included in 3.2.0 152 | | | | 3.3.0 | | | IPv6 controls and settings | in RHEL 7 these are in their own area 153 | | 3.3.9 | 3.2.9 | 3.3.1 | 3.3.9 | 3.2.9 | Ensure IPv6 router advertisements are not accepted 154 | | | | 3.3.2 | | | Ensure IPv6 redirects are not accepted | included in 3.2.2 in RHEL8 and Ubuntu | 155 | | | | 3.4.1 | | 3.3.1 | Install TCPwrappers 156 | | | | 3.4.2 | | 3.3.2 | Ensure /etc/hosts.allow is configured 157 | | | | 3.4.3 | | 3.3.3 | Ensure /etc/hosts.deny is configured 158 | | | | 3.4.4 | | 3.3.4 | Ensure permissions on /etc/hosts.allow 159 | | | | 3.4.5 | | 3.3.5 | Ensure permissions on /etc/hosts.deny 160 | | 3.1.2 | 3.1.2 | 3.5.2 | 3.4.2 | 3.4.2 | Ensure SCTP is disabled 161 | | 3.1.3 | 3.1.3 | 3.5.1 | 3.4.1 | 3.4.1 | Ensure DCCP is disabled 162 | | 3.1.4 | 3.1.4 | 3.5.4 | 3.4.4 | 3.4.4 | Ensure TIPC is disabled 163 | | | | 3.5.3 | 3.4.3 | 3.4.3 | Ensure RDS is disabled 164 | | 3.4.1.2 | | 3.6.1 | | 3.5.1.1 | Ensure a firewall package is installed (firewalld or iptables) 165 | | | | 3.6.2-5 | | | Ensure firewall is configured 166 | | | | | | | firewalld: Ensure firewalld is enabled and running 167 | | | | | | | firewalld: Disable iptables service 168 | | | | | | | firewalld: Disable netfilters service 169 | | | | | | | firewalld: Ensure default zone is set for firewalld 170 | | 3.4.2.1 | | | | | firewalld: Set default zone in firewalld 171 | | | | | | | firewalld: Ensure network interfaces are assigned to appropriate zone |skipped: machine dependent| 172 | | 3.4.2 | 3.4.1 | | | | firewalld: Configure firewalld (block tag) 173 | | | 3.4.1.1 | | | | firewalld: Ensure firewalld is installed 174 | | | 3.4.1.2 | | | | firewalld: Ensure iptables-services is not installed 175 | | | 3.4.1.3 | | | | firewalld: Ensure nftables either not installed or masked with firewalld 176 | | | 3.4.1.4 | | | | firewalld: Ensure firewalld is enabled and running 177 | | 3.4.2.1 | 3.4.1.5 | | | | firewalld: Ensure firewalld default zone is set 178 | | 3.4.2 | 3.4.2 | | 3.5.2 | | nftables: Configure nftables (block tag) 179 | | 3.4.1.1 | 3.4.2.1 | | 3.5.2.1 | 3.5.3 | nftables: Ensure nftables is installed 180 | | 3.4.1.2 | | | | | nftables: Ensure a single firewall package package is installed 181 | | | 3.4.2.2 | | | | nftables: Ensure firewalld is either uninstalled or masked with nftables 182 | | | 3.4.2.3 | | | | nftables: Ensure iptables-services not installed with nftables 183 | | | | | 3.5.2.2 | | nftables: Ensure ufw is uninstalled with nftables 184 | | | | 3.6.1 | 3.5.2.3 | | nftables: Ensure iptables are flushed 185 | | 3.4.2.2 | 3.4.2.5 | | 3.5.2.4 | | nftables: Ensure an nftables table is installed 186 | | 3.4.2.3 | | | 3.5.2.5 | | nftables: Ensure nftables base chains exist 187 | | 3.4.2.4 | | | 3.5.2.6 | | nftables: Ensure nftables loopback traffic is configured 188 | | | | | 3.5.2.7 | | nftables: Ensure establshed connections are configured 189 | | 3.4.1.1 | 3.4.2.10 | | 3.5.2.9 | | nftables: Ensure nftables is started 190 | | | 3.4.3 | | 3.5.3.1 | | Configure iptables (block tag) 191 | | | 3.4.3.1.1| | 3.5.3.2 | | Ensure iptables is installed 192 | | | 3.4.3.1.2| | 3.5.3.3 | | Ensure nftables is not installed with iptables 193 | | | 3.4.3.1.3| | 3.5.3.4 | | Ensure firewald is not installed with iptables 194 | | | | | 3.5.1.1 | 3.5.2.1 | Ensure ufw service is enabled 195 | | | | | 3.5.1.2 | | Ensure iptables-persistent is not installed with ufw 196 | | | | | 3.5.1.3 | | Ensure ufw service is enabled 197 | | | | | 3.5.1.4 | | Ensure ufw loopback traffic is configured 198 | | | | 3.6.2-5 | | 3.5.4 | Configure iptables (skipped: machine dependent) 199 | | | 3.6.0 | 3.3.3 | | 3.7 | Disable IPv6 200 | | 4.1.0 | 4.1.0 | | 4.1.0 | | Configure Auditing (block tag) 201 | | 4.1.1.1 | 4.1.1.1 | | 4.1.1.1 | 4.1.1.1 | Install audit package 202 | | 4.1.1.4 | 4.1.1.2 | 4.1.2 | 4.1.1.2 | 4.1.1.2 | Enable auditd service 203 | | 4.1.1.2 | 4.1.1.3 | 4.1.3 | 4.1.1.3 | 4.1.1.3 | Ensure auditing for processes that sart prior to auditd 204 | | 4.1.1.3 | 4.1.1.4 | | 4.1.1.4 | 4.1.1.4 | Ensure audit_backlog_limit is sufficient 205 | | 4.1.2.1 | 4.1.2.1 | 4.1.1.1 | 4.1.2.1 | 4.1.2.1 | Configure audit log storage size 206 | | 4.1.2.2 | 4.1.2.2 | 4.1.1.3 | 4.1.2.2 | 4.1.2.2 | Ensure audit logs are not automatically deleted 207 | | 4.1.2.3 | 4.1.2.3 | 4.1.1.2 | 4.1.2.3 | 4.1.2.3 | Ensure system is disabled when audit logs are full 208 | | 4.1.3.1 | 4.1.3.1 | 4.1.15 | 4.1.3.1 | 4.1.14 | Ensure changes to system administration scope \(sudoers\) is collected 209 | | 4.1.3.2 | 4.1.3.2 | | 4.1.3.2 | | Ensure actions on behalf of another user are collected 210 | | 4.1.3.3 | 4.1.3.3 | 4.1.16 | 4.1.3.3 | 4.1.15 | Ensure sysadmin actions (sudolog) are collected 211 | | 4.1.3.4 | 4.1.3.4 | 4.1.4 | 4.1.3.4 | 4.1.3 | Ensure to collect events that modify date/time 212 | | 4.1.3.5 | 4.1.3.5 | 4.1.6 | 4.1.3.5 | 4.1.5 | Ensure modifications to network environment are collected 213 | | 4.1.3.6 | 4.1.3.6 | 4.1.12 | 4.1.3.6 | 4.1.11 | Ensure use of privileged commands is collected |skipped: machine dependent| 214 | | 4.1.3.7 | 4.1.3.7 | 4.1.11 | 4.1.3.7 | 4.1.10 | Ensure unsuccessful unauthorized file access attempts are collected 215 | | 4.1.3.8 | 4.1.3.8 | 4.1.5 | 4.1.3.8 | 4.1.4 | Ensure events that modify user/group information are collected 216 | | 4.1.3.9 | 4.1.3.9 | 4.1.10 | 4.1.3.9 | 4.1.9 | Ensure modifications to discretionary access controls are collected 217 | | 4.1.3.10 | 4.1.3.10 | 4.1.13 | 4.1.3.10| 4.1.12 | Ensure successful file system mounts are collected 218 | | 4.1.3.11 | 4.1.3.11 | 4.1.9 | 4.1.3.11| 4.1.8 | Ensure session initiation information is collected 219 | | 4.1.3.12 | 4.1.3.12 | 4.1.8 | 4.1.3.12| 4.1.7 | Ensure system logins and logouts are collected 220 | | 4.1.3.13 | 4.1.3.13 | 4.1.14 | 4.1.3.13| 4.1.13 | Ensure file deletion events by users are collected 221 | | 4.1.3.14 | 4.1.3.14 | 4.1.7 | 4.1.3.14| 4.1.6 | Ensure modifications to Mandatory Access Controls are collected 222 | | 4.1.3.15 | 4.1.3.15 | | 4.1.3.15| | Ensure all attempts to use the chcon command are collected 223 | | 4.1.3.16 | 4.1.3.16 | | 4.1.3.16| | Ensure all attempts to use the setfacl command are collected 224 | | 4.1.3.17 | 4.1.3.17 | | 4.1.3.17| | Ensure all attempts to use the chacl command are collected 225 | | 4.1.3.18 | 4.1.3.18 | | 4.1.3.18| | Ensure all attempts to use the usermod command are collected 226 | | 4.1.3.19 | 4.1.3.19 | 4.1.17 | 4.1.3.19| 4.1.16 | Ensure kernel module loading and unloading is collected 227 | | 4.1.3.20 | 4.1.3.20 | 4.1.18 | 4.1.3.20| 4.1.17 | Ensure audit configuration is immutable 228 | | 4.1.4.1 | | | 4.1.4.1 | | Ensure audit log files are mode 0640 more more restrictive 229 | | 4.1.4.2 | | | 4.1.4.2 | | Ensure only authorized users own audit log files 230 | | 4.1.4.3 | | | 4.1.4.3 | | Ensure only authorized groups own audit log flies 231 | | | | | 4.1.4.4 | | Ensure audit log directory is 0750 or more restrictive 232 | | 4.1.4.5 | | | 4.1.4.5 | | Ensure audit config files are mode 640 or more restrictive 233 | | 4.1.4.6 | | | 4.1.4.6 | | Ensure audit config files are owned by user root 234 | | | | | 4.1.4.7 | | Ensure audit config files are owned by group root 235 | | 4.1.4.7 | | | 4.1.4.8 | | Ensure audit tools are mode 0755 or more restrictive 236 | | 4.1.4.9 | | | 4.1.4.9 | | Ensure audit tools are owned by user root 237 | | 4.1.4.10 | | | 4.1.4.10| | Ensure audit tools belong to group root 238 | | 4.2.1.1 | 4.2.1.1 | 4.2.3 | 4.2.2.1 | 4.2.1.1 | rsyslog: Ensure rsyslog is installed 239 | | 4.2.1.2 | 4.2.1.2 | | 4.2.2.2 | 4.2.1.2 | rsyslog: Enable rsyslog 240 | | 4.2.1.3 | 4.2.1.3 | | 4.2.2.3 | | rsyslog: Ensure journald is configured to send messages to rsyslog 241 | | 4.2.1.4 | 4.2.1.4 | 4.2.1.3 | 4.2.2.4 | 4.2.1.4 | rsyslog: Ensure rsyslog default file permissions are configured 242 | | 4.2.1.5 | 4.2.1.5 | 4.2.1.2 | 4.2.2.5 | 4.2.1.3 | rsyslog: Ensure logging is configured |Only runs if the variable rsyslog_file is set, which it is not set by default| 243 | | 4.2.1.6 | 4.2.1.6 | 4.2.1.4 | 4.2.2.6 | 4.2.1.5 | rsyslog: Ensure logging is configured to send logs to remote host |skipped: environment dependent| 244 | | 4.2.1.7 | 4.2.1.7 | 4.1.2.5 | 4.2.2.7 | 4.2.1.6 | rsyslog: Ensure remote rsyslog messages are only accepted on designated log hosts 245 | | | | 4.2.2.1 | | | Ensure syslog-ng is configured |skipped: not a Red Hat package| 246 | | | 4.2.2 | | 4.2.1 | 4.2.2 | journald: Configure journald 247 | | 4.2.2.1 | 4.2.2.1 | | 4.2.1.1 | | journald: Configure journald to send logs to a remote log host 248 | | 4.2.2.1.1| 4.2.2.1.1| | 4.2.1.1.1 | | journald: Ensure systemd-journal-remote is installed 249 | | 4.2.2.1.2| 4.2.2.1.2| | 4.2.1.1.2 | | journald: Ensure systemd-journal-remote is configured 250 | | 4.2.2.1.3| 4.2.2.1.3| | 4.2.1.1.3 | | journald: Ensure systmd-journal-remote is enabled 251 | | 4.2.2.1.4| 4.2.2.1.4| | 4.2.1.1.4 | | journald: Ensure journald is not configured to recieve logs from a remote client 252 | | 4.2.2.2 | 4.2.2.2 | | 4.2.1.2 | | journald: Ensure journald service is enabled 253 | | 4.2.2.3 | 4.2.2.3 | | 4.2.1.3 | 4.2.2.2 | journald: Ensure journald compresses large files 254 | | 4.2.2.4 | 4.2.2.4 | | 4.2.1.4 | 4.2.2.3 | journald: Ensure journald writes to peristent disk 255 | | 4.2.2.5 | 4.2.2.5 | | 4.2.1.5 | 4.2.2.1 | journald: Forward journald logs to rsyslog IF rsyslog is sending logs to a log host 256 | | 4.2.3 | 4.2.3 | | 4.2.3 | | Ensure all log files have appropriate permissions and ownership 257 | | 4.3.0 | 4.3.0 | 4.3.0 || 4.3 | Ensure logrotate is installed and configured 258 | | 5.1.0 | 5.1.0 | | 5.1.0 | | Configure Cron/At 259 | | 5.1.1 | 5.1.1 | 5.1.1 | 5.1.1 | 5.1.1 | Ensure cron is enabled 260 | | 5.1.2 | 5.1.2 | 5.1.2 | 5.1.2 | 5.1.2 | Ensure permissions on /etc/crontab 261 | | 5.1.3 | 5.1.3 | 5.1.3 | 5.1.3 | 5.1.3 | Ensure permissions on /etc/cron.hourly 262 | | 5.1.4 | 5.1.4 | 5.1.4 | 5.1.4 | 5.1.4 | Ensure permissions on /etc/cron.daily 263 | | 5.1.5 | 5.1.5 | 5.1.5 | 5.1.5 | 5.1.5 | Ensure permissions on /etc/cron.weekly 264 | | 5.1.6 | 5.1.6 | 5.1.6 | 5.1.6 | 5.1.6 | Ensure permissions on /etc/cron.monthly 265 | | 5.1.7 | 5.1.7 | 5.1.7 | 5.1.7 | 5.1.7 | Ensure permissions on /etc/cron.d 266 | | 5.1.8 | 5.1.8 | | 5.1.8 | | Ensure cron restricted to authorized users 267 | | 5.1.9 | 5.1.9 | | 5.1.9 | | Ensure at restricted to authorized users 268 | | 5.2.1.0 | 5.2.0 | 5.2.0 | 5.2.0 | 5.2.0 | SSH File configurations 269 | | 5.2.1.1 | 5.2.1 | 5.2.1 | 5.2.1 | 5.2.1 | Set permissions on SSH file 270 | | 5.2.1.2 | 5.2.2 | | 5.2.2 | 5.2.2 | Set Permissions on ssh private host keys 271 | | 5.2.1.3 | 5.2.3 | | 5.2.3 | 5.2.3 | Set Permissions on ssh public host keys 272 | | 5.2.1.4 | 5.2.4 | 5.2.14 | 5.2.4 | 5.2.18 | Ensure SSH access is limited |skipped: environment dependent| 273 | | | | 5.2.2 | | 5.2.4 | Ensure SSH Protocol is set to 2 274 | | 5.2.1.5 | 5.2.5 | 5.2.3 | 5.2.5 | 5.2.5 | Set LogLevel to INFO 275 | | 5.2.1.6 | 5.2.6 | 5.2.6 | 5.2.6 | 5.2.20 | Ensure SSH PAM is enabled 276 | | 5.2.1.7 | 5.2.7 | 5.2.8 | 5.2.7 | 5.2.10 | Ensure PermitRootLogin is disbled 277 | | 5.2.1.8 | 5.2.8 | 5.2.7 | 5.2.8 | 5.2.9 | Ensure HostbasedAuthentication is disabled 278 | | 5.2.1.9 | 5.2.9 | 5.2.9 | 5.2.9 | 5.2.11 | Ensure SSH PermitEmptyPasswords is disabled 279 | | 5.2.1.10 | 5.2.10 | 5.2.10 | 5.2.10 | 5.2.12 | Ensure PermitUserEnvironment is disabled 280 | | 5.2.1.11 | 5.2.11 | | 5.2.11 | | Ensure IgnoreRhosts is enabled 281 | | 5.2.1.12 | 5.2.12 | 5.2.4 | 5.2.12 | 5.2.6 | Disable X11 forwarding 282 | | 5.2.1.13 | 5.2.13 | | 5.2.16 | 5.2.21 | Disable SSH Forwarding 283 | | 5.2.1.14 | 5.2.14 | | | | Ensure system crypto policy isn't overriden in SSH 284 | | 5.2.1.15 | 5.2.15 | 5.2.15 | 5.2.17 | 5.2.19 | Ensure SSH Banner is configured 285 | | 5.2.1.16 | 5.2.16 | 5.2.5 | 5.2.18 | 5.2.7 | Ensure SSH MaxAuthTires is set 286 | | 5.2.1.17 | 5.2.17 | | 5.2.19 | 5.2.22 | Ensure MaxStartups is configured 287 | | 5.2.1.18 | 5.2.18 | | 5.2.20 | 5.2.23 | Ensure MaxSessions is set to 10 or less 288 | | 5.2.1.19 | 5.2.19 | 5.2.13 | 5.2.21 | 5.2.17 | Ensure SSH LoginGraceTime is set 289 | | 5.2.1.20 | 5.2.20 | 5.2.12 | 5.2.22 | 5.2.16 | Ensure SSH Idle Timeout is configured 290 | | | | | 5.2.13 | 5.2.13 | Ensure only strong Ciphers are used 291 | | | | 5.2.11 | 5.2.14 | 5.2.14 | Ensure only approved MAC alogrithms are used 292 | | 5.3.0 | 5.3.0 | | 5.3.0 | | Configure privilege escalation 293 | | 5.3.1 | 5.3.1 | | 5.3.1 | | Ensure sudo is installed 294 | | 5.3.2 | 5.3.2 | | 5.3.2 | | Ensure sudo commands use pty 295 | | 5.3.3 | 5.3.3 | | 5.3.3 | | Ensure sudo log file exists 296 | | 5.3.4 | 5.3.4 | | 5.3.4 | | Ensure users must provide password for escalation 297 | | 5.3.5 | 5.3.5 | | 5.3.5 | | Ensure re-authentication for privlege ecalation is not disabled globally 298 | | | | | 5.3.6 | | Ensure audo authentication timeout is configured correctly 299 | | 5.3.7 | 5.3.7 | 5.6.0 | 5.3.7 | 5.6 | Restrict su to wheel group | on Ubuntu control says to any one group, but for simplicity we are using wheel | 300 | | 5.5.1 | 5.5.1 | 5.3.1 | 5.4.1 | 5.3.1 | Configure PAM files and password requirements 301 | | 5.5.2 | 5.5.2 | | 5.4.2 | | Ensure lockout for failed password attempts 302 | | 5.5.4 | 5.5.4 | | 5.4.4 | | Configure password hashing algorithm is SHA-512 or YESCRIPT 303 | | 5.6.1.1 | 5.6.1.1 | 5.4.1.1 | 5.5.1.1 | 5.4.1.1 | Ensure password expiration is 365 days or less 304 | | 5.6.1.2 | 5.6.1.2 | 5.4.1.3 | 5.5.1.3 | 5.4.1.3 | Ensure password warning days is set to 7 305 | | 5.6.1.3 | 5.6.1.3 | 5.4.1.2 | 5.5.1.2 | 5.4.1.2 | Ensure password change days is set to 7 306 | | 5.6.1.4 | 5.6.1.4 | 5.4.1.4 | 5.5.1.5 | 5.4.1.4 | Disable accounts that are inactive for 30 days after password expiration 307 | | 5.6.3 | 5.6.3 | 5.4.5 | 5.5.5 | 5.4.5 | Ensure default shell timeout is 900 seconds or less 308 | | 5.6.4 | 5.6.4 | 5.4.3 | 5.5.3 | 5.4.3 | Ensure default group for root is GID 0 309 | | 5.6.5 | 5.6.5 | 5.4.4 | 5.5.4 | 5.4.4 | Ensure default umask is set 310 | | 6.1.1 | 6.1.3 | 6.1.2 | 6.1.1 | 6.1.2 | Ensure permissions on /etc/passwd 311 | | 6.1.2 | 6.1.7 | 6.1.6 | 6.1.2 | 6.1.6 | Ensure permissions on /etc/passwd- 312 | | 6.1.3 | 6.1.5 | 6.1.4 | 6.1.3 | 6.1.4 | Ensure permissions on /etc/group 313 | | 6.1.4 | 6.1.9 | 6.1.8 | 6.1.4 | 6.1.8 | Ensure permissions on /etc/group- 314 | | 6.1.5 | 6.1.4 | 6.1.3 | 6.1.5 | 6.1.3 | Ensure permissions on /etc/shadow 315 | | 6.1.6 | 6.1.8 | 6.1.7 | 6.1.6 | 6.1.7 | Ensure permissions on /etc/shadow- 316 | | 6.1.7 | 6.1.6 | 6.1.5 | 6.1.7 | 6.1.5 | Ensure permissions on /etc/gshadow 317 | | 6.1.8 | 6.1.10 | 6.1.9 | 6.1.8 | 6.1.9 | Ensure permissions on /etc/gshadow- 318 | | 6.1.9 | 6.1.11 | 6.1.10 | 6.1.9 | 6.1.10 | Report if any world writable files exist 319 | | 6.1.10 | 6.1.12 | 6.1.11 | 6.1.10 | 6.1.11 | Report if any unowned files or directories exist 320 | | 6.1.11 | 6.1.13 | 6.1.12 | 6.1.11 | 6.1.12 | Report if any ungrouped files or directories exist 321 | | 6.1.12 | 6.1.2 | 1.1.22 | | 1.1.21 | Ensure sticky bit on world writable directories 322 | | 6.2.1 | 6.2.2 | | 6.2.1 | | Ensure accounts in /etc/passwd use shadowed passwords 323 | | 6.2.2 | 6.2.1 | 6.2.1 | 6.2.2 | 6.2.1 | Report on password fields that are empty 324 | | 6.2.3 | | 6.2.15 | 6.2.3 | 6.2.15 | Ensure al groups in /etc/passwd exist in /etc/group 325 | | | | | 6.2.4 | | Ensure shadow group is empty 326 | | 6.2.4 | 6.2.3 | 6.2.16 | 6.2.5 | 6.2.16 | Report on duplicate UIDs in /etc/passwd 327 | | 6.2.5 | 6.2.4 | 6.2.17 | 6.2.6 | 6.2.17 | Report on duplicate GIDs in /etc/group 328 | | 6.2.6 | 6.2.5 | 6.2.18 | 6.2.7 | 6.2.18 | Report on duplicate users in /etc/passwd 329 | | 6.2.7 | 6.2.6 | 6.2.19 | 6.2.8 | 6.2.19 | Report on duplicate groups in /etc/group 330 | | 6.2.8 | 6.2.7 | 6.2.6 | 6.2.9 | 6.2.7 | Ensure root PATH integrity 331 | | 6.2.9 | 6.2.8 | 6.2.5 | 6.2.10 | 6.2.6 | Report on multiple accounts with UID of 0 332 | | 6.2.10 | 6.2.10 | 6.2.9 | 6.2.11 | 6.2.9 | Ensure home directories exist |skipped: environment dependent| 333 | | 6.2.11 | 6.2.11 | 6.2.10 | | 6.2.8 | Ensure home directory permissions are 750 or more restrictive (skipped: environment dependent| 334 | | | | 6.2.2 | | 6.2.2 | Ensure no legacy "+" entries exist in /etc/passwd 335 | | | | 6.2.3 | | 6.2.4 | Ensure no legacy "+" entries exist in /etc/shadow 336 | | | | 6.2.4 | | 6.2.5 | Ensure no legacy "+" entries exist in /etc/group 337 | | | | 6.2.10-14| | 6.2.10-14 | Various controls recommended to be run by monitoring software 338 | | | | | | 6.2.20 | Report if shadow group exists in /etc/group 339 | -------------------------------------------------------------------------------- /docs/controls_list_win.md: -------------------------------------------------------------------------------- 1 | # cis-security 2 | 3 | Below are the tags used in the CIS roles on Windows Machines. 4 | 5 | | Windows Server 2019 | Control Description |Applies to DC|Applies to Member Server|Applies to Standalone Server| Notes | 6 | | -----------------|--------------------- | -----------------|--------------------- | --------------------- |-----------------| 7 | | 1.1.1 | Enforce password history is set to {{ password_history }} or more passwords|X|X|X| 8 | | 1.1.2 | Ensure maximum password age is set to "{{ password_expire_days }}" or fewer days, but not 0|X|X|X| 9 | | 1.1.3 | Ensure minimum password age is set to "{{ password_min_days }}"|X|X|X| 10 | | 1.1.4 | Ensure minimum password length is set to "{{ password_min_length }}"|X|X|X| 11 | | 1.1.5 | Ensure 'Password must meet complexity requirements' is set to enbled|X|X|X| 12 | | 1.1.6 | Ensure passwords are not stored with reversible encryption|X|X|X| 13 | | 1.2 | Account Lockout Policy|X|X|X| 14 | | 1.2.2 | Ensure Account lockout threshold is set to {{ account_lockout_threshold }} or fewer attempts, but not 0|X|X|X| 15 | | 1.2.3 | Ensure Reset account lockout counter after is set to 15 or more minutes|X|X|X| 16 | | 1.2.1 | Ensure Account lockout duration is set to {{ account_lockout_duration }}|X|X|X| 17 | | 2.2.0 | User rights policy|X|X|X| 18 | | 2.2.1 | Ensure Access Credential Manager as a trusted caller is set to No One|X|X|X| 19 | | 2.2.2 | Ensure Access this computer from network is restricted|X| | | 20 | | 2.2.3 | Ensure Access this computer from network is restricted| |X|X| 21 | | 2.2.4 | Ensure Act as part of operating system is set to no one.|X|X|X| 22 | | 2.2.5 | Add workstations to domain set to administrators only|X|X|X| 23 | | 2.2.6 | Ensure Adjust memory quotas for a process is restricted|X|X|X| 24 | | 2.2.7 | Ensure Access this computer from console is restricted|X|X|X| 25 | | 2.2.8 | Ensure allow long on through RDS is restricted (domain controllers)|X| | | 26 | | 2.2.9 | Ensure allow long on through RDS is restricted (member or standalone servers)| | |X| 27 | | 2.2.10 | Ensure backup operators are restricted|X|X|X| 28 | | 2.2.[11,12] | Ensure the ability to change the time is restricted|X|X|X| 29 | | 2.2.13 | Ensure Create a page file is set to Administrator|X|X|X| 30 | | 2.2.14 | Ensure no one can create a token object|X|X|X| 31 | | 2.2.15 | Ensure Create Token object is restricted|X|X|X| 32 | | 2.2.16 | Ensure no one can create permanent shared objects|X|X|X| 33 | | 2.2.17 | Ensure symbolic link creation is restricted (domain controller)|X|X|X| 34 | | 2.2.18 | Ensure symbolic link creation is restricted (member or standalone server )|X|X|X| 35 | | 2.2.19 | Ensure 'Debug programs' is set to 'Administrators'|X|X|X| 36 | | 2.2.20 | Deny accesss to this computer from network (domain computer)|X|X|X| 37 | | 2.2.20 | Deny accesss to this computer from network (domain computer)|X|X|X| 38 | | 2.2.[22-25] | Ensure deny local, remote, and batch logons includes 'Guests'|X|X|X| 39 | | 2.2.28 | Ensure 'Enable computer and user accounts to be trusted for delegation' is set to 'No One'| |X| | 40 | | 2.2.29 | Ensure 'Debug programs' is set to 'Administrators'|X|X|X| 41 | | 2.2.31 | Ensure 'Impersonate a client after authentication' is restricted|X|X|X| 42 | | 2.2.33 | Ensure 'Increase scheduling priority' is restricted|X|X|X| 43 | | 2.2.34 | Ensure 'Load and unload device drivers' is restricted|X|X|X| 44 | | 2.2.35 | Ensure 'Lock pages in memory' is set to 'No One'|X|X|X| 45 | | 2.2.36 | Ensure 'Log in as a batch job is set to 'Administrators'|X| | | 46 | | 2.2.[37,38] | Ensure 'Manage auditing and security log' is set to Adminstrators|X|X|X| 47 | | 2.2.39 | Ensure 'Modify an object label' is set to 'No One'|X|X|X| 48 | | 2.2.40 | Ensure 'Modify firmware environment values' is set to 'Administrators'|X|X|X| 49 | | 2.2.41 | Ensure 'Perform volume maintenance tasks' is set to 'Administrators'|X|X|X| 50 | | 2.2.42 | Ensure 'Profile single process' is set to 'Administrators'|X|X|X| 51 | | 2.2.43 | Ensure 'Profile system performance' is restricted|X|X|X| 52 | | 2.2.44 | Ensure 'Replace a process level token' is restricted|X|X|X| 53 | | 2.2.45 | Ensure 'Restore files and directories' is set to 'Administrators'|X|X|X| 54 | | 2.2.46 | Ensure 'Shut down the System' is set to 'Administrators'|X|X|X| 55 | | 2.2.47 | Ensure 'Synchronize directory service data' is set to 'No One'|X| | | 56 | | 2.2.48 | Ensure 'Take ownership of files or other objects' is set to 'Administrators'|X|X|X| 57 | | 2.3.1.2 | Ensure 'Accounts - Block Microsoft accounts' is set to 'Users can't add or log on with Microsoft accounts'|X|X|X| 58 | | 2.3.1.3 | Ensure 'Accounts - Guest account status' is set to 'Disabled'|X|X|X| 59 | | 2.3.1.4 | Ensure 'Accounts - Limit local account use of blank passwords to console logon only' is set to 'Enabled'|X|X|X| 60 | | 2.3.1.5 | Rename Administrator account|X|X|X| 61 | | 2.3.1.6 | Rename Guest account|X|X|X| 62 | | 2.3.2.1 | Force audit policy subcategories to override category settings|X|X|X| 63 | | 2.3.2.2 | Ensure system does not shut down if unable to log security audits|X|X|X| 64 | | 2.3.4.1 | Ensure only Administrators can format and eject removeable hardware|X|X|X| 65 | | 2.3.4.2 | Prevent Users from installing print drivers|X|X|X| 66 | | 2.3.5 | Domain controller specific settings|X| | | 67 | | 2.3.5.1 | Allow server operators to schedule tasks|X| | | 68 | | 2.3.5.2 | Require LDAP signing|X| | | 69 | | 2.3.5.3 | Refuse machine account password changes set to disabled|X| | | 70 | | 2.3.6 | Domain members specific settings (controllers and member servers)|X|X| | 71 | | 2.3.6.1 | Digitally encrypt or sign secure channel data (always)|X|X| | 72 | | 2.3.6.2 | Digitally secure channel data (when possible)|X|X| | 73 | | 2.3.6.3 | Digitally sign secure channel data (when possible)|X|X| | 74 | | 2.3.6.4 | Disable machine account password changes|X|X| | 75 | | 2.3.6.5 | Maximum machine account password age|X|X| | 76 | | 2.3.6.6 | Require strong session key|X|X| | 77 | | 2.3.7 | Interactive Logon|X|X|X| 78 | | 2.3.7.1 | Disable CAD Requirement|X|X|X| 79 | | 2.3.7.2 | Don't disply last signed in user|X|X|X| 80 | | 2.3.7.3 | Machine inactivtiy limit set to {{ inactivity_timeout }} but not 0|X|X|X| 81 | | 2.3.7.6 | Number of cached logins set to {{ cached_logins }} or fewer| |X| | 82 | | 2.3.7.7 | Number of days for password change warning {{ cached_logins }}|X|X|X| 83 | | 2.3.7.8 | Require domain controller authentication to unlock workstation|X|X|X| 84 | | 2.3.7.9 | Smart-card removal behavior|X|X|X| 85 | | 2.3.8.1 | Require SMB packet signing|X|X|X| 86 | | 2.3.8.2 | Sign communications (if server agrees)|X|X|X| 87 | | 2.3.8.3 | send uncencrypted password to third-party SMB servers|X|X|X| 88 | | 2.3.9.1 | SMB inactivty suspension|X|X|X| 89 | | 2.3.9.2 | Digitally sign communications (always)|X|X|X| 90 | | 2.3.9.3 | Digitally sign communications (if client agrees)|X|X|X| 91 | | 2.3.9.4 | Disconnect clients when logon hours expire|X|X|X| 92 | | 2.3.9.5 | SPN target name validation level|X|X|X| 93 | | 2.3.10.2 | Do not allow enumeration of SAM accounts|X|X|X| 94 | | 2.3.10.3 | Do not allow enumeration of SAM accounts and shares| |X| | 95 | | 2.3.10.4 | Do not allow storage of passwords and creds for network auth|X|X|X| 96 | | 2.3.10.5 | Let 'Everyone' permissions apply to anonymous users is disabled|X|X|X| 97 | | 2.3.10.6 | Named pipes can be accessed anonymously (DC only)|X| | | 98 | | 2.3.10.7 | Named pipes can be accessed anonymously (member servers)| |X|X| 99 | | 2.3.10.8 | Remotely accessible registry paths|X|X|X| 100 | | 2.3.10.9 | Remotely accessible registry paths and subpaths|X|X|X| 101 | | 2.3.10.10 | Restrict anonymous access to named pipes|X|X|X| 102 | | 2.3.10.11 | Restrict anonymous access to named pipes|X|X|X| 103 | | 2.3.10.12 | Clear all shares that can be accessd anonymously|X|X|X| 104 | | 2.3.10.13 | Local users authenticate as themselves|X|X|X| 105 | | 2.3.11.1 | Use machine ID for NTLM|X|X|X| 106 | | 2.3.11.2 | Disallow LocalSystem NULL session fallback|X|X|X| 107 | | 2.3.11.3 | Disallow PKU2U auth requests|X|X|X| 108 | | 2.3.11.4 | Supported Kerberos encryption types|X|X|X| 109 | | 2.3.11.5 | Do not store LAN Manager hash on password change|X|X|X| 110 | | 2.3.11.6 | Force Logoff when logon hours expire|X|X|X| 111 | | 2.3.11.7 | LAN Manager authentication - Send NTLMv2 reponse, refuse LM & NTLM|X|X|X| 112 | | 2.3.11.8 | LDAP Client signing|X|X|X| 113 | | 2.3.13.1 | Disable system from shuting down without having to log on|X|X|X| 114 | | 2.3.15.1 | Require case insensitivity for now windows subsystems|X|X|X| 115 | | 2.3.15.2 | Streghten default permissions of system objects|X|X|X| 116 | | 2.3.17.1 | Ensure UAC, admin approval mode for built-in admin account is enabled|X|X| | 117 | | 2.3.17.2 | Ensure UAC, behavior of the elevation prompt for admins|X|X|X| 118 | | 2.3.17.3 | Ensure UAC, behavior of the elevation prompt for standard users|X|X|X| 119 | | 2.3.17.4 | Ensure UAC, direct app installations prompt for elevation|X|X|X| 120 | | 2.3.17.5 | Ensure UAC, Only elevate UIAccess aps that are installed in secure location|X|X|X| 121 | | 2.3.17.6 | Ensure UAC, Run all admins in Admin Approval Mode|X|X|X| 122 | | 2.3.17.7 | Ensure UAC, Switch to secure desktop when prompting for elevation|X|X|X| 123 | | 2.3.17.8 | Ensure UAC, Virtualize file and registry write failures to per-user locations|X|X|X| 124 | | 17.1.1 | Ensure Audit credential validation is set to 'success and failure'|X|X|X| 125 | | 17.1.2 | Ensure Kerberos Authentication Service is set to 'success and failure'|X|X|X| 126 | | 17.1.3 | Ensure Kerberos Service Ticket Operations is set to 'success and failure'|X|X|X| 127 | | 17.2.1 | Ensure Application Group Management is set to 'success and failure'|X|X|X| 128 | | 17.2.2 | Ensure Computer Account Management is set to 'success and failure'|X| | | 129 | | 17.2.3 | Ensure Distribution Group Management is set to 'success and failure'|X| | | 130 | | 17.2.4 | Ensure Other Account Management Events is set to 'success and failure'|X| | | 131 | | 17.2.5 | Ensure Security Group Management is set to 'success and failure'|X|X|X| 132 | | 17.2.6 | Ensure User Account Management is set to 'success and failure'|X|X|X| 133 | | 18.1.1.1 | Ensure "Prevent enabling lock screen camera" is enabled|X|X|X| 134 | | 18.1.1.2 | Ensure 'Prevent enabling lock screen slide show' is enabled|X|X|X| 135 | | 18.1.2.1 | Ensure 'Allow users to enable online speech recognition services' is disabled|X|X|X| 136 | | 18.1.2.2 | Ensure 'Allow Online Tips' is disabled|X|X|X| 137 | | 18.3.1 | Ensure 'Apply UAC restrictions to local accounts on network logons' is enabled|X|X|X| 138 | | 18.3.2 | Disable SMBv1 client driver|X|X|X| 139 | | 18.3.3 | Disable SMBv1 server - Doesn't exist in 2019 but the setting won't hurt|X|X|X| 140 | | 18.3.4 | Ensure 'Enabled Structured Exception Handling Overwrite Protection' is enabled|X|X|X| 141 | | 18.3.5 | Ensure 'Extended Protection for LDAP Authentication (DCs only)' is enabled; always|X| | | 142 | | 18.3.6 | Set NetBT Node type to P-Node|X|X|X| 143 | | 18.3.7 | Ensure 'WDigest Authentication' is disabled|X|X|X| 144 | | 18.4.1 | Ensure 'Enable automatic Logon' is disabled|X|X|X| 145 | | 18.4.2 | Disabled IPv6 IP source routing|X|X|X| 146 | | 18.4.3 | Disabled IPv4 IP source routing|X|X|X| 147 | | 18.4.4 | Disallow ICMP redirects from ovrriding OSPF routes|X|X|X| 148 | | 18.4.5 | TCP Keep alive Time|X|X|X| 149 | | 18.4.6 | Allow computer to ignore NetBIOS name release requests except from WINS servers|X|X|X| 150 | | 18.4.7 | Disable 'Allow IRDP to detet and configure Default Gateway addresses'|X|X|X| 151 | | 18.4.8 | Enable Save DLL Search mode|X|X|X| 152 | | 18.4.9 | Screen saver grace time|X|X|X| 153 | | 18.4.10 | Max IPv6 TCP retransmissions|X|X|X| 154 | | 18.4.12 | Percentage where event log will generate a warning|X|X|X| 155 | | 18.5.4.1 | DNS Client - Turn off multicast name resolution|X|X|X| 156 | | 18.5.5.1 | Disable Font providers|X|X|X| 157 | | 18.5.8.1 | Disable insecure guest logons|X|X|X| 158 | | 18.5.9.1 | Disble Mapper I/0|X|X|X| 159 | | 18.5.9.2 | Disble Responder Driver|X|X|X| 160 | | 18.5.10.1 | Turn off MS Peer-to-Peer Networking Services|X|X|X| 161 | | 18.5.11.2 | Prohibit installation of Nework bridge on DNS domain network|X|X|X| 162 | | 18.5.11.3 | Prohibit use of internet Connection Sharing on DNS domain network|X|X|X| 163 | | 18.5.11.4 | domain users to elevate when setting a network's location|X|X|X| 164 | | 18.5.19.2 | Disable IPV6|X|X|X| 165 | | 18.5.20.1 | Disable configuration of wireless settings using windows Connect Now|X|X|X| 166 | | 18.5.20.3 | Disable Windows Connect Now Wizards|X|X|X| 167 | | 18.5.21.1 | Number of simultaneous connections to the internet or windows domain is 3|X|X|X| 168 | | 18.5.21.2 | Prohibit connection to non-domain networks when connected to domain network| |X| | 169 | | 18.7.1.1 | Turn off notifications network usage|X|X|X| 170 | | 18.8.3.1 | Disable including command line in process creation events|X|X|X| 171 | | 18.8.4.1 | Force updated oracle Remediation Clients|X|X|X| 172 | | 18.8.4.2 | Remote host allows delegation of non-exportable credentials|X|X|X| 173 | | 18.8.5.1 | Turn on virtualization based security|X|X|X| 174 | | 18.8.5.6 | Disable Credential guard on DCs|X| | | 175 | | 18.8.14.1 | Enable Boot-Start driver initialization Policy|X|X|X| 176 | | 18.8.21.[2-3] | Configure registry Policy processing|X|X|X| 177 | | 18.8.21.4 | Disable 'Continue experiences on this device'|X|X|X| 178 | | 18.8.21.5 | Diable background refresh of Group Policy|X|X|X| 179 | | 18.8.22.1.1 | Turn off downloading of print drivers over HTTP|X|X|X| 180 | | 18.8.22.1.2 | Turn off handwriting personalization data sharing|X|X|X| 181 | | 18.8.22.1.3 | Enable hand writing recognition error reporting|X|X|X| 182 | | 18.8.22.1.4 | Turn off ICW if URL connection is referring to microsoft.com|X|X|X| 183 | | 18.8.22.1.5 | Turn off Internet download for Web publishing and online ordering wizards|X|X|X| 184 | | 18.8.22.1.6 | Turn off printing over HTTP|X|X|X| 185 | | 18.8.22.1.7 | Turn off REgistration if URL connection is referring to microsoft.com|X|X|X| 186 | | 18.8.22.1.8 | Turn off search companion content file updates|X|X|X| 187 | | 18.8.22.1.9 | Turn off the order prints picture task|X|X|X| 188 | | 18.8.22.1.10 | Turn off the Publish to Web task for files and folders|X|X|X| 189 | | 18.8.22.1.11 | Turn off the WMC Experience Improvement Program|X|X|X| 190 | | 18.8.22.1.12 | Turn off WCEIP|X|X|X| 191 | | 18.8.22.1.13 | Turn off Windows Error Reporting (part 1)|X|X|X| 192 | | 18.8.22.1.13 | Turn off Windows Error Reporting (part 2)|X|X|X| 193 | | 18.8.25.1 | Support device auth using certificate|X|X|X| 194 | | 18.8.26.1 | Enable Enumberation policy for external devices|X|X|X| 195 | | 18.8.27.1 | Disallow copying of user input methods to the system account|X|X|X| 196 | | 18.8.28.1 | Block user from shoing account details at sign-in|X|X|X| 197 | | 18.8.28.2 | Do not display network selection UI|X|X|X| 198 | | 18.8.28.3 | Do not enumerate connected users on domain joined computers|X|X|X| 199 | | 18.8.28.4 | Do not enumerate local users on domain-joined computers| |X| | 200 | | 18.8.28.5 | Turn off app notifications on the lock screen|X|X|X| 201 | | 18.8.28.6 | Turn off picture password sign-in|X|X|X| 202 | | 18.8.28.7 | Disable convenience PIN sign-in|X|X|X| 203 | | 18.8.31.1 | Disallow clipboard sync across devices|X|X|X| 204 | | 18.8.31.2 | Disallow uplod of user activities|X|X|X| 205 | | 18.8.34.6.1 | Disallow network connectivity during connected standby (battery)|X|X|X| 206 | | 18.8.34.6.2 | Disable network connectivity during connected standby (plugged in)|X|X|X| 207 | | 18.8.34.6.3 | Require password when computer wakes (battery)|X|X|X| 208 | | 18.8.34.6.4 | Require password when computer wakes (plugged in)|X|X|X| 209 | | 18.8.36.1 | Disable offer remote assistance|X|X|X| 210 | | 18.8.36.2 | Disable solicited remote assistance|X|X|X| 211 | | 18.8.37.1 | Enable RPC Endpoint Mapper Client|X|X|X| 212 | | 18.8.37.2 | Restrict Unauthenticated RPC clients| |X| | 213 | | 18.8.47.5.1 | Disable MSDT Interactive communication with support provider (if disabled cannot send support data to microsoft during support session)|X|X|X| 214 | | 18.8.47.11.1 | Disable PerfTrack|X|X|X| 215 | | 18.8.49.1 | Turn off advertising ID|X|X|X| 216 | | 18.8.52.1.1 | enable Windows NTP Client|X|X|X| 217 | | 18.8.52.1.2 | Disable Windows NTP Server| |X| | 218 | | 18.9.4.1 | Disallow a window app to share data between users|X|X|X| 219 | | 18.9.6.1 | Allow Microsoft Accounts to be optional|X|X|X| 220 | | 18.9.8.1 | Disallow Autoplay for non-volume devices|X|X|X| 221 | | 18.9.8.2 | Do not execute any autorun commands|X|X|X| 222 | | 18.9.8.3 | Turn off Autoplay|X|X|X| 223 | | 18.9.10.1.1 | Configure enhanced anti-spoofing|X|X|X| 224 | | 18.9.12.1 | Disallow use of camera|X|X|X| 225 | | 18.9.13.1 | Enabled microsoft consumer experiences|X|X|X| 226 | | 18.9.14.1 | Ensure Require pin for pairing is set|X|X|X| 227 | | 18.9.15.1 | Do not display the password reveal button|X|X|X| 228 | | 18.9.15.2 | Disable enumerate administrator accounts on elevation|X|X|X| 229 | | 18.9.16.1 | Ensure Allow Telemetry is set to 0 - Enterprise Only or 1 - Basic|X|X|X| 230 | | 18.9.16.2 | Disable authenticated proxy usage|X|X|X| 231 | | 18.9.16.3 | Do not show feedback notifications|X|X|X| 232 | | 18.9.16.4 | Disable toggler user control over insider builds|X|X|X| 233 | | 18.9.26.1.1 | Disable Application Event Log behavior when the log file reaches max size|X|X|X| 234 | | 18.9.26.1.2 | Set Application maximum log size|X|X|X| 235 | | 18.9.26.2.1 | Disable Security Event Log behavior when the log file reaches max size|X|X|X| 236 | | 18.9.26.2.2 | Set Security maximum log size|X|X|X| 237 | | 18.9.26.3.1 | Disable Setup Event Log behavior when the log file reaches max size|X|X|X| 238 | | 18.9.26.3.2 | Set Setup maximum log size|X|X|X| 239 | | 18.9.26.4.1 | Disable System Event Log behavior when the log file reaches max size|X|X|X| 240 | | 18.9.26.4.2 | Set System maximum log size|X|X|X| 241 | | 18.9.30.2 | Enable data execution prevention for Explorer|X|X|X| 242 | | 18.9.30.3 | Turn on hep termination on corruption|X|X|X| 243 | | 18.9.30.4 | Turn on shell protocol protected mode|X|X|X| 244 | | 18.9.39.2 | Turn off location|X|X|X| 245 | | 18.9.43.1 | Disallow message servvice cloud sync|X|X|X| 246 | | 18.9.44.1 | Block all consumer Microsoft acount user authentication|X|X|X| 247 | | 18.9.52.1 | Prevent the usage of OneDrive for file storage|X|X|X| 248 | | 18.9.59.2.2 | Do not allow passwords to be saved|X|X|X| 249 | | 18.9.59.3.2.1 | Restrict RDS Susers to a single RDS session|X|X|X| 250 | | 18.9.59.3.3.1 | Do not allow COM port redirection|X|X|X| 251 | | 18.9.59.3.3.2 | Do not allow drive redirection|X|X|X| 252 | | 18.9.59.3.3.3 | Do not allow LPT port redirection|X|X|X| 253 | | 18.9.59.3.3.4 | Do not allow PnP device redirection|X|X|X| 254 | | 18.9.59.3.9.1 | Always prompt for password upon connection|X|X|X| 255 | | 18.9.59.3.9.2 | Require secure RPC communication|X|X|X| 256 | | 18.9.59.3.9.3 | Require TLS security layer for RDP connections|X|X|X| 257 | | 18.9.59.3.9.4 | Require user auth for remote connections|X|X|X| 258 | | 18.9.59.3.9.5 | Set client connection encryption level|X|X|X| 259 | | 18.9.59.3.10.1 | Set time limit for active but idle RDS Sessions|X|X|X| 260 | | 18.9.59.3.10.2 | Set time limit for disconnected sessions|X|X|X| 261 | | 18.9.59.3.11.1 | Delete temp folders upon exit|X|X|X| 262 | | 18.9.59.3.11.2 | Use temporary folders per session|X|X|X| 263 | | 18.9.60.1 | Prevent downloading of enclosures|X|X|X| 264 | | 18.9.61.2 | Disallow Cloud Search|X|X|X| 265 | | 18.9.61.3 | Allow indexing of encrypted files|X|X|X| 266 | | 18.9.66.1 | Turn off KMS Client Online AVS Validation|X|X|X| 267 | | 18.9.77.3.1 | Do not Configure local setting override for reporting to MAPS|X|X|X| 268 | | 18.9.77.3.2 | Do not Join Microsoft MAPS|X|X|X| 269 | | 18.9.77.7.1 | Turn on behavior monitoring|X|X|X| 270 | | 18.9.77.9.1 | Disable Watson Events|X|X|X| 271 | | 18.9.77.10.1 | Scan removable drives|X|X|X| 272 | | 18.9.77.10.2 | Turn on Email scanning|X|X|X| 273 | | 18.9.77.13.1.1 | Configure Attack Surface Reduction rules|X|X|X| 274 | | 18.9.77.13.1.2 | Configure Attack Surface Reduction rules and set state for each ASR rule|X|X|X| 275 | | 18.9.77.13.3.1 | Block users and apps from accessing dangerous websites|X|X|X| 276 | | 18.9.77.14 | Configure detection for potentially unwanted applications|X|X|X| 277 | | 18.9.77.15 | Turn on Windows Defender Antivirus|X|X|X| 278 | | 18.9.80.1.1 | Enable Windows Defender SmartScreen|X|X|X| 279 | | 18.9.84.1 | Disallow suggested apps in Windows Ink Workspace|X|X|X| 280 | | 18.9.84.2 | Disallow Windows Ink Workspace|X|X|X| 281 | | 18.9.85.1 | Do not allow user control over installs|X|X|X| 282 | | 18.9.85.2 | Do not install with elevated privileges|X|X|X| 283 | | 18.9.85.3 | Enable Interent Explorder security prompt for Installer Scripts|X|X|X| 284 | | 18.9.86.1 | Do not sign in last user after a restart|X|X|X| 285 | | 18.9.95.1 | Turn off PowerShell Transcription|X|X|X| 286 | | 18.9.97.1.1 | Allow Basic WinRM authentication|X|X|X| 287 | | 18.9.97.1.2 | Allow WinRM unencrypted traffic|X|X|X| 288 | | 18.9.97.1.3 | Disallow Digest Authentication|X|X|X| 289 | | 18.9.97.2.1 | Allow Basic WinRM authentication|X|X|X| 290 | | 18.9.97.2.2 | Disallow remote server management through WinRM|X|X|X| 291 | | 18.9.97.2.3 | Disallow uncncrypted WinRM traffic|X|X|X| 292 | | 18.9.97.2.4 | Disallow WinRM from storing RunAs credentials|X|X|X| 293 | | 18.9.98.1 | Disallow Remote Shell Acccess|X|X|X| 294 | | 18.9.99.2.1 | Prevent users from modifying settings|X|X|X| 295 | | 18.9.102.1.1 | Disable preview builds|X|X|X| 296 | | 18.9.102.2 | Configure Automatic Updates|X|X|X| 297 | | 18.9.102.2 | Configure Automatic Updates|X|X|X| 298 | | 18.9.102.3 | Configure update download and patching day|X|X|X| 299 | | 18.9.102.3 | Configure update download and patching time|X|X|X| 300 | | 18.9.102.4 | Restart after updates even if user is logged in|X|X|X| 301 | | 19.6.6.1.1 | off Help Expereience Improvement Program|X|X|X| 302 | | 19.7.4.1 | Do not preserve information in file attachments|X|X|X| 303 | | 19.7.4.2 | Notify antivirus programs when opening attachments|X|X|X| 304 | -------------------------------------------------------------------------------- /galaxy.yml: -------------------------------------------------------------------------------- 1 | # REQUIRED 2 | 3 | # The namespace of the collection. This can be a company/brand/organization or product namespace under which all 4 | # content lives. May only contain alphanumeric characters and underscores. Additionally namespaces cannot start with 5 | # underscores or numbers and cannot contain consecutive underscores 6 | namespace: dsglaser 7 | 8 | # The name of the collection. Has the same character restrictions as 'namespace' 9 | name: cis_security 10 | 11 | # The version of the collection. Must be compatible with semantic versioning 12 | version: 1.5.4 13 | 14 | # The path to the Markdown (.md) readme file. This path is relative to the root of the collection 15 | readme: README.md 16 | 17 | # A list of the collection's content authors. Can be just the name or in the format 'Full Name (url) 18 | # @nicks:irc/im.site#channel' 19 | authors: 20 | - David Glaser 21 | 22 | 23 | ### OPTIONAL but strongly recommended 24 | 25 | # A short summary description of the collection 26 | description: | 27 | A collection to implement Center for Internet Security (CIS) controls for RHEL (7-9) and RHEL clones 28 | (Oracle, CentOS), SLES 15, Ubuntu [18,20,22].04 LTS, Microsoft Windows Server 2019, and Microsoft Windows 10. 29 | 30 | # Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only 31 | # accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file' 32 | license: 33 | 34 | 35 | # The path to the license file for the collection. This path is relative to the root of the collection. This key is 36 | # mutually exclusive with 'license' 37 | license_file: 'LICENSE' 38 | 39 | # A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character 40 | # requirements as 'namespace' and 'name' 41 | tags: [system, security] 42 | 43 | # Collections that this collection requires to be installed for it to be usable. The key of the dict is the 44 | # collection label 'namespace.name'. The value is a version range 45 | # L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification). Multiple version 46 | # range specifiers can be set and are separated by ',' 47 | dependencies: 48 | "community.general": "*" 49 | "community.windows": "*" 50 | 51 | # The URL of the originating SCM repository 52 | repository: https://github.com/dsglaser/cis-security 53 | 54 | # The URL to any online docs 55 | # documentation: http://docs.example.com 56 | 57 | # The URL to the homepage of the collection/project 58 | # homepage: http://example.com 59 | 60 | # The URL to the collection issue tracker 61 | issues: https://github.com/dsglaser/cis-security/issues 62 | -------------------------------------------------------------------------------- /meta/runtime.yml: -------------------------------------------------------------------------------- 1 | requires_ansible: ">2.9" 2 | -------------------------------------------------------------------------------- /roles/cis_security/README.md: -------------------------------------------------------------------------------- 1 | # cis_security 2 | 3 | A collection to implement Center for Internet Security (CIS) controls for RHEL (7-9) and RHEL clones (Oracle, CentOS), SLES 15, and Ubuntu (18,22).04 LTS and certain Windows servers. 4 | 5 | ## Introduction 6 | 7 | The [Center for Internet Security](https://www.cisecurity.org/) provides a set of 8 | security benchmarks for operating systems designed to decrease the vulnerability vectors of a system. 9 | 10 | These benchmarks are published in PDFs for non-commercial use. This role is an implementation of 11 | those controls for various Operating Systems per the list below. The controls themselves are not published here and 12 | you should visit CIS for a copy of the PDF. These automations are provided as a resposne and a tool to 13 | help systems administrators secure machines based off those recommendations. This collection is not 14 | endorsed by the Center for Internet Security in any way. 15 | 16 | This collection contains a role that is designed to layer under other Ansible roles that install software packages, users, etc. It should be idempotent and can be run at any time. As usual with Ansible, make sure that later playbooks don't modify 17 | files that are modified in this role. 18 | 19 | Benchmark Versions: 20 | | Operating System | OS Benchmark version | 21 | | -----------------|--------------------- | 22 | | RHEL 7 | v2.2.0 | 23 | | RHEL 8 | v2.0.0 | 24 | | RHEL 9 | v1.0.0 25 | | CentOS 7 | v2.2.0 | 26 | | CentOS 8 | v1.0.0 | 27 | | Fedora 31 | \(Fedora 28\) v1.1.0 | 28 | | Oracle Linux 7 | v2.2.0 | 29 | | Oracle Linux 8 | v1.0.0 | 30 | | SUSE Linux Enterprise 15 SP1 | \(SUSE Linux Enterprise 12\) v2.1.0 | 31 | | Ubuntu 18.04 LTS | v2.0.1 | 32 | | Ubuntu 22.04 LTS | 1.0.0 | 33 | | Windows Server 2019 | v1.8.1 | 34 | 35 | - Some distributions use older CIS benchmarks that were the most recent at the time of creation. Efforts have 36 | been made to update the controls to work with the newer operating systems. Older versions of the benchmarks are listed in parenthesis. 37 | - SUSE Linux Enterprise 15 SP1 uses the RHEL 7 task file since their controls are so similar. If you want to exclude a SUSE tag, make sure you use the associated RHEL 7 tag number if they are different. Tags can be found in the appropriate controls_list file found in the docs directory. 38 | 39 | ### Requirements 40 | 41 | To implement the collection correctly, you will require the following 42 | 43 | Control machine: 44 | 45 | - Ansible-core 2.11+ 46 | - Machine connected to a package repository source (Satellite or yum repo) 47 | 48 | Target machine: 49 | 50 | - SSH connection with prviiledge escalation on Linux machines. 51 | - Python interpreter 52 | - WinRM connection with user with admin priviledge for Windows. Alternatively you can use an SSH connection. 53 | - PowerShell v3 or higher 54 | 55 | Collection Requirements: 56 | 57 | - ansible.builtin 58 | - community.general 59 | - ansible.windows 60 | 61 | Requries Ansible 3 or ansible-core 2.11 or better due to runtime.yml being set up for Automation Hub. 62 | 63 | For most of the collection to work, you will need to have a package repo where you can install packages for 64 | the target machine. Registering with Satellite, a package repository, SCM, or a local package collection is recommended before using this, unless you exclude any tags that install packages. 65 | 66 | ### Use and Care 67 | 68 | The collection is designed to run on the machines in the chart above. It may run on other Red Hat and Ubuntu deriviatives, but it has not been tested on them. Upon initiation, the collection will automatically detect the OS and run the appropriate task list. 69 | 70 | As the role runs, you will see an output listing the control number and a brief description of the 71 | task being performed (or skipped): 72 | 73 | ```text 74 | TASK [security-rollup : 1.7.1.3 - Set SELinux policy to targeted] ****************************** 75 | ok: [192.168.122.252] 76 | ``` 77 | 78 | The controls are implemented as Ansible tags. By default all tags are run on a given system. To 79 | disable a tag from running, run the playbook with the tag excluded (--skip-tags "x.y.z"): 80 | 81 | ```text 82 | ansible-playbook -i --skip-tags "x.y.z" 83 | ``` 84 | 85 | Multiple tags can be listed, separated by commas: 86 | 87 | ```text 88 | ansible-playbook -i --skip-tags "x.y.z,a.b.c" 89 | ``` 90 | 91 | Note: Some automation tasks handle multiple controls. In the role you may see something like this: 92 | 93 | ```yaml 94 | - name: 6.1.[2,4] - Ensure permissions on /etc/passwd /etc/group 95 | file: 96 | path: /etc/{{item}} 97 | owner: root 98 | group: root 99 | mode: 0644 100 | loop: 101 | - passwd 102 | - group 103 | tags: 104 | - 6.1.2 105 | - 6.1.4 106 | ``` 107 | 108 | In this control, two tags are being processed, '6.1.2' and '6.1.4' if you want this control to not run, you must exclude both tags: 109 | 110 | ```text 111 | ansible-playbook -i --skip-tags "6.1.2,6.1.4" 112 | ``` 113 | 114 | Some controls are surrouned by Ansible blocks that themselves have tags. Excluding the tag that applies 115 | to the block will exclude all of the tasks inside of the block. If the block's tag is **not** excluded, 116 | then individual tasks inside of the block can be excluded by excluding their tags. 117 | 118 | The list of tags and their associated crontol descriptions are listed in the [controls_list](./docs/controls_list.md) file for Linux and [control_list_win](./docs/controls_list_win.md_ file for Windows) 119 | in the docs directory. 120 | 121 | In addition to tags, there are a number of variables that can be set which will enable or disable 122 | tasks, or set values. These are explained and given default values in the **roles/cis-security/defaults/main.yml** 123 | file. Do not set these values in that file, but create and include your own variable file to override the 124 | defaults or set them as host variables. 125 | 126 | ### Idempotency 127 | 128 | Every effort has been made to make the controls idempotent, however some Ansible modules do not have the ability 129 | to measure every need as currently written and shell or command has been utilized to implement controls. This 130 | has the effect of bringing down the quality score on Ansible Galaxy, but the roles can be run multiple times 131 | without fear of breaking. 132 | 133 | ### Learning Tool 134 | 135 | A secondary purpose of this collection is to show numerous ways that Ansible can be used to 136 | manage systems with various modules. The first time a module is used it is commented on many times 137 | to explain what the module is doing. Other times you may see something like the following: 138 | 139 | ```yaml 140 | - name: 5.4.4 - Ensure umask is set 141 | replace: 142 | path: "{{ item }}" 143 | replace: " umask {{ default_umask }}" 144 | regexp: '^\s*umask\s*022' 145 | loop: 146 | - /etc/bashrc 147 | - /etc/profile 148 | when: ansible_distribution != "SLES" 149 | tags: 150 | - 5.4.4 151 | 152 | - name: 5.4.5 - Ensure shell timeout is {{ shell_timeout }} seconds or less 153 | blockinfile: 154 | path: "{{ item }}" 155 | block: "TMOUT={{ shell_timeout }}" 156 | marker: "# {mark} Ansible Managed CIS Timeout" 157 | loop: 158 | - /etc/bashrc 159 | - /etc/profile 160 | when: ansible_distribution != "SLES" 161 | tags: 162 | - 5.4.5 163 | ``` 164 | 165 | Both of these tasks manipulate the same file in the same way. They could have been written 166 | with the same module, even in the same task with a loop, but here it illustrates different 167 | ways files can be manipuldated with modules. 168 | 169 | ### Change Log 170 | 171 | - 1/20/2020 - dsglaser@gmail.com - Initial creation 172 | - 1/22/2020 - dsglaser@gmail.com - Added enhanced selinux controls 173 | - 2/18/2020 - dsglaser@gmail.com - Added support for Ubuntu 18.04 LTS, added RHEL clone links 174 | - 2/20/2020 - dsglaser@gmail.com - Fixed numerous tests and rearranged network controls 175 | - 2/25/2020 - dsglaser@gmail.com - Added SLES 15 SP 1 support 176 | - 3/17/2020 - dsglaser@gmail.com - Added Windows 2019 support 177 | - 7/24/2022 - dsglaser@gmail.com - Coversion to full collection status (Namespace: dsglaser) 178 | - 4/14/2023 - dsglaser@gmail.com - Added support for RHEL 9, updated RHEL 8 to CIS v2.0.0o 179 | - 5/2/2023 - dsglaser@gmail.com - Added support for Ubuntu 22.04 LTS 180 | -------------------------------------------------------------------------------- /roles/cis_security/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for cis-security see variable descriptions in security-rollup/README.md 3 | 4 | ### Mandatory Access controls 5 | ## Red Hat and Red Hat clones using selinux 6 | selinux: "enforcing" # Options are enforcing, permissive, and disabled. Control is 'enforcing' 7 | selinux_policy: "targeted" # Options are targeted, minimum, or mls. Control has no default 8 | crypto_policy: "DEFAULT" # Options are DEFAULT, FIPS, or LEGACY 9 | 10 | ## Ubuntu, ubuntu clones, and SLES using apparmor 11 | apparmor_level: "enforce" # Set all profiles in /etc/apparmor.d/* to this level. Options are enforce or complain 12 | 13 | # Network Time Services 14 | time_service: "chrony" # Linux: Option for RHEL7/Ubuntu only; options are 'chrony' or 'timesyncd'. 15 | # RHEL8/9 only ships with chrony and this variable is not used 16 | # Linux: Choices are 'ntp' or chrony'. For Ubuntu, this can also accept 'none' as an option to use only systemd timedatectl 17 | time_server: "2.rhel.pool.ntp.org" # Linux: Time server for ntp, chrony, or timedatectl 18 | time_operators: # Windows: Users that can set the system time 19 | - "Administrators" 20 | - "LOCAL SERVICE" 21 | time_user: "_chrony" # Linux: Ubuntu 22 only, user to run time daemon as 22 | 23 | # Sudo Configuration 24 | sudo_log: "/var/log/sudoers" # Linux: log file for sudo 25 | 26 | # GDM Timeout Configuration 27 | idle_delay: 900 # Seconds of inactivity before locking screen 28 | lock_delay: 5 # Seconds of blank screen before locking 29 | 30 | # AIDE configuration settings 31 | aide_db_name: "/var/lib/aide/aide.db.gz" # Linux: Database name that AIDE will look for for comparison 32 | aide_new_db_name: "/var/lib/aide/aide.db.new.gz" # Linux: Database name created during an --init run 33 | aide_gzip: "yes" # Linux: 'yes' or 'no' to enable gzip compression on database 34 | 35 | # Yum repos and system updates 36 | update_system: false # Linux: Update the system to the latest during the role run 37 | gpgcheck: true # Linux: Enable GPG checks on ALL repos 38 | enable_audit: true # Linux: Enable auditing of processes and filesystem changes 39 | audit_backlog_limit: 8192 # Linux: RHEL default is 8MB backlog limit 40 | 41 | # Server roles, setting any of the variables to false will remove the default RHEL packages for that service. 42 | # Setting them to true will not remove them, but will not set them up. 43 | dhcp_server: false # Linux: DHCP Server 44 | dns_server: false # Linux: DNS Server 45 | email_server: false # Linux: Mail Server, If set to true, and the packages exist, it will set mail relay to local only 46 | ftp_server: false # Linux: FTP SErver 47 | http_server: false # Linux: HTTP Server (will remove dependent packages as well) 48 | nfs_server: false # Linux: NFS Server 49 | proxy_server: false # Linux: Squid proxy server 50 | smb_server: false # Linux: Samba Server 51 | tftp_server: false # Linux: TFTPd Server. Option for RHEL7 only 52 | 53 | # Desktop roles, see 'Server roles' above. 54 | ypbind: false 55 | graphical_interface: false # Whether to disable the GDM greeter service. The service will disabled on 'false' 56 | 57 | # Services 58 | service_bluetooth: # Linux: Ubuntu 22 only. Set to 'false' to disable bluetooth service 59 | 60 | # Logging services variables 61 | log_service: "journald" # journald or rsyslog for logging. Choose one. Currently only implemented in RHEL 8/9! 62 | remote_log_service: false # Whether to configure journald to start systemd-journal-remote.service 63 | log_host: false # Linux: Whether this machine will host rsyslog messages for other machines 64 | log_port: 514 # Linux: Port to listen to RSYSLOG messages on (if log_host is true) 65 | log_file: /var/log/audit/auditd.log # Linux: path and location of audit log 66 | log_file_size: 8 # Linux: log file size. RHEL default is 8MB, control has no default 67 | log_group: root # Group that owns the auditd log files (root or adm) RHEL 8/9 68 | rsyslog_file: # Linux: Copy file listed for configuring rsyslog 69 | logrotate_file: # Linux: RHEL 8/9, Copy file listed for logrotate 70 | 71 | # network security settings 72 | tcpwrappers: false # Linux: Configure tcpwrappers controls. RHEL 7 control only 73 | tcpwrappers_pkg: "tcp_wrappers" # Linux: Name of tcp wrappers package in repository 74 | enable_firewall: firewalld # Linux: supported values are firewalld (RHEL), nftables (RHEL, Ubuntu) or iptables (Ubuntu) 75 | firewalld_default_zone: public # Linux: default firwall zone 76 | motd_use: true # Linux: RHEL 9: set to 'true' to use motd file, 'false' to not use 77 | motd_file: "banner" # Linux: File location by default in 'files' directory 78 | issue_use: true # Linux: RHEL 9: set to 'true' to use issue file, 'false' to not use 79 | issue_file: "issue" # Linux: File location by default in 'files' directory 80 | issue_net_use: true # Linux: RHEL 9: set to 'true' to use issue.net file, 'false' to not use 81 | issue_net_file: "issue" # Linux: File location by default in 'files' diretory 82 | ipv6_disable: true # Common: Set to true to disable ipv6 support on host 83 | 84 | # Cron/at variables 85 | cron_allow: [] # Linux: RHEL9, list of users to add to cron.allow 86 | at_allow: [] # Linux: RHEL9, list of users to add to at_allow.allow 87 | 88 | # SSH Server settings 89 | ssh_log_level: INFO # Linux: Control is INFO or VERBOSE. Stricter is not approved and more verbose exposes user info 90 | ssh_max_auth_tries: 4 # Linux: Control is 4 retries 91 | ssh_mac_list: "hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com" 92 | # Linux: RHEL7 only control 93 | ssh_ciphers_list: "chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr" 94 | # Linux: Ubuntu control only 95 | ssh_kex_list: 96 | - 'curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1' 97 | # Linux: Ubuntu control only 98 | ssh_alive_interval: 300 # Linux: Control is 5 minutes 99 | ssh_alive_count_max: 0 # Linux: Control is 0 count 100 | ssh_grace_time: 60 # Linux: Control is for 60 seconds or less 101 | ssh_max_sessions: 4 # Linux: Control is 4 sessions from a single host 102 | ssh_login_banner: issue.net # Linux: a file with no path will exist in the role's files directory, an absolute path will exist on the control host 103 | ssh_allowed_users: "" # Linux: RHEL9, space separated list of users to add to AllowUsers list 104 | ssh_allowed_groups: "" # Linux: RHEL9, space separated list of users to add to DenyUsers list 105 | ssh_denied_users: "root" # Linux: RHEL9, space separated list of users to add to AllowGroups list 106 | ssh_denied_groups: "" # Linux: RHEL9, space separated list of users to add to DneyGroups list 107 | 108 | # Password and account settings, all settings below match controls 109 | password_min_length: 14 # Common 110 | password_req_digit: true # Linux 111 | password_req_upper: true # Linux 112 | password_req_lower: true # Linux 113 | password_req_special: true # Linux 114 | password_hash_alg: "yescrypt" # Linux (RHEL 8/9), set password hashing algorithm, set to 'sha512' or 'yescrypt' 115 | password_min_days: 7 # Common: Windows has this control listed as 1 day 116 | password_expire_days: 365 # Common: Windows has this control listed as 24 days 117 | password_warning_days: 7 # Common: Windows has this control listed as 'between 5 and 14 days' 118 | password_inactive_lock_days: 30 # Linux 119 | password_failed_attempts: 5 # RHEL 9: Number of attempts before locking account 120 | password_failed_time: 900 # RHEL 9: amount of time to lock an account that has exceeded failed attemps 121 | password_history: 24 # Windows: number of passwords to remember. 122 | password_max_repeat: 3 # Linux: Ubuntu 22 only, number of same characters in a passwd 123 | account_lockout_duration: 15 # Windows: 124 | account_lockout_threshold: 10 # Windows: 125 | account_reset_duration: 15 # Windows: 126 | cached_logins: 4 # Windows: Number of login credentials to cache 127 | enable_guest: false # Windows: enable guest account 128 | rename_guest: "Guest" # Windows: name of guest account. Will have no effect if enable_gues variable is set to false 129 | enable_administrator: true # Windows: enable Administrator account 130 | rename_administrator: "Administrator" # Windows: name of Administrator account. Will have no effect if enable_Administrator variable is set to false 131 | dc_network_logon_right: # Windows: Users that have access to log on from the network (domain controllers) 132 | - "Administrators" 133 | - "Authenticated Users" 134 | - "ENTERPRISE DOMAIN CONTROLLERS" 135 | ms_network_logon_right: # Windows: Users that have access to log on from the network (member servers and standalone servers) 136 | - "Administrators" 137 | - "Authenticated Users" 138 | local_logon_right: # Windows: Users that have access to log onto the console 139 | - "Administrators" 140 | dc_rds_logon_right: # Windows: Users that have access to log onto the system through Remote Desktop Services (domain controller) 141 | - "Administrators" 142 | - "Remote Desktop Users" 143 | ms_rds_logon_right: # Windows: Users that have access to log onto the system through Remote Desktop Services (member or standalone server) 144 | - "Administrators" 145 | adjust_memory_quotas: # Windows: Users that can adjust the memory quotas for a process 146 | - "Administrators" 147 | - "LOCAL SERVICE" 148 | - "NETWORK SERVICE" 149 | backup_operators: # Windows: Users that can backup files and diretories via a backup application 150 | - "Administrators" 151 | dc_symbolic_link_right: # Windows: Users that can create symbolic links. 152 | - "Administrators" 153 | ms_symbolic_link_right: # Windows: Users that can create symbolic links. If Hyper-V is installed, this should include "Virtual Machines" 154 | - "Administrators" 155 | - 'NT VIRTUAL MACHINE\Virtual Machines' 156 | max_machine_account_days: 30 # Windows: Maximum number of days a machine can keep its password before changing. A zero here will 157 | # automatically be changed to 30 by the task to force some password rotation 158 | 159 | # Environment settings, all settings below match controls 160 | shell_timeout: 900 # Linux: 161 | default_umask: "027" # Linux: Control is 027 or more strict 162 | inactivity_timeout: 900 # Windows: Number of seconds before screen saver. A zero here will default to 900 for some security 163 | 164 | smart_card_removal: 1 # Windows. what do do when a smart card used for authentication is removed. 165 | # Options that can be set in or take effect: 166 | # 1 - Lock Workstation 167 | # 2 - Force Logoff 168 | # 3 - Disconnect if a Remote Desktop Services session 169 | smb_inactivity_minutes: 15 # Windows. Minutes until server suspends SMB connection due to inactivity 170 | spn_level: 1 # Windows. level of validation with shared folders the server performs on the service principal name 171 | # Options that can be set in or take effect: 172 | # 1 - Accept if provided by client 173 | # 2 - Required from client 174 | ldap_client_signing: 1 # Windows. Sign ldap client communications 175 | # Options that can be set to take effect: 176 | # 1 - Negotiate signing 177 | # 2 - Require signing 178 | uac_prompt_for_consent_admin: 2 # Windows. When to prompt admins for elevated Admin Approval Mode 179 | # 0 - Elevate without prompting 180 | # 1 - Prompt for credentials on the secure desktop 181 | # 2 - Prompt for consent on the secure desktop (default) 182 | # 3 - Prompt for credentials 183 | # 4 - Prompt for consent 184 | # 5 - Prompt for consent for non-Windows binaries 185 | uac_prompt_for_consent_user: 3 # Windows. When to prompt users for elevated Admin Approval Mode 186 | # 0 - Automatically deny elevation requests 187 | # 1 - Prompt for credentials on the secure desktop 188 | # 3 - Prompt for credentials 189 | screensaver_grace_time: 0 # Windows. Seconds from screen saver start until computer locks 190 | win_application_log_size: "32768" # Windows. Max application event log file size 191 | win_security_log_size: "196608" # Windows. Max security event log file size 192 | win_setup_log_size: "32768" # Windows. Max setup event log file size 193 | win_system_log_size: "32768" # Windows. Max setup event log file size 194 | disable_automatic_updates: "0" # Windows. Disable automatic updates. Set to '1' to disable automatic updates. (Choose if using 3rd party update systems) 195 | au_update_options: "4" # Windows. Configure automatic updates. Possible values 196 | # 2 - Notify for download and auto install (Notify before downloading any updates) 197 | # 3 - Auto download and notify for install (Download the updates automatically and notify. ) (Default) 198 | # 4 - Auto download and schedule the install (Automatically download updates and install them on the schedule specified.) 199 | # 5 - Allow local admin to choose setting (Leave decision on above choices up to the local Administrators (Not Recommended) 200 | au_update_day: "0" # Windows. Configure which day automatic updates will be installed. 201 | # Only takes effect if "automatic_updates" == "4". Possible values 202 | # 0 - Every delay 203 | # 1 - Every Sunday 204 | # 2 - Every Monday 205 | # 3 - Every Tuesday 206 | # 4 - Every Wednesday 207 | # 5 - Every Thursday 208 | # 6 - Every Friday 209 | # 7 - Every Saturday 210 | au_update_time: "3" # Windows. Configure what time automatic updates will be installed. 211 | # Only takes effect if "automatic_updates" == "4". This is the hour portion of the 212 | # time only. "3" means 03:00am. Set this value to '24' for windows to automatically pick a time 213 | -------------------------------------------------------------------------------- /roles/cis_security/files/banner: -------------------------------------------------------------------------------- 1 | Authorized uses only. All activity may be monitored and reported. 2 | -------------------------------------------------------------------------------- /roles/cis_security/files/duplicate_groups.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cat /etc/group | cut -f1 -d":" | sort -n | uniq -c | while read x ; do 3 | [ -z "${x}" ] && break 4 | set - $x 5 | if [ $1 -gt 1 ]; then 6 | gids=`awk -F: '($1 == n) { print $3 }' n=$2 /etc/passwd | xargs` 7 | echo "Duplicate Group Name ($2): ${gids}" 8 | fi 9 | done 10 | -------------------------------------------------------------------------------- /roles/cis_security/files/duplicate_guids.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cat /etc/group | cut -f3 -d":" | sort -n | uniq -c | while read x ; do 3 | [ -z "${x}" ] && break 4 | set - $x 5 | if [ $1 -gt 1 ]; then 6 | groups=`awk -F: '($3 == n) { print $1 }' n=$2 /etc/group | xargs` 7 | echo "Duplicate GID ($2): ${groups}" 8 | fi 9 | done 10 | -------------------------------------------------------------------------------- /roles/cis_security/files/duplicate_uids.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cat /etc/passwd | cut -f3 -d":" | sort -n | uniq -c | while read x ; do 3 | [ -z "${x}" ] && break 4 | set - $x 5 | if [ $1 -gt 1 ]; then 6 | users=`awk -F: '($3 == n) { print $1 }' n=$2 /etc/passwd | xargs` 7 | echo "Duplicate UID ($2): ${users}" 8 | fi 9 | done 10 | -------------------------------------------------------------------------------- /roles/cis_security/files/duplicate_users.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cat /etc/passwd | cut -f1 -d":" | sort -n | uniq -c | while read x ; do 3 | [ -z "${x}" ] && break 4 | set - $x 5 | if [ $1 -gt 1 ]; then 6 | uids=`awk -F: '($1 == n) { print $3 }' n=$2 /etc/passwd | xargs` 7 | echo "Duplicate User Name ($2): ${uids}" 8 | fi 9 | done 10 | -------------------------------------------------------------------------------- /roles/cis_security/files/issue: -------------------------------------------------------------------------------- 1 | Authorized uses only. All activity may be monitored and reported. 2 | -------------------------------------------------------------------------------- /roles/cis_security/files/non_existant_homedirs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | awk -F: '($1!~/(halt|sync|shutdown|nfsnobody)/ && $7!~/^(\/usr)?\/sbin\/nologin(\/)?$/ && $7!~/(\/usr)?\/bin\/false(\/)?$/) { print $1 " " $6 }' /etc/passwd | while read -r user dir; do 3 | if [ ! -d "$dir" ]; then 4 | echo "User: \"$user\" home directory: \"$dir\" does not exist." 5 | fi 6 | done 7 | -------------------------------------------------------------------------------- /roles/cis_security/files/path_check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ## Find issues in user's PATH variable 3 | 4 | if [ "`echo $PATH | grep ::`" != "" ]; then 5 | echo "Empty Directory in PATH (::)" 6 | fi 7 | if [ "`echo $PATH | grep :$`" != "" ]; then 8 | echo "Trailing : in PATH" 9 | fi 10 | p=`echo $PATH | sed -e 's/::/:/' -e 's/:$//' -e 's/:/ /g'` 11 | set -- $p 12 | while [ "$1" != "" ]; do 13 | if [ "$1" = "." ]; then 14 | echo "PATH contains ." 15 | shift 16 | continue 17 | fi 18 | if [ -d $1 ]; then 19 | dirperm=`ls -ldH $1 | cut -f1 -d" "` 20 | if [ `echo $dirperm | cut -c6` != "-" ]; then 21 | echo "Group Write permission set on directory $1" 22 | fi 23 | if [ `echo $dirperm | cut -c9` != "-" ]; then 24 | echo "Other Write permission set on directory $1" 25 | fi 26 | dirown=`ls -ldH $1 | awk '{print $3}'` 27 | if [ "$dirown" != "root" ] ; then 28 | echo $1 is not owned by root 29 | fi 30 | else 31 | echo $1 is not a directory 32 | fi 33 | shift 34 | done 35 | -------------------------------------------------------------------------------- /roles/cis_security/files/rsyslog.conf: -------------------------------------------------------------------------------- 1 | # Default rules for rsyslog. 2 | # 3 | # For more information see rsyslog.conf(5) and /etc/rsyslog.conf 4 | 5 | # 6 | # First some standard log files. Log by facility. 7 | # 8 | auth,authpriv.* /var/log/auth.log 9 | *.*;auth,authpriv.none -/var/log/syslog 10 | #cron.* /var/log/cron.log 11 | #daemon.* -/var/log/daemon.log 12 | kern.* -/var/log/kern.log 13 | #lpr.* -/var/log/lpr.log 14 | mail.* -/var/log/mail.log 15 | #user.* -/var/log/user.log 16 | 17 | # 18 | # Logging for the mail system. Split it up so that 19 | # it is easy to write scripts to parse these files. 20 | # 21 | #mail.info -/var/log/mail.info 22 | #mail.warn -/var/log/mail.warn 23 | mail.err /var/log/mail.err 24 | 25 | # 26 | # Some "catch-all" log files. 27 | # 28 | #*.=debug;\ 29 | # auth,authpriv.none;\ 30 | # news.none;mail.none -/var/log/debug 31 | #*.=info;*.=notice;*.=warn;\ 32 | # auth,authpriv.none;\ 33 | # cron,daemon.none;\ 34 | # mail,news.none -/var/log/messages 35 | 36 | # 37 | # Emergencies are sent to everybody logged in. 38 | # 39 | *.emerg :omusrmsg:* 40 | 41 | # 42 | # I like to have messages displayed on the console, but only on a virtual 43 | # console I usually leave idle. 44 | # 45 | #daemon,mail.*;\ 46 | # news.=crit;news.=err;news.=notice;\ 47 | # *.=debug;*.=info;\ 48 | # *.=notice;*.=warn /dev/tty8 49 | -------------------------------------------------------------------------------- /roles/cis_security/files/undefined_groups.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | for i in $(cut -s -d: -f4 /etc/passwd | sort -u ); do 3 | grep -q -P "^.*?:[^:]*:$i:" /etc/group 4 | if [ $? -ne 0 ]; then 5 | echo "Group $i is referenced by /etc/passwd but does not exist in /etc/group" 6 | fi 7 | done 8 | -------------------------------------------------------------------------------- /roles/cis_security/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for cis-security 3 | 4 | # The auditd service has to be restarted with the actual SYS5 service 5 | # command rather than the service module (which uses systemd) 6 | # https://access.redhat.com/solutions/2664811 7 | 8 | - name: Restart auditd 9 | ansible.builtin.command: service auditd restart 10 | when: ansible_os_family != "windows" 11 | listen: "Restart auditd" 12 | 13 | # reboot a machine. Give it 10 minutes to come up in case it 14 | # needs to do a selinux relabel 15 | - name: Reboot 16 | ansible.builtin.reboot: 17 | # reboot_timeout: 600 18 | 19 | - name: Restart ntpd 20 | ansible.builtin.service: 21 | name: ntpd 22 | state: restarted 23 | 24 | - name: Restart sshd 25 | ansible.builtin.service: 26 | name: sshd 27 | state: restarted 28 | 29 | - name: Restart chronyd 30 | ansible.builtin.service: 31 | name: chronyd 32 | state: restarted 33 | 34 | - name: Restart rsyslog 35 | ansible.builtin.service: 36 | name: rsyslog 37 | state: restarted 38 | 39 | - name: Restart journald 40 | ansible.builtin.service: 41 | name: systemd-journald 42 | state: restarted 43 | 44 | - name: Restart postfix 45 | ansible.builtin.service: 46 | name: postfix 47 | state: restarted 48 | 49 | - name: Start firewalld 50 | ansible.builtin.service: 51 | name: firewalld 52 | state: started 53 | 54 | - name: Restart firewalld 55 | ansible.builtin.service: 56 | name: firewalld 57 | state: restarted 58 | 59 | - name: Start iptables 60 | ansible.builtin.service: 61 | name: iptables 62 | state: started 63 | 64 | - name: Restart tmpfs 65 | ansible.builtin.systemd: 66 | name: tmp.mount 67 | state: restarted 68 | enabled: true 69 | masked: false 70 | daemon_reload: true 71 | 72 | # Call the grub config file rebuilding program 73 | # There is no grub module, so we have to do it with shell 74 | - name: Rebuild grub 75 | ansible.builtin.command: /usr/sbin/grub2-mkconfig -o /boot/grub2/grub.cfg 76 | 77 | # Call the grub config file rebuilding program on ubuntu 78 | # There is no grub module, so we have to do it with shell 79 | - name: Rebuild ubuntu-grub 80 | ansible.builtin.command: /usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg 81 | 82 | - name: Update crypto_policy 83 | ansible.builtin.command: /usr/bin/update-crypto-policies 84 | 85 | - name: Restart aidecheck 86 | ansible.builtin.systemd: 87 | name: aidecheck 88 | enabled: true 89 | daemon_reload: true 90 | state: restarted 91 | 92 | - name: Flush network routes 93 | ansible.posix.sysctl: 94 | name: "{{ item }}" 95 | value: "1" 96 | reload: true 97 | state: present 98 | sysctl_set: true 99 | loop: 100 | - net.ipv4.route.flush 101 | - net.ipv6.route.flush 102 | 103 | - name: Restart timesyncd 104 | ansible.builtin.systemd: 105 | name: systemd.timesyncd 106 | enabled: true 107 | state: restarted 108 | 109 | - name: Restart ufw 110 | community.general.ufw: 111 | state: enabled 112 | -------------------------------------------------------------------------------- /roles/cis_security/meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | author: David Glaser 3 | description: Apply The [Center for Internet Security](https://www.cisecurity.org/) controls against supported platforms. 4 | 5 | # If the issue tracker for your role is not on github, uncomment the 6 | # next line and provide a value 7 | # issue_tracker_url: http://example.com/issue/tracker 8 | 9 | # Choose a valid license ID from https://spdx.org - some suggested licenses: 10 | # - BSD-3-Clause (default) 11 | # - MIT 12 | # - GPL-2.0-or-later 13 | # - GPL-3.0-only 14 | # - Apache-2.0 15 | # - CC-BY-4.0 16 | license: GPL-2.0-or-later 17 | 18 | min_ansible_version: 2.9 19 | 20 | # If this a Container Enabled role, provide the minimum Ansible Container version. 21 | # min_ansible_container_version: 22 | 23 | # 24 | # Provide a list of supported platforms, and for each platform a list of versions. 25 | # If you don't wish to enumerate all versions for a particular platform, use 'all'. 26 | # To view available platforms and versions (or releases), visit: 27 | # https://galaxy.ansible.com/api/v1/platforms/ 28 | # 29 | # platforms: 30 | # - name: Fedora 31 | # versions: 32 | # - all 33 | # - 25 34 | # - name: SomePlatform 35 | # versions: 36 | # - all 37 | # - 1.0 38 | # - 7 39 | # - 99.99 40 | platforms: 41 | - name: EL 42 | versions: 43 | - 8 44 | - 7 45 | - name: Fedora 46 | versions: 47 | - 28 48 | - 29 49 | - 30 50 | - 31 51 | - name: Ubuntu 52 | versions: 53 | - 18.04 54 | - 20.04 55 | - name: SLES 56 | versions: 57 | - 15 58 | - name: Windows 59 | versions: 60 | - 2019 61 | - 10 62 | 63 | galaxy_tags: [] 64 | # List tags for your role here, one per line. A tag is a keyword that describes 65 | # and categorizes the role. Users find roles by searching for tags. Be sure to 66 | # remove the '[]' above, if you add tags to this list. 67 | # 68 | # NOTE: A tag is limited to a single word comprised of alphanumeric characters. 69 | # Maximum 20 tags per role. 70 | 71 | dependencies: [] 72 | # List your role dependencies here, one per line. Be sure to remove the '[]' above, 73 | # if you add dependencies to this list. 74 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-CentOS-7.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for RHEL 7 type machines 3 | 4 | - include: type-files/redhat-7-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-CentOS-8.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for RHEL 8 type machines 3 | 4 | - include: type-files/redhat-8-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-Fedora-31.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for RHEL 8 type machines 3 | 4 | - include: type-files/redhat-8-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-Fedora-32.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for RHEL 8 type machines 3 | 4 | - include: type-files/redhat-8-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-Microsoft Windows 10 Pro.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for MS Windows type machines 3 | 4 | - include: type-files/MS-Server-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-Oracle-7.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for Oracle 7 type machines 3 | 4 | - include: type-files/redhat-7-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-OracleLinux-8.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for RHEL 8 type machines 3 | 4 | - include: type-files/redhat-8-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-RedHat-7.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for RHEL 7 type machines 3 | 4 | - include: type-files/redhat-7-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-RedHat-8.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for RHEL 8 type machines 3 | 4 | - include: type-files/redhat-8-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-RedHat-9.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for RHEL 8 type machines 3 | 4 | - include: type-files/redhat-9-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-SLES-15.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Technically SUSE 15 is more like RHEL 8 than RHEL 7, but since we 3 | # are using an older benchmark, the controls numbers are closer to the RHEL 7 ones, so 4 | # it's easier to include that file and make the few changes for SUSE. 5 | 6 | - include: type-files/redhat-7-type.yml 7 | - include: type-files/SLES-addons.yml 8 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-Ubuntu-18.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for Ubuntu 18 type machines 3 | 4 | - include: type-files/ubuntu-18-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-Ubuntu-20.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for Ubuntu 20 type machines 3 | 4 | - include: type-files/ubuntu-18-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/CIS-Ubuntu-22.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # indclude the type file for Ubuntu 18 type machines 3 | 4 | - include: type-files/ubuntu-22-type.yml 5 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for cis-security 3 | 4 | - name: include appropriate type file 5 | ansible.builtin.include_tasks: CIS-{{ ansible_distribution }}-{{ ansible_distribution_major_version | replace("Evaluation", "") }}.yml 6 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/type-files/SLES-addons.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Task file for CIS Controls 3 | # This file is commented to help view what Ansible Automation is doing 4 | # and under what circumstances. 5 | 6 | - name: 1.3 - Filesystem integrity checking w/AIDE 7 | block: 8 | - name: 1.3.1 - Initialize AIDE if it hasn't been already (/usr/bin/aide) 9 | ansible.builtin.command: /usr/bin/aide --init 10 | when: ( not aide_path.stat.exists or not aide_path.stat.isreg ) and ansible_distribution == "SLES" 11 | tags: 12 | - 1.3.1 13 | tags: 14 | - 1.3.0 15 | 16 | - name: 1.6.0 - Mandatory Access Control 17 | block: 18 | - name: 1.6.2 - Configure AppArmor (SLES only) 19 | block: 20 | - name: 1.6.2.1 Ensure Apparmor is not disabled in bootloader configuration 21 | ansible.builtin.replace: 22 | dest: /etc/default/grub 23 | regexp: "{{ item }}" 24 | replace: "" 25 | with_items: 26 | - apparmor=0 27 | notify: Rebuild grub 28 | tags: 29 | - 1.6.2.1 30 | 31 | - name: 1.6.2.2 - Ensure all AppArmor profiles are enforcing 32 | ansible.builtin.command: enforce /etc/apparmor.d/* 33 | when: apparmor_level == "enforce" 34 | failed_when: false 35 | changed_when: false 36 | tags: 37 | - 1.6.2.2 38 | 39 | - name: 1.6.3 - Ensure SELinux or AppArmor are installed (pull package list again) 40 | ansible.builtin.package_facts: 41 | manager: auto 42 | 43 | - name: 1.6.3 - Ensure SELinux or AppArmor are installed (report to user) 44 | ansible.builtin.debug: 45 | msg: "Either SELinux or AppArmor is not installed. Please enable them with tags and restart" 46 | when: "'libselinux1' in ansible_facts.packages and 'libapparmor1' in ansible_facts.packages" 47 | when: ansible_distribution == "SLES" 48 | tags: 49 | - 1.6.2 50 | tags: 51 | - 1.6.0 52 | 53 | - name: 2.2.2 - Set default runlevel (non graphical) 54 | ansible.builtin.file: 55 | src: /usr/lib/systemd/system/multi-user.target 56 | dest: /etc/systemd/system/default.target 57 | owner: root 58 | group: root 59 | when: not graphical_interface 60 | 61 | - name: 2.2.2 - Set default runlevel (graphical) 62 | ansible.builtin.file: 63 | src: /usr/lib/systemd/system/graphical.target 64 | dest: /etc/systemd/system/default.target 65 | owner: root 66 | group: root 67 | when: graphical_interface 68 | 69 | - name: create empty list for unneeded packages 70 | ansible.builtin.set_fact: 71 | unneeded_packages: [] 72 | tags: 73 | - always 74 | 75 | - name: 2.2.6 - add openldap server to removal list 76 | ansible.builtin.set_fact: 77 | unneeded_packages: "{{ unneeded_packages + [ 'openldap2' ] }}" 78 | tags: 79 | - 2.2.6 80 | 81 | - name: 2.2.10 - Remove httpd; add to removal list 82 | ansible.builtin.set_fact: 83 | unneeded_packages: "{{ unneeded_packages + [ 'apache2' ] }}" 84 | when: http_server is defined and not http_server 85 | tags: 86 | - 2.2.10 87 | 88 | # With the list complete, use it with the system's package manager 89 | # to remove packages from the system that are not needed. 90 | - name: Process removal list 91 | ansible.builtin.yum: 92 | name: "{{ unneeded_packages }}" 93 | state: absent 94 | tags: 95 | - always 96 | 97 | - name: 5.1.1 - Ensure cron is enabled (SLES) 98 | ansible.builtin.service: 99 | name: cron 100 | enabled: true 101 | state: started 102 | when: ansible_distribution == "SLES" 103 | tags: 104 | - 5.1.1 105 | 106 | - name: 5.3.4 - SLES specific password settings 107 | block: 108 | - name: 5.3.4 - Determine if we are currently using sha512 password 109 | ansible.builtin.lineinfile: 110 | path: /etc/pam.d/common-password 111 | regexp: 'pam_unix.so*sha512' 112 | state: absent 113 | check_mode: true 114 | changed_when: false 115 | register: sha512_exist 116 | failed_when: fals 117 | 118 | - name: 5.3.4 - Determine if we are currently using sha512 password 119 | ansible.builtin.replace: 120 | dest: /etc/pam.d/common-password 121 | regexp: 'pam_unix.so' 122 | replace: 'pam_unix.so sha512' 123 | when: not sha512_exist.found 124 | when: ansible_distribution == "SLES" 125 | tags: 126 | - 5.3.4 127 | 128 | - name: 5.4.4 - Ensure umask is set (SLES) 129 | ansible.builtin.replace: 130 | path: "{{ item }}" 131 | replace: " umask {{ default_umask }}" 132 | regexp: '^\s*umask\s*022' 133 | when: ansible_distribution == "SLES" 134 | loop: 135 | - /etc/bash.bashrc.local 136 | - /etc/profile.local 137 | tags: 138 | - 5.4.4 139 | 140 | - name: 5.4.5 - Ensure shell timeout is set (SLES) 141 | ansible.builtin.blockinfile: 142 | path: "{{ item }}" 143 | block: "TMOUT={{ shell_timeout }}" 144 | marker: "# {mark} Ansible Managed CIS Timeout" 145 | create: true 146 | owner: root 147 | group: root 148 | mode: 0644 149 | loop: 150 | - /etc/bash.bashrc.local 151 | - /etc/profile.local 152 | when: ansible_distribution == "SLES" 153 | tags: 154 | - 5.4.5 155 | -------------------------------------------------------------------------------- /roles/cis_security/tasks/type-files/redhat-7-type.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Task file for CIS Controls 3 | # This file is commented to help view what Ansible Automation is doing 4 | # and under what circumstances. 5 | 6 | # Some blocks below have tasks with tags and some without. Blocks of tasks that 7 | # contain multiple controls have tasks with tags. Blocks that consist of a 8 | # single control and are just put together for convience sake, do not have 9 | # sub-block tasks with tags. 10 | 11 | # Comments about how the modules are used will become more infrequent as 12 | # the file goes along to avoid repeating oneself. 13 | 14 | # Let the user know what version of the controls file is running 15 | # Use a variable so it prints out the correct version. 16 | - name: Print Header 17 | ansible.builtin.debug: 18 | msg: "CIS Controls for {{ ansible_distribution }} {{ ansible_distribution_major_version }} type systems" 19 | 20 | # Collect the packages installed on the system so we can check agains them later 21 | - name: Collect package list 22 | ansible.builtin.package_facts: 23 | manager: auto 24 | tags: 25 | - always 26 | 27 | # Find the minimum UID of the machine for normal acocunts. This varies 28 | # between machines and environments, so we pull it from the file it 29 | # is supposed to exist in. 30 | - name: Determine the Minimum UID for new, non-system, accounts 31 | ansible.builtin.command: "/usr/bin/awk '/^s*UID_MIN/{print $2}' /etc/login.defs" 32 | register: min_uid 33 | changed_when: min_uid.rc == "2" 34 | check_mode: false 35 | tags: 36 | - always 37 | 38 | # Update the system with security packages using the system's package manager 39 | # Only update the system if the 'update_system' variable is set to true 40 | - name: 1.8 - Ensure updated system 41 | ansible.builtin.package: 42 | name: "*" 43 | state: latest 44 | security: true 45 | when: update_system 46 | tags: 47 | - 1.8.0 48 | 49 | # This collection of tasks creates a empty list and save it as a fact. 50 | # For every item that is encountered (without the tag being skipped), 51 | # add a string to the list. 52 | - name: 1.1 Disable unused filesystems 53 | ansible.builtin.set_fact: 54 | unused_filesystems: [] 55 | 56 | - name: 1.1.1.1 - Add cramfs to list of unused filesystems 57 | ansible.builtin.set_fact: 58 | unused_filesystems: "{{ unused_filesystems + ['cramfs'] }}" 59 | tags: 60 | - 1.1.1.1 61 | 62 | - name: 1.1.1.2 - Add freevxfs to list of unused filesystems 63 | ansible.builtin.set_fact: 64 | unused_filesystems: "{{ unused_filesystems + ['freevxfs'] }}" 65 | tags: 66 | - 1.1.1.2 67 | 68 | - name: 1.1.1.3 - Add jffs2 to list of unused filesystems 69 | ansible.builtin.set_fact: 70 | unused_filesystems: "{{ unused_filesystems + ['jffs2'] }}" 71 | tags: 72 | - 1.1.1.3 73 | 74 | - name: 1.1.1.4 - Add hfs to list of unused filesystems 75 | ansible.builtin.set_fact: 76 | unused_filesystems: "{{ unused_filesystems + ['hfs'] }}" 77 | tags: 78 | - 1.1.1.4 79 | 80 | - name: 1.1.1.5 - Add hfsplus to list of unused filesystems 81 | ansible.builtin.set_fact: 82 | unused_filesystems: "{{ unused_filesystems + ['hfsplus'] }}" 83 | tags: 84 | - 1.1.1.5 85 | 86 | - name: 1.1.1.6 - Add squashfs to list of unused filesystems 87 | ansible.builtin.set_fact: 88 | unused_filesystems: "{{ unused_filesystems + ['squashfs'] }}" 89 | tags: 90 | - 1.1.1.6 91 | 92 | - name: 1.1.1.7 - Add udf to list of unused filesystems 93 | ansible.builtin.set_fact: 94 | unused_filesystems: "{{ unused_filesystems + ['udf'] }}" 95 | tags: 96 | - 1.1.1.7 97 | 98 | - name: 1.1.1.8 - Add vfat to list of unused filesystems 99 | ansible.builtin.set_fact: 100 | unused_filesystems: "{{ unused_filesystems + ['vfat'] }}" 101 | tags: 102 | - 1.1.1.8 103 | 104 | # With the list complete, use it with the system's package manager 105 | # to remove packages from the system that are not needed. 106 | - name: Remove unused_filesystem list 107 | ansible.builtin.package: 108 | name: unused_filesystems 109 | state: absent 110 | 111 | - name: Add unused_filesystems to /etc/modprobe.d/CIS.conf 112 | ansible.builtin.lineinfile: 113 | dest: /etc/modprobe.d/CIS.conf 114 | line: "install {{ item }} /bin/true" 115 | state: present 116 | create: true 117 | mode: 0644 118 | with_items: 119 | - "{{ unused_filesystems }}" 120 | 121 | # Determine if a filesystem is on a separate partition, if so, then 122 | # check to see if various filesystem options exist for the filesystem 123 | 124 | 125 | - name: 1.1.2 - /tmp partition and mount options 126 | # This whole block can be turned off by excluding the following tag(s) 127 | tags: 128 | 1.1.2 129 | block: 130 | # Create a empty integer variable and set it as a fact on the managed 131 | # machine. 132 | - name: 1.1.2 - Set/reset mount counter 133 | ansible.builtin.set_fact: 134 | mount_count: 0 135 | tags: 136 | - 1.1.2 137 | - 1.1.3 138 | - 1.1.4 139 | 140 | # Examine the ansible_mounts variable which includes all of the system mounts 141 | # on machine. Search for the appropriate mount information. If it exists, 142 | # increment the integer variable by '1' and save the filesystems options to a 143 | # new variable called mount_options. 144 | - name: 1.1.2 - Determine if /tmp is on a separate partition 145 | ansible.builtin.set_fact: 146 | mount_count: "addition{{ mount_count + 1 }}" 147 | mount_options: "{{ item.options }}" 148 | when: item.mount == "/tmp" 149 | with_items: 150 | - "{{ ansible_mounts }}" 151 | tags: 152 | - 1.1.2 153 | 154 | # If the number in mount_count variable is > 0, then we found the mount. If not, 155 | # then report to the user that the given filesystem was not on a separate partition. 156 | - name: 1.1.2 - Report to user if not on separate partition 157 | ansible.builtin.debug: 158 | msg: "FAILED CONTROL: /tmp is not on a separate partition. Skipping mount option checks" 159 | when: mount_count == 0 160 | changed_when: true 161 | tags: 162 | - 1.1.2 163 | 164 | # Look through the mount_options variable for the given filesystem option. if it is 165 | # not found, or if the filesystem is not on a separate partition (therefore has no mount options) 166 | # let the user know. 167 | - name: 1.1.3 - Report to user if /tmp does not have noexec set 168 | ansible.builtin.debug: 169 | msg: "FAILED CONTROL: /tmp/ does not have noexec set" 170 | when: mount_options is defined and "noexec" not in mount_options and mount_count == 0 171 | changed_when: true 172 | tags: 173 | - 1.1.3 174 | 175 | # Look through the mount_options variable for the given filesystem option. if it is 176 | # not found, or if the filesystem is not on a separate partition (therefore has no mount options) 177 | # let the user know. 178 | - name: 1.1.4 - Report to user if /tmp does not have nodev set 179 | ansible.builtin.debug: 180 | msg: "FAILED CONTROL: /tmp/ does not have nodev set" 181 | when: mount_options is defined and "nodev" not in mount_options and mount_count == 0 182 | changed_when: true 183 | tags: 184 | - 1.1.4 185 | 186 | # Look through the mount_options variable for the given filesystem option. if it is 187 | # not found, or if the filesystem is not on a separate partition (therefore has no mount options) 188 | # let the user know. 189 | - name: 1.1.5 - Report to user if tmp does not have nosuid set 190 | ansible.builtin.debug: 191 | msg: "FAILED CONTROL: /tmp does not have nosuid set" 192 | when: mount_options is defined and "nodsuid" not in mount_options and mount_count == 0 193 | changed_when: true 194 | tags: 195 | - 1.1.5 196 | 197 | # Determine if a filesystem is on a separate partition, if so, then 198 | # check to see if various filesystem options exist for the filesystem 199 | - name: 1.1.6 - Report if /var is not on a separate partition 200 | # This whole block can be turned off by excluding the following tag(s) 201 | tags: 202 | - 1.1.6 203 | block: 204 | # Create a empty integer variable and set it as a fact on the managed 205 | # machine. 206 | - name: 1.1.6 - Set/reset mount counter 207 | ansible.builtin.set_fact: 208 | mount_count: 0 209 | 210 | # Examine the ansible_mounts variable which includes all of the system mounts 211 | # on machine. Search for the appropriate mount information. If it exists, 212 | # increment the integer variable by '1' and save the filesystems options to a 213 | # new variable called mount_options. 214 | - name: 1.1.6 - Determine if /var is on a separate partition 215 | ansible.builtin.set_fact: 216 | mount_count: "addition{{ mount_count + 1 }}" 217 | when: item.mount == "/var" 218 | with_items: 219 | - "{{ ansible_mounts }}" 220 | 221 | # If the number in mount_count variable is > 0, then we found the mount. If not, 222 | # then report to the user that the given filesystem was not on a separate partition. 223 | - name: 1.1.6 - Report to user 224 | ansible.builtin.debug: 225 | msg: "FAILED CONTROL: /var is not on a separate partition" 226 | when: mount_count == 0 227 | changed_when: true 228 | 229 | # Determine if a filesystem is on a separate partition, if so, then 230 | # check to see if various filesystem options exist for the filesystem 231 | - name: 1.1.7 - /var/tmp partition and mount options 232 | # This whole block can be turned off by excluding the following tag(s) 233 | tags: 234 | - 1.1.7 235 | block: 236 | # Create a empty integer variable and set it as a fact on the managed 237 | # machine. 238 | - name: 1.1.7 - Set/reset mount counter 239 | ansible.builtin.set_fact: 240 | mount_count: 0 241 | tags: 242 | - 1.1.7 243 | - 1.1.8 244 | - 1.1.9 245 | - 1.1.10 246 | 247 | # Examine the ansible_mounts variable which includes all of the system mounts 248 | # on machine. Search for the appropriate mount information. If it exists, 249 | # increment the integer variable by '1' and save the filesystems options to a 250 | # new variable called mount_options. 251 | - name: 1.1.7 - Determine if /var/tmp is on a separate partition 252 | ansible.builtin.set_fact: 253 | mount_count: "addition{{ mount_count + 1 }}" 254 | mount_options: "{{ item.options }}" 255 | when: item.mount == "/var/tmp" 256 | with_items: 257 | - "{{ ansible_mounts }}" 258 | tags: 259 | - 1.1.7 260 | 261 | # If the number in mount_count variable is > 0, then we found the mount. If not, 262 | # then report to the user that the given filesystem was not on a separate partition. 263 | - name: 1.1.7 - Report to user if not on separate partition 264 | ansible.builtin.debug: 265 | msg: "FAILED CONTROL: /var/tmp is not on a separate partition. Skipping mount option checks" 266 | when: mount_count == 0 267 | changed_when: true 268 | tags: 269 | - 1.1.7 270 | 271 | # Look through the mount_options variable for the given filesystem option. if it is 272 | # not found, or if the filesystem is not on a separate partition (therefore has no mount options) 273 | # let the user know. 274 | - name: 1.1.8 - Report to user if /var/tmp does not have nodev set 275 | ansible.builtin.debug: 276 | msg: "FAILED CONTROL: /var/tmp/ does not have nodev set" 277 | when: mount_options is defined and "nodev" not in mount_options and mount_count == 0 278 | changed_when: true 279 | tags: 280 | - 1.1.8 281 | 282 | # Look through the mount_options variable for the given filesystem option. if it is 283 | # not found, or if the filesystem is not on a separate partition (therefore has no mount options) 284 | # let the user know. 285 | - name: 1.1.9 - Report to user if /var/tmp does not have nosuid set 286 | ansible.builtin.debug: 287 | msg: "FAILED CONTROL: /var/tmp/ does not have nosuid set" 288 | when: mount_options is defined and "nodsuid" not in mount_options and mount_count == 0 289 | changed_when: true 290 | tags: 291 | - 1.1.9 292 | 293 | # Look through the mount_options variable for the given filesystem option. if it is 294 | # not found, or if the filesystem is not on a separate partition (therefore has no mount options) 295 | # let the user know. 296 | - name: 1.1.10 - Report to user if /var/tmp does not have noexec set 297 | ansible.builtin.debug: 298 | msg: "FAILED CONTROL: /var/tmp/ does not have noexec set" 299 | when: mount_options is defined and "noexec" not in mount_options and mount_count == 0 300 | changed_when: true 301 | tags: 302 | - 1.1.10 303 | 304 | # Determine if a filesystem is on a separate partition, if so, then 305 | # check to see if various filesystem options exist for the filesystem 306 | - name: 1.1.11 - Report if /var/log is not on a separate partition 307 | # This whole block can be turned off by excluding the following tag(s) 308 | tags: 309 | - 1.1.11 310 | block: 311 | # Create a empty integer variable and set it as a fact on the managed 312 | # machine. 313 | - name: 1.1.11 - Set/reset mount counter 314 | ansible.builtin.set_fact: 315 | mount_count: 0 316 | 317 | # Examine the ansible_mounts variable which includes all of the system mounts 318 | # on machine. Search for the appropriate mount information. If it exists, 319 | # increment the integer variable by '1' and save the filesystems options to a 320 | # new variable called mount_options. 321 | - name: 1.1.11 - Determine if /var/log is on a separate partition 322 | ansible.builtin.set_fact: 323 | mount_count: "addition{{ mount_count + 1 }}" 324 | when: item.mount == "/var/log" 325 | with_items: 326 | - "{{ ansible_mounts }}" 327 | 328 | # If the number in mount_count variable is > 0, then we found the mount. If not, 329 | # then report to the user that the given filesystem was not on a separate partition. 330 | - name: 1.1.11 - Report to user 331 | ansible.builtin.debug: 332 | msg: "FAILED CONTROL: /var/log is not on a separate partition" 333 | when: mount_count == 0 334 | changed_when: true 335 | 336 | # Determine if a filesystem is on a separate partition, if so, then 337 | # check to see if various filesystem options exist for the filesystem 338 | - name: 1.1.12 - Report if /var/log/audit is not on a separate partition 339 | # This whole block can be turned off by excluding the following tag(s) 340 | tags: 341 | - 1.1.12 342 | block: 343 | # Create a empty integer variable and set it as a fact on the managed 344 | # machine. 345 | - name: 1.1.12 - Set/reset mount counter 346 | ansible.builtin.set_fact: 347 | mount_count: 0 348 | 349 | # Examine the ansible_mounts variable which includes all of the system mounts 350 | # on machine. Search for the appropriate mount information. If it exists, 351 | # increment the integer variable by '1' and save the filesystems options to a 352 | # new variable called mount_options. 353 | - name: 1.1.12 - Determine if /var/log/audit is on a separate partition 354 | ansible.builtin.set_fact: 355 | mount_count: "addition{{ mount_count + 1 }}" 356 | when: item.mount == "/var/log/audit" 357 | with_items: 358 | - "{{ ansible_mounts }}" 359 | 360 | # If the number in mount_count variable is > 0, then we found the mount. If not, 361 | # then report to the user that the given filesystem was not on a separate partition. 362 | - name: 1.1.12 - Report to user 363 | ansible.builtin.debug: 364 | msg: "FAILED CONTROL: /var/log/audit is not on a separate partition" 365 | when: mount_count == 0 366 | changed_when: true 367 | 368 | # Determine if a filesystem is on a separate partition, if so, then 369 | # check to see if various filesystem options exist for the filesystem 370 | - name: 1.1.13 - Report if /home is not on a separate partition 371 | # This whole block can be turned off by excluding the following tag(s) 372 | tags: 373 | - 1.1.13 374 | block: 375 | # Create a empty integer variable and set it as a fact on the managed 376 | # machine. 377 | - name: 1.1.13 - Set/reset mount counter 378 | ansible.builtin.set_fact: 379 | mount_count: 0 380 | 381 | # Examine the ansible_mounts variable which includes all of the system mounts 382 | # on machine. Search for the appropriate mount information. If it exists, 383 | # increment the integer variable by '1' and save the filesystems options to a 384 | # new variable called mount_options. 385 | - name: 1.1.13 - Determine if /home is on a separate partition 386 | ansible.builtin.set_fact: 387 | mount_count: "addition{{ mount_count + 1 }}" 388 | mount_options: "{{ item.options }}" 389 | when: item.mount == "/home" 390 | with_items: 391 | - "{{ ansible_mounts }}" 392 | 393 | # If the number in mount_count variable is > 0, then we found the mount. If not, 394 | # then report to the user that the given filesystem was not on a separate partition. 395 | - name: 1.1.13 - Report to user if /home is not on a separate partition 396 | ansible.builtin.debug: 397 | msg: "FAILED CONTROL: /home is not on a separate partition. Skipping mount option checks" 398 | when: mount_count == 0 399 | changed_when: true 400 | 401 | # Look through the mount_options variable for the given filesystem option. if it is 402 | # not found, or if the filesystem is not on a separate partition (therefore has no mount options) 403 | # let the user know. 404 | - name: Report to user if /home does not have nodev set 405 | ansible.builtin.debug: 406 | msg: "FAILED CONTROL: /home does not have nodev set" 407 | when: mount_options is defined and "nodev" not in mount_options and mount_count == 0 408 | changed_when: true 409 | 410 | # /dev/shm does not exist in ansible_mounts so we have to check the 411 | # mount ansible.builtin.command directly. This requires the use of the shell ansible.builtin.command which 412 | # is not ideal. 413 | # Grep out /dev/shm and see if the given option is set. 414 | - name: 1.1.15 - Report if /dev/shm does not have nodev set 415 | # This whole block can be turned off by excluding the following tag(s) 416 | tags: 417 | - 1.1.15 418 | block: 419 | - name: Determine if /dev/shm has nodev set 420 | ansible.builtin.shell: cat /proc/mounts | /usr/bin/grep /dev/shm | /usr/bin/grep -v nodev 421 | register: devshm_nodev_out 422 | failed_when: devshm_nodev_out == "2" 423 | changed_when: false 424 | check_mode: false 425 | 426 | # Let the user know if we did not find the option set. 427 | - name: 1.1.15 - Report to user 428 | ansible.builtin.debug: 429 | msg: "FAILED CONTROL: /dev/shm does not have nodev set" 430 | when: devshm_nodev_out is defined and devshm_nodev_out.stdout 431 | changed_when: true 432 | 433 | # Grep out /dev/shm and see if the given option is set. 434 | - name: 1.1.16 - Report if /dev/shm does not have nosuid set 435 | # This whole block can be turned off by excluding the following tag(s) 436 | tags: 437 | - 1.1.16 438 | block: 439 | - name: Determine if /dev/shm has nosuid set 440 | ansible.builtin.shell: cat /proc/mounts | /usr/bin/grep /dev/shm | /usr/bin/grep -v nosuid 441 | register: devshm_nosuid_out 442 | failed_when: devshm_nosuid_out == "2" 443 | changed_when: false 444 | check_mode: false 445 | 446 | # Let the user know if we did not find the option set. 447 | - name: 1.1.16 - Report to user 448 | ansible.builtin.debug: 449 | msg: "FAILED CONTROL: /dev/shm does not have nosuid set" 450 | when: devshm_nosuid_out is defined and devshm_nosuid_out.stdout 451 | changed_when: true 452 | 453 | # Grep out /dev/shm and see if the given option is set. 454 | - name: 1.1.17 - Report if /dev/shm does not have noexec set 455 | # This whole block can be turned off by excluding the following tag(s) 456 | tags: 457 | - 1.1.17 458 | block: 459 | - name: 1.1.17 - Determine if /dev/shm has noexec set 460 | ansible.builtin.shell: cat /proc/mounts | /usr/bin/grep /dev/shm | /usr/bin/grep -v noexec 461 | register: devshm_noexec_out 462 | failed_when: devshm_noexec_out == "2" 463 | changed_when: false 464 | check_mode: false 465 | 466 | # Let the user know if we did not find the option set. 467 | - name: 1.1.17 - Report to user 468 | ansible.builtin.debug: 469 | msg: "FAILED CONTROL: /dev/shm does not have noexec set" 470 | when: devexec_nosuid_out is defined and devshm_noexec_out.stdout 471 | changed_when: true 472 | 473 | # Control 1.1.18, 1.1.19, 1.1.20 are for removable media 474 | 475 | # Control 1.1.21 is a large find, omitting 476 | 477 | # Turn off and disable the autofs service using the service module. 478 | # We check to see if the package that autofs belongs to (convienently called autofs) 479 | # exists in the ansible_facts.packages list we gathered early in the play 480 | - name: 1.1.22 - disable automounting 481 | ansible.builtin.service: 482 | name: autofs 483 | enabled: false 484 | state: stopped 485 | when: "'autofs' in ansible_facts.packages" 486 | tags: 487 | - 1.1.22 488 | 489 | 490 | # Control 1.2.1 and 1.2.4 are system updating. Make sure system is set for some kind of system software update 491 | 492 | # Use the service module to disable the rhnsd service. If you want the machine 493 | # to respond to queued services from Satellite, do not disable this. 494 | - name: 1.2.5 Disable rhnsd 495 | ansible.builtin.service: 496 | name: rhnsd 497 | enabled: false 498 | state: stopped 499 | failed_when: false 500 | when: ansible_distribution == "RedHat" 501 | tags: 502 | - 1.2.5 503 | 504 | # GPGKeys are used to sign packages. enabling them will mean that all packages 505 | # from a given repo must be signed with the appropriate key 506 | - name: 1.2.[2,3] - Ensure GPG keys are configured 507 | when: ansible_distribution != "SLES" 508 | tags: 509 | - 1.2.2 510 | - 1.2.3 511 | block: 512 | # Replace any instances of gpgcheck with a 1 after it to 'gpgcheck = 1' 513 | - name: 1.2.2 - set master yum.conf gpgcheck to '1' 514 | ansible.builtin.replace: 515 | dest: /etc/yum.conf 516 | regexp: '^gpgcheck\s*=\s*[^1]*$' 517 | replace: "gpgcheck = 1" 518 | when: gpgcheck is defined and gpgcheck 519 | 520 | # Find all files in /etc/yum.repos.d and add them to a list variable 521 | - name: 1.2.3 - find all repo files in /etc/yum.repos.d/ 522 | ansible.builtin.find: 523 | paths: "/etc/yum.repos.d" 524 | patterns: "*.repo" 525 | register: yumrepos 526 | when: gpgcheck is defined and gpgcheck 527 | 528 | # parse the list variable and replace any instances of gpgcheck with a 1 after it to 'gpgcheck = 1' 529 | - name: 1.2.3 - Set all repos gpgchecks to '1' 530 | ansible.builtin.replace: 531 | dest: "{{ item.path }}" 532 | regexp: '^gpgcheck\s*=\s*[^1]*$' 533 | replace: gpgcheck = 1 534 | with_items: "{{ yumrepos.files }}" 535 | when: gpgcheck is defined and gpgcheck 536 | 537 | # - name: 1.2.1 - Ensure package manager repositories are configured, site dependent 538 | 539 | 540 | # AIDE is a file system integrity checker which will document all 541 | # filesystem changes. It's very noisy on busy systems and should be 542 | # enabled when you have the sapce and need for it. 543 | - name: 1.3 - Filesystem integrity checking w/AIDE 544 | tags: 545 | - 1.3.0 546 | block: 547 | # use the system package manager to install AIDE 548 | - name: 1.3.1 Ensure aide is installed 549 | ansible.builtin.package: 550 | name: aide 551 | state: present 552 | tags: 553 | - 1.3.1 554 | 555 | # AIDE requires initialization the first time and it takes time on a large system. 556 | # DUse stat module on the file that should be there if it is set up. 557 | - name: 1.3.1 - Determine if AIDE has already been initialized 558 | ansible.builtin.stat: 559 | path: /var/lib/aide/aide.db.gz 560 | register: aide_path 561 | tags: 562 | - 1.3.1 563 | 564 | - name: 1.3.1 - Set up database file location 565 | ansible.builtin.replace: 566 | dest: /etc/aide.conf 567 | regexp: "^database=ansible.builtin.file:((?!{{ aide_db_name }}).)*$" 568 | replace: "database=ansible.builtin.file:{{ aide_db_name }}" 569 | tags: 570 | - 1.3.1 571 | 572 | - name: 1.3.1 - Set up database_out file location 573 | ansible.builtin.replace: 574 | dest: /etc/aide.conf 575 | regexp: "^database_out=ansible.builtin.file:((?!{{ aide_new_db_name }}).)*$" 576 | replace: "database_out=ansible.builtin.file:{{ aide_new_db_name }}" 577 | tags: 578 | - 1.3.1 579 | 580 | - name: 1.3.1 - enable gzip compression for database 581 | ansible.builtin.lineinfile: 582 | dest: /etc/aide.conf 583 | regexp: '^gzip_dbout\s*=\s*((?!{{ aide_gzip }}).)*$' 584 | line: "gzip_dbout={{ aide_gzip }}" 585 | state: present 586 | tags: 587 | - 1.3.1 588 | 589 | # stat returns a lot of information. 'exists' is true if the file exists and 'isreg' 590 | # is true if the file is a regular file. If either of these are not true, then 591 | # run the initializatoin again. 592 | - name: 1.3.1 - Initialize AIDE if it hasn't been already (/usr/sbin/aide) 593 | ansible.builtin.command: /usr/sbin/aide --init 594 | when: ( not aide_path.stat.exists or not aide_path.stat.isreg ) and ansible_distribution != "SLES" 595 | register: aide 596 | async: 1200 # 20 minutes until timeout 597 | poll: 0 # run concurrently 598 | tags: 599 | - 1.3.1 600 | 601 | - name: Wait for AIDE initialization to complete 602 | ansible.builtin.async_status: 603 | jid: '{{ aide.ansible_job_id }}' 604 | register: aide_status 605 | until: aide_status.finished 606 | when: ( not aide_path.stat.exists or not aide_path.stat.isreg ) and ansible_distribution != "SLES" 607 | retries: 300 608 | 609 | # AIDE creates the new database as a different name. Use the copy module with 610 | # the remote_src argument to copy the file on the remote machine to another location 611 | # on the remote machine. 612 | - name: 1.3.1 - Move the newly created database into place 613 | ansible.builtin.copy: 614 | src: /var/lib/aide/aide.db.new.gz 615 | remote_src: true 616 | dest: /var/lib/aide/aide.db.gz 617 | mode: preserve 618 | when: ( not aide_path.stat.exists or not aide_path.stat.isreg ) and ansible_distribution != "SLES" 619 | changed_when: false 620 | tags: 621 | - 1.3.1 622 | 623 | # Copy in the already configured systemd service file using the copy module. 624 | # Be sure to set the selinux context. 625 | # Notify systemd to reload its daemons and start the service 626 | - name: 1.3.2 - Ensure File integrity is regularly checked (aidecheck service) 627 | ansible.builtin.template: 628 | src: aidecheck.service 629 | dest: /etc/systemd/system/aidecheck.service 630 | owner: root 631 | group: root 632 | mode: 0644 633 | setype: systemd_unit_file_t 634 | notify: Restart aidecheck 635 | tags: 636 | - 1.3.2 637 | 638 | - name: 1.3.2 - Enable aidecheck.service 639 | ansible.builtin.systemd: 640 | name: aidecheck.service 641 | enabled: true 642 | tags: 643 | - 1.3.2 644 | 645 | # Copy in the already configured systemd timer file using the copy module. 646 | # Be sure to set the selinux context. 647 | # Notify systemd to reload its daemons and start the timer 648 | - name: 1.3.2 - Ensure File integrity is regulary checked (aidecheck timer) 649 | ansible.builtin.template: 650 | src: aidecheck.timer 651 | dest: /etc/systemd/system/aidecheck.timer 652 | owner: root 653 | group: root 654 | mode: 0644 655 | setype: systemd_unit_file_t 656 | notify: Restart aidecheck 657 | tags: 658 | - 1.3.2 659 | 660 | # 1.4 Secure Boot settings 661 | # Determine if we are using LILO or EFI 662 | - name: 1.4.0 - Check if the EFI directory exists 663 | ansible.builtin.stat: 664 | path: "/boot/efi/EFI/{{ ansible_distribution | lower }}/grub.cfg" 665 | register: efidir 666 | tags: 667 | 1.4.1 668 | 669 | - name: 1.4.1 - set variable for grub.cfg in EFI location 670 | ansible.builtin.set_fact: 671 | grub_cfg_path: "{{ efidir.stat.path }}" 672 | when: efidir.stat.path is defined 673 | tags: 674 | 1.4.1 675 | 676 | - name: 1.4.0 - Check if the LILO path exists 677 | ansible.builtin.stat: 678 | path: "/boot/grub2/grub.cfg" 679 | register: grubdir 680 | tags: 681 | 1.4.1 682 | 683 | - name: 1.4.1 - set variable for grub.cfg in LILO location 684 | ansible.builtin.set_fact: 685 | grub_cfg_path: "{{ grubdir.stat.path }}" 686 | when: grubdir.stat.path is defined 687 | tags: 688 | 1.4.1 689 | 690 | # Use file module to set permissions on grub files 691 | - name: 1.4.1 - Set permissions on grub.cfg 692 | ansible.builtin.file: 693 | path: "{{ item }}" 694 | owner: root 695 | group: root 696 | mode: 0600 697 | loop: 698 | - "{{ grub_cfg_path }}" 699 | - /boot/grub2/grubenv 700 | tags: 701 | - 1.4.1 702 | 703 | # Control 1.4.2, Grub bootloader password - skipped 704 | 705 | # Use replace module to add the requirement to enter password on single user startup 706 | - name: 1.4.3 - Set single user password 707 | ansible.builtin.replace: 708 | dest: /usr/lib/systemd/system/{{ item }} 709 | regexp: '^ExecStart=-((?!/bin/sh\s+-c\s+\"\s+/sbin/sulogin).)*' 710 | replace: "ExecStart=-/bin/sh -c \"/sbin/sulogin; /usr/bin/systemctl --fail --no-block default\"" 711 | with_items: 712 | - rescue.service 713 | - emergency.service 714 | tags: 715 | - 1.4.3 716 | 717 | # 1.5 Additional Process Hardening 718 | 719 | - name: 1.5.1 - Ensure core dumps are restricted 720 | tags: 721 | - 1.5.1 722 | block: 723 | # The sysctl module will set variables in /etc/sysctl.conf and tell sysctl 724 | # to reload them immediately if 'reload' is set to 'true'. 725 | - name: 1.5.1 - Ensure core dumps are restricted 726 | ansible.builtin.sysctl: 727 | name: fs.suid_dumpable 728 | value: "0" 729 | state: present 730 | reload: true 731 | 732 | # The pam_limits module will configure the lines in the limits files. 733 | - name: 1.5.1 - Ensure core limits are set 734 | community.general.pam_limits: 735 | dest: /etc/security/limits.d/CIS.conf 736 | domain: "*" 737 | limit_type: hard 738 | limit_item: core 739 | value: "0" 740 | 741 | # Enable the No Execute / Execute Disable functionality on processors 742 | - name: 1.5.2 Ensure XD/NX support is enabled 743 | tags: 744 | - 1.5.2 745 | block: 746 | # To see if it is set already, we poll the joural with a grep and register a variable 747 | - name: Search journal to see if protection was active at boot 748 | ansible.builtin.shell: "/usr/bin/journalctl | /usr/bin/grep 'protection: active' " 749 | register: nx_protection 750 | changed_when: false 751 | check_mode: false 752 | 753 | # If we can't verify that it is active, we notify the user. This has to be set 754 | # in the BIOS or with a special kernel (32 bit kernels only) 755 | - name: Verify XD/NX support is active 756 | ansible.builtin.debug: 757 | msg: "XD/NX support is active" 758 | when: nx_protection.stdout is search("active") 759 | 760 | - name: 1.5.3 - Ensure address space layout reandomization (ASLR) is enabled 761 | # The sysctl module will set variables in /etc/sysctl.conf and tell sysctl 762 | # to reload them immediately if 'reload' is set to 'true'. 763 | ansible.builtin.sysctl: 764 | name: kernel.randomize_va_space 765 | value: "2" 766 | reload: true 767 | state: present 768 | sysctl_set: true 769 | tags: 770 | - 1.5.3 771 | 772 | # Use system package manager to remove the prelink package 773 | - name: 1.5.4 - Remove prelink package 774 | ansible.builtin.package: 775 | name: prelink 776 | state: absent 777 | tags: 778 | - 1.5.4 779 | 780 | # 1.6 Mandatory Access Control 781 | 782 | # SLES does not provide a policy for selinux, so enabling it will freeze a system. For SLES skip 783 | # This section 784 | - name: 1.6.0 - Mandatory Access Control 785 | when: ansible_distribution != "SLES" 786 | tags: 787 | - 1.6.0 788 | block: 789 | # Use system package manager to install libselinux (RHEL CLones) 790 | - name: 1.6.2 - Ensure SELinux is installed 791 | ansible.builtin.package: 792 | name: libselinux 793 | state: present 794 | when: (selinux is defined and selinux != "Disabled") and ansible_distribution == "RedHat" 795 | tags: 796 | - 1.6.2 797 | 798 | # Use the replace module to remove any disablment of selinux in grub if 799 | # it isn't expressly disabled from a variable 800 | - name: 1.6.1.1 - Ensure SELinux is not disabled in bootloader configuration 801 | ansible.builtin.replace: 802 | dest: /etc/default/grub 803 | regexp: "{{ item }}" 804 | replace: "" 805 | with_items: 806 | - selinux=0 807 | - enforcing=0 808 | when: selinux is defined and selinux != "Disabled" 809 | notify: Rebuild grub 810 | tags: 811 | - 1.6.1.1 812 | 813 | # re-gather system facts if we installed selinux packages. 814 | # If selinux wasn't installed, it will not populate ansible_selinux fact correctly, regathering 815 | # will pull it with the right information 816 | - name: Regather facts 817 | ansible.builtin.setup: 818 | tags: 819 | - 1.6.1.1 820 | 821 | # Replace the current selinux policy with whatever the variable is set for 822 | - name: 1.6.1.2 - Set SELinux policy to {{ selinux_policy }} 823 | ansible.builtin.replace: 824 | dest: /etc/selinux/config 825 | regexp: "^SELINUXTYPE=((?!{{ selinux_policy }}).)*$" 826 | replace: "SELINUXTYPE={{ selinux_policy }}" 827 | when: ( selinux is defined and selinux_policy is defined ) and selinux != "Disabled" 828 | tags: 829 | - 1.6.1.2 830 | 831 | # If we are going to be enabling selinux in passive or enforcing mode, 832 | # set the autorelabel and notify the machine to reboot 833 | - name: 1.6.1.2 - If disabled and we are enabling it, autorelabel 834 | ansible.builtin.file: 835 | path: /.autorelabel 836 | owner: root 837 | group: root 838 | mode: 0644 839 | state: touch 840 | when: ansible_selinux.status == "disabled" and selinux | lower != "disabled" 841 | notify: Reboot 842 | tags: 843 | - 1.6.1.2 844 | 845 | # Replace the current selinux mode with what the variable is set to 846 | - name: 1.6.1.3 - Set SELinux to {{ selinux | lower }} 847 | ansible.builtin.replace: 848 | dest: /etc/selinux/config 849 | regexp: "^SELINUX=((?!{{ selinux }}).)*$" 850 | replace: "SELINUX={{ selinux | lower }}" 851 | when: selinux is defined and ( selinux | lower == "enforcing" or selinux | lower == "permissive" or selinux | lower == "disabled" ) 852 | tags: 853 | - 1.6.1.3 854 | 855 | # Use system package manager to remove package 856 | - name: 1.6.1.4 - Remove setroubleshoot 857 | ansible.builtin.package: 858 | name: "{{ item }}" 859 | state: absent 860 | loop: 861 | - setroubleshoot 862 | - setroubleshoot-server 863 | - setroubleshoot-plugins 864 | tags: 865 | - 1.6.1.4 866 | 867 | # Use system package manager to remove package 868 | - name: 1.6.1.5 - Remove MCS Translation Service 869 | ansible.builtin.package: 870 | name: mcstrans 871 | state: absent 872 | tags: 873 | - 1.6.1.5 874 | 875 | # Let the user know if there are any processes that are not running under the 876 | # a selinux context 877 | - name: 1.6.1.6 - Report on unconfined running services 878 | tags: 879 | - 1.6.1.5 880 | block: 881 | # use ps and grep to find services running under initrc context 882 | - name: 1.6.1.5 - Generate report on unconfined running services 883 | ansible.builtin.shell: /usr/bin/ps -eZ | egrep "initrc" 884 | register: unconfined_services_out 885 | failed_when: unconfined_services_out.rc == "2" 886 | changed_when: false 887 | check_mode: false 888 | 889 | # Print any findings to the user 890 | - name: 1.6.1.5 - Report on unconfined running services to user 891 | ansible.builtin.debug: 892 | msg: 893 | - "Unconfined processes found:" 894 | - "{{ unconfined_services_out.stdout_lines }}" 895 | changed_when: true 896 | when: unconfined_services_out.stdout 897 | 898 | # 1.7 Warning Banners 899 | 900 | # Use copy module to copy in the appropriate files based on variable and set permissions 901 | - name: 1.7.1.1 - Install motd banners 902 | ansible.builtin.copy: 903 | src: "{{ motd_file }}" 904 | dest: /etc/motd 905 | owner: root 906 | group: root 907 | mode: 0644 908 | tags: 909 | - 1.7.1.1 910 | - 1.7.1.4 911 | 912 | # Use copy module to copy in the appropriate files based on variable and set permissions 913 | - name: 1.7.1.2 - Install issue banners 914 | ansible.builtin.copy: 915 | src: "{{ issue_file }}" 916 | dest: /etc/issue 917 | owner: root 918 | group: root 919 | mode: 0644 920 | tags: 921 | - 1.7.1.2 922 | - 1.7.1.5 923 | 924 | # Use copy module to copy in the appropriate files based on variable and set permissions 925 | - name: 1.7.1.3 - Install issue.net banners 926 | ansible.builtin.copy: 927 | src: "{{ issue_net_file }}" 928 | dest: /etc/issue.net 929 | owner: root 930 | group: root 931 | mode: 0644 932 | tags: 933 | - 1.7.1.3 934 | - 1.7.1.6 935 | 936 | # add a banner to the login screen if the graphical_interface variable is set to true 937 | - name: 1.7.2 Ensure GDM banner set up 938 | when: graphical_inteface is defined and graphical_interface 939 | tags: 940 | - 1.7.2 941 | block: 942 | # Add our required pieces to the dconf file for GDM 943 | - name: 1.7.2 - Set up the dconf profile for GDM 944 | ansible.builtin.file: 945 | path: /etc/dconf/profile/gdm 946 | owner: root 947 | group: root 948 | mode: 0644 949 | block: | 950 | user-db:user 951 | system-db:gdm 952 | file-db:/usr/share/gdm/greeter-dconf-defaults 953 | 954 | # Set the greeter message 955 | - name: 1.7.2 - Set GDM to use banner message 956 | ansible.builtin.file: 957 | path: /etc/dconf/db/gdm.d/01-banner-message 958 | owern: root 959 | group: root 960 | mode: 0644 961 | block: | 962 | [org/gnome/login-screen] 963 | banner-message-enable=true 964 | banner-message-text='Authorized uses only. All activity may be monitored and reported.' 965 | 966 | ## Part 2, Services ### 967 | # Remove old, unused, insecure services 968 | - name: 2.1.7 - Remove xinetd service [controlled by host variable tftp_server] 969 | ansible.builtin.package: 970 | name: xinetd 971 | state: absent 972 | when: tftp_server is defined and not tftp_server 973 | tags: 974 | - 2.1.7 975 | 976 | # use replace to make sure that listed services are disabled 977 | - name: Disable non-tftp services (if we are a tftp server) 978 | ansible.builtin.replace: 979 | regexp: 'disable\s+=\s+[^yes]' 980 | replace: " disable = yes" 981 | dest: "/etc/xinetd.d/{{ item }}" 982 | with_items: 983 | - chargen-dgram 984 | - chargen-stream 985 | - chargen-dgram 986 | - daytime-dgram 987 | - daytime-stream 988 | - discard-dgram 989 | - discard-stream 990 | - echo-dgram 991 | - tcpmux-server 992 | - time-dgram 993 | - time-stream 994 | when: tftp_server is defined and tftp_server 995 | failed_when: false 996 | tags: 997 | - 2.1.2 998 | 999 | # Set up the time server listed in the time_service variable 1000 | - name: 2.2.1.1 - Install {{ time_service }} 1001 | ansible.builtin.package: 1002 | name: "{{ time_service }}" 1003 | state: present 1004 | when: time_service == "chrony" or time_service == "ntp" 1005 | tags: 1006 | - 2.2.1.1 1007 | 1008 | # Use the template module to deploy the config file for the time sync program 1009 | # The default file does not have any template variables, but it's there so 1010 | # they can be added in the future. 1011 | - name: 2.2.1.2 - Configure {{ time_service }} 1012 | ansible.builtin.template: 1013 | src: "{{ time_service }}.conf" 1014 | dest: /etc/{{ time_service }}.conf 1015 | owner: root 1016 | group: root 1017 | mode: 0644 1018 | when: time_service == "chrony" or time_service == "ntp" 1019 | notify: Restart {{ time_service }}d 1020 | tags: 1021 | - 2.2.1.2 1022 | - 2.2.1.3 1023 | 1024 | - name: 2.2.1.3 - configure sysconfig time_server options 1025 | ansible.builtin.template: 1026 | src: "{{ time_service }}d" 1027 | dest: /etc/sysconfig/{{ time_service }}d 1028 | owner: root 1029 | group: root 1030 | mode: 0644 1031 | when: time_service == "chrony" or time_service == "ntp" 1032 | notify: Restart {{ time_service }}d 1033 | tags: 1034 | - 2.2.1.3 1035 | 1036 | # Chrony and ntp argue if they are both active at the same time. Disable 1037 | # the other service. 1038 | - name: 2.2.1.2 - disable chronyd if time_service is set to ntp 1039 | ansible.builtin.systemd: 1040 | name: chronyd 1041 | state: stopped 1042 | enabled: false 1043 | when: time_server is defined and time_service == "ntp" 1044 | tags: 1045 | - 2.2.1.2 1046 | - 2.2.1.3 1047 | 1048 | - name: 2.2.1.2 - disable ntpd if time_service is set to chrony 1049 | ansible.builtin.systemd: 1050 | name: ntpd 1051 | state: stopped 1052 | enabled: false 1053 | when: time_service is defined and time_service == "chrony" 1054 | failed_when: false 1055 | tags: 1056 | - 2.2.1.2 1057 | - 2.2.1.3 1058 | 1059 | # Disable the display manager by changing the default boot target to multi-user 1060 | - name: 2.2.2 - disable display manager if graphical desktop not needed 1061 | tags: 1062 | - 2.2.2 1063 | block: 1064 | # Find the current default run level. The systemctl module does not handle the 1065 | # get-default routine, so we are looking at the target of the symlink at /etc/systemd/system/default.target 1066 | - name: 2.2.2 - get default runlevel 1067 | ansible.builtin.stat: 1068 | path: /etc/systemd/system/default.target 1069 | register: default_runlevel_out 1070 | tags: 1071 | - 2.2.2 1072 | 1073 | # Use systemd module to stop the GDM service 1074 | - name: 2.2.2 - Disable the gdm display manager 1075 | ansible.builtin.systemd: 1076 | name: gdm 1077 | enabled: false 1078 | masked: true 1079 | state: stopped 1080 | daemon-reload: true 1081 | when: "'gdm' in ansible_facts.packages and not graphical_interface" 1082 | tags: 1083 | - 2.2.2 1084 | 1085 | # Set the current run level. The systemctl module does not handle the 1086 | # get-default routine, so we are looking at the target of the symlink at /etc/systemd/system/default.target 1087 | - name: 2.2.2 - Set current runlevel (non graphical) 1088 | ansible.builtin.command: /usr/bin/systemctl isolate multi-user.target 1089 | register: isolate_out 1090 | changed_when: isolate_out.changed 1091 | when: default_runlevel_out.stat.lnk_target is search("graphical.target") and not graphical_interface 1092 | tags: 1093 | - 2.2.2 1094 | 1095 | - name: 2.2.2 - Set current runlevel (graphical) 1096 | ansible.builtin.command: /usr/bin/systemctl isolate graphical.target 1097 | register: isolate_out 1098 | changed_when: isolate_out.changed 1099 | when: default_runlevel_out.stat.lnk_target is search("multi-user.target") and graphical_interface 1100 | tags: 1101 | - 2.2.2 1102 | 1103 | # Set the default run level. We are doing it the hard way since systemctl doesn't handle set-default 1104 | - name: 2.2.2 - Set default runlevel (non graphical) 1105 | ansible.builtin.file: 1106 | src: /lib/systemd/system/multi-user.target 1107 | dest: /etc/systemd/system/default.target 1108 | owner: root 1109 | group: root 1110 | when: not graphical_interface and ansible_distribution != "SLES" 1111 | 1112 | - name: 2.2.2 - Set default runlevel (graphical) 1113 | ansible.builtin.file: 1114 | src: /lib/systemd/system/graphical.target 1115 | dest: /etc/systemd/system/default.target 1116 | owner: root 1117 | group: root 1118 | when: graphical_interface and ansible_distribution != "SLES" 1119 | 1120 | # This collection of tasks creates a empty list and save it as a fact. 1121 | # For every item that is encountered (without the tag being skipped), 1122 | # add a string to the list. 1123 | - name: Create empty list for unneeded packages 1124 | ansible.builtin.set_fact: 1125 | unneeded_packages: [] 1126 | tags: 1127 | - always 1128 | 1129 | - name: 2.2.3 - add avahi to unneeded package list 1130 | ansible.builtin.set_fact: 1131 | unneeded_packages: "{{ unneeded_packages + ['avahi'] }}" 1132 | tags: 1133 | - 2.2.3 1134 | 1135 | - name: 2.2.5 - Disable dhcpd server [controlled by host variable dhcp_server] 1136 | ansible.builtin.set_fact: 1137 | unneeded_packages: "{{ unneeded_packages + ['dhcp'] }}" 1138 | when: dhcp_server is defined and not dhcp_server 1139 | tags: 1140 | - 2.2.5 1141 | 1142 | - name: 2.2.6 - add openldap-servers to removal list 1143 | ansible.builtin.set_fact: 1144 | unneeded_packages: "{{ unneeded_packages + ['openldap-servers'] }}" 1145 | tags: 1146 | - 2.2.6 1147 | 1148 | - name: 2.2.7 - Remove nfs server; add to removal list 1149 | ansible.builtin.set_fact: 1150 | unneeded_packages: "{{ unneeded_packages + ['nfs-utils'] }}" 1151 | when: nfs_server is defined and not nfs_server 1152 | tags: 1153 | - 2.2.7 1154 | 1155 | - name: 2.2.8 - Remove bind; add to removal list 1156 | ansible.builtin.set_fact: 1157 | unneeded_packages: "{{ unneeded_packages + ['bind'] + ['unbound'] }}" 1158 | when: dns_server is defined and not dns_server 1159 | tags: 1160 | - 2.2.8 1161 | 1162 | - name: 2.2.9 - Remove vsftpd; add to removal list 1163 | ansible.builtin.set_fact: 1164 | unneeded_packages: "{{ unneeded_packages + ['vsftpd'] }}" 1165 | when: ftp_server is defined and not ftp_server 1166 | tags: 1167 | - 2.2.9 1168 | 1169 | - name: 2.2.10 - Remove httpd; add to removal list 1170 | ansible.builtin.set_fact: 1171 | unneeded_packages: "{{ unneeded_packages + ['httpd'] + ['httpd-tools'] + ['mod_ssl'] }}" 1172 | when: http_server is defined and not http_server 1173 | tags: 1174 | - 2.2.10 1175 | 1176 | - name: 2.2.11 - add dovecot to removal list 1177 | ansible.builtin.set_fact: 1178 | unneeded_packages: "{{ unneeded_packages + ['dovecot'] }}" 1179 | tags: 1180 | - 2.2.11 1181 | 1182 | - name: 2.2.12 - Remove samba; add to removal list 1183 | ansible.builtin.set_fact: 1184 | unneeded_packages: "{{ unneeded_packages + ['samba'] }}" 1185 | when: smb_server is defined and not smb_server 1186 | tags: 1187 | - 2.2.12 1188 | 1189 | - name: 2.2.13 - add squid to removal list 1190 | ansible.builtin.set_fact: 1191 | unneeded_packages: "{{ unneeded_packages + ['squid'] }}" 1192 | when: not proxy_server 1193 | tags: 1194 | - 2.2.13 1195 | 1196 | - name: 2.2.14 - add net-snmp to removal list 1197 | ansible.builtin.set_fact: 1198 | unneeded_packages: "{{ unneeded_packages + ['net-snmp', 'net-snmp-libs'] }}" 1199 | tags: 1200 | - 2.2.14 1201 | 1202 | - name: 2.2.16 - add ypserv to removal list 1203 | ansible.builtin.set_fact: 1204 | unneeded_packages: "{{ unneeded_packages + ['ypserv'] }}" 1205 | tags: 1206 | - 2.2.16 1207 | 1208 | - name: 2.3.1 - add ypbind to removal list 1209 | ansible.builtin.set_fact: 1210 | unneeded_packages: "{{ unneeded_packages + ['ypbind'] }}" 1211 | when: not ypbind 1212 | tags: 1213 | - 2.3.1 1214 | 1215 | - name: 2.2.17 - add rsh to unneeded package list 1216 | ansible.builtin.set_fact: 1217 | unneeded_packages: "{{ unneeded_packages + ['rsh'] }}" 1218 | tags: 1219 | - 2.2.17 1220 | 1221 | - name: 2.2.18 - add talk to unneeded package list 1222 | ansible.builtin.set_fact: 1223 | unneeded_packages: "{{ unneeded_packages + ['talk-server'] + ['talk'] }}" 1224 | tags: 1225 | - 2.2.18 1226 | - 2.3.3 1227 | 1228 | - name: 2.2.19 - add telnet to unneeded package list 1229 | ansible.builtin.set_fact: 1230 | unneeded_packages: "{{ unneeded_packages + ['telnet-server'] + ['telnet'] }}" 1231 | tags: 1232 | - 2.2.19 1233 | - 2.3.4 1234 | 1235 | - name: 2.2.20 - add tftp to unneeded package list 1236 | ansible.builtin.set_fact: 1237 | unneeded_packages: "{{ unneeded_packages + ['tftp'] + ['tftp-server'] }}" 1238 | when: not tftp_server 1239 | tags: 1240 | - 2.2.20 1241 | 1242 | - name: 2.2.21 - add rsync to unneeded package list 1243 | ansible.builtin.set_fact: 1244 | unneeded_packages: "{{ unneeded_packages + ['rsync'] }}" 1245 | tags: 1246 | - 2.2.21 1247 | 1248 | - name: 2.2.21 - list of packages to remove 1249 | ansible.builtin.debug: 1250 | var: unneeded_packages 1251 | 1252 | # With the list complete, use it with the system's package manager 1253 | # to remove packages from the system that are not needed. 1254 | - name: Process removal list 1255 | ansible.builtin.package: 1256 | name: "{{ unneeded_packages }}" 1257 | state: absent 1258 | tags: 1259 | - always 1260 | 1261 | # Cups should be remove per control 2.2.4, but it may not be able to due to 1262 | # dependencies, so disable the service instead 1263 | - name: 2.2.4 - Disable cups as we my not be able to uninstall it 1264 | ansible.builtin.service: 1265 | name: "{{ item }}" 1266 | enabled: false 1267 | state: stopped 1268 | when: "'cups' in ansible_facts.packages" 1269 | loop: 1270 | - cups.service 1271 | - cups.socket 1272 | - cups-browsed.service 1273 | tags: 1274 | - 2.2.4 1275 | 1276 | # Use the stat module to determine if the mail server config file exists. 1277 | # If it does and we are to be a mail server, then modify it per the control. 1278 | - name: 2.2.15 - Configure email for local-only mode if mail software is installed and not intending to be an external email relay (mail_server=false) 1279 | tags: 1280 | - 2.2.15 1281 | block: 1282 | - name: 2.2.15 - Find if we have a mail agent config file 1283 | ansible.builtin.stat: 1284 | path: /etc/postfix/main.cf 1285 | register: postfix_out 1286 | changed_when: false 1287 | 1288 | - name: 2.2.15 - If the file exists and not a mail server, then set loopback only 1289 | ansible.builtin.replace: 1290 | dest: /etc/postfix/main.cf 1291 | regexp: "^inet_interfaces = ((?!localhost).)*$" 1292 | replace: "inet_interfaces = loopback-only" 1293 | when: postfix_out.stat.exists and not email_server 1294 | notify: Restart postfix 1295 | 1296 | # openldap clients skipped (2.3.5) 1297 | 1298 | # Section 3, Network parameters 1299 | 1300 | # The sysctl module will configure certain sysctl parameters. They are 1301 | # collected into a loop here to speed the implementation 1302 | # Once complete, notify the system to flush the network routes 1303 | - name: 3.1 - Set networking parameters for host only communications 1304 | tags: 1305 | - 3.1.0 1306 | block: 1307 | - name: 3.1 - Set ipv4 networking parameters (OFF) 1308 | ansible.builtin.sysctl: 1309 | name: "{{ item }}" 1310 | value: "0" 1311 | reload: true 1312 | state: present 1313 | sysctl_set: true 1314 | loop: 1315 | - net.ipv4.ip_forward # (3.1.1) 1316 | - net.ipv4.conf.all.send_redirects # (3.1.2) 1317 | - net.ipv4.conf.default.send_redirects # (3.1.2) 1318 | notify: Flush network routes 1319 | 1320 | - name: 3.1 - Set ipv6 networking parameters (OFF) 1321 | ansible.builtin.sysctl: 1322 | name: "{{ item }}" 1323 | value: "0" 1324 | reload: true 1325 | state: present 1326 | sysctl_set: true 1327 | loop: 1328 | - net.ipv6.conf.all.forwarding # (3.1.1) 1329 | when: not ipv6_disable 1330 | notify: Flush network routes 1331 | 1332 | - name: 3.2 - Set networking parameters for host as router communications 1333 | tags: 1334 | - 3.2.0 1335 | block: 1336 | - name: 3.2 - Set ipv4 network parameters (OFF) 1337 | ansible.builtin.sysctl: 1338 | name: "{{ item }}" 1339 | value: "0" 1340 | reload: true 1341 | state: present 1342 | sysctl_set: true 1343 | loop: 1344 | - net.ipv4.conf.all.accept_source_route # (3.2.1) 1345 | - net.ipv4.conf.default.accept_source_route # (3.2.1) 1346 | - net.ipv4.conf.all.accept_redirects # (3.2.2) 1347 | - net.ipv4.conf.default.accept_redirects # (3.2.2) 1348 | - net.ipv4.conf.all.secure_redirects # (3.2.3) 1349 | - net.ipv4.conf.default.secure_redirects # (3.2.3) 1350 | notify: Flush network routes 1351 | 1352 | - name: 3.2.[4-8] - Set ipv4 networking parameters (ON) 1353 | ansible.builtin.sysctl: 1354 | name: "{{ item }}" 1355 | value: "1" 1356 | reload: true 1357 | state: present 1358 | sysctl_set: true 1359 | loop: 1360 | - net.ipv4.conf.all.log_martians # (3.2.4) 1361 | - net.ipv4.conf.default.log_martians # (3.2.4) 1362 | - net.ipv4.icmp_echo_ignore_broadcasts # (3.2.5) 1363 | - net.ipv4.icmp_ignore_bogus_error_responses # (3.2.6) 1364 | - net.ipv4.conf.all.rp_filter # (3.2.7) 1365 | - net.ipv4.conf.default.rp_filter # (3.2.7) 1366 | - net.ipv4.tcp_syncookies # ( 3.2.8) 1367 | notify: Flush network routes 1368 | 1369 | - name: 3.2 - Set ipv6 networking parameters (OFF) 1370 | ansible.builtin.sysctl: 1371 | name: "{{ item }}" 1372 | value: "0" 1373 | reload: true 1374 | state: present 1375 | sysctl_set: true 1376 | loop: 1377 | - net.ipv6.conf.all.accept_source_route # (3.2.1) 1378 | - net.ipv6.conf.default.accept_source_route # (3.2.1) 1379 | - net.ipv6.conf.all.accept_redirects # (3.2.2) 1380 | - net.ipv6.conf.default.accept_redirects # (3.2.2) 1381 | - net.ipv6.conf.all.accept_ra # (3.2.9) 1382 | - net.ipv6.conf.default.accept_ra # (3.2.9) 1383 | notify: Flush network routes 1384 | when: not ipv6_disable 1385 | 1386 | - name: 3.3 - IPv6 configuration and/or disablement 1387 | when: ipv6_disable 1388 | tags: 1389 | 3.3.0 1390 | block: 1391 | - name: 3.3 - Set ipv6 networking parameters (OFF) 1392 | ansible.builtin.sysctl: 1393 | name: "{{ item }}" 1394 | value: "0" 1395 | reload: true 1396 | state: present 1397 | sysctl_set: true 1398 | loop: 1399 | - net.ipv6.conf.all.accept_redirects # (3.3.2) 1400 | - net.ipv6.conf.default.accept_redirects # (3.3.2) 1401 | - net.ipv6.conf.all.accept_ra # (3.3.1) 1402 | - net.ipv6.conf.default.accept_ra # (3.3.1) 1403 | notify: Flush network routes 1404 | when: not ipv6_disable 1405 | tags: 1406 | - 3.3.1 1407 | - 3.3.2 1408 | 1409 | # We check here because we don't know what position the ipv6.disable is in 1410 | # order to simply do the replace, so we are instead looking for the match in the file first. 1411 | # If it doesn't exist, then we can just insert it 1412 | - name: 3.3 - Find if IPv6 is currently in the grub file, shows changed when it is in the file 1413 | ansible.builtin.lineinfile: 1414 | path: /etc/default/grub 1415 | regexp: '^\s*GRUB_CMDLINE_LINUX.*ipv6.disable=1' 1416 | state: absent 1417 | check_mode: true 1418 | changed_when: false 1419 | register: ipv6_disable_grub 1420 | failed_when: false 1421 | tags: 1422 | - 3.3.3 1423 | 1424 | # use the replace module to add it to grub bootloader and then notify 1425 | # grub to rebuild 1426 | - name: 3.3 - Disable IPv6 in grub 1427 | ansible.builtin.replace: 1428 | path: /etc/default/grub 1429 | regexp: '^GRUB_CMDLINE_LINUX="' 1430 | replace: 'GRUB_CMDLINE_LINUX="ipv6.disable=1 ' 1431 | notify: Rebuild grub 1432 | when: not ipv6_disable_grub.found and ipv6_disable 1433 | tags: 1434 | - 3.3.3 1435 | 1436 | # TCP Wrappers is not distributed by RHEL, but was distributed via EPEL until the end 1437 | # of 2018. It is being left in the RHEL7 controls because it may still be in some security 1438 | # requirements. It is not included in the RHEL8 controls 1439 | - name: 3.4 - TCP Wrappers 1440 | when: tcpwrappers 1441 | tags: 1442 | - 3.4.0 1443 | block: 1444 | - name: 3.4.1 - Install tcpwrappers 1445 | ansible.builtin.package: 1446 | name: "{{ tcpwrappers_pkg }}" 1447 | state: present 1448 | 1449 | # use lineinfile to make sure everyone has access to tcpwrappers 1450 | # from the local machine 1451 | - name: 3.4.2 - create basic hosts.allow 1452 | ansible.builtin.lineinfile: 1453 | dest: /etc/hosts.allow 1454 | owner: root 1455 | group: root 1456 | mode: 0644 1457 | line: "ALL: 127.0.0.1" 1458 | 1459 | # 3.4.3 is heavy handed so we aren't implementing it 1460 | - name: Refuse to set all on hosts.deny (3.4.3) because it's too heavy handed 1461 | ansible.builtin.debug: 1462 | msg: "not setting all on hosts.deny (3.4.3)" 1463 | 1464 | - name: 3.4.[4-5] - Set permissions on tcpwrappers files 1465 | ansible.builtin.file: 1466 | path: "{{ item }}" 1467 | owner: root 1468 | group: root 1469 | mode: 0644 1470 | loop: 1471 | - /etc/hosts.allow # (3.4.4) 1472 | - /etc/hosts.deny # (3.4.5) 1473 | 1474 | - name: 3.5 - Disable uncommon network protocols 1475 | tags: 1476 | - 3.5.0 1477 | block: 1478 | # This collection of tasks creates a empty list and save it as a fact. 1479 | # For every item that is encountered (without the tag being skipped), 1480 | # add a string to the list. 1481 | - name: 3.5.0 - Create empty list of uncommon network protocols to disable 1482 | ansible.builtin.set_fact: 1483 | uncommon_network: [] 1484 | 1485 | - name: 3.5.1 - Add dccp to list of uncommon network protocols to disable 1486 | ansible.builtin.set_fact: 1487 | uncommon_network: "{{ uncommon_network + ['dccp'] }}" 1488 | tags: 1489 | - 3.5.1 1490 | 1491 | - name: 3.5.2 - Add sctp to list of uncommon network protocols to disable 1492 | ansible.builtin.set_fact: 1493 | uncommon_network: "{{ uncommon_network + ['sctp'] }}" 1494 | tags: 1495 | - 3.5.2 1496 | 1497 | - name: 3.5.3 - Add rds to list of uncommon network protocols to disable 1498 | ansible.builtin.set_fact: 1499 | uncommon_network: "{{ uncommon_network + ['rds'] }}" 1500 | tags: 1501 | - 3.5.3 1502 | 1503 | - name: 3.5.4 - Add tipc to list of uncommon network protocols to disable 1504 | ansible.builtin.set_fact: 1505 | uncommon_network: "{{ uncommon_network + ['tipc'] }}" 1506 | tags: 1507 | - 3.5.4 1508 | 1509 | # With the list complete, use it with the system's package manager 1510 | # to remove packages from the system that are not needed. 1511 | - name: 3.5.0 - Process uncommon network list 1512 | ansible.builtin.lineinfile: 1513 | dest: /etc/modprobe.d/CIS.conf 1514 | line: "install {{ item }} /bin/true" 1515 | state: present 1516 | create: true 1517 | mode: 0644 1518 | with_items: 1519 | - "{{ uncommon_network }}" 1520 | 1521 | # Section 3 - Firewall 1522 | 1523 | - name: 3.6 - Configure firewalld 1524 | when: enable_firewall is defined and enable_firewall == "firewalld" 1525 | tags: 1526 | - 3.6.0 1527 | block: 1528 | - name: 3.6.1 - Install firewalld 1529 | ansible.builtin.package: 1530 | name: "firewalld" 1531 | state: present 1532 | notify: Start firewalld 1533 | 1534 | - name: 3.6.1 - Disable iptables 1535 | ansible.builtin.service: 1536 | name: iptables 1537 | state: stopped 1538 | enabled: false 1539 | masked: true 1540 | failed_when: false 1541 | 1542 | - name: 3.6.1 - Remove iptables-services 1543 | ansible.builtin.package: 1544 | name: "iptables-services" 1545 | state: absent 1546 | 1547 | - name: 3.6.1 - Set default zone 1548 | ansible.builtin.lineinfile: 1549 | path: "/etc/firewalld/firewalld.conf" 1550 | regexp: '^DefaultZone\s*((?!{{ firewalld_default_zone }}).)*$' 1551 | line: "DefaultZone={{ firewalld_default_zone }}" 1552 | when: firewalld_default_zone is defined 1553 | notify: Restart firewalld 1554 | 1555 | - name: 3.6.1 - Configure iptables 1556 | when: enable_firewall is defined and enable_firewall == "iptables" 1557 | tags: 1558 | - 3.6.0 1559 | block: 1560 | - name: 3.6.1 Install iptables 1561 | ansible.builtin.package: 1562 | name: 1563 | - "iptables" 1564 | - "iptables-services" 1565 | state: present 1566 | notify: Start iptables 1567 | tags: 1568 | - 3.6.1 1569 | 1570 | - name: 3.6.1 - Disable firewalld 1571 | ansible.builtin.service: 1572 | name: firewalld 1573 | state: stopped 1574 | enabled: false 1575 | ignore_errors: true 1576 | 1577 | - name: Notify user to configure firewall policy 1578 | ansible.builtin.debug: 1579 | msg: " Ensure default firewall policy (3.6.[2-5]) must be handled locally" 1580 | 1581 | 1582 | # Control 3.7 Ensure wireless interfaces are disabled is interface dependent 1583 | # skipping 1584 | 1585 | # Section 4 - Logging and Auditing 1586 | 1587 | - name: 4.1 Install and configure system auditing 1588 | when: enable_audit is defined and enable_audit 1589 | block: 1590 | - name: 4.1.1 - Install Audit 1591 | ansible.builtin.package: 1592 | name: 1593 | - audit 1594 | - audit-libs 1595 | state: present 1596 | tags: 1597 | - 4.1.1.1 1598 | # The replace module here is looking through file and make replacements of partial lines 1599 | - name: 4.1.1-[2-3] - Configure audit log storage size 1600 | ansible.builtin.replace: 1601 | path: /etc/audit/auditd.conf 1602 | regexp: "{{ item.find }}" 1603 | replace: "{{ item.replace }}" 1604 | loop: 1605 | - {find: '^max_log_file\s+=\s+[^{{ log_file_size }}]', replace: 'max_log_file = {{ log_file_size }}'} # 4.1.1.1 1606 | - {find: '^max_log_file_action\s+=\s+((?!keep_logs).)*$', replace: 'max_log_file_action = keep_logs'} # 4.1.1.2 1607 | - {find: '^space_left_action\s+=\s+((?!email).)*$', replace: 'space_left_action = email'} # 4.1.1.2 1608 | - {find: '^action_mail_acct\s+=\s+((?!root).)*$', replace: 'action_mail_acct = root'} # 4.1.1.2 1609 | - {find: '^admin_space_left_action\s+=\s+((?!suspend).)*$', replace: 'admin_space_left_action = suspend'} # 4.1.1.2 1610 | notify: Restart auditd 1611 | tags: 1612 | - 4.1.1.2 1613 | - 4.1.1.3 1614 | 1615 | - name: 4.1.2 - Enable auditd service 1616 | ansible.builtin.service: 1617 | name: auditd 1618 | enabled: true 1619 | state: started 1620 | tags: 1621 | - 4.1.2 1622 | 1623 | - name: 4.1.1.3 - Ensure auditing for processes that start prior to auditd 1624 | # We check here because we don't know what position the audit=1 is in 1625 | # order to simply do the replace, so we are instead looking for the match in the file first. 1626 | # If it doesn't exist, then we can just insert it 1627 | ansible.builtin.lineinfile: 1628 | path: /etc/default/grub 1629 | regexp: '^\s*GRUB_CMDLINE_LINUX.*audit=1' 1630 | state: absent 1631 | check_mode: true 1632 | changed_when: false 1633 | register: audit_exist 1634 | failed_when: false 1635 | tags: 1636 | - 4.1.1.3 1637 | 1638 | # use the replace module to add it to grub bootloader and then notify 1639 | # grub to rebuild 1640 | - name: 4.1.1.3 - enable audit service in grub 1641 | ansible.builtin.replace: 1642 | path: /etc/default/grub 1643 | regexp: '^GRUB_CMDLINE_LINUX="' 1644 | replace: 'GRUB_CMDLINE_LINUX="audit=1 ' 1645 | notify: Rebuild grub 1646 | when: not audit_exist.found 1647 | tags: 1648 | - 4.1.1.3 1649 | 1650 | # For the next several checks, each one is in their own file, so we are using 1651 | # the copy module to place each file independently and then motifying 1652 | # a restart of auditd if anything changes. 1653 | - name: 4.1.4 - Ensure to collect events that modify date/time 1654 | ansible.builtin.template: 1655 | dest: /etc/audit/rules.d/datetime.rules 1656 | src: audit_rules/datetime.rules 1657 | owner: root 1658 | group: root 1659 | mode: 0600 1660 | notify: Restart auditd 1661 | tags: 1662 | - 4.1.4 1663 | 1664 | - name: 4.1.5 - Ensure events that modify user/group information are collected 1665 | ansible.builtin.template: 1666 | dest: /etc/audit/rules.d/user-group-info.rules 1667 | src: audit_rules/user-group-info.rules 1668 | owner: root 1669 | group: root 1670 | mode: 0600 1671 | notify: Restart auditd 1672 | tags: 1673 | 4.1.5 1674 | 1675 | - name: 4.1.6 - Ensure to collect events that modify network 1676 | ansible.builtin.template: 1677 | dest: /etc/audit/rules.d/network.rules 1678 | src: audit_rules/network.rules 1679 | owner: root 1680 | group: root 1681 | mode: 0600 1682 | notify: Restart auditd 1683 | tags: 1684 | - 4.1.6 1685 | 1686 | - name: 4.1.7 - Ensure modifications to Mandatory Access Controls are collected 1687 | ansible.builtin.template: 1688 | dest: /etc/audit/rules.d/MAC-policy.rules 1689 | src: audit_rules/MAC-policy.rules 1690 | owner: root 1691 | group: root 1692 | mode: 0600 1693 | notify: Restart auditd 1694 | tags: 1695 | 4.1.7 1696 | 1697 | - name: 4.1.8 - Ensure system logins are collected 1698 | ansible.builtin.template: 1699 | dest: /etc/audit/rules.d/login.rules 1700 | src: audit_rules/login.rules 1701 | owner: root 1702 | group: root 1703 | mode: 0600 1704 | notify: Restart auditd 1705 | tags: 1706 | 4.1.8 1707 | 1708 | - name: 4.1.9 - Ensure session initiation information is collected 1709 | ansible.builtin.template: 1710 | dest: /etc/audit/rules.d/sessions.rules 1711 | src: audit_rules/sessions.rules 1712 | owner: root 1713 | group: root 1714 | mode: 0600 1715 | notify: Restart auditd 1716 | tags: 1717 | 4.1.9 1718 | 1719 | # This is the first control that we use the min_uid variable that we determined earlier 1720 | - name: 4.1.10 - Ensure modifications to discretionary access controls are collected 1721 | ansible.builtin.template: 1722 | dest: /etc/audit/rules.d/dac.rules 1723 | src: audit_rules/dac.rules 1724 | owner: root 1725 | group: root 1726 | mode: 0600 1727 | notify: Restart auditd 1728 | tags: 1729 | 4.1.10 1730 | 1731 | - name: 4.1.11 - Ensure unsuccessful unauthorized file access attempts are collected 1732 | ansible.builtin.template: 1733 | dest: /etc/audit/rules.d/bad-file-access.rules 1734 | content: 1735 | src: audit_rules/bad-file-access.rules 1736 | owner: root 1737 | group: root 1738 | mode: 0600 1739 | notify: Restart auditd 1740 | tags: 1741 | 4.1.11 1742 | 1743 | # Control 4.1.12 - Ensure use of privileged ansible.builtin.commands is collected, is machine dependent 1744 | # skipping 1745 | 1746 | - name: 4.1.13 - Ensure successful file system mounts are collected 1747 | ansible.builtin.template: 1748 | dest: /etc/audit/rules.d/file-system-mounts.rules 1749 | src: audit_rules/file-system-mounts.rules 1750 | owner: root 1751 | group: root 1752 | mode: 0600 1753 | notify: Restart auditd 1754 | tags: 1755 | 4.1.13 1756 | 1757 | - name: 4.1.14 - Ensure file deletion events by users are collected 1758 | ansible.builtin.template: 1759 | dest: /etc/audit/rules.d/delete.rules 1760 | src: audit_rules/delete.rules 1761 | owner: root 1762 | group: root 1763 | mode: 0600 1764 | notify: Restart auditd 1765 | tags: 1766 | 4.1.14 1767 | 1768 | - name: 4.1.15 - Ensure sysadmin actions (sudolog) are collected 1769 | ansible.builtin.template: 1770 | dest: /etc/audit/rules.d/sudolog.rules 1771 | src: audit_rules/sudolog.rules 1772 | owner: root 1773 | group: root 1774 | mode: 0600 1775 | notify: Restart auditd 1776 | tags: 1777 | 4.1.15 1778 | 4.1.16 1779 | 1780 | - name: 4.1.17 - Ensure kernel module loading and unloading is collected 1781 | ansible.builtin.template: 1782 | dest: /etc/audit/rules.d/modules.rules 1783 | src: audit_rules/modules.rules 1784 | owner: root 1785 | group: root 1786 | mode: 0600 1787 | notify: Restart auditd 1788 | tags: 1789 | 4.1.17 1790 | 1791 | - name: 4.1.18 - Ensure audit configuration is immutable 1792 | ansible.builtin.copy: 1793 | dest: /etc/audit/rules.d/99-finalize.rules 1794 | content: | 1795 | -e 2 1796 | owner: root 1797 | group: root 1798 | mode: 0600 1799 | notify: Restart auditd 1800 | tags: 1801 | 4.1.18 1802 | 1803 | 1804 | - name: 4.2.1.1 - Ensure rsyslog is installed 1805 | ansible.builtin.package: 1806 | name: rsyslog 1807 | state: present 1808 | tags: 1809 | - 4.2.3 1810 | 1811 | - name: 4.2.1.1 - Enable Rsyslog 1812 | ansible.builtin.service: 1813 | name: rsyslog 1814 | enabled: true 1815 | tags: 1816 | - 4.2.1.1 1817 | 1818 | - name: 4.2.1.2 - Ensure logging is configured 1819 | ansible.builtin.copy: 1820 | src: "{{ rsyslog_file }}" 1821 | dest: "/etc/rsyslog.d/{{ rsyslog_file }}" 1822 | owner: root 1823 | group: root 1824 | mode: 0640 1825 | when: rsylog_file is defined 1826 | tags: 1827 | - 4.2.1.2 1828 | 1829 | - name: 4.2.1.3 - Ensure rsyslog default file permissions are configured 1830 | ansible.builtin.lineinfile: 1831 | path: /etc/rsyslog.conf 1832 | regexp: '^\$FileCreateMode\s+0640' 1833 | line: "$FileCreateMode 0640" 1834 | create: true 1835 | state: present 1836 | mode: 0644 1837 | tags: 1838 | - 4.2.1.3 1839 | 1840 | # Control 4.2.1.4 - Ensure rsyslog is configured to send logs to a remote log host is machine dependent 1841 | # skipping 1842 | 1843 | - name: 4.2.1.5 - Ensure remote rsyslog messages are only acepted on designated log hosts 1844 | tags: 1845 | - 4.2.1.5 1846 | block: 1847 | - name: 4.2.1.5 - Find all rsyslog conf files in /etc/rsyslog.d 1848 | ansible.builtin.find: 1849 | paths: "/etc/rsyslog.d" 1850 | patterns: "*.conf" 1851 | register: rsyslog_module_found 1852 | 1853 | - name: 4.2.1.5 - Disable imtcp loading module on non log hosts (rsyslog.d conf files) 1854 | ansible.builtin.lineinfile: 1855 | dest: "{{ item.path }}" 1856 | regexp: '^\$ModLoad\s+imtcp' 1857 | state: absent 1858 | loop: "{{ rsyslog_module_found.files }}" 1859 | when: log_host is defined and not log_host 1860 | 1861 | - name: 4.2.1.5 - Disable imtcp loading module on non log hosts (main rsyslog conf file) 1862 | ansible.builtin.lineinfile: 1863 | dest: "/etc/rsyslog.conf" 1864 | regexp: '^\$ModLoad\s+imtcp' 1865 | state: absent 1866 | when: log_host is defined and not log_host 1867 | 1868 | - name: 4.2.1.5 - Disable TCP port listening on non log hosts (rsylog.d conf files) 1869 | ansible.builtin.lineinfile: 1870 | dest: "{{ item.path }}" 1871 | regexp: '^\$InputTCPServerRun' 1872 | state: absent 1873 | loop: "{{ rsyslog_module_found.files }}" 1874 | when: log_host is defined and not log_host 1875 | 1876 | - name: 4.2.1.5 - Disable TCP port listening on non log hosts (main rsyslog conf file) 1877 | ansible.builtin.lineinfile: 1878 | dest: "/etc/rsyslog.conf" 1879 | regexp: '^\$InputTCPServerRun' 1880 | state: absent 1881 | when: log_host is defined and not log_host 1882 | 1883 | - name: 4.2.1.5 - Enable loading of imtcp module on log hosts 1884 | ansible.builtin.lineinfile: 1885 | dest: /etc/rsyslog.d/CIS.conf 1886 | regexp: '^\$ModLoad\s+imtcp' 1887 | line: "$ModLoad imtcp" 1888 | create: true 1889 | owner: root 1890 | group: root 1891 | mode: 0644 1892 | when: log_host is defined and log_host 1893 | 1894 | - name: 4.2.1.5 - Enable TCP Port listening on port {{ log_port }} 1895 | ansible.builtin.lineinfile: 1896 | dest: /etc/rsyslog.d/CIS.conf 1897 | regexp: '^\$InputTCPServerRun {{ log_port }}' 1898 | line: "$InputTCPServerRun {{ log_port }}" 1899 | create: true 1900 | owner: root 1901 | group: root 1902 | mode: 0644 1903 | when: log_host is defined and log_host 1904 | 1905 | # 4.2.2 - Configure syslog-ng skipped as it is not a supported package from RHEL 1906 | 1907 | # Ensure rsyslog package is installed (4.2.3) moved to before 4.2.1.1 which is the package install 1908 | 1909 | - name: 4.3 - Ensure logrotate is installed and configured 1910 | ansible.builtin.package: 1911 | name: logrotate 1912 | state: present 1913 | tags: 1914 | - 4.3.0 1915 | 1916 | # 4.3 - Ensure logrotate is configured skipped as machine and environment dependent 1917 | 1918 | # Section 5 - Access and Authorization 1919 | # 1920 | 1921 | # This control is early in order to create the files. This will 1922 | # make sure they are available when cron starts 1923 | - name: Create the cron/at allow files (5.1.8) 1924 | ansible.builtin.copy: 1925 | dest: "{{ item }}" 1926 | content: "" 1927 | force: false 1928 | owner: root 1929 | group: root 1930 | mode: 0644 1931 | with_items: 1932 | - /etc/cron.allow 1933 | - /etc/at.allow 1934 | tags: 1935 | - 5.1.8 1936 | 1937 | - name: 5.1.1 - Ensure cron is enabled (RHEL Clones) 1938 | ansible.builtin.service: 1939 | name: crond 1940 | enabled: true 1941 | state: started 1942 | when: ansible_distribution != "SLES" 1943 | tags: 1944 | - 5.1.1 1945 | 1946 | - name: 5.1.2 - Ensure permissions on /etc/crontab 1947 | ansible.builtin.file: 1948 | path: /etc/crontab 1949 | owner: root 1950 | group: root 1951 | mode: 0600 1952 | tags: 1953 | - 5.1.2 1954 | 1955 | - name: 5.1.[3-7] - Ensure permissions on crontab directories 1956 | ansible.builtin.file: 1957 | path: "{{ item }}" 1958 | owner: root 1959 | group: root 1960 | mode: 0700 1961 | loop: 1962 | - /etc/cron.hourly 1963 | - /etc/cron.daily 1964 | - /etc/cron.weekly 1965 | - /etc/cron.monthly 1966 | - /etc/cron.d 1967 | tags: 1968 | - 5.1.3 1969 | - 5.1.4 1970 | - 5.1.5 1971 | - 5.1.6 1972 | - 5.1.7 1973 | 1974 | # Restrict at/cron skipped (5.1.8) as is rarely used and environment dependent 1975 | 1976 | # If you want to deploy your own SSH config file, exclude the entire 5.2.0 tag 1977 | - name: 5.2 - SSH File configurations 1978 | tags: 1979 | 5.2.0 1980 | block: 1981 | - name: 5.2.1 - Set permissions on SSH file 1982 | ansible.builtin.file: 1983 | dest: /etc/ssh/sshd_config 1984 | owner: root 1985 | group: root 1986 | mode: 0600 1987 | tags: 1988 | - 5.2.1 1989 | 1990 | # Control 5.2.2, Ensure SSH Protocol is set to 2, is not supported in OpenSSH 1991 | # supplied by Red Hat (or SUSE 15) any longer. Omitting 1992 | 1993 | - name: 5.2.3 - Set LogLevel to {{ ssh_log_level }} or more verbose, but not ansible.builtin.debug 1994 | ansible.builtin.replace: 1995 | path: /etc/ssh/sshd_config 1996 | replace: "LogLevel {{ ssh_log_level | upper }}" 1997 | regexp: '^#?LogLevel\s*(QUIET|FATAL|ERROR|DEBUG)*$' 1998 | notify: Restart sshd 1999 | when: ssh_log_level == "INFO" or ssh_log_level == "WARN" 2000 | tags: 2001 | - 5.2.3 2002 | 2003 | # Using replace with a replace argument of "" removes the selected 2004 | # text. 2005 | - name: 5.2.4 - Disable X11 forwarding 2006 | ansible.builtin.lineinfile: 2007 | path: /etc/ssh/sshd_config 2008 | state: absent 2009 | regexp: '^X11Forwarding\s*yes' 2010 | notify: Restart sshd 2011 | tags: 2012 | - 5.2.4 2013 | 2014 | - name: 5.2.5 - Ensure SSH MaxAuthTires is set to {{ ssh_max_auth_tries }} or less 2015 | ansible.builtin.lineinfile: 2016 | path: /etc/ssh/sshd_config 2017 | line: "MaxAuthTries {{ ssh_max_auth_tries }}" 2018 | regexp: '^MaxAuthTries\s*[^1-{{ ssh_max_auth_tries | int + 1 }}]' 2019 | insertafter: "^#MaxAuthTries" 2020 | notify: Restart sshd 2021 | tags: 2022 | - 5.2.5 2023 | 2024 | - name: 5.2.6 - Ensure IgnoreRhosts is set 2025 | ansible.builtin.lineinfile: 2026 | path: /etc/ssh/sshd_config 2027 | line: "IgnoreRhosts yes" 2028 | regexp: '^IgnoreRhosts\s*[^y]' 2029 | notify: Restart sshd 2030 | tags: 2031 | - 5.2.6 2032 | 2033 | - name: 5.2.7 - Ensure HostbasedAuthentication is disabled 2034 | ansible.builtin.lineinfile: 2035 | path: /etc/ssh/sshd_config 2036 | line: "HostbasedAuthentication no" 2037 | regexp: '^HostbasedAuthentication\s*[^n]' 2038 | notify: Restart sshd 2039 | tags: 2040 | - 5.2.7 2041 | 2042 | - name: 5.2.8 Ensure PermitRootLogin is disbled 2043 | ansible.builtin.lineinfile: 2044 | path: /etc/ssh/sshd_config 2045 | line: "PermitRootLogin no" 2046 | regexp: '^PermitRootLogin\s*[^n]' 2047 | notify: Restart sshd 2048 | tags: 2049 | - 5.2.8 2050 | 2051 | - name: 5.2.19 - Ensure SSH PermitEmptyPasswords is disabled 2052 | ansible.builtin.lineinfile: 2053 | path: /etc/ssh/sshd_config 2054 | state: absent 2055 | regexp: '^PermitEmptyPasswords\s*[^n]' 2056 | notify: Restart sshd 2057 | tags: 2058 | - 5.2.9 2059 | 2060 | - name: 5.2.10 - Ensure PermitUserEnvironment is disabled 2061 | ansible.builtin.lineinfile: 2062 | path: /etc/ssh/sshd_config 2063 | state: absent 2064 | regexp: '^PermitUserEnvironment\s*[^n]' 2065 | notify: Restart sshd 2066 | tags: 2067 | - 5.2.10 2068 | 2069 | - name: Set approved MAC algorithms (5.2.11) 2070 | ansible.builtin.lineinfile: 2071 | path: /etc/ssh/sshd_config 2072 | line: "MACs {{ ssh_mac_list }}" 2073 | insertafter: EOF 2074 | regexp: '^MACs {{ ssh_mac_list }}' 2075 | notify: Restart sshd 2076 | tags: 2077 | - 5.2.11 2078 | 2079 | - name: 5.2.12 - Ensure SSH Idle Timeout is configured ClientAliveInterval 2080 | ansible.builtin.lineinfile: 2081 | path: /etc/ssh/sshd_config 2082 | line: "ClientAliveInterval {{ ssh_alive_interval }}" 2083 | regexp: "^ClientAliveInterval {{ ssh_alive_interval }}" 2084 | insertafter: "^#ClientAliveInterval" 2085 | notify: Restart sshd 2086 | tags: 2087 | - 5.2.12 2088 | 2089 | - name: 5.2.12 - Ensure SSH Idle Timeout is configured ClientAliveCountMax 2090 | ansible.builtin.lineinfile: 2091 | path: /etc/ssh/sshd_config 2092 | line: "ClientAliveCountMax {{ ssh_alive_count_max }}" 2093 | regexp: "^ClientAliveCountMax {{ ssh_alive_count_max }}" 2094 | insertafter: "^#ClientAliveCountMax" 2095 | notify: Restart sshd 2096 | tags: 2097 | - 5.2.12 2098 | 2099 | - name: 5.2.13 - Ensure SSH LoginGraceTime is set to {{ ssh_grace_time }} or less 2100 | ansible.builtin.lineinfile: 2101 | path: /etc/ssh/sshd_config 2102 | line: "LoginGraceTime {{ ssh_grace_time }}" 2103 | regexp: "^LoginGraceTime {{ ssh_grace_time }}" 2104 | insertafter: "^#LoginGraceTime" 2105 | notify: Restart sshd 2106 | tags: 2107 | - 5.2.13 2108 | 2109 | # Control 5.2.14 is system dependent 2110 | # skipping 2111 | 2112 | - name: 5.2.15 - Ensure SSH Banner is configured 2113 | ansible.builtin.lineinfile: 2114 | path: "/etc/ssh/sshd_config" 2115 | line: "Banner /etc/{{ ssh_login_banner }}" 2116 | regexp: "^Banner /etc/{{ ssh_login_banner }}" 2117 | notify: Restart sshd 2118 | tags: 2119 | - 5.2.15 2120 | 2121 | # 5.2.16 - Configure PAM - skipped 2122 | # 5.2.17 - Disable SSH AllowTCPForwarding 2123 | - name: 5.2.17 - Ensure SSH AllowTcpForwarding is disabled 2124 | ansible.builtin.lineinfile: 2125 | path: "/etc/ssh/sshd_config" 2126 | line: "AllowTcpForwarding no" 2127 | regexp: '^AllowTcpForwarding\s+(yes|no)' 2128 | insertafter: "^#AllowTcpForwarding" 2129 | notify: Restart sshd 2130 | tags: 2131 | - 5.2.17 2132 | 2133 | - name: 5.3.1 - Configure PAM files and password requirements 2134 | tags: 2135 | - 5.3.1 2136 | block: 2137 | - name: 5.3.1 - require at least one digit in passwords 2138 | ansible.builtin.lineinfile: 2139 | path: /etc/security/pwquality.conf 2140 | line: dcredit = -1 2141 | regexp: "^dcredit = -1" 2142 | insertafter: "^# dcredit =" 2143 | when: password_req_digit 2144 | 2145 | - name: 5.3.1 - require at least one uppercase letter in passwords 2146 | ansible.builtin.lineinfile: 2147 | path: /etc/security/pwquality.conf 2148 | line: ucredit = -1 2149 | regexp: "^ucredit = -1" 2150 | insertafter: "^# ucredit =" 2151 | when: password_req_upper 2152 | 2153 | - name: 5.3.1 - require at least one lowercase letter in passwords 2154 | ansible.builtin.lineinfile: 2155 | path: /etc/security/pwquality.conf 2156 | line: lcredit = -1 2157 | regexp: "^lcredit = -1" 2158 | insertafter: "^# lcredit =" 2159 | when: password_req_lower 2160 | 2161 | - name: 5.3.1 - Require at least one special character in passwords 2162 | ansible.builtin.lineinfile: 2163 | path: /etc/security/pwquality.conf 2164 | line: ocredit = -1 2165 | regexp: "^ocredit = -1" 2166 | insertafter: "^# ocredit =" 2167 | when: password_req_digit 2168 | 2169 | - name: 5.3.1 - Require at least {{ password_min_length }} characters in passwords 2170 | ansible.builtin.lineinfile: 2171 | path: /etc/security/pwquality.conf 2172 | line: minlen = {{ password_min_length }} 2173 | regexp: "^minlen = {{ password_min_length }}" 2174 | insertafter: "^# minlen =" 2175 | when: password_req_digit 2176 | 2177 | # Control 5.3.2, Ensure lockout for failed password attempts, really requires a file replacement 2178 | # skipping 2179 | 2180 | # Control 5.3.3, Set password retention, requries file replacement 2181 | # skipping 2182 | 2183 | - name: 5.3.4 - Ensure password hashing algorithm is set to sha-512 2184 | when: not ansible_check_mode 2185 | tags: 2186 | 5.3.4 2187 | block: 2188 | - name: 5.3.4 - Determine if we are currently using sha512 password 2189 | ansible.builtin.command: authconfig --test 2190 | register: sha512_exist 2191 | changed_when: false 2192 | 2193 | - name: 5.3.4 - SHA-512 Password setting 2194 | ansible.builtin.command: /usr/sbin/authconfig --enableshadow --passalgo sha512 --update 2195 | when: not sha512_exist.stdout is search("sha512") 2196 | failed_when: false 2197 | 2198 | - name: 5.4.1.1 - Ensure password expiration is {{ password_expire_days }} days or less 2199 | ansible.builtin.lineinfile: 2200 | dest: /etc/login.defs 2201 | regexp: '^PASS_MAX_DAYS\s*((?!{{ password_expire_days }}).)*$' 2202 | line: "PASS_MAX_DAYS {{ password_expire_days }}" 2203 | state: present 2204 | tags: 2205 | - 5.4.1.1 2206 | 2207 | - name: 5.4.1.2 - Ensure password change days is set to {{ password_min_days }} 2208 | ansible.builtin.lineinfile: 2209 | dest: /etc/login.defs 2210 | regexp: '^PASS_MIN_DAYS\s*((?!{{ password_min_days }}).)*$' 2211 | line: "PASS_MIN_DAYS {{ password_min_days }}" 2212 | state: present 2213 | tags: 2214 | - 5.4.1.2 2215 | 2216 | - name: 5.4.1.3 - Ensure password warning days is set to {{ password_warning_days }} 2217 | ansible.builtin.lineinfile: 2218 | dest: /etc/login.defs 2219 | regexp: '^PASS_WARN_AGE\s*((?!{{ password_warning_days }}).)*$' 2220 | line: "PASS_WARN_AGE {{ password_warning_days }}" 2221 | state: present 2222 | tags: 2223 | - 5.4.1.3 2224 | 2225 | # We need to do this the hard way because the user module that calls /usr/sbin/useradd does not support setting inactive days 2226 | # The defaults perms are 0644 on the file, but after useradd is run against it, it changes to 0600, so we'll change it as well 2227 | - name: 5.4.1.4 - Disable accounts that are inactive for {{ password_inactive_lock_days }} days after password expiration 2228 | ansible.builtin.replace: 2229 | path: /etc/default/useradd 2230 | regexp: "^INACTIVE=((?!{{ password_inactive_lock_days }}).)*$" 2231 | replace: "INACTIVE={{ password_inactive_lock_days }}" 2232 | owner: root 2233 | group: root 2234 | mode: 0600 2235 | tags: 2236 | - 5.4.1.4 2237 | 2238 | # 5.4.1.5, Ensure all users last password change date is in the past, 2239 | # is not easily automated. Will revisit later 2240 | 2241 | # 5.4.2, Ensure all system accounts do not have an active shell, 2242 | # is not easily automated. Will revisit later 2243 | 2244 | # Control is actually setting to GID of 0 and the user module takes a group name, not a GID, so have to use usermod 2245 | - name: 5.4.3 - Ensure default group for root is GID 0 2246 | ansible.builtin.command: /usr/sbin/usermod -g 0 root 2247 | changed_when: false 2248 | tags: 2249 | - 5.4.3 2250 | 2251 | - name: 5.4.4 - Ensure umask is set 2252 | ansible.builtin.replace: 2253 | path: "{{ item }}" 2254 | replace: " umask {{ default_umask }}" 2255 | regexp: '^\s*umask\s*022' 2256 | loop: 2257 | - /etc/bashrc 2258 | - /etc/profile 2259 | when: ansible_distribution != "SLES" 2260 | tags: 2261 | - 5.4.4 2262 | 2263 | - name: 5.4.5 - Ensure shell timeout is {{ shell_timeout }} seconds or less 2264 | ansible.builtin.blockinfile: 2265 | path: "{{ item }}" 2266 | block: "TMOUT={{ shell_timeout }}" 2267 | marker: "# {mark} Ansible Managed CIS Timeout" 2268 | loop: 2269 | - /etc/bashrc 2270 | - /etc/profile 2271 | when: ansible_distribution != "SLES" 2272 | tags: 2273 | - 5.4.5 2274 | 2275 | 2276 | # 5.5.5, Ensure root login is restricted to system console 2277 | # not easily automatable because of the various TTYs on a machine 2278 | # Manually verify that only physically secure TTYs are listed in 2279 | # /etc/securetty 2280 | 2281 | - name: 5.6 - Restrict su to wheel group 2282 | tags: 2283 | - 5.6.0 2284 | block: 2285 | - name: Configure PAM to only allow su from wheel group (5.6) 2286 | ansible.builtin.replace: 2287 | path: /etc/pam.d/su 2288 | regexp: '^#auth\s+required\s+pam_wheel.so\s+use_uid' 2289 | replace: "auth required pam_wheel.so use_uid" 2290 | 2291 | - name: Add root to the wheel group (5.6) 2292 | ansible.builtin.user: 2293 | name: root 2294 | groups: wheel 2295 | append: true 2296 | 2297 | # Section 6 - System Maintenance 2298 | # 2299 | 2300 | - name: 6.1.[2,4] - Ensure permissions on /etc/passwd /etc/group 2301 | ansible.builtin.file: 2302 | path: /etc/{{ item }} 2303 | owner: root 2304 | group: root 2305 | mode: 0644 2306 | loop: 2307 | - passwd 2308 | - group 2309 | tags: 2310 | - 6.1.2 2311 | - 6.1.4 2312 | 2313 | - name: 6.1.[3,5] - Ensure permissions on /etc/shadow /etc/gshadow 2314 | ansible.builtin.file: 2315 | path: /etc/{{ item }} 2316 | owner: root 2317 | group: root 2318 | mode: 0000 2319 | loop: 2320 | - shadow 2321 | tags: 2322 | - 6.1.3 2323 | 2324 | - name: 6.1.[3,5] - Ensure permissions on /etc/gshadow 2325 | ansible.builtin.file: 2326 | path: /etc/{{ item }} 2327 | owner: root 2328 | group: root 2329 | mode: 0000 2330 | loop: 2331 | - gshadow 2332 | when: ansible_distribution != "SLES" 2333 | tags: 2334 | - 6.1.5 2335 | 2336 | - name: 6.1.[6-8] - Ensure permissions on /etc/passwd- /etc/shadow- /etc/group- 2337 | ansible.builtin.file: 2338 | path: /etc/{{ item }} 2339 | owner: root 2340 | group: root 2341 | mode: 0000 2342 | with_items: 2343 | - passwd- 2344 | - shadow- 2345 | - group- 2346 | tags: 2347 | - 6.1.6 2348 | - 6.1.7 2349 | - 6.1.8 2350 | 2351 | - name: 6.1.9 - Ensure permissions on /etc/passwd- /etc/gshadow- 2352 | ansible.builtin.file: 2353 | path: /etc/{{ item }} 2354 | owner: root 2355 | group: root 2356 | mode: 0000 2357 | with_items: 2358 | - gshadow- 2359 | when: ansible_distribution != "SLES" 2360 | tags: 2361 | - 6.1.9 2362 | 2363 | # Control 6.1.10, Ensure no world writable files exist, is system dependent so we are only 2364 | # providing a list to the user here. 2365 | - name: 6.1.10 - Ensure no world writable files exist 2366 | tags: 2367 | - 6.1.10 2368 | block: 2369 | - name: 6.1.10 - Find any world writiable files 2370 | ansible.builtin.shell: "/usr/bin/df --local -P | /usr/bin/awk {' if (NR!=1) print $6'} | /usr/bin/xargs -I '{}' find '{}' -xdev -type f -perm -0002" 2371 | register: ww_files 2372 | changed_when: false 2373 | check_mode: false 2374 | 2375 | - name: 6.1.10 - Print any world writable files found 2376 | ansible.builtin.debug: 2377 | msg: "World writiable files found: {{ ww_files.stdout }}" 2378 | changed_when: true 2379 | when: ww_files.stdout 2380 | 2381 | # Control 6.1.11, Ensure no unowned files exist, is system dependent so we are only 2382 | # providing a list to the user here. 2383 | - name: 6.1.11 - Ensure no unowned files exist 2384 | tags: 2385 | - 6.1.11 2386 | block: 2387 | - name: 6.1.11 - Find any unowned files 2388 | ansible.builtin.shell: "/usr/bin/df --local -P | /usr/bin/awk {' if (NR!=1) print $6'} | /usr/bin/xargs -I '{}' find '{}' -xdev -nouser" 2389 | register: uo_files 2390 | changed_when: false 2391 | check_mode: false 2392 | 2393 | - name: 6.1.11 - Print any unowned files found 2394 | ansible.builtin.debug: 2395 | msg: "unowned files found: {{ uo_files.stdout }}" 2396 | changed_when: true 2397 | when: uo_files.stdout 2398 | 2399 | # Control 6.1.12, Enscure no ungrouped files exist, is system dependent so we are only 2400 | # providing a list to the user here. 2401 | - name: 6.1.12 - Ensure no ungrouped files exist 2402 | tags: 2403 | - 6.1.12 2404 | block: 2405 | - name: 6.1.12 - Find any ungrouped files 2406 | ansible.builtin.shell: "/usr/bin/df --local -P | /usr/bin/awk {' if (NR!=1) print $6'} | /usr/bin/xargs -I '{}' find '{}' -xdev -nogroup" 2407 | register: ug_files 2408 | changed_when: false 2409 | check_mode: false 2410 | 2411 | - name: 6.1.12 - Print any ungrouped files found 2412 | ansible.builtin.debug: 2413 | msg: "ungrouped files found: {{ uo_files.stdout }}" 2414 | changed_when: true 2415 | when: ug_files.stdout 2416 | 2417 | # Control 6.1.13, Audit SUID executables, is a verification and is system dependent. 2418 | # Not implementing because it will always return some SUID files 2419 | # Manually review the control 2420 | 2421 | # Control 6.1.14, Audit SGID executables, is a verification and is system dependent. 2422 | # Not implementing because it will always return some SUID files 2423 | # Manually review the control 2424 | 2425 | - name: 6.2.1 - Ensure password fields are not empty 2426 | tags: 2427 | - 6.2.1 2428 | block: 2429 | - name: 6.2.1 - Check to see if there are any accounts with empty passwords 2430 | ansible.builtin.shell: "/usr/bin/cat /etc/shadow | awk -F: '($2 == \"\" ) { print $1 }'" 2431 | changed_when: false 2432 | register: empty_passwords 2433 | check_mode: false 2434 | 2435 | - name: 6.2.1 - Report the named users to the report 2436 | ansible.builtin.debug: 2437 | msg: "The user {{ item }} has an empty password" 2438 | when: empty_passwords.stdout 2439 | changed_when: true 2440 | loop: "{{ empty_passwords.stdout_lines }}" 2441 | 2442 | - name: 6.2.[2,4-5] - Ensure no legacy "+" entries exist in password files 2443 | ansible.builtin.lineinfile: 2444 | regexp: '^\+:.*' 2445 | state: absent 2446 | path: "{{ item }}" 2447 | when: ypbind is defined and not ypbind 2448 | loop: 2449 | - /etc/passwd 2450 | - /etc/shadow 2451 | - /etc/group 2452 | tags: 2453 | - 6.2.2 2454 | - 6.2.3 2455 | - 6.2.4 2456 | 2457 | - name: Report on multiple accounts with UID of 0 (6.2.5) 2458 | tags: 2459 | - 6.2.5 2460 | block: 2461 | - name: Find accounts with UID of 0 2462 | ansible.builtin.shell: "/usr/bin/cat /etc/passwd | awk -F: '($3 == 0) { print $1 }'" 2463 | register: rootuid 2464 | changed_when: rootuid.rc == 2 2465 | check_mode: false 2466 | 2467 | - name: Report on mulitple accounts with UID of 0 2468 | ansible.builtin.debug: 2469 | msg: "Accounts with UID zero in addition to root" 2470 | var: rootuid.stdout 2471 | when: rootuid.stdout != 'root' 2472 | 2473 | - name: 6.2.6 - Ensure root PATH integrity 2474 | tags: 2475 | - 6.2.6 2476 | block: 2477 | - name: 6.2.6 - Run script on path variable 2478 | ansible.builtin.script: files/path_check.sh 2479 | changed_when: false 2480 | register: path_check 2481 | check_mode: false 2482 | 2483 | - name: 6.2.6 - Print report to user 2484 | ansible.builtin.debug: 2485 | msg: 2486 | - "Note, Ansible runs this as SUDO with the ansible user's PATH variable. The script may not print issues" 2487 | - "that exist in root's path because of this. It should be run as root on the target machine manually." 2488 | - " {{ path_check.stdout }}" 2489 | when: path_check.stdout 2490 | 2491 | # Control 6.2.7 is environment dependent, skipping 2492 | # Control 6.2.8 is environment dependent, skipping 2493 | # Control 6.2.9 is environment dependent, skipping 2494 | # Controls 6.2.[10-14] are recommended to be handled by monitoring software 2495 | 2496 | - name: 6.2.15 - Report on groups in /etc/passwd with a GID not in /etc/group 2497 | tags: 2498 | - 6.2.15 2499 | block: 2500 | - name: 6.2.15 - Use script to pull the list of groups 2501 | ansible.builtin.script: 2502 | cmd: files/undefined_groups.sh 2503 | register: undefined_groups 2504 | changed_when: false 2505 | check_mode: false 2506 | 2507 | - name: 6.2.15 - Report to user any unreferenced groups 2508 | ansible.builtin.debug: 2509 | msg: "{{ undefined_groups.stdout_lines }}" 2510 | changed_when: true 2511 | when: undefined_groups.stdout 2512 | 2513 | - name: 6.2.16 - Report on duplicate UIDs in /etc/passwd 2514 | tags: 2515 | - 6.2.16 2516 | block: 2517 | - name: 6.2.16 - Use script to pull the list of duplicate UIDs 2518 | ansible.builtin.script: 2519 | cmd: files/duplicate_uids.sh 2520 | register: duplicate_uids 2521 | changed_when: false 2522 | check_mode: false 2523 | 2524 | - name: 6.2.16 - Print report of duplicated UIDs to user 2525 | ansible.builtin.debug: 2526 | msg: "{{ duplicate_uids.stdout_lines }}" 2527 | changed_when: true 2528 | when: duplicate_uids.stdout 2529 | 2530 | - name: 6.2.17 - Report on duplicate GIDs in /etc/group 2531 | tags: 2532 | - 6.2.17 2533 | block: 2534 | - name: 6.2.17 - Use script to pull the list of duplicate GIDs 2535 | ansible.builtin.script: 2536 | cmd: files/duplicate_guids.sh 2537 | register: duplicate_guids 2538 | changed_when: false 2539 | check_mode: false 2540 | 2541 | - name: 6.2.17 - Print report of duplcate GIDs to user 2542 | ansible.builtin.debug: 2543 | msg: "{{ duplicate_guids.stdout_lines }}" 2544 | changed_when: true 2545 | when: duplicate_guids.stdout 2546 | 2547 | - name: 6.2.18 - Report on duplicate users in /etc/passwd 2548 | tags: 2549 | - 6.2.18 2550 | block: 2551 | - name: 6.2.18 - Use script to pull the list of users 2552 | ansible.builtin.script: 2553 | cmd: files/duplicate_users.sh 2554 | register: duplicate_users 2555 | changed_when: false 2556 | check_mode: false 2557 | 2558 | - name: 6.2.18 - Print report of duplicate users to user 2559 | ansible.builtin.debug: 2560 | msg: "{{ duplicate_users.stdout_lines }}" 2561 | changed_when: true 2562 | when: duplicate_users.stdout 2563 | 2564 | - name: 6.2.19 - Report on duplicate groups in /etc/group 2565 | tags: 2566 | - 6.2.19 2567 | block: 2568 | - name: 6.2.19 - Use script to pull the list of groups 2569 | ansible.builtin.script: 2570 | cmd: files/duplicate_groups.sh 2571 | register: duplicate_groups 2572 | changed_when: false 2573 | check_mode: false 2574 | 2575 | - name: 6.2.19 - Print report of duplicate groups to user 2576 | ansible.builtin.debug: 2577 | msg: "{{ duplicate_groups.stdout_lines }}" 2578 | changed_when: true 2579 | when: duplicate_groups.stdout 2580 | -------------------------------------------------------------------------------- /roles/cis_security/templates/aidecheck.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Aide Check 3 | 4 | [Service] 5 | Type=simple 6 | {% if ansible_distribution == "RedHat" or ansible_distribution == "CentOS" or ansible_distribution == "Oracle" %} 7 | ExecStart=/usr/sbin/aide --check 8 | {% elif ansible_distribution == "Ubuntu" and ansible_distribution_major_version|int >= 22 %} 9 | ExecStart=/usr/bin/aide --check 10 | {% else %} 11 | ExecStart=/usr/bin/aide.wrapper -C 12 | {% endif %} 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /roles/cis_security/templates/aidecheck.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Aide check every day at midnight 3 | 4 | [Timer] 5 | OnCalendar=*-*-* 00:00:00 6 | Unit=aidecheck.service 7 | 8 | [Install] 9 | WantedBy=multi-user.target 10 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/MAC-policy.rules: -------------------------------------------------------------------------------- 1 | -w /etc/selinux/ -p wa -k MAC-policy 2 | -w /usr/share/selinux/ -p wa -k MAC-policy 3 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/bad-file-access.rules: -------------------------------------------------------------------------------- 1 | -a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>={{ min_uid.stdout }} -F auid!=-1 -k access 2 | -a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>={{ min_uid.stdout }} -F auid!=-1 -k access 3 | -a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>={{ min_uid.stdout }} -F auid!=-1 -k access 4 | -a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>={{ min_uid.stdout }} -F auid!=-1 -k access 5 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/chacl.rules: -------------------------------------------------------------------------------- 1 | -a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>={{ min_uid.stdout }} -F auid!=-1 -k perm_chng 2 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/chcon.rules: -------------------------------------------------------------------------------- 1 | -a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>={{ min_uid.stdout }} -F auid!=unset -k perm_chng 2 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/dac.rules: -------------------------------------------------------------------------------- 1 | -a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid>={{ min_uid.stdout }} -F auid!=unset -k perm_mod 2 | -a always,exit -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid>={{ min_uid.stdout }} -F auid!=unset -k perm_mod 3 | -a always,exit -F arch=b64 -S chown -S fchown -S fchownat -S lchown -F auid>={{ min_uid.stdout }} -F auid!=unset -k perm_mod 4 | -a always,exit -F arch=b32 -S chown -S fchown -S fchownat -S lchown -F auid>={{ min_uid.stdout }} -F auid!=unset -k perm_mod 5 | -a always,exit -F arch=b64 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>={{ min_uid.stdout }} -F auid!=unset -k perm_mod 6 | -a always,exit -F arch=b32 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>={{ min_uid.stdout }} -F auid!=unset -k perm_mod 7 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/datetime.rules: -------------------------------------------------------------------------------- 1 | -a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -F key=time-change 2 | -a always,exit -F arch=b32 -S adjtimex,settimeofday,clock_settime -F key=time-change 3 | -w /etc/localtime -p wa -k time-change 4 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/delete.rules: -------------------------------------------------------------------------------- 1 | -a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>={{ min_uid.stdout }} -F auid!=unset -k delete 2 | -a always,exit -F arch=b32 -S unlink -S unlinkat -S rename -S renameat -F auid>={{ min_uid.stdout }} -F auid!=unset -k delete 3 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/file-system-mounts.rules: -------------------------------------------------------------------------------- 1 | -a always,exit -F arch=b64 -S mount -F auid>={{ min_uid.stdout }} -F auid!=4294967295 -k mounts 2 | -a always,exit -F arch=b32 -S mount -F auid>={{ min_uid.stdout }} -F auid!=4294967295 -k mounts 3 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/login.rules: -------------------------------------------------------------------------------- 1 | -w /var/log/faillog -p wa -k logins 2 | -w /var/log/lastlog -p wa -k logins 3 | -w /var/run/faillock -p wa -k logins 4 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/modules.rules: -------------------------------------------------------------------------------- 1 | -w /sbin/insmod -p x -k modules 2 | -w /sbin/rmmod -p x -k modules 3 | -w /sbin/modprobe -p x -k modules 4 | -a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>={{ min_uid.stdout }} -F auid!=unset -k modules 5 | -a always,exit -F arch=b64 -S init_module -S delete_module -S finit_module -S query_module -F auid>={{ min_uid.stdout }} -F auid!=unset -k modules 6 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/network.rules: -------------------------------------------------------------------------------- 1 | -a always,exit -F arch=b64 -S sethostname,setdomainname -k -F system-locale 2 | -a always,exit -F arch=b32 -S sethostname,setdomainname -k -F system-locale 3 | -w /etc/issue -p wa -k system-locale 4 | -w /etc/issue.net -p wa -k system-locale 5 | -w /etc/hosts -p wa -k system-locale 6 | -w /etc/sysconfig/network -p wa -k system-locale 7 | -w /etc/sysconfig/network-scripts -p wa -k system-locale -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/sessions.rules: -------------------------------------------------------------------------------- 1 | -w /var/run/utmp -p wa -k session 2 | -w /var/log/wtmp -p wa -k session 3 | -w /var/log/btmp -p wa -k session 4 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/setfacl.rules: -------------------------------------------------------------------------------- 1 | -a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>={{ min_uid.stdout }} -F auid!=unset -k perm_chng 2 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/sudolog.rules: -------------------------------------------------------------------------------- 1 | -w /etc/sudoers -p wa -k scope 2 | -w /etc/sudoers.d -p wa -k scope 3 | -w {{ sudo_log }} -p wa -k sudo_log_file 4 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/user-group-info.rules: -------------------------------------------------------------------------------- 1 | -w /etc/group -p wa -k identity 2 | -w /etc/passwd -p wa -k identity 3 | -w /etc/gshadow -p wa -k identity 4 | -w /etc/shadow -p wa -k identity 5 | -w /etc/security/opasswd -p wa -k identity 6 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/user_emulation.rules: -------------------------------------------------------------------------------- 1 | -a always,exit -F arch=b64 -C euid!=uid -F auid!=unset -S execve -k user_emulation 2 | -a always,exit -F arch=b32 -C euid!=uid -F auid!=unset -S execve -k user_emulation 3 | -------------------------------------------------------------------------------- /roles/cis_security/templates/audit_rules/usermod.rules: -------------------------------------------------------------------------------- 1 | -a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>={{ min_uid.stdout }} -F auid!=unset -k usermod 2 | -------------------------------------------------------------------------------- /roles/cis_security/templates/chrony.conf: -------------------------------------------------------------------------------- 1 | # Use public servers from the pool.ntp.org project. 2 | # Please consider joining the pool (http://www.pool.ntp.org/join.html). 3 | pool {{ time_server }} iburst 4 | 5 | # Record the rate at which the system clock gains/losses time. 6 | driftfile /var/lib/chrony/drift 7 | 8 | # Allow the system clock to be stepped in the first three updates 9 | # if its offset is larger than 1 second. 10 | makestep 1.0 3 11 | 12 | # Enable kernel synchronization of the real-time clock (RTC). 13 | rtcsync 14 | 15 | # Enable hardware timestamping on all interfaces that support it. 16 | #hwtimestamp * 17 | 18 | # Increase the minimum number of selectable sources required to adjust 19 | # the system clock. 20 | #minsources 2 21 | 22 | # Allow NTP client access from local network. 23 | #allow 192.168.0.0/16 24 | 25 | # Serve time even if not synchronized to a time source. 26 | #local stratum 10 27 | 28 | # Specify file containing keys for NTP authentication. 29 | keyfile /etc/chrony.keys 30 | 31 | # Get TAI-UTC offset and leap seconds from the system tz database. 32 | leapsectz right/UTC 33 | 34 | # Specify directory for log files. 35 | logdir /var/log/chrony 36 | 37 | # Select which information is logged. 38 | #log measurements statistics tracking 39 | -------------------------------------------------------------------------------- /roles/cis_security/templates/chronyd: -------------------------------------------------------------------------------- 1 | OPTIONS="-u chrony" -------------------------------------------------------------------------------- /roles/cis_security/templates/chronyd.ubuntu: -------------------------------------------------------------------------------- 1 | # This is a configuration file for /etc/init.d/chrony and 2 | # /lib/systemd/system/chrony.service; it allows you to pass various options to 3 | # the chrony daemon without editing the init script or service file. 4 | 5 | # Options to pass to chrony. 6 | DAEMON_OPTS="" 7 | 8 | # Sync systecm clock in containers or without CAP_SYS_TIME (likely to fail) 9 | # See /usr/share/doc/chrony/README.container for details. 10 | SYNC_IN_CONTAINER="no" 11 | -------------------------------------------------------------------------------- /roles/cis_security/templates/ntp.conf: -------------------------------------------------------------------------------- 1 | # Use public servers from the pool.ntp.org project. 2 | # Please consider joining the pool (http://www.pool.ntp.org/join.html). 3 | pool {{ time_server }} iburst 4 | 5 | restrict -4 default kod nomodify notrap nopeer noquery 6 | 7 | # Record the rate at which the system clock gains/losses time. 8 | driftfile /var/lib/ntp/drift 9 | 10 | # Allow the system clock to be stepped in the first three updates 11 | # if its offset is larger than 1 second. 12 | makestep 1.0 3 13 | 14 | # Enable kernel synchronization of the real-time clock (RTC). 15 | rtcsync 16 | 17 | # Enable hardware timestamping on all interfaces that support it. 18 | #hwtimestamp * 19 | 20 | # Increase the minimum number of selectable sources required to adjust 21 | # the system clock. 22 | #minsources 2 23 | 24 | # Allow NTP client access from local network. 25 | #allow 192.168.0.0/16 26 | 27 | # Serve time even if not synchronized to a time source. 28 | #local stratum 10 29 | 30 | # Specify file containing keys for NTP authentication. 31 | keyfile /etc/ntp.keys 32 | 33 | # Get TAI-UTC offset and leap seconds from the system tz database. 34 | leapsectz right/UTC 35 | 36 | # Specify directory for log files. 37 | logdir /var/log/ntp 38 | 39 | # Select which information is logged. 40 | #log measurements statistics tracking 41 | -------------------------------------------------------------------------------- /roles/cis_security/templates/ntpd: -------------------------------------------------------------------------------- 1 | OPTIONS="-u ntp:ntp" -------------------------------------------------------------------------------- /roles/cis_security/templates/timesyncd.conf: -------------------------------------------------------------------------------- 1 | # This file is part of systemd. 2 | # 3 | # systemd is free software; you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published by 5 | # the Free Software Foundation; either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # Entries in this file show the compile time defaults. 9 | # You can change settings by editing this file. 10 | # Defaults can be restored by simply deleting this file. 11 | # 12 | # See timesyncd.conf(5) for details. 13 | 14 | [Time] 15 | NTP={{ time_service }} 16 | #FallbackNTP=ntp.ubuntu.com 17 | #RootDistanceMaxSec=5 18 | #PollIntervalMinSec=32 19 | #PollIntervalMaxSec=2048 20 | -------------------------------------------------------------------------------- /roles/cis_security/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for cis-security 3 | --------------------------------------------------------------------------------