This commit is contained in:
mrwho 2026-05-12 00:21:37 +03:00
parent b493cf7459
commit 2c6d0394a1
46 changed files with 844 additions and 42 deletions

View file

@ -7,11 +7,17 @@
# - 172.20.21.193 # - 172.20.21.193
become: true become: true
vars: vars:
ansible_ssh_user: root #ansible_ssh_user: root
ansible_ssh_password: nmklop90 #ansible_ssh_password: nmklop90
reboot_system: false reboot_system: false
hostname: rocky9-template.local.mrwho.ru hostname: rocky9-template.local.mrwho.ru
roles: roles:
- users - users
- rocky9 - rocky9
- root-cert - root-cert
- linux_login_banner_rhel9
- linux_core_dumps_rhel9
- linux_ctrl_alt_del_rhel9
- linux_dnf_automatic_rhel9
# - linux_ssh_hardening_rhel9
- linux_wireless_rhel9

View file

@ -0,0 +1,17 @@
# linux_core_dumps_rhel9
## Purpose
Restricts core dump creation via PAM limits and sysctl settings to prevent sensitive memory contents from being written to disk.
## Targeted OS
RHEL 9 / AlmaLinux 9 / Rocky Linux 9
## CIS Alignment
CIS Section 1.5.1 — Ensure core dumps are restricted
## Key Variables
```yaml
linux_core_dumps_rhel9_disabled: false # set to true to skip this role
```
See `defaults/main.yml` for all tunable parameters.

View file

@ -0,0 +1,16 @@
---
# Enable core dump hardening (CIS 1.5.4)
linux_core_dumps_enabled: true
# Disable core dumps globally (recommended for servers)
linux_core_dumps_limit: "0"
# Disable setuid core dumps (CIS 1.5.4)
linux_core_suid_dumpable: "0"
# Restrict core pattern (no executable core files in cwd)
linux_core_pattern: "/dev/null"
# Role disable var
linux_core_dumps_disabled: false

View file

@ -0,0 +1,6 @@
---
# No handlers needed sysctl module applies changes live
# If you want a reload handler later, you can add it here
...

View file

@ -0,0 +1,5 @@
---
- name: "Apply core dump hardening (RHEL 9 family)"
when: "linux_core_dumps_disabled is not defined or not linux_core_dumps_disabled | bool"
ansible.builtin.import_tasks: "tasks.yml"
tags: "linux_core_dumps_rhel9"

View file

@ -0,0 +1,52 @@
---
- name: "Set core dump limit to 0 in limits.conf"
ansible.builtin.lineinfile:
path: "/etc/security/limits.conf"
regexp: "^\\*\\s+hard\\s+core\\s+"
line: "* hard core {{ linux_core_dumps_limit }}"
create: true
mode: "0644"
register: "limits_conf_result"
- name: "Set core dump limit to 0 for root in limits.conf"
ansible.builtin.lineinfile:
path: "/etc/security/limits.conf"
regexp: "^root\\s+hard\\s+core\\s+"
line: "root hard core {{ linux_core_dumps_limit }}"
create: true
mode: "0644"
register: "root_limits_result"
- name: "Disable setuid core dumps (fs.suid_dumpable)"
ansible.posix.sysctl:
name: "fs.suid_dumpable"
value: "{{ linux_core_suid_dumpable }}"
state: "present"
sysctl_set: true
sysctl_file: "/etc/sysctl.d/99-cis-core-dumps.conf"
reload: true
register: "suid_dumpable_result"
- name: "Set core pattern to /dev/null (prevent core files in cwd)"
ansible.posix.sysctl:
name: "kernel.core_pattern"
value: "{{ linux_core_pattern }}"
state: "present"
sysctl_set: true
sysctl_file: "/etc/sysctl.d/99-cis-core-dumps.conf"
reload: true
register: "core_pattern_result"
- name: "Apply sysctl changes immediately if needed"
when: "suid_dumpable_result.changed or core_pattern_result.changed"
ansible.builtin.command: "sysctl --system"
changed_when: false
- name: "Debug core dump hardening status (verbosity >=1)"
when: "ansible_verbosity >= 1"
ansible.builtin.debug:
msg:
- "Core limit applied: {{ limits_conf_result.changed | default(false) }}"
- "Root core limit applied: {{ root_limits_result.changed | default(false) }}"
- "fs.suid_dumpable: {{ linux_core_suid_dumpable }}"
- "kernel.core_pattern: {{ linux_core_pattern }}"

View file

