CIS role split and permission safety

This commit is contained in:
2025-12-27 22:27:26 +01:00
parent f62dba3ed6
commit dda1287f23
9 changed files with 261 additions and 249 deletions

15
roles/cis/tasks/auth.yml Normal file
View File

@@ -0,0 +1,15 @@
---
- name: Ensure the Default UMASK is Set Correctly
ansible.builtin.lineinfile:
path: "/mnt/etc/profile"
regexp: "^(\\s*)umask\\s+\\d+"
line: "umask 027"
- name: Prevent Login to Accounts With Empty Password
ansible.builtin.replace:
dest: "{{ item }}"
regexp: "\\s*nullok"
replace: ""
loop:
- /mnt/etc/pam.d/system-auth
- /mnt/etc/pam.d/password-auth

View File

@@ -0,0 +1,12 @@
---
- name: Configure System Cryptography Policy
when: os in ["almalinux", "rhel9", "rhel10", "rocky"]
ansible.builtin.command: arch-chroot /mnt /usr/bin/update-crypto-policies --set DEFAULT:NO-SHA1
register: cis_crypto_policy_result
changed_when: "'Setting system-wide crypto-policies to' in cis_crypto_policy_result.stdout"
- name: Mask Systemd Services
ansible.builtin.command: >
arch-chroot /mnt systemctl mask nftables bluetooth rpcbind
register: cis_mask_services_result
changed_when: cis_mask_services_result.rc == 0

19
roles/cis/tasks/files.yml Normal file
View File

@@ -0,0 +1,19 @@
---
- name: Ensure files exist
ansible.builtin.file:
path: "{{ item }}"
state: touch
mode: "0600"
loop:
- /mnt/etc/at.allow
- /mnt/etc/cron.allow
- /mnt/etc/hosts.allow
- /mnt/etc/hosts.deny
- name: Ensure files do not exist
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- /mnt/etc/at.deny
- /mnt/etc/cron.deny

View File

