CIS + inital
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
---
|
||||
# AppArmor Configuration (CIS 1.3.x)
|
||||
|
||||
- name: Install AppArmor packages (CIS 1.3.1)
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- apparmor
|
||||
- apparmor-utils
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: Enable AppArmor service (CIS 1.3.2)
|
||||
ansible.builtin.service:
|
||||
name: apparmor
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
- name: Check AppArmor status
|
||||
ansible.builtin.command: aa-status --json
|
||||
register: apparmor_status
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Parse AppArmor status
|
||||
ansible.builtin.set_fact:
|
||||
apparmor_json: "{{ apparmor_status.stdout | from_json }}"
|
||||
when: apparmor_status.rc == 0
|
||||
|
||||
- name: Set all AppArmor profiles to enforce mode (CIS 1.3.3)
|
||||
ansible.builtin.command: aa-enforce /etc/apparmor.d/*
|
||||
register: apparmor_enforce
|
||||
changed_when: "'Setting' in apparmor_enforce.stdout"
|
||||
failed_when: false
|
||||
when: apparmor_enforce_all | default(true)
|
||||
|
||||
- name: Display AppArmor status
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "AppArmor status: {{ apparmor_json.apparmor if apparmor_json is defined else 'unknown' }}"
|
||||
- "Profiles loaded: {{ apparmor_json.profiles | length if apparmor_json is defined and apparmor_json.profiles is defined else 0 }}"
|
||||
- "Profiles in enforce mode: {{ apparmor_json.profiles | selectattr('mode', 'equalto', 'enforce') | list | length if apparmor_json is defined and apparmor_json.profiles is defined else 0 }}"
|
||||
when: apparmor_json is defined
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
# Auditd Configuration Tasks (CIS 4.1.x)
|
||||
|
||||
- name: Ensure auditd is installed (CIS 4.1.1)
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- auditd
|
||||
- audispd-plugins
|
||||
state: present
|
||||
|
||||
- name: Configure auditd max log file size (CIS 4.1.3)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/audit/auditd.conf
|
||||
regexp: '^max_log_file\s*='
|
||||
line: "max_log_file = {{ auditd_max_log_file }}"
|
||||
state: present
|
||||
|
||||
- name: Configure auditd log retention (CIS 4.1.4)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/audit/auditd.conf
|
||||
regexp: '^max_log_file_action\s*='
|
||||
line: "max_log_file_action = keep_logs"
|
||||
state: present
|
||||
|
||||
- name: Configure auditd space left action (CIS 4.1.5)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/audit/auditd.conf
|
||||
regexp: '^space_left_action\s*='
|
||||
line: "space_left_action = email"
|
||||
state: present
|
||||
|
||||
- name: Configure auditd admin space left action
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/audit/auditd.conf
|
||||
regexp: '^admin_space_left_action\s*='
|
||||
line: "admin_space_left_action = halt"
|
||||
state: present
|
||||
|
||||
- name: Deploy CIS-compliant audit rules
|
||||
ansible.builtin.template:
|
||||
src: audit.rules.j2
|
||||
dest: /etc/audit/rules.d/cis.rules
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0640'
|
||||
notify: restart auditd
|
||||
|
||||
- name: Load audit rules
|
||||
ansible.builtin.command: augenrules --load
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Ensure auditd is started and enabled (CIS 4.1.2)
|
||||
ansible.builtin.systemd:
|
||||
name: auditd
|
||||
state: started
|
||||
enabled: yes
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
# Restrict Core Dumps (CIS 1.5.1)
|
||||
|
||||
- name: Disable core dumps via limits.conf
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/security/limits.conf
|
||||
line: "* hard core 0"
|
||||
create: yes
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Disable core dumps via sysctl (already done in sysctl_cis.yml)
|
||||
ansible.posix.sysctl:
|
||||
name: fs.suid_dumpable
|
||||
value: '0'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
|
||||
- name: Disable coredump in systemd
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/systemd/coredump.conf
|
||||
regexp: '^Storage='
|
||||
line: "Storage=none"
|
||||
create: yes
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Disable coredump processing
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/systemd/coredump.conf
|
||||
regexp: '^ProcessSizeMax='
|
||||
line: "ProcessSizeMax=0"
|
||||
create: yes
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
# Disable Uncommon Network Protocols (CIS 3.3.x)
|
||||
|
||||
- name: Disable DCCP protocol (CIS 3.3.1)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/modprobe.d/cis.conf
|
||||
line: "install dccp /bin/true"
|
||||
create: yes
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Disable SCTP protocol (CIS 3.3.2)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/modprobe.d/cis.conf
|
||||
line: "install sctp /bin/true"
|
||||
create: yes
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Disable RDS protocol (CIS 3.3.3)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/modprobe.d/cis.conf
|
||||
line: "install rds /bin/true"
|
||||
create: yes
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Disable TIPC protocol (CIS 3.3.4)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/modprobe.d/cis.conf
|
||||
line: "install tipc /bin/true"
|
||||
create: yes
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Unload uncommon protocols if loaded
|
||||
community.general.modprobe:
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- dccp
|
||||
- sctp
|
||||
- rds
|
||||
- tipc
|
||||
failed_when: false
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
# Fail2ban Configuration Tasks
|
||||
|
||||
- name: Ensure fail2ban is installed
|
||||
ansible.builtin.apt:
|
||||
name: fail2ban
|
||||
state: present
|
||||
|
||||
- name: Configure fail2ban
|
||||
ansible.builtin.template:
|
||||
src: fail2ban.local.j2
|
||||
dest: /etc/fail2ban/jail.local
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
notify: restart fail2ban
|
||||
|
||||
- name: Ensure fail2ban is started and enabled
|
||||
ansible.builtin.systemd:
|
||||
name: fail2ban
|
||||
state: started
|
||||
enabled: yes
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
# System Hardening Role - Main Tasks
|
||||
|
||||
- name: Set timezone
|
||||
community.general.timezone:
|
||||
name: "{{ system_timezone }}"
|
||||
when: system_timezone is defined and system_timezone != ""
|
||||
|
||||
- name: Set hostname
|
||||
ansible.builtin.hostname:
|
||||
name: "{{ system_hostname }}"
|
||||
when: system_hostname is defined and system_hostname != ""
|
||||
|
||||
- name: Update apt cache
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Upgrade all packages
|
||||
ansible.builtin.apt:
|
||||
upgrade: dist
|
||||
autoremove: yes
|
||||
autoclean: yes
|
||||
|
||||
- name: Install security packages
|
||||
ansible.builtin.apt:
|
||||
name: "{{ hardening_install_packages }}"
|
||||
state: present
|
||||
|
||||
- name: Remove insecure packages
|
||||
ansible.builtin.apt:
|
||||
name: "{{ hardening_remove_packages }}"
|
||||
state: absent
|
||||
purge: yes
|
||||
|
||||
- name: Configure SSH hardening
|
||||
ansible.builtin.include_tasks: ssh.yml
|
||||
|
||||
- name: Configure sysctl parameters (basic)
|
||||
ansible.builtin.include_tasks: sysctl.yml
|
||||
|
||||
- name: Configure CIS-compliant sysctl parameters
|
||||
ansible.builtin.include_tasks: sysctl_cis.yml
|
||||
|
||||
- name: Configure AppArmor (CIS 1.3.x)
|
||||
ansible.builtin.include_tasks: apparmor.yml
|
||||
when: apparmor_enabled | default(true)
|
||||
|
||||
- name: Configure fail2ban
|
||||
ansible.builtin.include_tasks: fail2ban.yml
|
||||
when: fail2ban_enabled | bool
|
||||
|
||||
- name: Configure auditd (CIS 4.1.x)
|
||||
ansible.builtin.include_tasks: audit.yml
|
||||
when: auditd_enabled | bool
|
||||
|
||||
- name: Configure unattended upgrades
|
||||
ansible.builtin.include_tasks: unattended_upgrades.yml
|
||||
when: unattended_upgrades_enabled | bool
|
||||
|
||||
- name: Disable uncommon network protocols (CIS 3.3.x)
|
||||
ansible.builtin.include_tasks: disable_protocols.yml
|
||||
|
||||
- name: Configure core dumps restriction (CIS 1.5.1)
|
||||
ansible.builtin.include_tasks: core_dumps.yml
|
||||
|
||||
- name: Disable unnecessary services
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ item }}"
|
||||
state: stopped
|
||||
enabled: no
|
||||
loop:
|
||||
- avahi-daemon
|
||||
- cups
|
||||
- isc-dhcp-server
|
||||
- isc-dhcp-server6
|
||||
- rpcbind
|
||||
- rsync
|
||||
- snmpd
|
||||
failed_when: false # Don't fail if service doesn't exist
|
||||
|
||||
- name: Set secure file permissions (CIS 6.1.x)
|
||||
ansible.builtin.file:
|
||||
path: "{{ item.path }}"
|
||||
mode: "{{ item.mode }}"
|
||||
loop:
|
||||
- { path: '/etc/passwd', mode: '0644' }
|
||||
- { path: '/etc/shadow', mode: '0600' }
|
||||
- { path: '/etc/group', mode: '0644' }
|
||||
- { path: '/etc/gshadow', mode: '0600' }
|
||||
- { path: '/etc/ssh/sshd_config', mode: '0600' }
|
||||
|
||||
- name: Create security banners (CIS 1.4.x)
|
||||
ansible.builtin.copy:
|
||||
dest: "{{ item }}"
|
||||
content: |
|
||||
**************************************************************************
|
||||
* *
|
||||
* WARNING: Unauthorized access to this system is forbidden and will *
|
||||
* be prosecuted by law. By accessing this system, you agree that your *
|
||||
* actions may be monitored if unauthorized usage is suspected. *
|
||||
* *
|
||||
**************************************************************************
|
||||
mode: '0644'
|
||||
loop:
|
||||
- /etc/issue
|
||||
- /etc/issue.net
|
||||
- /etc/motd
|
||||
|
||||
- name: Display hardening summary
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "========================================="
|
||||
- "System Hardening Complete"
|
||||
- "========================================="
|
||||
- "CIS Level 1 controls applied"
|
||||
- "AppArmor: {{ 'ENABLED' if apparmor_enabled | default(true) else 'DISABLED' }}"
|
||||
- "Auditd: {{ 'ENABLED' if auditd_enabled else 'DISABLED' }}"
|
||||
- "Fail2ban: {{ 'ENABLED' if fail2ban_enabled else 'DISABLED' }}"
|
||||
- "Unattended upgrades: {{ 'ENABLED' if unattended_upgrades_enabled else 'DISABLED' }}"
|
||||
- "========================================="
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
# SSH Hardening Tasks
|
||||
|
||||
- name: Backup original sshd_config
|
||||
ansible.builtin.copy:
|
||||
src: /etc/ssh/sshd_config
|
||||
dest: /etc/ssh/sshd_config.backup
|
||||
remote_src: yes
|
||||
force: no
|
||||
|
||||
- name: Configure SSH daemon
|
||||
ansible.builtin.template:
|
||||
src: sshd_config.j2
|
||||
dest: /etc/ssh/sshd_config
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0600'
|
||||
validate: '/usr/sbin/sshd -t -f %s'
|
||||
notify: restart sshd
|
||||
|
||||
- name: Ensure SSH directory exists for root
|
||||
ansible.builtin.file:
|
||||
path: /root/.ssh
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0700'
|
||||
|
||||
- name: Generate strong SSH host keys
|
||||
ansible.builtin.command: ssh-keygen -A
|
||||
args:
|
||||
creates: /etc/ssh/ssh_host_ed25519_key
|
||||
|
||||
- name: Remove weak SSH host keys
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- /etc/ssh/ssh_host_dsa_key
|
||||
- /etc/ssh/ssh_host_dsa_key.pub
|
||||
- /etc/ssh/ssh_host_ecdsa_key
|
||||
- /etc/ssh/ssh_host_ecdsa_key.pub
|
||||
|
||||
- name: Set permissions on SSH host keys
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0600'
|
||||
loop:
|
||||
- /etc/ssh/ssh_host_rsa_key
|
||||
- /etc/ssh/ssh_host_ed25519_key
|
||||
when: ansible_facts['os_family'] == "Debian"
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
# Sysctl Hardening Tasks
|
||||
|
||||
- name: Apply sysctl hardening parameters
|
||||
ansible.posix.sysctl:
|
||||
name: "{{ item.key }}"
|
||||
value: "{{ item.value }}"
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
loop: "{{ sysctl_config | dict2items }}"
|
||||
when: sysctl_config is defined
|
||||
@@ -0,0 +1,157 @@
|
||||
---
|
||||
# CIS-Compliant Sysctl Parameters
|
||||
|
||||
# CIS 3.1.1 - Disable IP forwarding (unless VPN server needs it)
|
||||
- name: Disable IPv4 forwarding
|
||||
ansible.posix.sysctl:
|
||||
name: net.ipv4.ip_forward
|
||||
value: '1' # Enabled for VPN server
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
|
||||
# CIS 3.1.2 - Disable packet redirect sending
|
||||
- name: Disable send packet redirects
|
||||
ansible.posix.sysctl:
|
||||
name: "{{ item }}"
|
||||
value: '0'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
loop:
|
||||
- net.ipv4.conf.all.send_redirects
|
||||
- net.ipv4.conf.default.send_redirects
|
||||
|
||||
# CIS 3.2.1 - Do not accept source routed packets
|
||||
- name: Disable source routed packets
|
||||
ansible.posix.sysctl:
|
||||
name: "{{ item }}"
|
||||
value: '0'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
loop:
|
||||
- net.ipv4.conf.all.accept_source_route
|
||||
- net.ipv4.conf.default.accept_source_route
|
||||
- net.ipv6.conf.all.accept_source_route
|
||||
- net.ipv6.conf.default.accept_source_route
|
||||
|
||||
# CIS 3.2.2 - Do not accept ICMP redirects
|
||||
- name: Disable ICMP redirects
|
||||
ansible.posix.sysctl:
|
||||
name: "{{ item }}"
|
||||
value: '0'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
loop:
|
||||
- net.ipv4.conf.all.accept_redirects
|
||||
- net.ipv4.conf.default.accept_redirects
|
||||
- net.ipv6.conf.all.accept_redirects
|
||||
- net.ipv6.conf.default.accept_redirects
|
||||
|
||||
# CIS 3.2.3 - Do not accept secure ICMP redirects
|
||||
- name: Disable secure ICMP redirects
|
||||
ansible.posix.sysctl:
|
||||
name: "{{ item }}"
|
||||
value: '0'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
loop:
|
||||
- net.ipv4.conf.all.secure_redirects
|
||||
- net.ipv4.conf.default.secure_redirects
|
||||
|
||||
# CIS 3.2.4 - Log suspicious packets
|
||||
- name: Enable suspicious packet logging
|
||||
ansible.posix.sysctl:
|
||||
name: "{{ item }}"
|
||||
value: '1'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
loop:
|
||||
- net.ipv4.conf.all.log_martians
|
||||
- net.ipv4.conf.default.log_martians
|
||||
|
||||
# CIS 3.2.5 - Ignore broadcast ICMP requests
|
||||
- name: Ignore ICMP broadcast requests
|
||||
ansible.posix.sysctl:
|
||||
name: net.ipv4.icmp_echo_ignore_broadcasts
|
||||
value: '1'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
|
||||
# CIS 3.2.6 - Ignore bogus ICMP responses
|
||||
- name: Ignore bogus ICMP error responses
|
||||
ansible.posix.sysctl:
|
||||
name: net.ipv4.icmp_ignore_bogus_error_responses
|
||||
value: '1'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
|
||||
# CIS 3.2.7 - Enable reverse path filtering
|
||||
- name: Enable reverse path filtering
|
||||
ansible.posix.sysctl:
|
||||
name: "{{ item }}"
|
||||
value: '1'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
loop:
|
||||
- net.ipv4.conf.all.rp_filter
|
||||
- net.ipv4.conf.default.rp_filter
|
||||
|
||||
# CIS 3.2.8 - Enable TCP SYN cookies
|
||||
- name: Enable TCP SYN cookies
|
||||
ansible.posix.sysctl:
|
||||
name: net.ipv4.tcp_syncookies
|
||||
value: '1'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
|
||||
# CIS 3.2.9 - Do not accept IPv6 router advertisements
|
||||
- name: Disable IPv6 router advertisements
|
||||
ansible.posix.sysctl:
|
||||
name: "{{ item }}"
|
||||
value: '0'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
loop:
|
||||
- net.ipv6.conf.all.accept_ra
|
||||
- net.ipv6.conf.default.accept_ra
|
||||
|
||||
# Additional hardening
|
||||
- name: Disable IPv6 (if not used)
|
||||
ansible.posix.sysctl:
|
||||
name: "{{ item }}"
|
||||
value: '1'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
loop:
|
||||
- net.ipv6.conf.all.disable_ipv6
|
||||
- net.ipv6.conf.default.disable_ipv6
|
||||
when: disable_ipv6 | default(false)
|
||||
|
||||
# CIS 1.5.2 - Enable ASLR
|
||||
- name: Enable address space layout randomization
|
||||
ansible.posix.sysctl:
|
||||
name: kernel.randomize_va_space
|
||||
value: '2'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
|
||||
# CIS 1.5.1 - Restrict core dumps
|
||||
- name: Restrict core dumps
|
||||
ansible.posix.sysctl:
|
||||
name: fs.suid_dumpable
|
||||
value: '0'
|
||||
state: present
|
||||
sysctl_set: yes
|
||||
reload: yes
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
# Unattended Upgrades Configuration Tasks
|
||||
|
||||
- name: Ensure unattended-upgrades is installed
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- unattended-upgrades
|
||||
- apt-listchanges
|
||||
state: present
|
||||
|
||||
- name: Configure unattended-upgrades
|
||||
ansible.builtin.template:
|
||||
src: 50unattended-upgrades.j2
|
||||
dest: /etc/apt/apt.conf.d/50unattended-upgrades
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Enable automatic updates
|
||||
ansible.builtin.template:
|
||||
src: 20auto-upgrades.j2
|
||||
dest: /etc/apt/apt.conf.d/20auto-upgrades
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
Reference in New Issue
Block a user