@ -0,0 +1,17 @@
# linux_ctrl_alt_del_rhel9
## Purpose
Disables the Ctrl+Alt+Del keyboard shortcut to prevent accidental or malicious system reboots from the console.
## Targeted OS
RHEL 9 / AlmaLinux 9 / Rocky Linux 9
## CIS Alignment
CIS Section 1.6.1 — Ensure system-wide crypto policy is not legacy
## Key Variables
```yaml
linux_ctrl_alt_del_rhel9_disabled: false # set to true to skip this role
```
See `defaults/main.yml` for all tunable parameters.

View file

@ -0,0 +1,5 @@
---
linux_ctrl_alt_del_enabled: true
linux_ctrl_alt_del_disabled: false

View file

@ -0,0 +1,4 @@
---
- name: "Reload systemd after Ctrl+Alt+Del changes"
ansible.builtin.systemd:
daemon_reload: true

View file

@ -0,0 +1,5 @@
---
- name: "Apply Ctrl+Alt+Del disable hardening (RHEL 9 family)"
when: "linux_ctrl_alt_del_disabled is not defined or not linux_ctrl_alt_del_disabled | bool"
ansible.builtin.import_tasks: "tasks.yml"
tags: "linux_ctrl_alt_del_rhel9"

View file

@ -0,0 +1,52 @@
---
- name: Remove existing ctrl-alt-del.target symlink
ansible.builtin.file:
path: /etc/systemd/system/ctrl-alt-del.target
state: absent
- name: "Mask Ctrl+Alt+Del target to prevent reboot"
when: "linux_ctrl_alt_del_enabled | bool"
ansible.builtin.systemd:
name: "ctrl-alt-del.target"
masked: true
state: "stopped"
register: "cad_mask_result"
ignore_errors: true
# FIX: create the .target.d/ drop-in directory before writing into it.
# ansible.builtin.copy does NOT create missing parent directories.
- name: "Ensure ctrl-alt-del.target.d drop-in directory exists"
when: "linux_ctrl_alt_del_enabled | bool"
ansible.builtin.file:
path: "/etc/systemd/system/ctrl-alt-del.target.d"
state: "directory"
mode: "0755"
owner: "root"
group: "root"
- name: "Deploy ctrl-alt-del override to reinforce mask"
when: "linux_ctrl_alt_del_enabled | bool"
ansible.builtin.copy:
content: "[Unit]\nDescription=Ctrl-Alt-Del disabled by CyberAar hardening\n"
dest: "/etc/systemd/system/ctrl-alt-del.target.d/override.conf"
mode: "0644"
owner: "root"
group: "root"
register: "cad_override_result"
- name: "Reload systemd daemon after mask/override"
when: "cad_mask_result.changed or cad_override_result.changed"
ansible.builtin.systemd:
daemon_reload: true
- name: "Verify Ctrl+Alt+Del mask status (verbosity >=1)" # noqa: command-instead-of-module
when: "ansible_verbosity >= 1"
ansible.builtin.command: "systemctl is-enabled ctrl-alt-del.target"
changed_when: false
register: "cad_status"
failed_when: false
- name: "Show Ctrl+Alt+Del mask status"
when: "ansible_verbosity >= 1"
ansible.builtin.debug:
msg: "ctrl-alt-del.target status: {{ cad_status.stdout | default('unknown') }}"

View file

@ -0,0 +1,17 @@
# linux_dnf_automatic_rhel9
## Purpose
Installs and configures dnf-automatic to automatically apply security updates on a scheduled basis, ensuring critical patches are applied without manual intervention.
## Targeted OS
RHEL 9 / AlmaLinux 9 / Rocky Linux 9
## CIS Alignment
CIS Section 1.9 — Ensure updates, patches, and additional security software are installed
## Key Variables
```yaml
linux_dnf_automatic_rhel9_disabled: false # set to true to skip this role
```
See `defaults/main.yml` for all tunable parameters.

View file

@ -0,0 +1,21 @@
---
# Enable automatic security updates (CIS 1.7.1)
linux_dnf_automatic_enabled: true
# Apply only security updates (recommended for servers)
linux_dnf_automatic_apply_updates: "security"
# Email notifications (optional requires mail setup)
linux_dnf_automatic_email_notify: true
linux_dnf_automatic_email_to: "root@localhost"
linux_dnf_automatic_email_from: "dnf-automatic@{{ ansible_fqdn }}"
# When to apply updates (daily is CIS default)
linux_dnf_automatic_schedule: "daily"
# Random delay (minutes) to avoid thundering herd
linux_dnf_automatic_random_sleep: 300
# Role disable var
linux_dnf_automatic_disabled: false

