feat(cis): add selectable profile and per-rule hardening toggles

This commit is contained in:
2026-05-25 04:37:33 +02:00
parent d2a19cfd5c
commit 2c35409519
23 changed files with 753 additions and 192 deletions

View File

@@ -1,6 +1,5 @@
---
# OS-specific binary names for CIS permission targets.
# fusermount3 is the modern name; older distros still use fusermount.
# fusermount3 is the modern name; older distros still ship fusermount.
cis_fusermount_binary: >-
{{
'fusermount3'
@@ -19,3 +18,235 @@ cis_write_binary: >-
if (os == 'debian' and (os_version | string) == '11')
else 'write'
}}
cis_pkg_install: >-
{{ chroot_command }} {{
'apt-get install -y'
if is_debian | bool
else 'pacman -S --noconfirm'
if os == 'archlinux'
else 'dnf install -y'
}}
# Rule catalog: control -> CIS level + whether a task implements it.
# `default` enables only implemented rules; `l1`/`l2` add the level-tagged ones.
cis_rule_catalog:
module_blacklist: {level: l1, implemented: true} # fs/net modprobe blacklist (list per profile)
usb_lockdown: {level: l2, implemented: true} # udev authorized_default=0 (aggressive)
sysctl_hardening: {level: l1, implemented: true}
ipv6_disable: {level: l2, implemented: true} # disable_ipv6 subset of the sysctl set
umask_default: {level: l1, implemented: true}
empty_password_login: {level: l1, implemented: true}
pwquality: {level: l1, implemented: true}
core_dumps: {level: l1, implemented: true}
shell_timeout: {level: l1, implemented: true}
journald_persistent: {level: l1, implemented: true}
sudo_logfile: {level: l1, implemented: true}
su_restriction: {level: l1, implemented: true}
faillock: {level: l1, implemented: true}
password_history: {level: l1, implemented: true}
tcp_wrappers: {level: l1, implemented: true}
crypto_policy: {level: l1, implemented: true} # RedHat non-Fedora only
mask_services: {level: l1, implemented: true}
cron_at_access: {level: l1, implemented: true}
file_permissions: {level: l1, implemented: true}
sshd_hardening: {level: l1, implemented: true}
password_expiry: {level: l1, implemented: true} # login.defs aging policy
aide: {level: l1, implemented: true} # file-integrity db + daily check
warning_banners: {level: l1, implemented: true} # /etc/issue, issue.net, motd
auditd: {level: l2, implemented: true} # audit daemon + CIS rule set
grub_password: {level: l1, implemented: true} # opt-in only; needs params.grub_password_hash
# Rules not listed are off. A per-host system.features.cis.rules map overlays this.
cis_profiles:
# default = established house behaviour, kept byte-for-byte unchanged.
default:
module_blacklist: true
usb_lockdown: true
sysctl_hardening: true
ipv6_disable: true
umask_default: true
empty_password_login: true
pwquality: true
core_dumps: true
shell_timeout: true
journald_persistent: true
sudo_logfile: true
su_restriction: true
faillock: true
password_history: true
tcp_wrappers: true
crypto_policy: true
mask_services: true
cron_at_access: true
file_permissions: true
sshd_hardening: true
# l1 = clean CIS Level 1: drops the L2 extras (usb_lockdown, ipv6_disable).
l1:
module_blacklist: true
sysctl_hardening: true
umask_default: true
empty_password_login: true
pwquality: true
core_dumps: true
shell_timeout: true
journald_persistent: true
sudo_logfile: true
su_restriction: true
faillock: true
password_history: true
tcp_wrappers: true
crypto_policy: true
mask_services: true
cron_at_access: true
file_permissions: true
sshd_hardening: true
password_expiry: true
aide: true
warning_banners: true
# l2 = l1 plus the defence-in-depth Level 2 controls.
l2:
module_blacklist: true
usb_lockdown: true
sysctl_hardening: true
ipv6_disable: true
umask_default: true
empty_password_login: true
pwquality: true
core_dumps: true
shell_timeout: true
journald_persistent: true
sudo_logfile: true
su_restriction: true
faillock: true
password_history: true
tcp_wrappers: true
crypto_policy: true
mask_services: true
cron_at_access: true
file_permissions: true
sshd_hardening: true
password_expiry: true
aide: true
warning_banners: true
auditd: true
# Override per host via system.features.cis.params: dicts deep-merge,
# list-valued keys (e.g. sshd_options) replace wholesale.
cis_param_defaults:
modules_blacklist:
- freevxfs
- jffs2
- hfs
- hfsplus
- cramfs
- udf
- usb-storage
- dccp
- sctp
- rds
- tipc
- firewire-core
- firewire-sbp2
- thunderbolt
sysctl:
fs.suid_dumpable: 0
kernel.dmesg_restrict: 1
kernel.kptr_restrict: 2
kernel.perf_event_paranoid: 3
kernel.unprivileged_bpf_disabled: 1
kernel.yama.ptrace_scope: 2
kernel.randomize_va_space: 2
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.all.arp_ignore: 1
net.ipv4.conf.all.arp_announce: 2
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
sshd_options:
- {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: KbdInteractiveAuthentication, 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}
pwquality_minlen: 14
# pwquality strict set (l1/l2 only, cis_strict): SSG cis_server_l1 values.
pwquality_difok: 2
pwquality_maxrepeat: 3
pwquality_maxsequence: 3
pwquality_minclass: 4
pwquality_dictcheck: 1
tmout: 900
umask: "077"
umask_profile: "027"
faillock_deny: 5
faillock_unlock_time: 900
password_remember: 5
# pwhistory remember (l1/l2 only, cis_strict): SSG wants 24 via pam_pwhistory.
pwhistory_remember: 24
# password_expiry (l1/l2): /etc/login.defs aging.
pass_max_days: 365
pass_min_days: 1
pass_warn_age: 7
# account_disable_post_pw_expiration (l1/l2): days after expiry to lock (SSG=45).
pass_inactive: 45
# aide (l1/l2): daily integrity-check schedule.
aide_cron_hour: "5"
aide_cron_minute: "0"
# warning_banners (l1/l2): login/MOTD text.
banner_text: "Authorized access only. All activity may be monitored and reported."
# grub_password (opt-in only): a grub2 pbkdf2 hash; empty unless opted in.
grub_password_hash: ""
# insecure_packages (l1/l2 only, cis_strict): legacy cleartext clients to remove.
insecure_packages:
- telnet
# Only the module blacklist differs by profile: l1 trims to the L1 filesystem
# modules; default/l2 keep the full list.
cis_profile_params:
default: {}
l1:
modules_blacklist:
- cramfs
- freevxfs
- jffs2
- hfs
- hfsplus
- udf
- usb-storage
l2: {}