@@ -1,250 +1,14 @@
---
- name: Configurationg System for CIS conformity
block:
- name: Disable Kernel Modules
ansible.builtin.copy:
dest: /mnt/etc/modprobe.d/cis.conf
mode: "0644"
content: |
CIS LVL 3 Restrictions
install freevxfs /bin/false
install jffs2 /bin/false
install hfs /bin/false
install hfsplus /bin/false
install cramfs /bin/false
install squashfs /bin/false
install udf /bin/false
install usb-storage /bin/false
install dccp /bin/false
install sctp /bin/false
install rds /bin/false
install tipc /bin/false
- name: Create USB Rules
ansible.builtin.copy:
dest: /mnt/etc/udev/rules.d/10-cis_usb_devices.sh
mode: "0644"
content: |
By default, disable all.
ACTION=="add", SUBSYSTEMS=="usb", TEST=="authorized_default", ATTR{authorized_default}="0"
Enable hub devices.
ACTION=="add", ATTR{bDeviceClass}=="09", TEST=="authorized", ATTR{authorized}="1"
Enables keyboard devices
ACTION=="add", ATTR{product}=="*[Kk]eyboard*", TEST=="authorized", ATTR{authorized}="1"
PS2-USB converter
ACTION=="add", ATTR{product}=="*Thinnet TM*", TEST=="authorized", ATTR{authorized}="1"
- name: Create a consolidated sysctl configuration file
ansible.builtin.copy:
dest: /mnt/etc/sysctl.d/10-cis.conf
mode: "0644"
content: |
## CIS Sysctl configurations
kernel.yama.ptrace_scope=1
kernel.randomize_va_space=2
# Network
net.ipv4.ip_forward=0
net.ipv4.tcp_syncookies=1
net.ipv4.icmp_echo_ignore_broadcasts=1
net.ipv4.icmp_ignore_bogus_error_responses=1
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.accept_source_route=0
net.ipv4.conf.default.log_martians = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.accept_redirects = 0
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
# - name: Adjust login.defs
# replace:
# path: /mnt/etc/login.defs
# regexp: "{{ item.regexp }}"
# replace: "{{ item.replace }}"
# loop:
# - { regexp: '^PASS_MAX_DAYS.*', replace: 'PASS_MAX_DAYS 90' }
# - { regexp: '^PASS_MIN_DAYS.*', replace: 'PASS_MIN_DAYS 7' }
# - { regexp: '^UMASK.*', replace: 'UMASK 027' }
- name: Ensure the Default UMASK is Set Correctly
ansible.builtin.lineinfile:
path: "/mnt/etc/profile"
regexp: "^(\\s*)umask\\s+\\d+"
line: "umask 027"
- name: Prevent Login to Accounts With Empty Password
ansible.builtin.replace:
dest: "{{ item }}"
regexp: "nullok"
- name: Include CIS hardening tasks
ansible.builtin.include_tasks: "{{ cis_task }}"
loop:
- /mnt/etc/pam.d/system-auth
- /mnt/etc/pam.d/password-auth
- name: Configure System Cryptography Policy
when: os in ["almalinux", "rhel9", "rhel10", "rocky"]
ansible.builtin.command: arch-chroot /mnt /usr/bin/update-crypto-policies --set DEFAULT:NO-SHA1
register: crypto_policy_result
changed_when: "'Setting system-wide crypto-policies to' in crypto_policy_result.stdout"
- name: Mask Systemd Services
ansible.builtin.command: >
arch-chroot /mnt systemctl mask nftables bluetooth rpcbind
changed_when: result.rc == 0
register: result
- name: Ensure files exist
ansible.builtin.file:
path: "{{ item }}"
state: touch
mode: "0600"
loop:
- /mnt/etc/at.allow
- /mnt/etc/cron.allow
- /mnt/etc/hosts.allow
- /mnt/etc/hosts.deny
- name: Ensure files do not exist
ansible.builtin.file:
path: "{{ item }}"
state: touch
mode: "0600"
loop:
- /mnt/etc/at.deny
- /mnt/etc/cron.deny
- name: Add Security related lines into config files
ansible.builtin.lineinfile:
path: "{{ item.path }}"
line: "{{ item.content }}"
loop:
- { path: /mnt/etc/security/limits.conf, content: "* hard core 0" }
- { path: /mnt/etc/security/pwquality.conf, content: minlen = 14 }
- { path: /mnt/etc/security/pwquality.conf, content: dcredit = -1 }
- { path: /mnt/etc/security/pwquality.conf, content: ucredit = -1 }
- { path: /mnt/etc/security/pwquality.conf, content: ocredit = -1 }
- { path: /mnt/etc/security/pwquality.conf, content: lcredit = -1 }
- {
path: '/mnt/etc/{{ "bashrc" if os in ["almalinux", "fedora", "rhel8", "rhel9", "rhel10", "rocky"] else "bash.bashrc" }}',
content: umask 077,
}
- {
path: '/mnt/etc/{{ "bashrc" if os in ["almalinux", "fedora", "rhel8", "rhel9", "rhel10", "rocky"] else "bash.bashrc" }}',
content: export TMOUT=3000,
}
- {
path: '/mnt/{{ "usr/lib/systemd/journald.conf" if os == "fedora" else "etc/systemd/journald.conf" }}',
content: Storage=persistent,
}
- {
path: /mnt/etc/sudoers,
content: Defaults logfile="/var/log/sudo.log",
}
- { path: /mnt/etc/pam.d/su, content: auth required pam_wheel.so }
- {
path:
'/mnt/etc/{{ "pam.d/common-auth" if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"]
else "authselect/system-auth" if os == "fedora" else "pam.d/system-auth" }}',
content: auth required pam_faillock.so onerr=fail audit silent deny=5 unlock_time=900,
}
- {
path:
'/mnt/etc/{{ "pam.d/common-account" if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"] else "authselect/system-auth"
if os == "fedora" else "pam.d/system-auth" }}',
content: account required pam_faillock.so,
}
- {
path: '/mnt/etc/pam.d/{{ "common-password" if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"] else "passwd" }}',
content: "password [success=1 default=ignore] pam_unix.so obscure sha512 remember=5",
}
- { path: /mnt/etc/hosts.deny, content: "ALL: ALL" }
- { path: /mnt/etc/hosts.allow, content: "sshd: ALL" }
- name: Set permissions for various files and directories
ansible.builtin.file:
path: "{{ item.path }}"
owner: "{{ item.owner | default(omit) }}"
group: "{{ item.group | default(omit) }}"
mode: "{{ item.mode }}"
loop: >
{{ [
{ "path": "/mnt/etc/ssh/sshd_config", "mode": "0600" },
{ "path": "/mnt/etc/cron.hourly", "mode": "0700" },
{ "path": "/mnt/etc/cron.daily", "mode": "0700" },
{ "path": "/mnt/etc/cron.weekly", "mode": "0700" },
{ "path": "/mnt/etc/cron.monthly", "mode": "0700" },
{ "path": "/mnt/etc/cron.d", "mode": "0700" },
{ "path": "/mnt/etc/crontab", "mode": "0600" },
{ "path": "/mnt/etc/logrotate.conf", "mode": "0644" },
{ "path": "/mnt/usr/sbin/pppd", "mode": "0754" } if os not in ["rhel8", "rhel9", "rhel10"] else None,
{ "path": "/mnt/usr/bin/" + ("fusermount3" if os in ["almalinux", "archlinux", "debian12", "fedora", "rhel9", "rhel10", "rocky"]
else "fusermount"), "mode": "755" },
{ "path": "/mnt/usr/bin/" + ("write.ul" if os == "debian11" else "write"), "mode": "755" }
] | reject("none") }}
- name: Adjust SSHD config
ansible.builtin.lineinfile:
path: /mnt/etc/ssh/sshd_config
regexp: ^\s*#?{{ item.option }}\s+.*$
line: "{{ item.option }} {{ item.value }}"
with_items:
- { option: LogLevel, value: VERBOSE }
- { option: LoginGraceTime, value: "60" }
- { option: PermitRootLogin, value: "no" }
- { option: StrictModes, value: "yes" }
- { option: MaxAuthTries, value: "4" }
- { option: MaxSessions, value: "10" }
- { option: MaxStartups, value: 10:30:60 }
- { option: PubkeyAuthentication, value: "yes" }
- { option: HostbasedAuthentication, value: "no" }
- { option: IgnoreRhosts, value: "yes" }
- { option: PasswordAuthentication, value: "no" }
- { option: PermitEmptyPasswords, value: "no" }
- { option: KerberosAuthentication, value: "no" }
- { option: GSSAPIAuthentication, value: "no" }
- { option: AllowAgentForwarding, value: "no" }
- { option: AllowTcpForwarding, value: "no" }
- { option: ChallengeResponseAuthentication, value: "no" }
- { option: GatewayPorts, value: "no" }
- { option: X11Forwarding, value: "no" }
- { option: PermitUserEnvironment, value: "no" }
- { option: ClientAliveInterval, value: "300" }
- { option: ClientAliveCountMax, value: "1" }
- { option: PermitTunnel, value: "no" }
- { option: Banner, value: /etc/issue.net }
- name: Append CIS Specific configurations to sshd_config
ansible.builtin.lineinfile:
path: /mnt/etc/ssh/sshd_config
line: |2-
## CIS Specific
Protocol 2
### Ciphers and keying ###
RekeyLimit 512M 6h
KexAlgorithms mlkem768x25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
###########################
AllowStreamLocalForwarding no
PermitUserRC no
AllowUsers *
AllowGroups *
DenyUsers nobody
DenyGroups nobody
- modules.yml
- sysctl.yml
- auth.yml
- crypto.yml
- files.yml
- security_lines.yml
- permissions.yml
- sshd.yml
loop_control:
loop_var: cis_task