View file

@ -0,0 +1,6 @@
---
- name: "Restart dnf-automatic timer"
ansible.builtin.systemd:
name: "dnf-automatic.timer"
state: "restarted"
daemon_reload: true

View file

@ -0,0 +1,5 @@
---
- name: "Apply dnf-automatic security updates (RHEL 9 family)"
when: "linux_dnf_automatic_disabled is not defined or not linux_dnf_automatic_disabled | bool"
ansible.builtin.import_tasks: "tasks.yml"
tags: "linux_dnf_automatic_rhel9"

View file

@ -0,0 +1,34 @@
---
- name: "Install dnf-automatic package"
ansible.builtin.package:
name: "dnf-automatic"
state: "present"
- name: "Deploy dnf-automatic configuration"
ansible.builtin.template:
src: "automatic.conf.j2"
dest: "/etc/dnf/automatic.conf"
mode: "0644"
owner: "root"
group: "root"
backup: true
register: "dnf_auto_config_result"
notify: "Restart dnf-automatic timer"
- name: "Enable and start dnf-automatic timer (daily)"
ansible.builtin.systemd:
name: "dnf-automatic.timer"
state: "started"
enabled: true
masked: false
- name: "Debug dnf-automatic status (verbosity >=1)"
when: "ansible_verbosity >= 1"
ansible.builtin.command: "systemctl status dnf-automatic.timer"
changed_when: false
register: "dnf_timer_status"
- name: "Show dnf-automatic timer status"
when: "ansible_verbosity >= 1"
ansible.builtin.debug:
msg: "{{ dnf_timer_status.stdout_lines | default([]) }}"

View file

@ -0,0 +1,21 @@
# Managed by Ansible role linux_dnf_automatic_rhel9
[commands]
# Only apply security updates (CIS safe choice)
upgrade_type = {{ linux_dnf_automatic_apply_updates }}
# Random delay before starting (minutes)
random_sleep = {{ linux_dnf_automatic_random_sleep }}
[emit_via]
# Emit via email (requires postfix or mail setup)
emit_via = {{ 'email' if linux_dnf_automatic_email_notify | bool else 'stdio' }}
# Email settings
email_from = {{ linux_dnf_automatic_email_from }}
email_to = {{ linux_dnf_automatic_email_to }}
email_host = localhost
[base]
# Debug level (0-10, higher = more verbose)
debuglevel = 1

View file

@ -0,0 +1,17 @@
# linux_journald_rhel9
## Purpose
Configures systemd-journald with persistent log storage, compression, and rate limiting to ensure reliable and efficient system log retention.
## Targeted OS
RHEL 9 / AlmaLinux 9 / Rocky Linux 9
## CIS Alignment
CIS Section 4.2.1.x — Configure journald
## Key Variables
```yaml
linux_journald_rhel9_disabled: false # set to true to skip this role
```
See `defaults/main.yml` for all tunable parameters.

View file

@ -0,0 +1,32 @@
---
# Write logs to /var/log/journal (persistent across reboots) — CIS 4.2.1.1.1
linux_journald_storage: "persistent"
# Compress large journal files — CIS 4.2.1.1.2
linux_journald_compress: "yes"
# Forward entries to syslog socket (integrates with rsyslog)
linux_journald_forward_to_syslog: "yes"
# Rate limiting — prevent log flooding
linux_journald_rate_limit_interval: "30s"
linux_journald_rate_limit_burst: 10000
# Maximum total disk usage by journald
linux_journald_system_max_use: "1G"
# Minimum free disk space journald will leave available
linux_journald_system_keep_free: "256M"
# Maximum size of a single journal file
linux_journald_system_max_file_size: "100M"
# Rotate individual files after this period
linux_journald_max_file_sec: "1month"
# Delete old journal files beyond this total retention period
linux_journald_max_retention_sec: "2year"
# Role disable var
linux_journald_disabled: false

View file

@ -0,0 +1,7 @@
---
- name: "Restart journald"
ansible.builtin.systemd:
name: "systemd-journald"
state: "restarted"
daemon_reload: true
failed_when: false

View file

@ -0,0 +1,5 @@
---
- name: "Apply journald hardening (RHEL 9 family)"
when: "linux_journald_disabled is not defined or not linux_journald_disabled | bool"
ansible.builtin.import_tasks: "tasks.yml"
tags: "linux_journald_rhel9"

View file

