diff --git a/README.md b/README.md index 84470a1..28e7cd6 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,74 @@ -CIS - CentOs +CIS - RHEL 8 Based Systems ========= -Asible role to apply CIS Benchmark on RHEL 8 based systems (Under Development) +Asible role to apply CIS Benchmark on RHEL 8 based systems. Requirements ------------ -Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. +Create below partitions at the time of installation. The role will not create any of these partitions. + +``` +1.1.6 | Ensure separate partition exists for /var (Scored) +1.1.7 | Ensure separate partition exists for /var/tmp (Scored) +1.1.11 | Ensure separate partition exists for /var/log (Scored) +1.1.12 | Ensure separate partition exists for /var/log/audit (Scored) +1.1.13 | Ensure separate partition exists for /home (Scored) + +``` + +Support Matrix +-------------- + +| Destro | Status | +| --- | --- | +| CentOS 8 | Supported (Tested) | +| RHEL 8 | Supported (Tested) | +| Oracle Linux 8 | Supported (Under Testing) | + Role Variables -------------- -A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. +deafult/main.yml variables are pretty self explanatory. -Dependencies ------------- -A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. +Notes +------ + + +The role will setup Authselect with a custom profile when you enable CIS rules 5.3.1, 5.3.2, 5.4.2, 5.4.3, 5.4.4. + +The recommended approch to join the node to an Active Directory domain with 'realmd' + +Update realmd-distro conf (/usr/lib/realmd/realmd-distro.conf) with below. +``` +[commands] +sssd-enable-logins = /usr/bin/sh -c "/usr/bin/systemctl enable oddjobd.service +&& /usr/bin/systemctl start oddjobd.service" +sssd-disable-logins = /bin/true +``` Example Playbook ---------------- -Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: +``` + - name: CIS Baseline Setup + hosts: cis + remote_user: vagrant + become: yes - - hosts: servers - roles: - - { role: username.rolename, x: 42 } + roles: + - cis-centos +``` License ------- -BSD +MIT Author Information ------------------ -An optional section for the role authors to include contact information, or a website (HTML is not allowed). +Muhammed Iqbal diff --git a/defaults/main.yml b/defaults/main.yml index ea96791..2636c3a 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -15,9 +15,9 @@ rule_1_1_1_2: true # Ensure mounting of vFAT filesystems is disabled rule_1_1_1_3: true # Ensure mounting of squashfs filesystems is disabled rule_1_1_1_4: true # Ensure mounting of udf filesystems is disabled rule_1_1_2: true # Ensure separate partition exists for /tmp | enable and start/restart tmp.mount -rule_1_1_3: true # Ensure nodev option set on /tmp partition -rule_1_1_4: true # Ensure nosuid option set on /tmp partition -rule_1_1_5: true # Ensure noexec option set on /tmp partition +rule_1_1_3: true # Ensure nodev option set on /tmp partition +rule_1_1_4: true # Ensure nosuid option set on /tmp partition +rule_1_1_5: true # Ensure noexec option set on /tmp partition rule_1_1_6: true # Ensure separate partition exists for /var rule_1_1_7: true # Ensure separate partition exists for /var/tmp rule_1_1_8: true # Ensure nodev option set on /var/tmp partition @@ -25,22 +25,22 @@ rule_1_1_9: true # Ensure nosuid option set on /var/tmp partition rule_1_1_10: true # Ensure noexec option set on /var/tmp partition rule_1_1_11: true # Ensure separate partition exists for /var/log rule_1_1_12: true # Ensure separate partition exists for /var/log/audit -rule_1_1_13: true # Ensure separate partition exists for /home -rule_1_1_14: true # Ensure nodev option set on /home +rule_1_1_13: true # Ensure separate partition exists for /home +rule_1_1_14: true # Ensure nodev option set on /home rule_1_1_15: true # Ensure nodev option set on /dev/shm partition rule_1_1_16: true # Ensure nosuid option set on /dev/shm partition rule_1_1_17: true # Ensure noexec option set on /dev/shm partition -rule_1_1_18: true # Ensure nodev option set on removable media partitions +rule_1_1_18: true # Ensure nodev option set on removable media partitions rule_1_1_19: true # Ensure nosuid option set on removable media partitions rule_1_1_20: true # Ensure noexec option set on removable media partitions rule_1_1_21: true # Ensure sticky bit is set on all world-writable directories -rule_1_1_22: true # Diable automounting -rule_1_1_23: false # Disable USB Storage +rule_1_1_22: true # Disable automounting +rule_1_1_23: true # Disable USB Storage rule_1_2_1: true # Ensure Red Hat Subscription Manager connection is configured rule_1_2_2: true # Disable the RHNSD daemon rule_1_2_3: true # Ensure gpg keys are configured rule_1_2_4: true # Ensure gpgcheck is globally activated -rule_1_2_5: true # Ensure package manager repositories are configured +rule_1_2_5: true # Ensure package manager repositories are configured rule_1_3_1: true # Ensure sudo is installed rule_1_3_2: true # Ensure sudo commands user pty rule_1_3_3: true # Ensure sudo log file exists @@ -52,7 +52,7 @@ rule_1_5_3: true # Ensure authentication required for single user mode rule_1_6_1: true # Ensure core dumps are restricted rule_1_6_2: true # Ensure address space layout randomization (ASLR) is enabled rule_1_7_1_1: true # Ensure selinux is installed -rule_1_7_1_2: true # Ensure selinux is not disabled in bootloader configuration +rule_1_7_1_2: true # Ensure selinux is not disabled in bootloader configuration rule_1_7_1_3: true # Ensure selinux policy is configured rule_1_7_1_4: true # Ensure the selinux state is enforcing rule_1_7_1_5: true # Ensure no unconfined services exist @@ -67,13 +67,13 @@ rule_1_8_1_6: true # Ensure permissions on /etc/issue.net are configured rule_1_8_2: true # Ensure GDM login banner is configured rule_1_9: false # Ensure updates, patches, and additional security software are installed rule_1_10: true # Ensure system-wide crypto policy is not legacy -rule_1_11: true # Ensure system-wide crypto policy is is FUTURE or FIPS --> not idempotent +rule_1_11: true # Ensure system-wide crypto policy is is FUTURE or FIPS # Section 2 rules rule_2_1_1: true # Ensure xinetd is not installed rule_2_2_1_1: true # Ensure time synchronization is in use rule_2_2_1_2: true # Ensure chrony is configured -rule_2_2_2: true # Ensure X Window System is not installed +rule_2_2_2: false # Ensure X Window System is not installed rule_2_2_3: true # Ensure rsync service is not enabled rule_2_2_4: true # Ensure Avahi Server is not enabled rule_2_2_5: true # Ensure SNMP Server is not enabled" @@ -94,14 +94,170 @@ rule_2_3_1: true # Ensure NIS Client is not installed rule_2_3_2: true # Ensure telnet client is not installed rule_2_3_3: true # Ensure LDAP client is not installed -##################################################################### -# 1.4.2 Bootloader password -bootloader_password: random -set_boot_pass: true +# Section 3 rules +rule_3_1_1: true # Ensure IP forwarding is disabled +rule_3_1_2: true # Ensure packet redirect sending is disabled +rule_3_2_1: true # Ensure source routed packets are not accepted +rule_3_2_2: true # Ensure ICMP redirects are not accepted +rule_3_2_3: true # Ensure secure ICMP redirects are not accepted +rule_3_2_4: true # Ensure suspicious packets are logged +rule_3_2_5: true # Ensure broadcast ICMP requests are ignored +rule_3_2_6: true # Ensure bogus ICMP responses are ignored +rule_3_2_7: true # Ensure Reverse Path Filtering is enabled +rule_3_2_8: true # Ensure TCP SYN Cookies is enabled +rule_3_2_9: true # Ensure IPv6 router advertisements are not accepted +rule_3_3_1: true # Ensure DCCP is disabled +rule_3_3_2: true # Ensure SCTP is disabled +rule_3_3_3: true # Ensure RDS is disabled +rule_3_3_4: true # Ensure TIPC is disabled +rule_3_4_1_1: true # Ensure a Firewall package is installed +rule_3_4_2_1: true # Ensure firewalld service is enabled and running +rule_3_4_2_2: true # Ensure iptables is not enabled +rule_3_4_2_3: true # Ensure nftables is not enabled +rule_3_4_2_4: true # Ensure default zone is set +rule_3_4_2_5: true # Ensure network interfaces are assigned to the appropriate zone +rule_3_4_2_6: true # Ensure unnessary services and ports are not accepted +rule_3_4_3: true # Configure nftables +rule_3_4_3_1: true # Ensure iptables are flushed +rule_3_4_3_2: true # Ensure a table exists +rule_3_4_3_3: true # Ensure base chains exist +rule_3_4_3_4: true # Ensure loopback traffic is configured +rule_3_4_3_5: true # Ensure outbound and established connections are configured +rule_3_4_3_6: true # Ensure default deny firewall policy +rule_3_4_3_7: true # Ensure nftables service is enabled +rule_3_4_3_8: true # Ensure nftables rules are permanent +rule_3_5: true # Ensure wireless interfaces are disabled +rule_3_6: true # Ensure IPv6 is disabled + +# Section 4 rules +rule_4_1_1_1: true # Ensure auditd is installed +rule_4_1_1_2: true # Ensure auditd service is enabled +rule_4_1_1_3: true # Ensure auditing for processes that start prior to auditd is enabled +rule_4_1_1_4: true # Ensure audit_backlog_limit is sufficient +rule_4_1_2_1: true # Ensure audit log storage size is configured +rule_4_1_2_2: true # Ensure audit logs are not automatically deleted +rule_4_1_2_3: true # Ensure system is disabled when audit logs are full +rule_4_1_3: true # Ensure changes to system administration scope (sudoers) is collected +rule_4_1_4: true # Ensure login and logout events are collected (Scored) +rule_4_1_5: true # Ensure session initiation information is collected (Scored) +rule_4_1_6: true # Ensure events that modify date and time information are collected +rule_4_1_7: true # Ensure events that modify the system's Mandatory Access Controls are collected +rule_4_1_8: true # Ensure events that modify the system's network environment are collected +rule_4_1_9: true # Ensure discretionary access control permission modification events are collected +rule_4_1_10: true # Ensure unsuccessful unauthorized file access attempts are collected +rule_4_1_11: true # Ensure events that modify user/group information are collected +rule_4_1_12: true # Ensure successful file system mounts are collected +rule_4_1_13: true # Ensure use of privileged commands is collected +rule_4_1_14: true # Ensure file deletion events by users are collected +rule_4_1_15: true # Ensure kernel module loading and unloading is collected +rule_4_1_16: true # Ensure system administrator actions (sudolog) are collected +rule_4_1_17: true # Ensure the audit configuration is immutable +rule_4_2_1_1: true # Ensure rsyslog is installed +rule_4_2_1_2: true # Ensure rsyslog Service is enabled +rule_4_2_1_3: true # Ensure rsyslog default file permissions configured +rule_4_2_1_4: true # Ensure logging is configured +rule_4_2_1_5: false # Ensure rsyslog is configured to send logs to a remote log host +rule_4_2_1_6: true # Ensure remote rsyslog messages are only accepted on designated log hosts +rule_4_2_2_1: true # Ensure journald is configured to send logs to rsyslog +rule_4_2_2_2: true # Ensure journald is configured to compress large log files +rule_4_2_2_3: true # Ensure journald is configured to write logfiles to persistent disk +rule_4_2_3: true # Ensure permissions on all logfiles are configured +rule_4_3: true # Ensure logrotate is configured + +# Section 5 rules +rule_5_1_1: true # Ensure cron daemon is enabled +rule_5_1_2: true # Ensure permissions on /etc/crontab are configured +rule_5_1_3: true # Ensure permissions on /etc/cron.hourly are configured +rule_5_1_4: true # Ensure permissions on /etc/cron.daily are configured +rule_5_1_5: true # Ensure permissions on /etc/cron.weekly are configured +rule_5_1_6: true # Ensure permissions on /etc/cron.monthly are configured +rule_5_1_7: true # Ensure permissions on /etc/cron.d are configured +rule_5_1_8: true # Ensure at/cron is restricted to authorized users +rule_5_2_1: true # Ensure permissions on /etc/ssh/sshd_config are configured +rule_5_2_2: true # Ensure SSH access is limited +rule_5_2_3: true # Ensure permissions on SSH private host key files are configured +rule_5_2_4: true # Ensure permissions on SSH public host key files are configured +rule_5_2_5: true # Ensure SSH LogLevel is appropriate +rule_5_2_6: true # Ensure SSH X11 forwarding is disabled +rule_5_2_7: true # Ensure SSH MaxAuthTries is set to 4 or less +rule_5_2_8: true # Ensure SSH IgnoreRhosts is enabled +rule_5_2_9: true # Ensure SSH HostbasedAuthentication is disabled +rule_5_2_10: true # Ensure SSH root login is disabled +rule_5_2_11: true # Ensure SSH PermitEmptyPasswords is disable +rule_5_2_12: true # Ensure SSH PermitUserEnvironment is disabled +rule_5_2_13: true # Ensure SSH Idle Timeout Interval is configured +rule_5_2_14: true # Ensure SSH LoginGraceTime is set to one minute or les +rule_5_2_15: true # Ensure SSH warning banner is configured +rule_5_2_16: true # Ensure SSH PAM is enabled +rule_5_2_17: true # Ensure SSH AllowTcpForwarding is disabled +rule_5_2_18: true # Ensure SSH MaxStartups is configured +rule_5_2_19: true # Ensure SSH MaxSessions is set to 4 or less +rule_5_2_20: true # Ensure system-wide crypto policy is not over-ridden +rule_5_3_1: true # Create custom authselect profile +rule_5_3_2: true # Select authselect profile +rule_5_3_3: true # Ensure authselect includes with-faillock +rule_5_4_1: true # Ensure password creation requirements are configured +rule_5_4_2: true # Ensure lockout for failed password attempts is configured +rule_5_4_3: true # Ensure password reuse is limited +rule_5_4_4: true # Ensure password hashing algorithm is SHA-512 +rule_5_5_1_1: true # Ensure password expiration is 365 days or less +rule_5_5_1_2: true # Ensure minimum days between password changes is 0 or more +rule_5_5_1_3: true # Ensure password expiration warning days is 14 or more +rule_5_5_1_4: false # Ensure inactive password lock is 90 days or less +rule_5_5_1_5: true # Ensure all users last password change date is in the past +rule_5_5_2: true # Ensure system accounts are secured +rule_5_5_3: true # Ensure default user shell timeout is 900 seconds or less +rule_5_5_4: true # Ensure default group for the root account is GID 0 +rule_5_5_5: true # Ensure default user umask is 027 or more restrictive +rule_5_6: true # Ensure root login is restricted to system console +rule_5_7: true # Ensure access to the su command is restricted - wheel group contains root + +# Section 6 rules +rule_6_1_1: true # Audit system file permissions +rule_6_1_2: true # Ensure permissions on /etc/passwd are configured +rule_6_1_3: true # Ensure permissions on /etc/shadow are configured +rule_6_1_4: true # Ensure permissions on /etc/group are configured +rule_6_1_5: true # Ensure permissions on /etc/gshadow are configured +rule_6_1_6: true # Ensure permissions on /etc/passwd- are configured +rule_6_1_7: true # Ensure permissions on /etc/shadow- are configured +rule_6_1_8: true # Ensure permissions on /etc/group- are configured +rule_6_1_9: true # Ensure permissions on /etc/gshadow- are configured +rule_6_1_10: true # Ensure no world writable files exist +rule_6_1_11: true # Ensure no unowned files or directories exist +rule_6_1_12: true # Ensure no ungrouped files or directories exist +rule_6_1_13: true # Audit SUID executables +rule_6_1_14: true # Audit SGID executables +rule_6_2_1: true # Ensure password fields are not empty +rule_6_2_2: true # Ensure no legacy '+' entries exist in /etc/passwd +rule_6_2_3: true # Ensure root PATH Integrity +rule_6_2_4: true # Ensure no legacy '+' entries exist in /etc/shadow +rule_6_2_5: true # Ensure no legacy '+' entries exist in /etc/group +rule_6_2_6: true # Ensure root is the only UID 0 account +rule_6_2_7: true # Ensure users' home directories permissions are 750 or more restrictive +rule_6_2_8: true # Ensure users own their home directories +rule_6_2_9: true # Ensure users' dot files are not group or world writable +rule_6_2_10: true # Ensure no users have .forward files +rule_6_2_11: true # Ensure no users have .netrc files +rule_6_2_12: true # Ensure users' .netrc Files are not group or world accessible +rule_6_2_13: true # Ensure no users have .rhosts files +rule_6_2_14: true # Ensure all groups in /etc/passwd exist in /etc/group +rule_6_2_15: true # Ensure no duplicate UIDs exist +rule_6_2_16: true # Ensure no duplicate GIDs exist +rule_6_2_17: true # Ensure no duplicate user names exist +rule_6_2_18: true # Ensure no duplicate group names exist +rule_6_2_19: true # Ensure shadow group is empt +rule_6_2_20: true # Ensure all users' home directories exist + +###################################################### + +############### Section Variables #################### + + +# Bootloader password +bootloader_password: p@ssw0rd # AIDE config_aide: true -# AIDE cron settings aide_cron: cron_user: root cron_file: /etc/crontab @@ -112,17 +268,13 @@ aide_cron: aide_month: '*' aide_weekday: '*' -crypto_policy: FIPS #FUTURE +crypto_policy: FUTURE #FIPS # SELinux policy selinux_state: enforcing selinux_policy: targeted -# Set to 'true' if X Windows is needed in your environment -xwindows_required: false - # Time Synchronization -time_synchronization: chrony time_synchronization_servers: - 0.pool.ntp.org - 1.pool.ntp.org @@ -151,10 +303,76 @@ warning_banner_issue: | to law enforcement officials. # End Banner -vartmp: - source: /tmp - fstype: none - opts: "defaults,nodev,nosuid,noexec,bind" - enabled: no + +# Firewall Configs +firewall: firewalld # Firewall module (firewalld, nftable) + + +# Log Configs +logrotate: "daily" +rsyslog_dest: 192.168.122.10 + +# Audit Logs +audit_backlog_limit: 8192 +auditd: + admin_space_left_action: halt # Halts the system when the audit logs are ful + max_log_file_action: keep_logs # Handle the audit log file reaching the max file size. A value of keep_logs will rotate the logs but never delete old logs. + max_log_file: 10 # Configure the maximum size (MB of audit log file. + + +# Section5 Variables +sshd: + clientalivecountmax: 3 + clientaliveinterval: 300 + ciphers: "aes256-ctr,aes192-ctr,aes128-ctr" + macs: "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" + logingracetime: 60 + allowusers: iqbal + #allowgroups: wheel + #denyusers: + #denygroups: + + +# Password Policies +password_policy: + max_days: 60 # 5.5.1.1 + min_days: 1 # 5.5.1.2 + warn_age: 7 # 5.5.1.3 + history: 5 # 5.4.3 Password history + +pwquality: # 5.4.1 + minlen: 8 + dcredit: -1 + ucredit: -1 + ocredit: -1 + lcredit: -1 + +# User Accounts +user_account_policy: + inactive_days: 30 # 5.5.1.4 Number of days for inactive account password lock + +# Authselect +authselect_profile: cis-profile + + +# 5.4.2 +pam_failllock_deny: 3 +pam_failllock_timeout: 900 + +# 5.1.8 +cron_allow_users: [] +at_allow_users: [] +# 5.5.2 +min_uid: 1000 +# 5.5.3 +shell_timeout: 900 +# 5.5.5 +umask: "027" +# 6.1.1 +audit_rpms_permissions_output: /var/tmp/audit_rpms.log +# 6.1.11 +user_unowned_file: nobody +# 6.1.12 +group_ungrouped_file: nobody \ No newline at end of file diff --git a/files/etc/nftables/nftables.rules b/files/etc/nftables/nftables.rules new file mode 100644 index 0000000..2bcd277 --- /dev/null +++ b/files/etc/nftables/nftables.rules @@ -0,0 +1,49 @@ +#!/sbin/nft -f + +# This nftables.rules config should be saved as /etc/nftables/nftables.rules + +# flush nftables rulesset +flush ruleset + +# Load nftables ruleset + +# nftables config with inet table named filter + +table inet filter { + # Base chain for input hook named input (Filters inbound network packets) + chain input { + type filter hook input priority 0; policy drop; + + # Ensure loopback traffic is configured + iif "lo" accept + ip saddr 127.0.0.0/8 counter packets 0 bytes 0 drop + ip6 saddr ::1 counter packets 0 bytes 0 drop + + # Ensure established connections are configured + ip protocol tcp ct state established accept + ip protocol udp ct state established accept + ip protocol icmp ct state established accept + + # Accept port 22(SSH) traffic from anywhere + tcp dport ssh accept + + # Accept ICMP and IGMP from anywhere + icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-done, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept + icmp type { destination-unreachable, router-advertisement, router-solicitation, time-exceeded, parameter-problem } accept + ip protocol igmp accept + } + + # Base chain for hook forward named forward (Filters forwarded network packets) + chain forward { + type filter hook forward priority 0; policy drop; + } + + # Base chain for hook output named output (Filters outbount network packets) + chain output { + type filter hook output priority 0; policy drop; + # Ensure outbound and established connections are configured + ip protocol tcp ct state established,related,new accept + ip protocol udp ct state established,related,new accept + ip protocol icmp ct state established,related,new accept + } +} diff --git a/handlers/main.yml b/handlers/main.yml index 8125801..fccbd72 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -12,5 +12,27 @@ - name: generate new grub config become: yes - command: grub2-mkconfig -o "{{ grub_cfg.stat.lnk_source }}" + command: grub2-mkconfig -o {{ grub_config_file }} +- name: reload dconf + become: yes + command: dconf update + +- name: restart auditd + become: yes + command: /sbin/service auditd restart + changed_when: no + check_mode: no + failed_when: no + args: + warn: no + +- name: restart sshd + become: yes + service: + name: sshd + state: restarted + +- name: authselect apply changes + become: yes + command: authselect apply-changes \ No newline at end of file diff --git a/meta/main.yml b/meta/main.yml index 93438d0..af08fd7 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -9,7 +9,9 @@ galaxy_info: versions: - 8 galaxy_tags: - - docker - - compose - - containers + - cis + - rhel8 + - centos8 + - ol8 + - baseline dependencies: [] \ No newline at end of file diff --git a/tasks/main.yml b/tasks/main.yml index 73db05d..db2f6e9 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -17,12 +17,28 @@ tags: - always -- name: "Set package facts" +- name: "Set facts | Packages" package_facts: manager: "auto" + tags: + - always -- name: "Set service facts" +- name: "Set facts | Service" service_facts: + tags: + - always + +- name: Check if the system booted with UEFI or BIOS + set_fact: + booted_with_efi: "{{ ansible_mounts | selectattr('mount', 'equalto', '/boot/efi') | list | length > 0 }}" + tags: + - always + +- name: Set facts | Grub config file + set_fact: + grub_config_file: "{{ '/boot/efi/EFI/{{ ansible_distribution | lower }}/grub.cfg' if booted_with_efi else '/boot/grub2/grub.cfg' }}" + tags: + - always - include: section_1.yml become: true @@ -35,3 +51,27 @@ when: section_2 tags: - section_2 + +- include: section_3.yml + become: true + when: section_3 + tags: + - section_3 + +- include: section_4.yml + become: true + when: section_4 + tags: + - section_4 + +- include: section_5.yml + become: true + when: section_5 + tags: + - section_5 + +- include: section_6.yml + become: true + when: section_6 + tags: + - section_6 \ No newline at end of file diff --git a/tasks/section_1.yml b/tasks/section_1.yml index 271b675..fb83176 100644 --- a/tasks/section_1.yml +++ b/tasks/section_1.yml @@ -1,24 +1,23 @@ --- - name: "1.1.1.1 | Ensure mounting of cramfs filesystems is disabled (Scored)" lineinfile: - dest: /etc/modprobe.d/CIS.conf + dest: /etc/modprobe.d/cis.conf regexp: "^(#)?install cramfs(\\s|$)" line: "install cramfs /bin/true" create: yes when: - - rule_1_1_1_1|bool + - rule_1_1_1_1 tags: - section_1 - scored - cramfs -- name: "1.1.1.1 | Remove cramfs module" +- name: "1.1.1.1 | Remove cramfs module (Scored)" modprobe: name: cramfs state: absent when: - - rule_1_1_1_1|bool - - ansible_connection != 'docker' + - rule_1_1_1_1 tags: - section_1 - scored @@ -26,24 +25,13 @@ - name: "1.1.1.2 | Ensure mounting of vFAT filesystems is limited (Not Scored)" lineinfile: - dest: /etc/modprobe.d/CIS.conf + dest: /etc/modprobe.d/cis.conf regexp: "^(#)?install vfat(\\s|$)" line: "install vfat /bin/true" create: yes when: - - rule_1_1_1_2|bool - tags: - - section_1 - - not_scored - - vfat - -- name: "1.1.1.2 | Remove FAT module" - modprobe: - name: vfat - state: absent - when: - - rule_1_1_1_2|bool - - ansible_connection != 'docker' + - rule_1_1_1_2 + - not booted_with_efi tags: - section_1 - not_scored @@ -51,24 +39,23 @@ - name: "1.1.1.3 | Ensure mounting of squashfs filesystems is disabled (Scored)" lineinfile: - dest: /etc/modprobe.d/CIS.conf + dest: /etc/modprobe.d/cis.conf regexp: "^(#)?install squashfs(\\s|$)" line: "install squashfs /bin/true" create: yes when: - - rule_1_1_1_3|bool + - rule_1_1_1_3 tags: - section_1 - scored - squashfs -- name: "1.1.1.3 | Remove squashfs module" +- name: "1.1.1.3 | Remove squashfs module (Scored)" modprobe: name: squashfs state: absent when: - - rule_1_1_1_3|bool - - ansible_connection != 'docker' + - rule_1_1_1_3 tags: - section_1 - scored @@ -77,31 +64,30 @@ - name: "1.1.1.4 | Ensure mounting of udf filesystems is disabled (Scored)" lineinfile: - dest: /etc/modprobe.d/CIS.conf + dest: /etc/modprobe.d/cis.conf regexp: "^(#)?install udf(\\s|$)" line: "install udf /bin/true" create: yes when: - - rule_1_1_1_4|bool + - rule_1_1_1_4 tags: - section_1 - scored - udf -- name: "1.1.1.4 | Remove udf module" +- name: "1.1.1.4 | Remove udf module (Scored)" modprobe: name: udf state: absent when: - - rule_1_1_1_4|bool - - ansible_connection != 'docker' + - rule_1_1_1_4 tags: - section_1 - scored - udf -- name: "1.1.2 | Ensure separate partition exists for /tmp | enable and start/restart tmp.mount" +- name: "1.1.2 | Ensure separate partition exists for /tmp | Enable and start/restart tmp.mount (Scored)" systemd: name: tmp.mount daemon_reload: yes @@ -109,23 +95,23 @@ masked: no state: started when: - - rule_1_1_2|bool + - rule_1_1_2 tags: - section_1 - scored - rule_1.1.2 -- name: "1.1.3 | 1.1.4 | 1.1.5 | Ensure nodev,nosuid,noexec options set on /tmp partition" +- name: "1.1.3 | 1.1.4 | 1.1.5 | Ensure nodev,nosuid,noexec options set on /tmp partition (Scored)" template: src: tmp.mount.j2 dest: /etc/systemd/system/tmp.mount owner: root group: root mode: 0644 - notify: systemd restart tmp.mount - when: rule_1_1_3|bool or - rule_1_1_4|bool or - rule_1_1_5|bool +# notify: systemd restart tmp.mount + when: rule_1_1_3 or + rule_1_1_4 or + rule_1_1_5 tags: - section_1 - scored @@ -169,19 +155,21 @@ 1.1.9 | Ensure nosuid option set on /var/tmp partition (Scored)\n 1.1.10 | Ensure noexec option set on /var/tmp partition (Scored)" mount: - name: /var/tmp - src: "{{ vartmp['source'] }}" - state: present - fstype: "{{ vartmp['fstype'] }}" - opts: "{{ vartmp['opts'] }}" + name: "/var/tmp" + src: "{{ item.device }}" + state: mounted + fstype: "{{ item.fstype }}" + opts: "defaults{% if rule_1_1_8 %},nodev{% endif %}{% if rule_1_1_9 %},nosuid{% endif %}{% if rule_1_1_10 %},noexec{% endif %}" + with_items: "{{ ansible_mounts }}" when: - - rule_1_1_8|bool - - rule_1_1_9|bool - - rule_1_1_10|bool + - item.mount == "/var/tmp" + - rule_1_1_7 + - rule_1_1_8 or rule_1_1_9 or rule_1_1_10 tags: - level1 - scored - patch + - rule_1.1.7 - rule_1.1.8 - rule_1.1.9 - rule_1.1.10 @@ -226,7 +214,7 @@ changed_when: no failed_when: no when: - - rule_1_1_13|bool + - rule_1_1_13 tags: - level2 - scored @@ -242,7 +230,7 @@ fstype: "{{ item.fstype }}" opts: "nodev" when: - - rule_1_1_14|bool + - rule_1_1_14 - item.mount == "/home" with_items: "{{ ansible_mounts }}" tags: @@ -326,18 +314,25 @@ name: autofs enabled: no when: + - rule_1_1_22 - "'autofs.service' in ansible_facts.services" - - rule_1_1_22|bool tags: - level1 - patch - rule_1.1.22 - name: "1.1.23 | Disable USB Storage (Scored)" - command: rmmod usb-storage - ignore_errors: yes + lineinfile: + dest: /etc/modprobe.d/cis.conf + regexp: "^(#)?\\s*install\\s+usb-storage(\\s*|$)" + line: "install usb-storage /bin/true" + state: present + owner: root + group: root + mode: 0644 + create: true when: - - rule_1_1_23|bool + - rule_1_1_23 tags: - level1 - scored @@ -464,7 +459,7 @@ name: aide state: present when: - - rule_1_4_1|bool + - rule_1_4_1 tags: - level1 - scored @@ -481,8 +476,8 @@ async: 45 poll: 0 when: - - config_aide|bool - - rule_1_4_1|bool + - config_aide + - rule_1_4_1 tags: - level1 - scored @@ -502,7 +497,7 @@ weekday: "{{ aide_cron['aide_weekday'] | default('*') }}" job: "{{ aide_cron['aide_job'] }}" when: - - rule_1_4_2|bool + - rule_1_4_2 tags: - level1 - scored @@ -511,28 +506,17 @@ - patch - rule_1.4.2 -- name: "1.5.1 | Ensure permissions on bootloader config are configured (Scored)" - stat: - path: /etc/grub2.cfg - register: grub_cfg - when: - - rule_1_5_1|bool - tags: - - level1 - - scored - - grub - - patch - - rule_1.5.1 - - name: "1.5.1 | Ensure permissions on bootloader config are configured (Scored)" file: - path: "{{ grub_cfg.stat.lnk_source }}" + path: "{{ item }}" owner: root group: root mode: 0600 when: - - grub_cfg.stat.exists and grub_cfg.stat.islnk - - rule_1_5_1|bool + - rule_1_5_1 + with_items: + - /boot/grub2/grubenv + - "{{ grub_config_file }}" tags: - level1 - scored @@ -540,6 +524,7 @@ - patch - rule_1.5.1 + - name: "1.5.2 | Ensure bootloader password is set (Scored)" block: - name: "1.5.2 | Ensure bootloader password is set (Scored) | Install Python Expect" @@ -562,22 +547,22 @@ - grub - rule_1.5.2 -- name: "NOT1.5.3 | Ensure authentication required for single user mode (Scored)" +- name: "1.5.3 | Ensure authentication required for single user mode (Scored)" block: - - name: "NOT1.5.3 | Ensure authentication required for single user mode (Scored) - emergency" + - name: "1.5.3 | Ensure authentication required for single user mode (Scored) | Emergency" lineinfile: dest: /usr/lib/systemd/system/emergency.service regexp: '/sbin/sulogin' - line: 'execstart=-/usr/lib/systemd/systemd-sulogin-shell rescue' + line: 'ExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue' - - name: "NOT1.5.3 | Ensure authentication required for single user mode (Scored) - rescue" + - name: "1.5.3 | Ensure authentication required for single user mode (Scored) | Rescue" lineinfile: dest: /usr/lib/systemd/system/rescue.service regexp: '/sbin/sulogin' - line: 'execstart=-/usr/lib/systemd/systemd-sulogin-shell rescue' + line: 'ExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue' when: - rule_1_5_3 - - ansible_distribution_major_version == 8 + - ansible_distribution_major_version == "8" tags: - level1 - level2 @@ -592,7 +577,7 @@ line: '* hard core 0' insertbefore: '^# End of file' when: - - rule_1_6_1|bool + - rule_1_6_1 tags: - level1 - scored @@ -609,7 +594,7 @@ sysctl_set: yes ignoreerrors: yes when: - - rule_1_6_1|bool + - rule_1_6_1 tags: - level1 - scored @@ -626,7 +611,7 @@ sysctl_set: yes ignoreerrors: yes when: - - rule_1_6_2|bool + - rule_1_6_2 tags: - level1 - scored @@ -643,38 +628,22 @@ notify: generate new grub config when: - selinux_state == "enforcing" - - rule_1_7_1_2|bool + - rule_1_7_1_2 tags: - level2 - scored - patch - rule_1.7.1.2 -############################################### -#- name: "1.7.1.3 | Ensure SELinux policy is configured (Scored)" -# selinux: -# conf: /etc/selinux/config -# policy: "{{ selinux_policy }}" -# state: "{{ selinux_state }}" -# debug: -# msg: "--> Not relevant" -# changed_when: no -# when: -# - rule_1_7_1_3|bool -# tags: -# - level2 -# - scored -# - selinux -# - patch -# - rule_1.7.1.3 -################################################ -- name: "1.7.1.4 | Ensure the SELinux state is enforcing (Scored)" +- name: "1.7.1.3 | Ensure the SELinux policy is configured (Scored)\n + 1.7.1.4 | Ensure the SELinux state is enforcing (Scored)" selinux: conf: /etc/selinux/config policy: "{{ selinux_policy }}" state: "{{ selinux_state }}" when: - - rule_1_7_1_4|bool + - rule_1_7_1_3 + - rule_1_7_1_4 tags: - level2 - scored @@ -688,7 +657,7 @@ changed_when: no failed_when: no when: - - rule_1_7_1_5|bool + - rule_1_7_1_5 tags: - level2 - scored @@ -700,7 +669,7 @@ name: setroubleshoot state: absent when: - - rule_1_7_1_6|bool + - rule_1_7_1_6 tags: - level2 - scored @@ -713,7 +682,7 @@ name: mcstrans state: absent when: - - rule_1_7_1_7|bool + - rule_1_7_1_7 tags: - level2 - scored @@ -725,7 +694,7 @@ name: libselinux state: present when: - - rule_1_7_1_1|bool + - rule_1_7_1_1 tags: - level2 - scored @@ -737,7 +706,7 @@ src: etc/motd.j2 dest: /etc/motd when: - - rule_1_8_1_1|bool + - rule_1_8_1_1 tags: - level1 - banner @@ -749,7 +718,7 @@ src: etc/issue.j2 dest: /etc/issue when: - - rule_1_8_1_2|bool + - rule_1_8_1_2 tags: - level1 - patch @@ -760,7 +729,7 @@ src: etc/issue.net.j2 dest: /etc/issue.net when: - - rule_1_8_1_3|bool + - rule_1_8_1_3 tags: - level1 - banner @@ -775,7 +744,7 @@ group: root mode: 0644 when: - - rule_1_8_1_4|bool + - rule_1_8_1_4 tags: - level1 - perms @@ -790,7 +759,7 @@ group: root mode: 0644 when: - - rule_1_8_1_5|bool + - rule_1_8_1_5 tags: - level1 - perms @@ -805,7 +774,7 @@ group: root mode: 0644 when: - - rule_1_8_1_6|bool + - rule_1_8_1_6 tags: - level1 - perms @@ -828,10 +797,12 @@ - { file: '/etc/dconf/profile/gdm', regexp: 'file-db', line: 'file-db:/usr/share/gdm/greeter-dconf-defaults' } - { file: '/etc/dconf/db/gdm.d/01-banner-message', regexp: '\[org\/gnome\/login-screen\]', line: '[org/gnome/login-screen]' } - { file: '/etc/dconf/db/gdm.d/01-banner-message', regexp: 'banner-message-enable', line: 'banner-message-enable=true' } - - { file: '/etc/dconf/db/gdm.d/01-banner-message', regexp: 'banner-message-text', line: "banner-message-text='{{ warning_banner }}' " } + - { file: '/etc/dconf/db/gdm.d/01-banner-message', regexp: 'banner-message-text', line: "banner-message-text='Authorized uses only. All activity may be monitored and reported.'" } + notify: reload dconf when: - - gui|bool - - rule_1_8_2|bool + - not rule_2_2_2 | bool + - "'gdm' in ansible_facts.packages" + - rule_1_8_2 tags: - level1 - level2 @@ -852,30 +823,32 @@ - name: "1.10 | Ensure system-wide crypto policy is not legacy (Scored)" block: - - name: 1.10 | Ensure system-wide crypto policy is not legacy (Scored) | Check Current Crypto Policy - slurp: - src: /etc/crypto-policies/config - register: cryptopolicies - - - name: 1.10 | Ensure system-wide crypto policy is not legacy (Scored) | Update if not to DEFAULT - command: update-crypto-policies --set DEFAULT + - name: "1.10 | Ensure system-wide crypto policy is not legacy (Scored) | Check Current Crypto Policy" + command: grep -E '^\s*(DEFAULT|FUTURE|FIPS)\s*$' /etc/crypto-policies/config + register: c_policy + changed_when: false + failed_when: false + + - name: "1.10 | Ensure system-wide crypto policy is not legacy (Scored)" + command: update-crypto-policies --set {{ crypto_policy }} when: - - '"LEGACY" in cryptopolicies.content|b64decode' + - c_policy.stdout == 'LEGACY' when: - rule_1_10 + - rule_1_11 tags: - level1 - level2 - section_1 - rule_1.10 + - rule_1.11 - crypto - name: "1.11 | Ensure system-wide crypto policy is FUTURE or FIPS (Scored)" - shell: | - update-crypto-policies --set {{ crypto_policy }} - update-crypto-policies + command: update-crypto-policies --set {{ crypto_policy }} when: - - rule_1_11|bool + - rule_1_11 + - c_policy.stdout == 'DEFAULT' or c_policy.stdout == 'LEGACY' tags: - level1 - level2 diff --git a/tasks/section_2.yml b/tasks/section_2.yml index 43d43fd..a498fec 100644 --- a/tasks/section_2.yml +++ b/tasks/section_2.yml @@ -1,5 +1,5 @@ --- -- name: "2.1.1 | Ensure xinetd is not installed" +- name: "2.1.1 | Ensure xinetd is not installed (Scored)" dnf: name: xinetd state: absent @@ -11,7 +11,7 @@ - scored - rule_2.1.1 -- name: "2.2.1.1 | Ensure time synchronization is in use" +- name: "2.2.1.1 | Ensure time synchronization is in use (Not Scored)" dnf: name: chrony state: present @@ -20,7 +20,7 @@ - level1 - rule_2.2.1.1 -- name: "2.2.1.2 | Ensure chrony is configured" +- name: "2.2.1.2 | Ensure chrony is configured (Scored)" template: src: etc/chrony.conf.j2 dest: /etc/chrony.conf @@ -34,33 +34,25 @@ - level1 - rule_2.2.1.2 -- name: "2.2.2 | Ensure X Window System is not installed" - package: - state: absent - name: - - "xorg-x11*" - when: - - not xwindows_required | bool - - "'xorg-x11' in ansible_facts.packages" - - rule_2_2_2 - tags: - - section_2 - - level1 - - scored - - xwindows - - rule_2.2.2 - -- name: "Update facts" +- name: "2.2.2 | Ensure X Window System is not installed (Scored)" block: - - name: "Update package facts" - package_facts: - manager: "auto" + - name: "2.2.2 | Ensure X Window System is not installed (Scored)" + package: + state: absent + name: + - "xorg-x11*" + + - name: Refresh destination information + setup: - name: "Update service facts" service_facts: + + - name: "Update package facts" + package_facts: + manager: "auto" when: - - not xwindows_required | bool - - "'xorg-x11' in ansible_facts.packages" + - "'xorg-x11-server-common' in ansible_facts.packages" - rule_2_2_2 tags: - section_2 @@ -68,9 +60,9 @@ - scored - xwindows - rule_2.2.2 + - -- name: "2.2.3 | Ensure rsync service is not enabled " +- name: "2.2.3 | Ensure rsync service is not enabled (Scored)" systemd: name: rsyncd state: stopped @@ -83,13 +75,13 @@ - level1 - rule_2.2.3 -- name: "2.2.4 | Ensure Avahi Server is not enabled" +- name: "2.2.4 | Ensure Avahi Server is not enabled (Scored)" systemd: name: avahi-daemon state: stopped enabled: no when: - - "'avahi-daemon' in ansible_facts.services" + - "'avahi-daemon.service' in ansible_facts.services" - rule_2_2_4 tags: - section_2 @@ -99,7 +91,7 @@ - services - rule_2.2.4 -- name: "2.2.5 | Ensure SNMP Server is not enabled" +- name: "2.2.5 | Ensure SNMP Server is not enabled (Scored)" systemd: name: snmpd state: stopped @@ -112,7 +104,7 @@ - level1 - rule_2.2.5 -- name: "2.2.6 | Ensure HTTP Proxy Server is not enabled" +- name: "2.2.6 | Ensure HTTP Proxy Server is not enabled (Scored)" systemd: name: squid state: stopped @@ -125,7 +117,7 @@ - level1 - rule_2.2.6 -- name: "2.2.7 | Ensure Samba is not enabled" +- name: "2.2.7 | Ensure Samba is not enabled (Scored)" systemd: name: smb state: stopped @@ -138,7 +130,7 @@ - level1 - rule_2.2.7 -- name: "2.2.8 | Ensure IMAP and POP3 server is not enabled" +- name: "2.2.8 | Ensure IMAP and POP3 server is not enabled (Scored)" systemd: name: dovecot state: stopped @@ -180,7 +172,7 @@ - scored - rule_2.2.10 -- name: "2.2.11 | Ensure DNS Server is not enabled" +- name: "2.2.11 | Ensure DNS Server is not enabled (Scored)" systemd: name: named state: stopped @@ -193,13 +185,13 @@ - level1 - rule_2.2.11 -- name: "2.2.12 | Ensure NFS is not enabled" +- name: "2.2.12 | Ensure NFS is not enabled (Scored)" systemd: - name: nfs + name: nfs-server state: stopped enabled: no when: - - "'nfs.service' in ansible_facts.services" + - "'nfs-server.service' in ansible_facts.services" - rule_2_2_12 tags: - section_2 @@ -210,7 +202,7 @@ - services - rule_2.2.12 -- name: "2.2.13 | Ensure RPC is not enabled" +- name: "2.2.13 | Ensure RPC is not enabled (Scored)" systemd: name: rpcbind state: stopped @@ -227,7 +219,7 @@ - services - rule_2.2.13 -- name: "2.2.14 | Ensure LDAP server is not enabled" +- name: "2.2.14 | Ensure LDAP server is not enabled (Scored)" service: name: slapd state: stopped @@ -243,7 +235,7 @@ - services - rule_2.2.14 -- name: "2.2.15 | Ensure DHCP Server is not enabled" +- name: "2.2.15 | Ensure DHCP Server is not enabled (Scored)" systemd: name: dhcpd state: stopped @@ -259,13 +251,13 @@ - services - rule_2.2.14 -- name: "2.2.16 | Ensure CUPS is not enabled" +- name: "2.2.16 | Ensure CUPS is not enabled (Scored)" systemd: name: cups state: stopped enabled: no when: - - "'cups.service' in ansible_facts.services" + - "'cups' in ansible_facts.packages" - rule_2_2_16 tags: - section_2 @@ -275,7 +267,7 @@ - services - rule_2.2.16 -- name: "2.2.17 | Ensure NIS Server is not enabled" +- name: "2.2.17 | Ensure NIS Server is not enabled (Scored)" systemd: name: ypserv state: stopped @@ -288,7 +280,7 @@ - level1 - rule_2.2.17 -- name: "2.2.18 | Ensure mail transfer agent is configured for local-only mode" +- name: "2.2.18 | Ensure mail transfer agent is configured for local-only mode (Scored)" lineinfile: dest: /etc/postfix/main.cf regexp: "^(#)?inet_interfaces" @@ -301,7 +293,7 @@ - level1 - rule_2.2.18 -- name: "2.3.1 | Ensure NIS Client is not installed" +- name: "2.3.1 | Ensure NIS Client is not installed (Scored)" dnf: name: ypbind state: absent @@ -313,7 +305,7 @@ - level1 - rule_2.3.1 -- name: "2.3.2 | Ensure telnet client is not installed" +- name: "2.3.2 | Ensure telnet client is not installed (Scored)" dnf: name: telnet state: absent @@ -325,7 +317,7 @@ - level1 - rule_2.3.2 -- name: "2.3.3 | Ensure LDAP client is not installed" +- name: "2.3.3 | Ensure LDAP client is not installed (Scored)" dnf: name: openldap-clients state: absent diff --git a/tasks/section_3.yml b/tasks/section_3.yml new file mode 100644 index 0000000..7eaf57e --- /dev/null +++ b/tasks/section_3.yml @@ -0,0 +1,511 @@ +- name: "3.1.1 | Ensure IP forwarding is disabled (Scored)" + sysctl: + name: '{{ item.name }}' + value: '{{ item.value }}' + sysctl_set: yes + state: present + reload: yes + ignoreerrors: yes + with_items: + - { name: net.ipv4.ip_forward, value: 0 } + - { name: net.ipv6.ip_forward, value: 0 } + - { name: net.ipv4.conf.all.ip_forward, value: 0 } + - { name: net.ipv6.conf.all.ip_forward, value: 0 } + when: + - rule_3_1_1 + tags: + - level1 + - sysctl + - rule_3.1.1 + - section_3 + +- name: "3.1.2 | Ensure packet redirect sending is disabled (Scored)" + sysctl: + name: '{{ item.name }}' + value: '{{ item.value }}' + sysctl_set: yes + state: present + reload: yes + ignoreerrors: yes + with_items: + - { name: net.ipv4.conf.all.send_redirects, value: 0 } + - { name: net.ipv4.conf.default.send_redirects, value: 0 } + when: + - rule_3_1_2 + tags: + - level1 + - sysctl + - rule_3.1.2 + - section_3 + +- name: "3.2.1 | Ensure source routed packets are not accepted (Scored)" + sysctl: + name: '{{ item.name }}' + value: '{{ item.value }}' + sysctl_set: yes + state: present + reload: yes + ignoreerrors: yes + with_items: + - { name: net.ipv4.conf.all.accept_source_route, value: 0 } + - { name: net.ipv4.conf.default.accept_source_route, value: 0 } + - { name: net.ipv6.conf.all.accept_source_route, value: 0 } + - { name: net.ipv6.conf.default.accept_source_route, value: 0 } + when: + - rule_3_2_1 + tags: + - level1 + - sysctl + - rule_3.2.1 + - section_3 + +- name: "3.2.2 | Ensure ICMP redirects are not accepted (Scored)" + sysctl: + name: '{{ item.name }}' + value: '{{ item.value }}' + sysctl_set: yes + state: present + reload: yes + ignoreerrors: yes + with_items: + - { name: net.ipv4.conf.all.accept_redirects, value: 0 } + - { name: net.ipv4.conf.default.accept_redirects, value: 0 } + - { name: net.ipv6.conf.all.accept_redirects, value: 0 } + - { name: net.ipv6.conf.default.accept_redirects, value: 0 } + when: + - rule_3_2_2 + tags: + - level1 + - sysctl + - rule_3.2.2 + - section_3 + +- name: "3.2.3 | Ensure secure ICMP redirects are not accepted (Scored)" + sysctl: + name: '{{ item.name }}' + value: '{{ item.value }}' + sysctl_set: yes + state: present + reload: yes + ignoreerrors: yes + with_items: + - { name: net.ipv4.conf.all.secure_redirects, value: 0 } + - { name: net.ipv4.conf.default.secure_redirects, value: 0 } + when: + - rule_3_2_3 + tags: + - level1 + - sysctl + - rule_3.2.3 + - section_3 + +- name: "3.2.4 | Ensure suspicious packets are logged (Scored)" + sysctl: + name: '{{ item.name }}' + value: '{{ item.value }}' + sysctl_set: yes + state: present + reload: yes + ignoreerrors: yes + with_items: + - { name: net.ipv4.conf.all.log_martians, value: 1 } + - { name: net.ipv4.conf.default.log_martians, value: 1 } + when: + - rule_3_2_4 + tags: + - level1 + - sysctl + - rule_3.2.4 + - section_3 + +- name: "3.2.5 | Ensure broadcast ICMP requests are ignored (Scored)" + sysctl: + name: net.ipv4.icmp_echo_ignore_broadcasts + value: "1" + state: present + reload: yes + ignoreerrors: yes + when: + - rule_3_2_5 + tags: + - level1 + - sysctl + - rule_3.2.5 + - section_3 + +- name: "3.2.6 | Ensure bogus ICMP responses are ignored (Scored)" + sysctl: + name: net.ipv4.icmp_ignore_bogus_error_responses + value: "1" + state: present + reload: yes + ignoreerrors: yes + when: + - rule_3_2_6 + tags: + - level1 + - sysctl + - rule_3.2.6 + - section_3 + +- name: "3.2.7 | Ensure Reverse Path Filtering is enabled (Scored)" + sysctl: + name: '{{ item.name }}' + value: '{{ item.value }}' + sysctl_set: yes + state: present + reload: yes + ignoreerrors: yes + with_items: + - { name: net.ipv4.conf.all.rp_filter, value: 1 } + - { name: net.ipv4.conf.default.rp_filter, value: 1 } + when: + - rule_3_2_7 + tags: + - level1 + - sysctl + - rule_3.2.7 + - section_3 + +- name: "3.2.8 | Ensure TCP SYN Cookies is enabled (Scored)" + sysctl: + name: net.ipv4.tcp_syncookies + value: "1" + state: present + reload: yes + ignoreerrors: yes + when: + - rule_3_2_8 + tags: + - level1 + - sysctl + - rule_3.2.8 + - section_3 + +- name: "3.2.9 | Ensure IPv6 router advertisements are not accepted (Scored)" + sysctl: + name: '{{ item.name }}' + value: '{{ item.value }}' + sysctl_set: yes + state: present + reload: yes + ignoreerrors: yes + with_items: + - { name: net.ipv6.conf.all.accept_ra, value: 0 } + - { name: net.ipv6.conf.default.accept_ra, value: 0 } + when: + - rule_3_2_9 + tags: + - level1 + - sysctl + - rule_3.2.9 + - section_3 + +- name: "3.3.1 | Ensure DCCP is disabled (Scored)" + lineinfile: + dest: /etc/modprobe.d/CIS.conf + regexp: "^(#)?install dccp(\\s|$)" + line: "install dccp /bin/true" + create: yes + when: + - rule_3_3_1 + tags: + - level1 + - rule_3.3.1 + - section_3 + +- name: "3.3.2 | Ensure SCTP is disabled (Scored)" + lineinfile: + dest: /etc/modprobe.d/CIS.conf + regexp: "^(#)?install sctp(\\s|$)" + line: "install sctp /bin/true" + create: yes + when: + - rule_3_3_2 + tags: + - level1 + - rule_3.3.2 + - section_3 + +- name: "3.3.3 | Ensure RDS is disabled (Scored)" + lineinfile: + dest: /etc/modprobe.d/CIS.conf + regexp: "^(#)?install rds(\\s|$)" + line: "install rds /bin/true" + create: yes + when: + - rule_3_3_3 + tags: + - level1 + - rule_3.3.3 + - section_3 + +- name: "3.3.4 | Ensure TIPC is disabled (Scored)" + lineinfile: + dest: /etc/modprobe.d/CIS.conf + regexp: "^(#)?install tipc(\\s|$)" + line: "install tipc /bin/true" + create: yes + when: + - rule_3_3_4 + tags: + - level1 + - rule_3.3.4 + - section_3 + + +- name: "3.4.1.1 | Ensure a Firewall package is installed (Scored)" + dnf: + name: firewalld + state: present + when: + - rule_3_4_1_1 + tags: + - level1 + - rule_3.4.1.1 + - section_3 + +- name: "3.4.2.1 | Ensure firewalld service is enabled and running (Scored)" + systemd: + name: firewalld + state: started + enabled: yes + when: + - firewall == 'firewalld' + - rule_3_4_2_1 + tags: + - level1 + - rule_3.4.2.1 + - section_3 + +- name: "3.4.2.2 | Ensure iptables is not enabled (Scored)" + systemd: + name: iptables + enabled: no + masked: yes + when: + - packages['iptables-services'] is defined + - rule_3_4_2_2 + tags: + - level1 + - rule_3.4.2.2 + - section_3 + +- name: "3.4.2.3 | Ensure nftables is not enabled (Scored)" + systemd: + name: nftables + enabled: no + masked: yes + when: + - firewall == 'firewalld' + - rule_3_4_2_3 + tags: + - level1 + - rule_3.4.2.3 + - section_3 + +- name: "3.4.2.4 | Ensure default zone is set (Scored)" + block: + - name: "Get default Firewalld zone" + command: firewall-cmd --get-default-zone + register: firewalld_zone + + - name: "Set default Firewalld zone" + command: firewall-cmd --set-default-zone=public + when: + - firewalld_zone.stdout != "public" + when: + - firewall == 'firewalld' + - rule_3_4_2_4 + tags: + - level1 + - rule_3.4.2.4 + - section_3 + +- name: "3.4.2.5 | Ensure network interfaces are assigned to appropriate zone (Not Scored)" + command: /bin/true + when: + - firewall == 'firewalld' + - rule_3_4_2_5 + tags: + - level1 + - rule_3.4.2.5 + - section_3 + +- name: "3.4.2.6 | Ensure unnecessary services and ports are not accepted (Not Scored)" + command: /bin/true + when: + - firewall == 'firewalld' + - rule_3_4_2_6 + tags: + - level1 + - rule_3.4.2.6 + - section_3 + +- name: "3.4.3 | Configure nftables" + block: + - name: "3.4.3 | Configure nftables | Nftables Rules" + copy: + src: etc/nftables/nftables.rules + dest: /etc/nftables/nftables.rules + owner: root + group: root + mode: 0644 + + - name: "3.4.3 | Configure nftables | Load Nftables Rules" + command: nft -f /etc/nftables/nftables.rules + + - name: "3.4.3 | Configure nftables | Make Nftables Rules Permanent" + shell: nft list ruleset > /etc/nftables/nftables.rules + + - name: "3.4.3 | Configure nftables | Configure nftables.conf" + lineinfile: + dest: /etc/sysconfig/nftables.conf + regexp: ^(#)?include\s+"\/etc/nftables/nftables.rules\" + line: include "/etc/nftables/nftables.rules" + when: + - firewall == 'nftables' + - rule_3_4_3 + tags: + - level1 + - rule_3.4.3 + - section_3 + - notimplemented + +- name: "3.4.3.1 | Ensure iptables are flushed (Not Scored)" + iptables: + flush: yes + when: + - rule_3_4_3_1 + tags: + - level1 + - rule_3.4.3.1 + - section_3 + +- name: "3.4.3.2 | Ensure a table exists (Scored)" + command: /bin/true + changed_when: no + when: + - firewall == 'nftables' + - rule_3_4_3_2 + tags: + - level1 + - rule_3.4.3.2 + - section_3 + +- name: "3.4.3.3 | Ensure base chains exist (Scored)" + command: /bin/true + changed_when: no + when: + - firewall == 'nftables' + - rule_3_4_3_3 + tags: + - level1 + - rule_3.4.3.3 + - section_3 + +- name: "3.4.3.4 | Ensure loopback traffic is configured (Scored)" + command: /bin/true + changed_when: no + when: + - firewall == 'nftables' + - rule_3_4_3_4 + tags: + - level1 + - rule_3.4.3.4 + - section_3 + +- name: "3.4.3.5 | Ensure outbound and established connections are configured (Not Scored)" + command: /bin/true + changed_when: no + when: + - firewall == 'nftables' + - rule_3_4_3_5 + tags: + - level1 + - rule_3.4.3.5 + - section_3 + +- name: "3.4.3.6 | Ensure default deny firewall policy (Scored)" + command: /bin/true + changed_when: no + when: + - firewall == 'nftables' + - rule_3_4_3_6 + tags: + - level1 + - rule_3.4.3.6 + - section_3 + +- name: "3.4.3.7 | Ensure nftables service is enabled (Scored)" + systemd: + name: nftables + state: started + enabled: yes + when: + - firewall == 'nftables' + - rule_3_4_3_7 + tags: + - level1 + - rule_3.4.3.7 + - section_3 + +- name: "3.4.3.8 | Ensure nftables rules are permanent (Scored)" + command: /bin/true + changed_when: no + when: + - firewall == 'nftables' + - rule_3_4_3_8 + tags: + - level1 + - rule_3.4.3.8 + - section_3 + +- name: "3.5 | Ensure wireless interfaces are disabled (Scored)" + block: + - name: 3.5 Ensure wireless interfaces are disabled (Scored) | Get status + shell: | + set -o pipefail + nmcli radio all | awk '$1 !~ /WIFI/{ print $2}' + register: wireless_status + changed_when: false + + - name: 3.5 Ensure wireless interfaces are disabled (Scored) + command: nmcli radio all off + when: + - wireless_status.stdout == 'enabled' + when: + - rule_3_5 + tags: + - level1 + - rule_3.5 + - section_3 + - notimplemented + +- name: "3.6 | Disable IPv6 (Not Scored)" + block: + - name: "3.6 | Disable IPv6 (Not Scored) | Check config" + command: grep -E "GRUB_CMDLINE_LINUX=.*ipv6.disable=1.*" /etc/default/grub + register: grep_ipv6_grub + failed_when: false + changed_when: false + + - name: "3.6 | Disable IPv6 (Not Scored) | Update config" + lineinfile: + dest: /etc/default/grub + regexp: '^GRUB_CMDLINE_LINUX="(.*)"$' + line: 'GRUB_CMDLINE_LINUX="\1 ipv6.disable=1"' + state: present + owner: root + group: root + mode: 0644 + backrefs: true + notify: generate new grub config + when: + - grep_ipv6_grub.rc == 1 + when: + - rule_3_6 + tags: + - level2 + - rule_3.6 + - section_3 diff --git a/tasks/section_4.yml b/tasks/section_4.yml new file mode 100644 index 0000000..6606088 --- /dev/null +++ b/tasks/section_4.yml @@ -0,0 +1,551 @@ +- name: "4.1.1.1 | Ensure auditd is installed (Scored)" + yum: + name: + - "audit" + - "audit-libs" + state: present + when: + - rule_4_1_1_1 + tags: + - level1 + - level2 + - rule_4.1.1.1 + - section_4 + +- name: "4.1.1.2 | Ensure auditd service is enabled (Scored)" + systemd: + name: auditd + state: started + enabled: yes + when: + - rule_4_1_1_2 + tags: + - level2 + - auditd + - rule_4.1.1.2 + - section_4 + +- name: "4.1.1.3 | Ensure auditing for processes that start prior to auditd is enabled (Scored)" + replace: + dest: /etc/default/grub + regexp: '(^GRUB_CMDLINE_LINUX\s*\=\s*)(?:")(.+)(?/dev/null; done + register: priv_procs + changed_when: no + check_mode: no + when: + - rule_4_1_13 + tags: + - level2 + - auditd + - rule_4.1.13 + - section_4 + +- name: "4.1.13 | Ensure use of privileged commands is collected (Scored)" + template: + src: audit/rule_4_1_13.rules.j2 + dest: /etc/audit/rules.d/rule_4_1_13.rules + owner: root + group: root + mode: 0600 + notify: restart auditd + when: + - rule_4_1_13 + tags: + - level2 + - auditd + - rule_4.1.13 + - section_4 + +- name: "4.1.14 | Ensure file deletion events by users are collected (Scored)" + template: + src: audit/rule_4_1_14.rules.j2 + dest: /etc/audit/rules.d/rule_4_1_14.rules + owner: root + group: root + mode: 0600 + when: + - rule_4_1_14 + notify: restart auditd + tags: + - level2 + - auditd + - rule_4.1.14 + - section_4 + +- name: "4.1.15 | Ensure kernel module loading and unloading is collected (Scored)" + template: + src: audit/rule_4_1_15.rules.j2 + dest: /etc/audit/rules.d/rule_4_1_15.rules + owner: root + group: root + mode: 0600 + when: + - rule_4_1_15 + notify: restart auditd + tags: + - level2 + - auditd + - rule_4.1.15 + - section_4 + +- name: "4.1.16 | Ensure system administrator actions (sudolog) are collected (Scored)" + template: + src: audit/rule_4_1_16.rules.j2 + dest: /etc/audit/rules.d/rule_4_1_16.rules + owner: root + group: root + mode: 0600 + when: + - rule_4_1_16 + notify: restart auditd + tags: + - level2 + - auditd + - rule_4.1.16 + - section_4 + +- name: "4.1.17 | Ensure the audit configuration is immutable (Scored)" + template: + src: audit/rule_4_1_17.rules.j2 + dest: /etc/audit/rules.d/rule_4_1_17.rules + owner: root + group: root + mode: 0600 + when: + - rule_4_1_17 + notify: restart auditd + tags: + - level2 + - auditd + - rule_4.1.17 + - section_4 + + +- name: "4.2.1.1 | Ensure rsyslog is installed (Scored)" + dnf: + name: rsyslog + state: present + when: + - rule_4_2_1_1 + tags: + - level1 + - level2 + - rule_4.2.1.1 + - section_4 + +- name: "4.2.1.2 | Ensure rsyslog Service is enabled (Scored)" + systemd: + name: rsyslog + state: started + enabled: yes + when: + - rule_4_2_1_2 + tags: + - level1 + - level2 + - rule_4.2.1.2 + - section_4 + - notimplemented + +- name: "4.2.1.3 | Ensure rsyslog default file permissions configured (Scored)" + lineinfile: + dest: /etc/rsyslog.conf + regexp: '^\$FileCreateMode' + line: '$FileCreateMode 0640' + when: + - rule_4_2_1_3 + tags: + - level1 + - level2 + - rule_4.2.1.3 + - section_4 + +- name: "4.2.1.4 | Ensure logging is configured (Not Scored)" + command: /bin/true + changed_when: no + when: + - rule_4_2_1_4 + tags: + - level1 + - level2 + - rule_4.2.1.4 + - section_4 + +- name: "4.2.1.5 | Ensure rsyslog is configured to send logs to a remote log host (Scored)" + lineinfile: + dest: /etc/rsyslog.conf + insertbefore: '^$FileCreateMode 0640' + line: '*.* @{{ rsyslog_dest }}' + when: + - rule_4_2_1_5 + tags: + - level1 + - level2 + - rule_4.2.1.5 + - section_4 + +- name: "4.2.1.6 | Ensure remote rsyslog messages are only accepted on designated log hosts (Not Scored)" + command: /bin/true + changed_when: no + when: + - rule_4_2_1_6 + tags: + - level1 + - level2 + - rule_4.2.1.6 + - section_4 + - notimplemented + +- name: "4.2.2.1 | Ensure journald is configured to send logs to rsyslog (Scored)" + lineinfile: + dest: /etc/systemd/journald.conf + regexp: "^ForwardToSyslog" + line: "ForwardToSyslog=yes" + state: present + when: + - rule_4_2_2_1 + tags: + - level1 + - rule_4.2.2.1 + - section_4 + +- name: "4.2.2.2 | Ensure journald is configured to compress large log files (Scored)" + lineinfile: + dest: /etc/systemd/journald.conf + regexp: "^Compress" + line: "Compress=yes" + state: present + when: + - rule_4_2_2_2 + tags: + - level1 + - rule_4.2.2.2 + - section_4 + +- name: "4.2.2.3 | Ensure journald is configured to write logfiles to persistent disk (Scored)" + lineinfile: + dest: /etc/systemd/journald.conf + regexp: "^Storage" + line: "Storage=persistent" + state: present + when: + - rule_4_2_2_3 + tags: + - level1 + - rule_4.2.2.3 + - section_4 + +- name: "4.2.3 | Ensure permissions on all logfiles are configured (Scored)" + block: + - name: "4.2.3 | Ensure permissions on all logfiles are configured (Scored) | Get files" + command: find /var/log -type f -perm /037 + register: logfile_wrong_permissions + failed_when: false + changed_when: false + + - name: "4.2.3 | Ensure permissions on all logfiles are configured (Scored) | Get directories" + command: find /var/log -type d -perm /026 + register: logdir_wrong_permissions + failed_when: false + changed_when: false + + - name: "4.2.3 | Ensure permissions on all logfiles are configured (Scored) | Set files permissions" + file: + dest: "{{ item }}" + mode: 0640 + with_items: "{{ logfile_wrong_permissions.stdout_lines }}" + when: logfile_wrong_permissions.stdout_lines | length > 0 + + - name: "4.2.3 | Ensure permissions on all logfiles are configured (Scored) | Set directories permissions" + file: + dest: "{{ item }}" + state: directory + mode: 0750 + with_items: "{{ logdir_wrong_permissions.stdout_lines }}" + when: logdir_wrong_permissions.stdout_lines | length > 0 + when: + - rule_4_2_3 + tags: + - level1 + - level2 + - rule_4.2.3 + - section_4 + +- name: "4.3 | Ensure logrotate is configured (Not Scored)" + block: + - name: "4.3 | Ensure logrotate is configured (Not Scored)" + find: + paths: /etc/logrotate.d/ + register: log_rotates + + - name: "4.3 | Ensure logrotate is configured (Not Scored)" + replace: + path: "{{ item.path }}" + regexp: '^(\s*)(daily|weekly|monthly|yearly)$' + replace: "\\1{{ logrotate }}" + with_items: + - "{{ log_rotates.files }}" + - { path: "/etc/logrotate.conf" } + tags: + - level1 + - level2 + - rule_4.3 + - section_4 diff --git a/tasks/section_5.yml b/tasks/section_5.yml new file mode 100644 index 0000000..5e61cf0 --- /dev/null +++ b/tasks/section_5.yml @@ -0,0 +1,746 @@ +- name: "5.1.1 | Ensure cron daemon is enabled (Scored)" + systemd: + name: crond + enabled: yes + state: started + when: + - rule_5_1_1 + tags: + - level1 + - rule_5.1.1 + - section_5 + +- name: "5.1.2 | Ensure permissions on /etc/crontab are configured (Scored)" + file: + dest: /etc/crontab + owner: root + group: root + mode: 0600 + when: + - rule_5_1_2 + tags: + - level1 + - rule_5.1.2 + - section_5 + + +- name: "5.1.3 | Ensure permissions on /etc/cron.hourly are configured (Scored)" + file: + dest: /etc/cron.hourly + state: directory + owner: root + group: root + mode: 0700 + when: + - rule_5_1_3 + tags: + - level1 + - rule_5.1.3 + - section_5 + + +- name: "5.1.4 | Ensure permissions on /etc/cron.daily are configured (Scored)" + file: + dest: /etc/cron.daily + state: directory + owner: root + group: root + mode: 0700 + when: + - rule_5_1_4 + tags: + - level1 + - rule_5.1.4 + - section_5 + + +- name: "5.1.5 | Ensure permissions on /etc/cron.weekly are configured (Scored)" + file: + dest: /etc/cron.weekly + state: directory + owner: root + group: root + mode: 0700 + when: + - rule_5_1_5 + tags: + - level1 + - rule_5.1.5 + - section_5 + + +- name: "5.1.6 | Ensure permissions on /etc/cron.monthly are configured (Scored)" + file: + dest: /etc/cron.monthly + state: directory + owner: root + group: root + mode: 0700 + when: + - rule_5_1_6 + tags: + - level1 + - rule_5.1.6 + - section_5 + + +- name: "5.1.7 | Ensure permissions on /etc/cron.d are configured (Scored)" + file: + dest: /etc/cron.d + state: directory + owner: root + group: root + mode: 0700 + when: + - rule_5_1_7 + tags: + - level1 + - rule_5.1.7 + - section_5 + + +- name: "5.1.8 | Ensure at/cron is restricted to authorized users (Scored)" + block: + - name: "5.1.8 | Ensure at/cron is restricted to authorized users (Scored)" + file: + dest: /etc/at.deny + state: absent + + - name: "5.1.8 | Check if at.allow exists" + stat: + path: "/etc/at.allow" + register: at_allow + + - name: "5.1.8 | Ensure at/cron is restricted to authorized users (Scored)" + file: + dest: /etc/at.allow + state: '{{ "file" if at_allow.stat.exists else "touch"}}' + owner: root + group: root + mode: 0600 + + - name: "5.1.8 | Ensure at/cron is restricted to authorized users (Scored)" + file: + dest: /etc/cron.deny + state: absent + + - name: "5.1.8 | Check if cron.allow exists (Scored)" + stat: + path: "/etc/cron.allow" + register: cron_allow + + - name: "5.1.8 | Ensure at/cron is restricted to authorized users (Scored)" + file: + dest: /etc/cron.allow + state: '{{ "file" if cron_allow.stat.exists else "touch"}}' + owner: root + group: root + mode: 0600 + when: + - rule_5_1_8 + tags: + - level1 + - rule_5.1.8 + - section_5 + +- name: "5.2.1 | Ensure permissions on /etc/ssh/sshd_config are configured (Scored)" + file: + dest: /etc/ssh/sshd_config + state: file + owner: root + group: root + mode: 0600 + when: + - rule_5_2_1 + tags: + - level1 + - rule_5.2.1 + - section_5 + + +- name: "5.2.2 | Ensure SSH Access is limited (Scored)" + block: + - name: "5.2.2 | Ensure SSH access is limited (Scored) | AllowUsers" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: "^AllowUsers" + line: AllowUsers {{ sshd['allowusers'] }} + notify: + - restart sshd + when: + - "sshd['allowusers']|default('') != ''" + + - name: "5.2.2 | Ensure SSH access is limited (Scored) | AllowGroups" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: "^AllowGroups" + line: AllowGroups {{ sshd['allowgroups'] }} + notify: + - restart sshd + when: + - "sshd['allowgroups']|default('') != ''" + + - name: "5.2.2 | Ensure SSH access is limited (Scored) | DenyUsers" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: "^DenyUsers" + line: DenyUsers {{ sshd['denyusers'] }} + notify: + - restart sshd + when: + - "sshd['denyusers']|default('') != ''" + + - name: "5.2.2 | Ensure SSH access is limited (Scored) | DenyGroups" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: "^DenyGroups" + line: DenyGroups {{ sshd['denygroups'] }} + notify: + - restart sshd + when: + - "sshd['denygroups']|default('') != ''" + when: + - rule_5_2_2 + tags: + - level1 + - rule_5.2.2 + - section_5 + +- name: "5.2.3 | Ensure permissions on SSH private host key files are configured (Scored)" + block: + - name: "Find Private SSH Hostkeys" + command: find /etc/ssh -xdev -type f -name 'ssh_host_*_key' + register: privhostkey + + - name: "Set Permissions on Private SSH Hostkeys" + file: + dest: "{{ item }}" + owner: root + group: root + mode: 0600 + with_items: + - "{{ privhostkey.stdout_lines }}" + when: + - rule_5_2_3 + tags: + - level1 + - rule_5.2.3 + - section_5 + +- name: "5.2.4 | Ensure permissions on SSH public host key files are configured (Scored)" + block: + - name: "Find Public SSH Hostkeys" + command: find /etc/ssh -xdev -type f -name 'ssh_host_*_key.pub' + register: pubhostkey + + - name: "Set Permissions on Public SSH Hostkeys" + file: + dest: "{{ item }}" + owner: root + group: root + mode: 0644 + when: + - rule_5_2_4 + with_items: + - "{{ pubhostkey.stdout_lines }}" + tags: + - level1 + - rule_5.2.4 + - section_5 + +- name: "5.2.5 | Ensure SSH LogLevel is appropriate (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^LogLevel' + line: 'LogLevel INFO' + when: + - rule_5_2_5 + tags: + - level1 + - level2 + - rule_5.2.5 + - section_5 + +- name: "5.2.6 | Ensure SSH X11 forwarding is disabled (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^X11Forwarding' + line: 'X11Forwarding no' + when: + - rule_5_2_6 + tags: + - level1 + - level2 + - rule_5.2.6 + - section_5 + +- name: "5.2.7 | Ensure SSH MaxAuthTries is set to 4 or less (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^(#)?MaxAuthTries \d' + line: 'MaxAuthTries 4' + when: + - rule_5_2_7 + tags: + - level1 + - rule_5.2.7 + - section_5 + +- name: "5.2.8 | Ensure SSH IgnoreRhosts is enabled (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^IgnoreRhosts' + line: 'IgnoreRhosts yes' + when: + - rule_5_2_8 + tags: + - level1 + - level2 + - rule_5.2.8 + - section_5 + +- name: "5.2.9 | Ensure SSH HostbasedAuthentication is disabled (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^HostbasedAuthentication' + line: 'HostbasedAuthentication no' + when: + - rule_5_2_9 + tags: + - level1 + - rule_5.2.9 + - section_5 + +- name: "5.2.10 | Ensure SSH root login is disabled (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^PermitRootLogin' + line: 'PermitRootLogin no' + when: + - rule_5_2_10 + tags: + - level1 + - rule_5.2.10 + - section_5 + +- name: "5.2.11 | Ensure SSH PermitEmptyPasswords is disabled (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^PermitEmptyPasswords' + line: 'PermitEmptyPasswords no' + when: + - rule_5_2_11 + tags: + - level1 + - rule_5.2.11 + - section_5 + +- name: "5.2.12 | Ensure SSH PermitUserEnvironment is disabled (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^PermitUserEnvironment' + line: 'PermitUserEnvironment no' + when: + - rule_5_2_12 + tags: + - level1 + - rule_5.2.12 + - section_5 + +- name: "5.2.13 | Ensure SSH Idle Timeout Interval is configured (Scored)" + block: + - name: "5.2.13 | Ensure SSH Idle Timeout Interval is configured (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^ClientAliveInterval' + line: "ClientAliveInterval {{ sshd['clientaliveinterval'] }}" + + - name: "5.2.13 | Ensure SSH ClientAliveCountMax set to <= 3" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^ClientAliveCountMax' + line: "ClientAliveCountMax {{ sshd['clientalivecountmax'] }}" + when: + - rule_5_2_13 + tags: + - level1 + - rule_5.2.13 + - section_5 + +- name: "5.2.14 | Ensure SSH LoginGraceTime is set to one minute or less (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^LoginGraceTime' + line: "LoginGraceTime {{ sshd['logingracetime'] }}" + when: + - rule_5_2_14 + tags: + - level1 + - rule_5.2.14 + - section_5 + +- name: "5.2.15 | Ensure SSH warning banner is configured (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^Banner' + line: 'Banner /etc/issue.net' + when: + - rule_5_2_15 + tags: + - level1 + - rule_5.2.15 + - section_5 + +- name: "5.2.16 | Ensure SSH PAM is enabled (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^UsePAM yes' + line: 'UsePAM yes' + when: + - rule_5_2_16 + tags: + - level1 + - rule_5.2.16 + - section_5 + +- name: "5.2.17 | Ensure SSH AllowTcpForwarding is disabled (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^AllowTcpForwarding' + line: 'AllowTcpForwarding no' + when: + - rule_5_2_17 + tags: + - level2 + - rule_5.2.17 + - section_5 + +- name: "5.2.18 | Ensure SSH MaxStartups is configured (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^maxstartups' + line: 'maxstartups 10:30:60' + when: + - rule_5_2_18 + tags: + - level2 + - rule_5.2.18 + - section_5 + +- name: "5.2.19 | Ensure SSH MaxSessions is set to 4 or less (Scored)" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^maxsessions' + line: 'maxsessions 4' + when: + - rule_5_2_19 + tags: + - level2 + - rule_5.2.19 + - section_5 + +- name: "5.2.20 | Ensure system-wide crypto policy is not over-ridden (Scored)" + lineinfile: + dest: /etc/sysconfig/sshd + regexp: "^\\s*CRYPTO_POLICY\\s*=\\s*.*$" + state: absent + when: + - rule_5_2_20 + tags: + - level1 + - rule_5.2.20 + - section_5 + +- name: "5.3.1 | Create custom authselect profile (Scored)" + block: + - name: 5.3.1 Create custom authselect profile (Scored) | Check for profile + shell: authselect list | grep custom/{{ authselect_profile }} + register: authselect_list_profiles + changed_when: false + failed_when: false + + - name: 5.3.1 Create custom authselect profile (Scored) | Create profile + command: authselect create-profile {{ authselect_profile }} -b sssd --symlink-meta + when: + - authselect_list_profiles.rc != 0 + when: + - rule_5_3_1 + tags: + - level1 + - rule_5.3.1 + - section_5 + +- name: "5.3.2 | Select authselect profile (Scored)" + block: + - name: 5.3.2 Select authselect profile (Scored) | Get current profile + shell: "authselect current | grep \"Profile ID\" | sed 's@Profile ID: @@'" + register: authselect_current_profile + changed_when: false + failed_when: false + + - name: "5.3.2 Select authselect profile (Scored) | Set profile\n + 5.3.3 Ensure authselect includes with-faillock (Scored)" + command: authselect select custom/{{ authselect_profile }} without-nullok with-sudo with-mkhomedir {{ 5_3_3 | ternary("with-faillock", "") }} --force + when: + - authselect_current_profile.rc == 0 + - authselect_current_profile.stdout != "/".join(["custom", authselect_profile]) + when: + - rule_5_3_2 + - rule_5_3_3 + tags: + - level1 + - rule_5.3.2 + - rule_5.3.3 + - section_5 + + +- name: "5.4.1 | Ensure password creation requirements are configured (Scored)" + lineinfile: + state: present + dest: /etc/security/pwquality.conf + regexp: '^{{ item.key }}' + line: '{{ item.key }} = {{ item.value }}' + with_items: + - { key: 'minlen', value: "{{ pwquality['minlen'] }}" } + - { key: 'dcredit', value: "{{ pwquality['dcredit'] }}" } + - { key: 'ucredit', value: "{{ pwquality['ucredit'] }}" } + - { key: 'ocredit', value: "{{ pwquality['ocredit'] }}" } + - { key: 'lcredit', value: "{{ pwquality['lcredit'] }}" } + when: + - rule_5_4_1 + tags: + - level1 + - rule_5.4.1 + - section_5 + +- name: "5.4.2 | Ensure lockout for failed password attempts is configured (Scored)\n + 5.4.3 | Ensure password reuse is limited (Scored)\n + 5.4.4 | Ensure password hashing algorithm is SHA-512 (Scored)" + template: + src: etc/pam/template_authselect.j2 + dest: /etc/authselect/custom/{{ authselect_profile }}/{{ item }} + with_items: + - password-auth + - system-auth + notify: authselect apply changes + when: + - rule_5_3_2 + - rule_5_3_3 + - rule_5_4_2 + - rule_5_4_3 + - rule_5_4_4 + tags: + - level1 + - rule_5.4 + - rule_5.4.2 + - rule_5.4.3 + - section_5 + +- name: "5.5.1.1 | Ensure password expiration is 365 days or less (Scored)" + lineinfile: + dest: /etc/login.defs + regexp: "^\\s*PASS_MAX_DAYS\\s*.*$" + line: "PASS_MAX_DAYS {{ password_policy['max_days'] }}" + state: present + when: + - rule_5_5_1_1 + tags: + - level1 + - rule_5.5.1.1 + - section_5 + +- name: "5.5.1.2 | Ensure minimum days between password changes is 7 or more (Scored)" + block: + - name: "5.5.1.2 | Ensure minimum days between password changes is 7 or more (Scored)" + lineinfile: + dest: /etc/login.defs + regexp: "^\\s*PASS_MIN_DAYS\\s*.*$" + line: "PASS_MIN_DAYS {{ password_policy['min_days'] }}" + state: present + + - name: "5.5.1.2 | Ensure minimum days between password changes is 7 or more (Scored)" + command: "awk -F: '{if($4 != {{ password_policy['min_days'] }}) print $1}' /etc/shadow" + register: users_min_output + + - name: "5.5.1.2 | Ensure minimum days between password changes is 7 or more (Scored)" + command: "chage --mindays {{ password_policy['min_days'] }} {{ item }}" + with_items: "{{ users_min_output.stdout_lines }}" + tags: + - level1 + - rule_5.5.1 + - rule_5.5.1.2 + - section_5 + +- name: "5.5.1.3 | Ensure password expiration warning days is 7 or more (Scored)" + block: + - name: "5.5.1.3 | Ensure password expiration warning days is 7 or more (Scored)" + lineinfile: + dest: /etc/login.defs + regexp: "^\\s*PASS_WARN_AGE\\s*.*$" + line: "PASS_WARN_AGE {{ password_policy['warn_age'] }}" + state: present + + - name: "5.5.1.3 | Ensure password expiration warning days is 7 or more (Scored)" + command: "awk -F: '{if($6 != {{ password_policy['warn_age'] }}) print $1}' /etc/shadow" + register: users_warn_output + + - name: "5.5.1.3 | Ensure password expiration warning days is 7 or more (Scored)" + command: "chage --warndays {{ password_policy['warn_age'] }} {{ item }}" + with_items: "{{ users_warn_output.stdout_lines }}" + when: + - rule_5_5_1_3 + tags: + - level1 + - rule_5.5.1.3 + - section_5 + +- name: "5.5.1.4 | Ensure inactive password lock is 30 days or less (Scored)" + lineinfile: + dest: /etc/default/useradd + regexp: "^\\s*INACTIVE\\s*=\\s*.*$" + line: "INACTIVE={{ user_account_policy['inactive_days'] }}" + state: present + when: + - rule_5_5_1_4 + tags: + - level1 + - rule_5.5.1 + - rule_5.5.1.4 + - section_5 + +- name: "5.5.1.5 | Ensure all users last password change date is in the past (Scored)" + command: /bin/true + changed_when: no + when: + - rule_5_5_1_5 + tags: + - level1 + - rule_5_5_1_5 + - section_5 + - notimplemented + +- name: "5.5.2 | Ensure system accounts are secured (Scored)" + block: + - name: 5.5.2 Ensure system accounts are secured (Scored) | Get users + shell: "awk -F: '($3 < {{ min_uid }}) {print $1 }' /etc/passwd" + changed_when: false + check_mode: false + register: system_account + + - name: 5.5.2 Ensure system accounts are secured (Scored) | Lock users + user: + name: "{{ item }}" + password_lock: true + with_items: + - "{{ system_account.stdout_lines }}" + when: + - item != "root" + + - name: 5.5.2 Ensure system accounts are secured (Scored) | Set shell to nologin + user: + name: "{{ item }}" + shell: /sbin/nologin + with_items: + - "{{ system_account.stdout_lines }}" + when: + - item != "root" + - item != "sync" + - item != "shutdown" + - item != "halt" + when: + - rule_5_5_2 + tags: + - level1 + - rule_5.5.2 + - section_5 + - notimplemented + +- name: "5.5.3 | Ensure default user shell timeout is 900 seconds or less (Scored)" + lineinfile: + state: present + dest: "{{ item }}" + create: true + regexp: '^TMOUT=' + line: "TMOUT={{ shell_timeout }} ; export TMOUT" + with_items: + - /etc/bashrc + - /etc/profile + when: + - rule_5_5_4 + tags: + - level1 + - rule_5.5.4 + - section_5 + +- name: "5.5.4 | Ensure default group for the root account is GID 0 (Scored)" + user: + name: root + group: "0" + when: + - rule_5_5_4 + tags: + - level1 + - rule_5.5.4 + - section_5 + - notimplemented + +- name: "5.5.5 | Ensure default user umask is 027 or more restrictive (Scored)" + replace: + dest: "{{ item }}" + regexp: '^(\s*umask\s+)\d+$' + replace: '\g<1>{{ umask }}' + with_items: + - /etc/bashrc + - /etc/profile + when: + - rule_5_5_5 + tags: + - level1 + - rule_5.5.5 + - section_5 + +- name: "5.6 | Ensure root login is restricted to system console (Not Scored)" + command: /bin/true + changed_when: no + tags: + - level1 + - rule_5.6 + - section_5 + +- name: "5.7 | Ensure access to the su command is restricted (Scored)" + block: + - name: 5.7 Ensure access to the su command is restricted (Scored) | Config PAM + lineinfile: + state: present + dest: /etc/pam.d/su + regexp: '^(#)?auth\s+required\s+pam_wheel\.so' + line: 'auth required pam_wheel.so use_uid' + + - name: 5.7 Ensure access to the su command is restricted (Scored) | Add root to Wheel Group + user: + name: root + groups: wheel + tags: + - level1 + - rule_5.7 + - section_5 diff --git a/tasks/section_6.yml b/tasks/section_6.yml new file mode 100644 index 0000000..1cbe935 --- /dev/null +++ b/tasks/section_6.yml @@ -0,0 +1,521 @@ +--- + +- name: "Get users accounts" + command: "awk -F: '{print $1}' /etc/passwd" + register: users + changed_when: false + tags: + - notscored + - level2 + - section_6 + + +- name: "6.1.1 | Audit system file permissions (Not Scored)" + cron: + name: CIS 6.1.1 Audit system file permissions + weekday: "*" + minute: "0" + hour: "3" + user: root + job: "rpm -Va --nomtime --nosize --nomd5 --nolinkto > {{ audit_rpms_permissions_output }}" + when: + - rule_6_1_1 + tags: + - notscored + - level2 + - section_6 + +- name: "6.1.2 | Ensure permissions on /etc/passwd are configured (Scored)" + file: + dest: /etc/passwd + owner: root + group: root + mode: 0644 + when: + - rule_6_1_2 + tags: + - scored + - level1 + - section_6 + +- name: "6.1.3 | Ensure permissions on /etc/shadow are configured (Scored)" + file: + dest: /etc/shadow + owner: root + group: root + mode: 0640 + when: + - rule_6_1_3 + tags: + - scored + - level1 + - section_6 + +- name: "6.1.4 | Ensure permissions on /etc/group are configured (Scored)" + file: + dest: /etc/group + owner: root + group: root + mode: 0644 + when: + - rule_6_1_4 + tags: + - scored + - level1 + - section_6 + +- name: "6.1.5 | Ensure permissions on /etc/gshadow are configured (Scored)" + file: + dest: /etc/gshadow + owner: root + group: root + mode: 0640 + when: + - rule_6_1_5 + tags: + - scored + - level1 + - section_6 + +- name: "6.1.6 | Ensure permissions on /etc/passwd- are configured (Scored)" + file: + dest: /etc/passwd- + owner: root + group: root + mode: 0600 + when: + - rule_6_1_6 + tags: + - scored + - level1 + - section_6 + +- name: "6.1.7 | Ensure permissions on /etc/shadow- are configured (Scored)" + file: + dest: /etc/shadow- + owner: root + group: root + mode: 0600 + when: + - rule_6_1_7 + tags: + - scored + - level1 + - section_6 + +- name: "6.1.8 | Ensure permissions on /etc/group- are configured (Scored)" + file: + dest: /etc/group- + owner: root + group: root + mode: 0644 + when: + - rule_6_1_8 + tags: + - scored + - level1 + - section_6 + +- name: "6.1.9 | Ensure permissions on /etc/gshadow- are configured (Scored)" + file: + dest: /etc/gshadow- + owner: root + group: root + mode: 0640 + when: + - rule_6_1_9 + tags: + - scored + - level1 + - section_6 + +- name: "6.1.10 | Ensure no world writable files exist (Scored)" + block: + - name: "6.1.10 Ensure no world writable files exist (Scored) | Get files" + shell: | + set -o pipefail + df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -0002 + args: + executable: /bin/bash + register: world_writable_files + changed_when: false + failed_when: false + + - name: "6.1.10 | Ensure no world writable files exist (Scored) | Set permission" + command: "chmod o-x '{{ item }}'" + args: + warn: false + when: + - world_writable_files.stdout_lines | length > 0 + with_items: + - "{{ world_writable_files.stdout_lines }}" + when: + - rule_6_1_10 + tags: + - scored + - level1 + - section_6 + +- name: "6.1.11 | Ensure no unowned files or directories exist (Scored)" + block: + - name: "6.1.11 | Ensure no unowned files or directories exist (Scored) | Get files" + shell: | + set -o pipefail + df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -nouser + args: + executable: /bin/bash + changed_when: false + failed_when: false + register: unowned_files + + - name: "6.1.11 | Ensure no unowned files or directories exist (Scored) | Set permission" + file: + path: "{{ item }}" + owner: "{{ rule_user_unowned_file }}" + when: + - unowned_files.stdout_lines | length > 0 + with_items: "{{ unowned_files.stdout_lines }}" + when: + - rule_6_1_11 + tags: + - scored + - level1 + - section_6 + +- name: "6.1.12 | Ensure no ungrouped files or directories exist (Scored)" + block: + - name: "6.1.12 | Ensure no ungrouped files or directories exist (Scored) | Get files" + shell: | + set -o pipefail + df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -nogroup + args: + executable: /bin/bash + changed_when: false + failed_when: false + register: ungrouped_files + + - name: "6.1.12 | Ensure no ungrouped files or directories exist (Scored) | Set permission" + file: + path: "{{ item }}" + group: "{{ rule_group_ungrouped_file }}" + with_items: "{{ ungrouped_files.stdout_lines }}" + when: + - ungrouped_files.stdout_lines | length > 0 + when: + - rule_6_1_12 + tags: + - scored + - level1 + - section_6 + +- name: "6.1.13 | Audit SUID executables (Not Scored)" + shell: | + set -o pipefail + df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -4000 + args: + executable: /bin/bash + when: + - rule_6_1_13 + changed_when: false + failed_when: false + register: suid_files + tags: + - notscored + - level1 + - section_6 + +- name: "6.1.14 | Audit SGID executables (Not Scored)" + shell: | + set -o pipefail + df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -2000 + args: + executable: /bin/bash + when: + - rule_6_1_14 + changed_when: false + failed_when: false + register: sgid_files + tags: + - notscored + - level1 + - section_6 + +- name: "6.2.1 | Ensure password fields are not empty (Scored) | Get users" + shell: | + set -o pipefail + getent shadow | grep -Po '^[^:]*(?=::)' + register: users_without_password + failed_when: false + changed_when: false + tags: + - scored + - level1 + - section_6 + +- name: "6.2.1 | Ensure password fields are not empty (Scored) | Set password" + user: + name: "{{ item }}" + password_lock: true + with_items: "{{ users_without_password.stdout_lines }}" + when: + - rule_6_2_1 + - users_without_password.stdout_lines | length > 0 + tags: + - scored + - level1 + - section_6 + +- name: "6.2.2 | Ensure no legacy '+' entries exist in /etc/passwd (Scored)" + lineinfile: + dest: /etc/passwd + regexp: '^\+.*' + state: absent + when: + - rule_6_2_2 + tags: + - scored + - level1 + - section_6 + +- name: "6.2.3 | Ensure root PATH Integrity (Scored)" + command: /bin/true + changed_when: false + when: + - rule_6_2_3 + tags: + - scored + - level1 + - section_6 + - notimplmented + +- name: "6.2.4 | Ensure no legacy '+' entries exist in /etc/shadow (Scored)" + lineinfile: + dest: /etc/shadow + regexp: '^\+.*' + state: absent + when: + - rule_6_2_4 + tags: + - scored + - level1 + - section_6 + +- name: "6.2.5 | Ensure no legacy '+'' entries exist in /etc/group (Scored)" + lineinfile: + dest: /etc/group + regexp: '^\+.*' + state: absent + when: + - rule_6_2_5 + tags: + - scored + - level1 + - section_6 + +- name: "6.2.6 | Ensure root is the only UID 0 account (Scored)" + block: + - name: "6.2.6 | Ensure root is the only UID 0 account (Scored) | Get users" + shell: | + set -o pipefail + awk -F':' '($3 == 0) { print $1 }' /etc/passwd + register: users_uid_zero + changed_when: false + failed_when: false + + - name: "6.2.6 | Ensure root is the only UID 0 account (Scored) | Lock users" + user: + name: "{{ item }}" + password_lock: true + with_items: "{{ users_uid_zero.stdout_lines }}" + when: + - item != 'root' + when: + - rule_6_2_6 + tags: + - scored + - level1 + - section_6 + +- name: "6.2.7 | Ensure users' home directories permissions are 750 or more restrictive (Scored)" + command: /bin/true + changed_when: false + when: + - rule_6_2_7 + tags: + - scored + - level1 + - section_6 + - notimplemented + +- name: "6.2.8 | Ensure users own their home directories (Scored)" + command: /bin/true + changed_when: false + when: + - rule_6_2_8 + tags: + - scored + - level1 + - section_6 + - notimplemented + +- name: "6.2.9 | Ensure users' dot files are not group or world writable (Scored)" + command: /bin/true + changed_when: false + when: + - rule_6_2_9 + tags: + - scored + - level1 + - section_6 + - notimplemented + +- name: "6.2.10 | Ensure no users have .forward files (Scored)" + file: + state: absent + dest: "~{{ item }}/.forward" + with_items: "{{ users }}" + when: + - rule_6_2_10 + tags: + - level1 + - scored + - section_6 + +- name: "6.2.11 | Ensure no users have .netrc files (Scored)" + file: + state: absent + dest: "~{{ item }}/.netrc" + with_items: "{{ users }}" + when: + - rule_6_2_11 + tags: + - scored + - level1 + - section_6 + +- name: "6.2.12 | Ensure users' .netrc Files are not group or world accessible (Scored)" + command: /bin/true + changed_when: false + when: + - rule_6_2_12 + tags: + - scored + - level1 + - section_6 + - notimplemented + +- name: "6.2.13 | Ensure no users have .rhosts files (Scored)" + file: + state: absent + dest: "~{{ item }}/.rhosts" + with_items: "{{ users }}" + when: + - rule_6_2_13 + tags: + - scored + - level1 + - section_6 + +- name: "6.2.14 | Ensure all groups in /etc/passwd exist in /etc/group (Scored)" + command: /bin/true + changed_when: false + when: + - rule_6_2_14 + tags: + - scored + - level1 + - section_6 + - notimplemented + +- name: "6.2.15 | Ensure no duplicate UIDs exist (Scored)" + block: + - name: Get UIDs + command: "awk -F: '{print $3}' /etc/passwd" + register: uids + changed_when: false + + - name: "6.2.15 | Ensure no duplicate UIDs exist (Scored)" + shell: grep -cE "^[A-Za-z0-9_-]+:[A-Za-z0-9_-]+:{{ item }}:" /etc/passwd + register: grep_uid + changed_when: "grep_uid.stdout != '1'" + with_items: "{{ uids.stdout_lines }}" + when: + - rule_6_2_15 + tags: + - scored + - level1 + - section_6 + +- name: "6.2.16 | Ensure no duplicate GIDs exist (Scored)" + block: + - name: "6.2.16 | Ensure no duplicate GIDs exist (Scored) | Get GIDs" + command: "awk -F: '{print $3}' /etc/group" + register: gids + changed_when: false + + - name: "6.2.16 | Ensure no duplicate GIDs exist (Scored)" + shell: grep -cE "^[A-Za-z0-9_-]+:x:{{ item }}:" /etc/group + register: grep_gid + changed_when: "grep_gid.stdout != '1'" + with_items: "{{ gids.stdout_lines }}" + when: + - rule_6_2_16 + tags: + - scored + - level1 + - section_6 + +- name: "6.2.17 | Ensure no duplicate user names exist (Scored)" + command: grep -cE "^{{ item }}:" /etc/passwd + register: grep_user_name + changed_when: "grep_user_name.stdout != '1'" + with_items: "{{ users.stdout_lines }}" + when: + - rule_6_2_17 + tags: + - scored + - level1 + - section_6 + - notimplmented + +- name: "6.2.18 | Ensure no duplicate group names exist (Scored)" + block: + - name: "6.2.18 | Ensure no duplicate group names exist (Scored) | Get groups" + command: "awk -F: '{print $1}' /etc/group" + register: group_names + changed_when: false + + - name: "6.2.18 | Ensure no duplicate group names exist (Scored)" + command: grep -cE "^{{ item }}:" /etc/group + register: grep_group_name + changed_when: "grep_group_name.stdout != '1'" + with_items: "{{ group_names.stdout_lines }}" + when: + - rule_6_2_18 + tags: + - scored + - level1 + - section_6 + - rule_6.2.18 + +- name: "6.2.19 | Ensure shadow group is empty (Scored)" + command: /bin/true + changed_when: false + when: + - rule_6_2_19 + tags: + - scored + - level1 + - section_6 + - notimplmented + +- name: "6.2.20 | Ensure all users' home directories exist (Scored)" + command: /bin/true + changed_when: false + when: + - rule_6_2_20 + tags: + - scored + - level1 + - section_6 + - notimplmented \ No newline at end of file diff --git a/templates/audit/rule_4_1_10.rules.j2 b/templates/audit/rule_4_1_10.rules.j2 new file mode 100644 index 0000000..1a86703 --- /dev/null +++ b/templates/audit/rule_4_1_10.rules.j2 @@ -0,0 +1,4 @@ +-a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access +-a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access +-a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=4294967295 -k access +-a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=4294967295 -k access diff --git a/templates/audit/rule_4_1_11.rules.j2 b/templates/audit/rule_4_1_11.rules.j2 new file mode 100644 index 0000000..358f999 --- /dev/null +++ b/templates/audit/rule_4_1_11.rules.j2 @@ -0,0 +1,5 @@ +-w /etc/group -p wa -k identity +-w /etc/passwd -p wa -k identity +-w /etc/gshadow -p wa -k identity +-w /etc/shadow -p wa -k identity +-w /etc/security/opasswd -p wa -k identity diff --git a/templates/audit/rule_4_1_12.rules.j2 b/templates/audit/rule_4_1_12.rules.j2 new file mode 100644 index 0000000..c70add1 --- /dev/null +++ b/templates/audit/rule_4_1_12.rules.j2 @@ -0,0 +1,2 @@ +-a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=4294967295 -k mounts +-a always,exit -F arch=b32 -S mount -F auid>=1000 -F auid!=4294967295 -k mounts diff --git a/templates/audit/rule_4_1_13.rules.j2 b/templates/audit/rule_4_1_13.rules.j2 new file mode 100644 index 0000000..a005b3c --- /dev/null +++ b/templates/audit/rule_4_1_13.rules.j2 @@ -0,0 +1,3 @@ +{% for proc in priv_procs.stdout_lines -%} +-a always,exit -F path={{ proc }} -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged +{% endfor %} diff --git a/templates/audit/rule_4_1_14.rules.j2 b/templates/audit/rule_4_1_14.rules.j2 new file mode 100644 index 0000000..39fedff --- /dev/null +++ b/templates/audit/rule_4_1_14.rules.j2 @@ -0,0 +1,2 @@ +-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete +-a always,exit -F arch=b32 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete diff --git a/templates/audit/rule_4_1_15.rules.j2 b/templates/audit/rule_4_1_15.rules.j2 new file mode 100644 index 0000000..5fae54e --- /dev/null +++ b/templates/audit/rule_4_1_15.rules.j2 @@ -0,0 +1,4 @@ +-w /sbin/insmod -p x -k modules +-w /sbin/rmmod -p x -k modules +-w /sbin/modprobe -p x -k modules +-a always,exit -F arch=b64 -S init_module -S delete_module -k modules diff --git a/templates/audit/rule_4_1_16.rules.j2 b/templates/audit/rule_4_1_16.rules.j2 new file mode 100644 index 0000000..e5d31c7 --- /dev/null +++ b/templates/audit/rule_4_1_16.rules.j2 @@ -0,0 +1,2 @@ +-w /var/log/sudo.log -p wa -k actions + diff --git a/templates/audit/rule_4_1_17.rules.j2 b/templates/audit/rule_4_1_17.rules.j2 new file mode 100644 index 0000000..bc95eba --- /dev/null +++ b/templates/audit/rule_4_1_17.rules.j2 @@ -0,0 +1 @@ +-e 2 diff --git a/templates/audit/rule_4_1_3.rules.j2 b/templates/audit/rule_4_1_3.rules.j2 new file mode 100644 index 0000000..0ae21fd --- /dev/null +++ b/templates/audit/rule_4_1_3.rules.j2 @@ -0,0 +1,2 @@ +-w /etc/sudoers -p wa -k scope +-w /etc/sudoers.d/ -p wa -k scope diff --git a/templates/audit/rule_4_1_4.rules.j2 b/templates/audit/rule_4_1_4.rules.j2 new file mode 100644 index 0000000..dda9d98 --- /dev/null +++ b/templates/audit/rule_4_1_4.rules.j2 @@ -0,0 +1,2 @@ +-w /var/log/faillog -p wa -k logins +-w /var/log/lastlog -p wa -k logins diff --git a/templates/audit/rule_4_1_5.rules.j2 b/templates/audit/rule_4_1_5.rules.j2 new file mode 100644 index 0000000..51d7254 --- /dev/null +++ b/templates/audit/rule_4_1_5.rules.j2 @@ -0,0 +1,3 @@ +-w /var/run/utmp -p wa -k session +-w /var/log/wtmp -p wa -k logins +-w /var/log/btmp -p wa -k logins diff --git a/templates/audit/rule_4_1_6.rules.j2 b/templates/audit/rule_4_1_6.rules.j2 new file mode 100644 index 0000000..7f79962 --- /dev/null +++ b/templates/audit/rule_4_1_6.rules.j2 @@ -0,0 +1,5 @@ +-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change +-a always,exit -F arch=b32 -S adjtimex -S settimeofday -S stime -k time-change +-a always,exit -F arch=b64 -S clock_settime -k time-change +-a always,exit -F arch=b32 -S clock_settime -k time-change +-w /etc/localtime -p wa -k time-change diff --git a/templates/audit/rule_4_1_7.rules.j2 b/templates/audit/rule_4_1_7.rules.j2 new file mode 100644 index 0000000..640c21a --- /dev/null +++ b/templates/audit/rule_4_1_7.rules.j2 @@ -0,0 +1,2 @@ +-w /etc/selinux/ -p wa -k MAC-policy +-w /usr/share/selinux/ -p wa -k MAC-policy diff --git a/templates/audit/rule_4_1_8.rules.j2 b/templates/audit/rule_4_1_8.rules.j2 new file mode 100644 index 0000000..63d590e --- /dev/null +++ b/templates/audit/rule_4_1_8.rules.j2 @@ -0,0 +1,6 @@ +-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale +-a always,exit -F arch=b32 -S sethostname -S setdomainname -k system-locale +-w /etc/issue -p wa -k system-locale +-w /etc/issue.net -p wa -k system-locale +-w /etc/hosts -p wa -k system-locale +-w /etc/sysconfig/network -p wa -k system-locale diff --git a/templates/audit/rule_4_1_9.rules.j2 b/templates/audit/rule_4_1_9.rules.j2 new file mode 100644 index 0000000..2bab6dd --- /dev/null +++ b/templates/audit/rule_4_1_9.rules.j2 @@ -0,0 +1,6 @@ +-a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod +-a always,exit -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod +-a always,exit -F arch=b64 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=4294967295 -k perm_mod +-a always,exit -F arch=b32 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=4294967295 -k perm_mod +-a always,exit -F arch=b64 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=1000 -F auid!=4294967295 -k perm_mod +-a always,exit -F arch=b32 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=1000 -F auid!=4294967295 -k perm_mod diff --git a/templates/etc/pam/template_authselect.j2 b/templates/etc/pam/template_authselect.j2 new file mode 100644 index 0000000..7dee8d1 --- /dev/null +++ b/templates/etc/pam/template_authselect.j2 @@ -0,0 +1,34 @@ +auth required pam_env.so +auth required pam_faildelay.so delay=2000000 +auth required pam_deny.so # Smartcard authentication is required {include if "with-smartcard-required"} +auth required pam_faillock.so preauth silent deny={{ pam_failllock_deny }} unlock_time={{ pam_failllock_timeout }} {include if "with-faillock"} +auth sufficient pam_u2f.so cue {include if "with-pam-u2f"} +auth required pam_u2f.so cue nouserok {include if "with-pam-u2f-2fa"} +auth [default=1 ignore=ignore success=ok] pam_succeed_if.so uid >= 1000 quiet +auth [default=1 ignore=ignore success=ok] pam_localuser.so +auth sufficient pam_unix.so {if not "without-nullok":nullok} try_first_pass +auth requisite pam_succeed_if.so uid >= 1000 quiet_success +auth sufficient pam_sss.so forward_pass +auth required pam_faillock.so authfail deny={{ pam_failllock_deny }} unlock_time={{ pam_failllock_timeout }} {include if "with-faillock"} +auth required pam_deny.so + +account required pam_access.so {include if "with-pamaccess"} +account required pam_faillock.so {include if "with-faillock"} +account required pam_unix.so +account sufficient pam_localuser.so +account sufficient pam_succeed_if.so uid < 1000 quiet +account [default=bad success=ok user_unknown=ignore] pam_sss.so +account required pam_permit.so + +password requisite pam_pwquality.so try_first_pass local_users_only enforce_for_root retry={{ pam_failllock_deny }} remember={{ password_policy['history'] }} +password sufficient pam_unix.so sha512 shadow {if not "without-nullok":nullok} try_first_pass use_authtok remember={{ password_policy['history'] }} +password sufficient pam_sss.so use_authtok +password required pam_deny.so + +session optional pam_keyinit.so revoke +session required pam_limits.so +-session optional pam_systemd.so +session optional pam_oddjob_mkhomedir.so umask=0077 {include if "with-mkhomedir"} +session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid +session required pam_unix.so +session optional pam_sss.so