View File

@@ -0,0 +1,38 @@
---
- name: Disable Kernel Modules
ansible.builtin.copy:
dest: /mnt/etc/modprobe.d/cis.conf
mode: "0644"
content: |
# CIS LVL 3 Restrictions
install freevxfs /bin/false
install jffs2 /bin/false
install hfs /bin/false
install hfsplus /bin/false
install cramfs /bin/false
install squashfs /bin/false
install udf /bin/false
install usb-storage /bin/false
install dccp /bin/false
install sctp /bin/false
install rds /bin/false
install tipc /bin/false
- name: Remove legacy USB rules file
ansible.builtin.file:
path: /mnt/etc/udev/rules.d/10-cis_usb_devices.sh
state: absent
- name: Create USB rules
ansible.builtin.copy:
dest: /mnt/etc/udev/rules.d/10-cis_usb_devices.rules
mode: "0644"
content: |
# By default, disable all.
ACTION=="add", SUBSYSTEMS=="usb", TEST=="authorized_default", ATTR{authorized_default}="0"
# Enable hub devices.
ACTION=="add", ATTR{bDeviceClass}=="09", TEST=="authorized", ATTR{authorized}="1"
# Enable keyboard devices.
ACTION=="add", ATTR{product}=="*[Kk]eyboard*", TEST=="authorized", ATTR{authorized}="1"
# PS2-USB converter.
ACTION=="add", ATTR{product}=="*Thinnet TM*", TEST=="authorized", ATTR{authorized}="1"