@ -0,0 +1,39 @@
---
- name: "Ensure /etc/systemd/journald.conf.d directory exists (CIS 4.2.1.x)"
ansible.builtin.file:
path: "/etc/systemd/journald.conf.d"
state: directory
owner: "root"
group: "root"
mode: "0755"
- name: "Deploy journald hardening configuration (CIS 4.2.1.x)"
ansible.builtin.template:
src: "99-cis-journald.conf.j2"
dest: "/etc/systemd/journald.conf.d/99-cis-journald.conf"
owner: "root"
group: "root"
mode: "0644"
notify: "Restart journald"
register: "journald_config_result"
- name: "Ensure /var/log/journal directory exists for persistent storage (CIS 4.2.1.1.1)"
when: "linux_journald_storage == 'persistent'"
ansible.builtin.file:
path: "/var/log/journal"
state: directory
owner: "root"
group: "systemd-journal"
mode: "2755"
register: "journal_dir_result"
- name: "Debug journald configuration status (verbosity >= 1)"
when: "ansible_verbosity >= 1"
ansible.builtin.debug:
msg:
- "Storage: {{ linux_journald_storage }}"
- "Compress: {{ linux_journald_compress }}"
- "ForwardToSyslog: {{ linux_journald_forward_to_syslog }}"
- "RateLimitBurst: {{ linux_journald_rate_limit_burst }}"
- "SystemMaxUse: {{ linux_journald_system_max_use }}"
- "Config changed: {{ journald_config_result.changed | default(false) }}"

View file

@ -0,0 +1,14 @@
# CyberAar — systemd-journald hardening (CIS 4.2.1.x)
# Managed by Ansible — do not edit manually
[Journal]
Storage={{ linux_journald_storage }}
Compress={{ linux_journald_compress }}
ForwardToSyslog={{ linux_journald_forward_to_syslog }}
RateLimitInterval={{ linux_journald_rate_limit_interval }}
RateLimitBurst={{ linux_journald_rate_limit_burst }}
SystemMaxUse={{ linux_journald_system_max_use }}
SystemKeepFree={{ linux_journald_system_keep_free }}
SystemMaxFileSize={{ linux_journald_system_max_file_size }}
MaxFileSec={{ linux_journald_max_file_sec }}
MaxRetentionSec={{ linux_journald_max_retention_sec }}

View file

@ -0,0 +1,17 @@
# linux_login_banner_rhel9
## Purpose
Configures legal warning banners for SSH and local console login prompts to satisfy regulatory requirements and deter unauthorized access.
## Targeted OS
RHEL 9 / AlmaLinux 9 / Rocky Linux 9
## CIS Alignment
CIS Section 1.7 — Warning Banners
## Key Variables
```yaml
linux_login_banner_rhel9_disabled: false # set to true to skip this role
```
See `defaults/main.yml` for all tunable parameters.

View file

@ -0,0 +1,16 @@
---
# Enable login banners (CIS 5.6)
linux_login_banner_enabled: true
# Pre-login banner (/etc/issue.net) shown before SSH login
linux_login_banner_prelogin: true
# Post-login banner (/etc/motd) shown after successful login
linux_login_banner_postlogin: true
# Additional static issue file (/etc/issue) shown on console/TTY
linux_login_banner_issue: true
# Role disable var
linux_login_banner_disabled: false

View file

@ -0,0 +1,9 @@
---
# No handlers needed banner changes are immediate (shown on next login)
# If you want to force a message on current sessions, you could add:
# - name: "Notify banner updated"
# ansible.builtin.debug:
# msg: "Login banners updated visible on next login/console session"
...

View file

@ -0,0 +1,5 @@
---
- name: "Apply login banners hardening (RHEL 9 family)"
when: "linux_login_banner_disabled is not defined or not linux_login_banner_disabled | bool"
ansible.builtin.import_tasks: "tasks.yml"
tags: "linux_login_banner_rhel9"

View file