View File

@@ -0,0 +1,37 @@
---
- name: Build CIS permission targets
ansible.builtin.set_fact:
cis_permission_targets: >-
{{
[
{ "path": "/mnt/etc/ssh/sshd_config", "mode": "0600" },
{ "path": "/mnt/etc/cron.hourly", "mode": "0700" },
{ "path": "/mnt/etc/cron.daily", "mode": "0700" },
{ "path": "/mnt/etc/cron.weekly", "mode": "0700" },
{ "path": "/mnt/etc/cron.monthly", "mode": "0700" },
{ "path": "/mnt/etc/cron.d", "mode": "0700" },
{ "path": "/mnt/etc/crontab", "mode": "0600" },
{ "path": "/mnt/etc/logrotate.conf", "mode": "0644" },
{ "path": "/mnt/usr/sbin/pppd", "mode": "0754" } if os not in ["rhel8", "rhel9", "rhel10"] else None,
{ "path": "/mnt/usr/bin/" + ("fusermount3" if os in ["archlinux", "debian12", "fedora", "rhel9",
"rhel10", "rocky"] else "fusermount"), "mode": "755" },
{ "path": "/mnt/usr/bin/" + ("write.ul" if os == "debian11" else "write"), "mode": "755" }
] | reject("none")
}}
changed_when: false
- name: Check CIS permission targets
ansible.builtin.stat:
path: "{{ item.path }}"
loop: "{{ cis_permission_targets }}"
register: cis_permission_stats
changed_when: false
- name: Set permissions for existing targets
ansible.builtin.file:
path: "{{ item.item.path }}"
owner: "{{ item.item.owner | default(omit) }}"
group: "{{ item.item.group | default(omit) }}"
mode: "{{ item.item.mode }}"
loop: "{{ cis_permission_stats.results }}"
when: item.stat.exists

View File