@ -0,0 +1,44 @@
---
- name: "Deploy CyberAar pre-login banner (/etc/issue.net)"
when: "linux_login_banner_prelogin | bool"
ansible.builtin.template:
src: "issue.net.j2"
dest: "/etc/issue.net"
mode: "0644"
owner: "root"
group: "root"
backup: true
register: "prelogin_banner_result"
changed_when: "prelogin_banner_result.changed"
- name: "Deploy CyberAar post-login banner (/etc/motd)"
when: "linux_login_banner_postlogin | bool"
ansible.builtin.template:
src: "motd.j2"
dest: "/etc/motd"
mode: "0644"
owner: "root"
group: "root"
backup: true
register: "motd_result"
changed_when: "motd_result.changed"
- name: "Deploy CyberAar console login banner (/etc/issue)"
when: "linux_login_banner_issue | bool"
ansible.builtin.template:
src: "issue.j2"
dest: "/etc/issue"
mode: "0644"
owner: "root"
group: "root"
backup: true
register: "issue_banner_result"
changed_when: "issue_banner_result.changed"
- name: "Debug login banner status (verbosity >=1)"
when: "ansible_verbosity >= 1"
ansible.builtin.debug:
msg:
- "Pre-login banner (/etc/issue.net) updated: {{ prelogin_banner_result.changed | default(false) }}"
- "Post-login banner (/etc/motd) updated: {{ motd_result.changed | default(false) }}"
- "Console banner (/etc/issue) updated: {{ issue_banner_result.changed | default(false) }}"

View file

@ -0,0 +1,29 @@
⣠⣤⣤⣄⣀
⣴⣿⠟⠛⠛⠛⠿⣿⣿⣿⣿⣶⣤⡀
⣠⣴⣿⡟⠁⢀⣤⣀ ⠉⠻⣿⣦
⣾⡿⠿⠛⠁⣰⣿⣿⣿⡆ ⣴⣶⣶⠄ ⢻⣿⡄
⣾⡿⠁ ⠻⣿⣿⣿⠃ ⣼⣿⣿⣿ ⢿⣷⣄
⣾⣿⠁ ⣤⣶⡄ ⠈⠉⠁ ⠈⠛⠊⠁ ⠙⢿⣷
⣿⡇ ⢸⣿⣿⡿⡆ ⣴⣶⣶⣴⣶⣄ ⢠⣶⣿⣦ ⣿⡇
⣿⡇ ⠛⠙⠉ ⣰⣿⣿⣿⣿⣿⣿⣿⣇ ⣿⣿⣿⣿ ⣿⡇
⣿⣇ ⢀⣾⣿⣿⣿⣿⣿⣿⣷⣿⣷⡀ ⠉⠉ ⣸⣿⠇
⣿⣿ ⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ ⣻⡟⠘
⢹⣿ ⠉⠛⠉⠁⠉⠁⠙⠻⠿⠟ ⣾⣿⠁
⣿⡆ ⣿⡏
⣿⣿ ⢸⣿⡇
⣻⣿ ⢸⣿⡇
⢸⣿⡄ ⢸⣿⡇
..|'''.| | |''||''|
.|' ' ||| ||
|| | || ||
'|. . .''''|. ||
''|....' .|. .||. .||.
'||''|. ..|''|| '|| '||' '|' '||''''| '||''|.
|| || .|' || '|. '|. .' || . || ||
||...|' || || || || | ||''| ||''|'
|| '|. || ||| ||| || || |.
.||. ''|...|' | | .||.....| .||. '|'

View file

@ -0,0 +1,29 @@
⣠⣤⣤⣄⣀
⣴⣿⠟⠛⠛⠛⠿⣿⣿⣿⣿⣶⣤⡀
⣠⣴⣿⡟⠁⢀⣤⣀ ⠉⠻⣿⣦
⣾⡿⠿⠛⠁⣰⣿⣿⣿⡆ ⣴⣶⣶⠄ ⢻⣿⡄
⣾⡿⠁ ⠻⣿⣿⣿⠃ ⣼⣿⣿⣿ ⢿⣷⣄
⣾⣿⠁ ⣤⣶⡄ ⠈⠉⠁ ⠈⠛⠊⠁ ⠙⢿⣷
⣿⡇ ⢸⣿⣿⡿⡆ ⣴⣶⣶⣴⣶⣄ ⢠⣶⣿⣦ ⣿⡇
⣿⡇ ⠛⠙⠉ ⣰⣿⣿⣿⣿⣿⣿⣿⣇ ⣿⣿⣿⣿ ⣿⡇
⣿⣇ ⢀⣾⣿⣿⣿⣿⣿⣿⣷⣿⣷⡀ ⠉⠉ ⣸⣿⠇
⣿⣿ ⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ ⣻⡟⠘
⢹⣿ ⠉⠛⠉⠁⠉⠁⠙⠻⠿⠟ ⣾⣿⠁
⣿⡆ ⣿⡏
⣿⣿ ⢸⣿⡇
⣻⣿ ⢸⣿⡇
⢸⣿⡄ ⢸⣿⡇
..|'''.| | |''||''|
.|' ' ||| ||
|| | || ||
'|. . .''''|. ||
''|....' .|. .||. .||.
'||''|. ..|''|| '|| '||' '|' '||''''| '||''|.
|| || .|' || '|. '|. .' || . || ||
||...|' || || || || | ||''| ||''|'
|| '|. || ||| ||| || || |.
.||. ''|...|' | | .||.....| .||. '|'