@@ -0,0 +1,46 @@
---
- name: Add Security related lines into config files
ansible.builtin.lineinfile:
path: "{{ item.path }}"
line: "{{ item.content }}"
loop:
- {path: /mnt/etc/security/limits.conf, content: "* hard core 0"}
- {path: /mnt/etc/security/pwquality.conf, content: minlen = 14}
- {path: /mnt/etc/security/pwquality.conf, content: dcredit = -1}
- {path: /mnt/etc/security/pwquality.conf, content: ucredit = -1}
- {path: /mnt/etc/security/pwquality.conf, content: ocredit = -1}
- {path: /mnt/etc/security/pwquality.conf, content: lcredit = -1}
- {path: '/mnt/etc/{{ "bashrc" if is_rhel | default(false) else "bash.bashrc" }}', content: umask 077}
- {path: '/mnt/etc/{{ "bashrc" if is_rhel | default(false) else "bash.bashrc" }}', content: export TMOUT=3000}
- {path: '/mnt/{{ "usr/lib/systemd/journald.conf" if os == "fedora" else "etc/systemd/journald.conf" }}', content: Storage=persistent}
- {path: /mnt/etc/sudoers, content: Defaults logfile="/var/log/sudo.log"}
- {path: /mnt/etc/pam.d/su, content: auth required pam_wheel.so}
- path: >-
/mnt/etc/{{
"pam.d/common-auth"
if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"]
else "authselect/system-auth"
if os == "fedora"
else "pam.d/system-auth"
}}
content: >-
auth required pam_faillock.so onerr=fail audit silent deny=5 unlock_time=900
- path: >-
/mnt/etc/{{
"pam.d/common-account"
if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"]
else "authselect/system-auth"
if os == "fedora"
else "pam.d/system-auth"
}}
content: account required pam_faillock.so
- path: >-
/mnt/etc/pam.d/{{
"common-password"
if os in ["debian11", "debian12", "ubuntu", "ubuntu-lts"]
else "passwd"
}}
content: >-
password [success=1 default=ignore] pam_unix.so obscure sha512 remember=5
- {path: /mnt/etc/hosts.deny, content: "ALL: ALL"}
- {path: /mnt/etc/hosts.allow, content: "sshd: ALL"}

51
roles/cis/tasks/sshd.yml Normal file
View File

@@ -0,0 +1,51 @@
---
- name: Adjust SSHD config
ansible.builtin.lineinfile:
path: /mnt/etc/ssh/sshd_config
regexp: ^\s*#?{{ item.option }}\s+.*$
line: "{{ item.option }} {{ item.value }}"
loop:
- {option: LogLevel, value: VERBOSE}
- {option: LoginGraceTime, value: "60"}
- {option: PermitRootLogin, value: "no"}
- {option: StrictModes, value: "yes"}
- {option: MaxAuthTries, value: "4"}
- {option: MaxSessions, value: "10"}
- {option: MaxStartups, value: "10:30:60"}
- {option: PubkeyAuthentication, value: "yes"}
- {option: HostbasedAuthentication, value: "no"}
- {option: IgnoreRhosts, value: "yes"}
- {option: PasswordAuthentication, value: "no"}
- {option: PermitEmptyPasswords, value: "no"}
- {option: KerberosAuthentication, value: "no"}
- {option: GSSAPIAuthentication, value: "no"}
- {option: AllowAgentForwarding, value: "no"}
- {option: AllowTcpForwarding, value: "no"}
- {option: ChallengeResponseAuthentication, value: "no"}
- {option: GatewayPorts, value: "no"}
- {option: X11Forwarding, value: "no"}
- {option: PermitUserEnvironment, value: "no"}
- {option: ClientAliveInterval, value: "300"}
- {option: ClientAliveCountMax, value: "1"}
- {option: PermitTunnel, value: "no"}
- {option: Banner, value: /etc/issue.net}
- name: Append CIS specific configurations to sshd_config
ansible.builtin.blockinfile:
path: /mnt/etc/ssh/sshd_config
marker: "# {mark} CIS SSH HARDENING"
block: |-
## CIS Specific
Protocol 2
### Ciphers and keying ###
RekeyLimit 512M 6h
KexAlgorithms mlkem768x25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
###########################
AllowStreamLocalForwarding no
PermitUserRC no
AllowUsers *
AllowGroups *
DenyUsers nobody
DenyGroups nobody

View File

@@ -0,0 +1,30 @@
---
- name: Create a consolidated sysctl configuration file
ansible.builtin.copy:
dest: /mnt/etc/sysctl.d/10-cis.conf
mode: "0644"
content: |
## CIS Sysctl configurations
kernel.yama.ptrace_scope=1
kernel.randomize_va_space=2
# Network
net.ipv4.ip_forward=0
net.ipv4.tcp_syncookies=1
net.ipv4.icmp_echo_ignore_broadcasts=1
net.ipv4.icmp_ignore_bogus_error_responses=1
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.accept_source_route=0
net.ipv4.conf.default.log_martians = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.accept_redirects = 0
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1