View file

@ -0,0 +1,17 @@
__ __
/\ \ /\ \
\ `\`\\/'/ ___ __ __
`\ `\ /' / __`\/\ \/\ \ /\_/\
`\ \ \/\ \L\ \ \ \_\ \ ( o.o )
\ \_\ \____/\ \____/ > ^ <
\/_/\/___/ \/___/
___ __
/\_ \ /\ \ __
\//\ \ ___ __ __ __ \_\ \ /\_\ ___
\ \ \ / __`\ /'_ `\ /'_ `\ /'__`\ /'_` \ \/\ \ /' _ `\
\_\ \_/\ \L\ \/\ \L\ \/\ \L\ \/\ __//\ \L\ \ \ \ \/\ \/\ \
/\____\ \____/\ \____ \ \____ \ \____\ \___,_\ \ \_\ \_\ \_\
\/____/\/___/ \/___L\ \/___L\ \/____/\/__,_ / \/_/\/_/\/_/
/\____/ /\____/
\_/__/ \_/__/

View file

@ -0,0 +1,17 @@
# linux_ssh_hardening_rhel9
## Purpose
Applies deep SSH server hardening by enforcing strong ciphers, MACs, key exchange algorithms, authentication restrictions, and login banners to minimize SSH attack exposure.
## Targeted OS
RHEL 9 / AlmaLinux 9 / Rocky Linux 9
## CIS Alignment
CIS Section 5.1 — Configure SSH Server
## Key Variables
```yaml
linux_ssh_hardening_rhel9_disabled: false # set to true to skip this role
```
See `defaults/main.yml` for all tunable parameters.

View file

@ -0,0 +1,45 @@
---
# Enable SSH server hardening (default true)
linux_ssh_hardening_enabled: true
# Disable root login over SSH (CIS 5.1.3.1)
linux_ssh_permit_root_login: "no"
# Disable password authentication (force keys CIS 5.1.3.2)
linux_ssh_password_auth: "no"
# Disable empty passwords (CIS 5.1.8)
linux_ssh_permit_empty_passwords: "no"
# Disable X11 forwarding (CIS 5.1.10)
linux_ssh_x11_forwarding: "no"
# Disable TCP forwarding (CIS 5.1.11)
linux_ssh_allow_tcp_forwarding: "no"
# Strong ciphers/MACs/Kex (align with crypto policies CIS 5.1.135.1.15)
linux_ssh_ciphers: "chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr"
linux_ssh_macs: "hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256"
linux_ssh_kexalgorithms: "curve25519-sha256,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512"
# Banner / legal notice (CIS 5.1.7)
linux_ssh_banner: "/etc/issue.net"
# Max auth tries (anti-brute-force CIS 5.1.5)
linux_ssh_max_auth_tries: 4
linux_ssh_max_sessions: 8
linux_ssh_max_startups: "10:30:60"
linux_ssh_login_grace_time: "60"
# Keepalive — CountMax 3 means 3 missed probes before drop (15 min total)
# Do NOT set CountMax to 0 — that drops the session on the first missed probe,
# which kills Ansible connections during long package installs or AIDE init.
linux_ssh_client_alive_interval: 300
linux_ssh_client_alive_count_max: 3
# Disable unused subsystems (e.g. sftp if not needed)
linux_ssh_subsystem: "sftp internal-sftp"
# Role disable var
linux_ssh_hardening_disabled: false

View file

@ -0,0 +1,5 @@
---
- name: "Restart sshd"
ansible.builtin.service:
name: "sshd"
state: "restarted"

View file

@ -0,0 +1,5 @@
---
- name: "Apply SSH server hardening (RHEL 9 family)"
when: "linux_ssh_hardening_disabled is not defined or not linux_ssh_hardening_disabled | bool"
ansible.builtin.import_tasks: "tasks.yml"
tags: "linux_ssh_hardening_rhel9"

View file

@ -0,0 +1,48 @@
---
- name: "Ensure openssh-server is installed"
ansible.builtin.package:
name: "openssh-server"
state: "present"
- name: "Deploy hardened sshd_config"
ansible.builtin.template:
src: "sshd_config.j2"
dest: "/etc/ssh/sshd_config"
mode: "0600"
owner: "root"
group: "root"
backup: true
validate: "/usr/sbin/sshd -T -f %s"
register: "sshd_config_result"
notify: "Restart sshd"
- name: "Deploy CyberAar-branded SSH pre-login banner (/etc/issue.net)"
ansible.builtin.template:
src: "issue.net.j2"
dest: "/etc/issue.net"
mode: "0644"
owner: "root"
group: "root"
backup: true
when: "linux_ssh_banner != ''"
register: "banner_result"
changed_when: "banner_result.changed"
- name: "Enable and start sshd service"
ansible.builtin.service:
name: "sshd"
state: "started"
enabled: true
- name: "Verify SSH configuration is valid"
ansible.builtin.command: "sshd -t"
changed_when: false
register: "sshd_test"
failed_when: "sshd_test.rc != 0"
- name: "Debug SSH hardening status (verbosity >=1)"
ansible.builtin.debug:
msg:
- "sshd_config updated: {{ sshd_config_result.changed | default(false) }}"
- "SSHD test: {{ sshd_test.rc | default('unknown') }}"
# when: "ansible_verbosity >= 1"

View file

@ -0,0 +1,13 @@
********************************************************************************
* MRWHO DIGITAL SECURITY *
* *
* This system is the exclusive property of mrwho *
* Unauthorized access is strictly prohibited and will be prosecuted. *
* *
* This system is for the use of authorized users only. *
* Individuals using this computer system without authority, or in excess of *
* their authority, are subject to having all of their activities on this *
* system monitored and recorded by system personnel. *
* *
* Welcome to {{ ansible_hostname }} *
********************************************************************************

View file

@ -0,0 +1,27 @@
# Managed by Ansible role linux_ssh_hardening_rhel9
# CIS-aligned SSH server hardening
PermitRootLogin {{ linux_ssh_permit_root_login }}
PasswordAuthentication {{ linux_ssh_password_auth }}
PermitEmptyPasswords {{ linux_ssh_permit_empty_passwords }}
X11Forwarding {{ linux_ssh_x11_forwarding }}
AllowTcpForwarding {{ linux_ssh_allow_tcp_forwarding }}
Ciphers {{ linux_ssh_ciphers }}
MACs {{ linux_ssh_macs }}
KexAlgorithms {{ linux_ssh_kexalgorithms }}
MaxAuthTries {{ linux_ssh_max_auth_tries }}
MaxSessions {{ linux_ssh_max_sessions }}
MaxStartups {{ linux_ssh_max_startups }}
Banner {{ linux_ssh_banner }}
Subsystem sftp {{ linux_ssh_subsystem }}
# Additional security
LoginGraceTime {{ linux_ssh_login_grace_time }}
ClientAliveInterval {{ linux_ssh_client_alive_interval }}
ClientAliveCountMax {{ linux_ssh_client_alive_count_max }}
IgnoreRhosts yes
PermitUserEnvironment no

View file

@ -0,0 +1,17 @@
# linux_wireless_rhel9
## Purpose
Disables wireless interfaces via nmcli and rfkill and blacklists wireless kernel modules to eliminate wireless network access on servers that do not require it.
## Targeted OS
RHEL 9 / AlmaLinux 9 / Rocky Linux 9
## CIS Alignment
CIS Section 3.1.2 — Ensure wireless interfaces are disabled
## Key Variables
```yaml
linux_wireless_rhel9_disabled: false # set to true to skip this role
```
See `defaults/main.yml` for all tunable parameters.

View file

@ -0,0 +1,10 @@
---
# CIS 3.1.2 — Ensure wireless interfaces are disabled
linux_wireless_disable: true
# Blacklist wireless kernel modules (fallback if nmcli not available)
linux_wireless_blacklist_modules: true
# Role disable var
linux_wireless_disabled: false

View file

@ -0,0 +1,5 @@
---
# No service handlers needed for wireless disabling
...

View file

@ -0,0 +1,5 @@
---
- name: "Disable wireless interfaces (RHEL 9 family)"
when: "not (linux_wireless_disabled | default(false) | bool)"
ansible.builtin.import_tasks: "tasks.yml"
tags: "linux_wireless_rhel9"

View file

@ -0,0 +1,63 @@
---
# CIS 3.1.2 — Ensure wireless interfaces are disabled
- name: "Check if NetworkManager CLI (nmcli) is available"
ansible.builtin.command: "which nmcli"
changed_when: false
register: "nmcli_available"
failed_when: false
- name: "Check current wireless radio state"
ansible.builtin.command: "nmcli radio all"
changed_when: false
register: "nmcli_radio_state"
when:
- "linux_wireless_disable | bool"
- "nmcli_available.rc == 0"
failed_when: false
- name: "Disable all wireless interfaces via nmcli (CIS 3.1.2)"
ansible.builtin.command: "nmcli radio all off"
when:
- "linux_wireless_disable | bool"
- "nmcli_available.rc == 0"
- "'enabled' in (nmcli_radio_state.stdout | lower)"
register: "wireless_nmcli_result"
changed_when: true
failed_when: false
- name: "Blacklist wireless kernel modules as fallback / defense-in-depth (CIS 3.1.2)"
ansible.builtin.copy:
content: |
# CIS 3.1.2 — Disable wireless kernel modules
# Managed by Ansible role: linux_wireless_rhel9
install iwlwifi /bin/false
blacklist iwlwifi
install cfg80211 /bin/false
blacklist cfg80211
install mac80211 /bin/false
blacklist mac80211
install rtl8xxxu /bin/false
blacklist rtl8xxxu
install ath9k /bin/false
blacklist ath9k
dest: "/etc/modprobe.d/99-cis-wireless.conf"
owner: "root"
group: "root"
mode: "0644"
backup: true
when: "linux_wireless_blacklist_modules | bool"
register: "wireless_modprobe_result"
- name: "Notify about module blacklist (reboot needed for full effect)" # noqa: no-handler
when: "wireless_modprobe_result.changed"
ansible.builtin.debug:
msg: "Wireless module blacklist applied. Reboot required for full effect."
- name: "Debug wireless hardening status (verbosity >=1)"
when: "ansible_verbosity >= 1"
ansible.builtin.debug:
msg:
- "nmcli available: {{ nmcli_available.rc == 0 }}"
- "nmcli wireless disabled: {{ wireless_nmcli_result.changed | default(false) }}"
- "kernel module blacklist applied: {{ wireless_modprobe_result.changed | default(false) }}"

View file

@ -1,38 +1,8 @@
--- ---
- name: Check if EPEL repo is already configured. - name: Enable EPEL repo
stat:
path: "{{ epel_repofile_path }}"
register: epel_repofile_result
- name: Import EPEL GPG key.
rpm_key:
key: "{{ epel_repo_gpg_key_url }}"
state: present
register: result
until: result is succeeded
retries: 5
delay: 10
when: not epel_repofile_result.stat.exists
ignore_errors: "{{ ansible_check_mode }}"
- name: Install EPEL repo.
ansible.builtin.dnf: ansible.builtin.dnf:
name: "{{ epel_repo_url }}" name: epel-release
state: present state: present
register: result
until: result is succeeded
retries: 5
delay: 10
when: not epel_repofile_result.stat.exists
#- name: Disable Main EPEL repo.
# ini_file:
# path: "/etc/yum.repos.d/epel.repo"
# section: epel
# option: enabled
# value: "{{ epel_repo_disable | ternary(0, 1) }}"
# no_extra_spaces: true
# mode: 0644
- name: Install soft from EPEL - name: Install soft from EPEL
ansible.builtin.dnf: ansible.builtin.dnf:

View file

@ -11,13 +11,13 @@
# regexp: '^fastestmirror=' # regexp: '^fastestmirror='
# line: 'fastestmirror=True' # line: 'fastestmirror=True'
- name: Enable fastestmirror in DNF # - name: Enable fastestmirror in DNF
community.general.ini_file: # community.general.ini_file:
path: /etc/dnf/dnf.conf # path: /etc/dnf/dnf.conf
section: main # section: main
option: fastestmirror # option: fastestmirror
value: "True" # value: "True"
state: present # state: present
- name: Enable parallel downloads in DNF - name: Enable parallel downloads in DNF
community.general.ini_file: community.general.ini_file:

View file

@ -18,13 +18,16 @@
- name: Syctl tuning - name: Syctl tuning
ansible.builtin.include_tasks: sysctl_tuning.yml ansible.builtin.include_tasks: sysctl_tuning.yml
############# DEPRICATED ###################
# - name: Setup NIC to eth0 # - name: Setup NIC to eth0
# ansible.builtin.include_tasks: # ansible.builtin.include_tasks:
# file: set_network_nic.yml # file: set_network_nic.yml
#
# - name: Setup NIC to eth0 # - name: Setup NIC to eth0
# ansible.builtin.include_tasks: # ansible.builtin.include_tasks:
# file: set_nic_names_eth.yml # file: set_nic_names_eth.yml
#############################################
- name: Install packages - name: Install packages
ansible.builtin.include_tasks: ansible.builtin.include_tasks: