Compare commits

..

5 commits

11 changed files with 87 additions and 13 deletions

View file

@ -9,10 +9,18 @@ collections:
- src: git+https://guardianproject.dev/sr2/ansible-collection-core.git
version: "main"
roles:
- src: git+https://github.com/ansible-lockdown/RHEL9-CIS.git
version: "2.0.3"
- src: git+https://guardianproject.dev/sr2/RHEL9-CIS.git
version: "2.0.3-become"
```
## Convention
We assume that these roles will be run initially as root, and then as an unprivileged user after initial bootstrap.
Some hardening may only be performed in the second run when we can see that the unprivileged user access is configured
and root access is no longer required.
If anything fails due to permissions when running as an unprivileged user, please report that in our
[issue tracker](https://guardianproject.dev/sr2/ansible-collection-core/issues).
## Licence
Copyright © SR2 Communications Limited 2021-2025.

View file

@ -39,3 +39,10 @@
tags: bootstrap
- role: sr2c.core.podman_keycloak
tags: keycloak
- name: Baseline for generic servers (manual or externally managed application deployment)
hosts:
- generic
roles:
- role: sr2c.core.baseline
tags: bootstrap

View file

@ -2,9 +2,11 @@
- name: Regenerate grub config
ansible.builtin.command:
cmd: grub2-mkconfig -o /boot/grub2/grub.cfg
become: true
- name: Restart systemd-resolved
ansible.builtin.systemd_service:
name: systemd-resolved
state: restarted
daemon_reload: true
become: true

View file

@ -12,11 +12,13 @@
msg: "Variable 'baseline_second_disk_device' must be defined."
- name: Disk Partitions | PATCH | Ensure lvm2 is installed
become: true
ansible.builtin.package:
name: lvm2
state: present
- name: Disk Partitions | PATCH | Create LVM partition spanning entire disk
become: true
community.general.parted:
device: "{{ baseline_second_disk_device }}"
number: 1
@ -26,35 +28,41 @@
part_end: "100%"
- name: Disk Partitions | PATCH | Create volume group
become: true
community.general.lvg:
vg: "{{ baseline_second_disk_vg_name }}"
pvs: "{{ baseline_second_disk_device }}1"
- name: Disk Partitions | PATCH | Create /var logical volume
become: true
community.general.lvol:
vg: "{{ baseline_second_disk_vg_name }}"
lv: var
size: "{{ baseline_second_disk_var_size }}"
- name: Disk Partitions | PATCH | Create /var/log logical volume
become: true
community.general.lvol:
vg: "{{ baseline_second_disk_vg_name }}"
lv: var_log
size: "{{ baseline_second_disk_var_log_size }}"
- name: Disk Partitions | PATCH | Create /var/log/audit logical volume
become: true
community.general.lvol:
vg: "{{ baseline_second_disk_vg_name }}"
lv: var_log_audit
size: "{{ baseline_second_disk_var_log_audit_size }}"
- name: Disk Partitions | PATCH | Create /var/tmp logical volume
become: true
community.general.lvol:
vg: "{{ baseline_second_disk_vg_name }}"
lv: var_tmp
size: "{{ baseline_second_disk_var_tmp_size }}"
- name: Disk Partitions | PATCH | Create /home logical volume with remaining space
become: true
community.general.lvol:
vg: "{{ baseline_second_disk_vg_name }}"
lv: home
@ -62,11 +70,13 @@
size: "100%FREE"
- name: Disk Partitions | PATCH | Ensure cryptsetup is installed
become: true
ansible.builtin.package:
name: cryptsetup
state: present
- name: Disk Partitions | PATCH | Encrypt /home with LUKS2 and provided passphrase
become: true
community.crypto.luks_device:
device: "/dev/{{ baseline_second_disk_vg_name }}/home"
state: present
@ -74,6 +84,7 @@
type: luks2
- name: Disk Partitions | PATCH | Open LUKS device
become: true
community.crypto.luks_device:
device: "/dev/{{ baseline_second_disk_vg_name }}/home"
name: home_crypt
@ -81,6 +92,7 @@
passphrase: "{{ baseline_home_luks_passphrase }}"
- name: Disk Partitions | PATCH | Add /home logical volume to crypttab
become: true
community.general.crypttab:
backing_device: /dev/mapper/datavg-home
name: home_crypt
@ -88,6 +100,7 @@
state: present
- name: Disk Partitions | PATCH | Create xfs filesystems on new partitions
become: true
community.general.filesystem:
dev: "{{ item }}"
fstype: xfs
@ -99,6 +112,7 @@
- /dev/mapper/home_crypt
- name: Disk Partitions | AUDIT | Check if /home is mounted
become: true
ansible.builtin.command:
cmd: mountpoint -q /home
register: baseline_second_disk_home_mounted
@ -106,6 +120,7 @@
failed_when: false
- name: Disk Partitions | AUDIT | Check if /home is empty
become: true
ansible.builtin.command:
cmd: ls -A /home
register: baseline_second_disk_home_files
@ -113,11 +128,13 @@
changed_when: false
- name: Disk Partitions | AUDIT | Fail if /home is not mounted and not empty
become: true
ansible.builtin.assert:
that:
- ((baseline_second_disk_home_files.skipped is defined) and baseline_second_disk_home_files.skipped) or (baseline_second_disk_home_files.stdout == "")
- name: Disk Partitions | PATCH | Ensure /home is mounted
become: true
ansible.posix.mount:
src: "/dev/mapper/home_crypt"
path: '/home'
@ -126,6 +143,7 @@
state: mounted
- name: Disk Partitions | AUDIT | Check if /var is mounted
become: true
ansible.builtin.command:
cmd: mountpoint -q /var
register: baseline_second_disk_var_mounted
@ -133,6 +151,7 @@
failed_when: false
- name: Disk Partitions | PATCH | Migrate content if /var is not mounted
become: true
when: baseline_second_disk_var_mounted.rc != 0
block:
- name: Disk Partitions | PATCH | Enter emergency mode

View file

@ -1,9 +1,11 @@
---
- name: 'Disk Partitions | PATCH | Rename directory to directory.old | {{ baseline_second_disk_migrate_path }}'
become: true
ansible.builtin.command:
cmd: 'mv {{ baseline_second_disk_migrate_path }} {{ baseline_second_disk_migrate_path }}.old'
- name: 'Disk Partitions | PATCH | Mount {{ baseline_second_disk_migrate_path }}'
become: true
ansible.posix.mount:
src: "/dev/mapper/datavg-{{ baseline_second_disk_migrate_path | replace('/', '', 1) | replace('/', '_') }}"
path: '{{ baseline_second_disk_migrate_path }}'
@ -13,6 +15,7 @@
# TODO: systemctl daemon-reload after modifying /etc/fstab
- name: 'Disk Partitions | PATCH | Set permissions | {{ baseline_second_disk_migrate_path }}'
become: true
ansible.builtin.file:
path: '{{ baseline_second_disk_migrate_path }}'
owner: root
@ -21,11 +24,13 @@
state: directory
- name: 'Disk Partitions | PATCH | Move content | {{ baseline_second_disk_migrate_path }}'
become: true
ansible.builtin.shell:
cmd: 'cp -ax * {{ baseline_second_disk_migrate_path }}/'
chdir: '{{ baseline_second_disk_migrate_path }}.old'
- name: 'Disk Partitions | PATCH | Delete directory.old | {{ baseline_second_disk_migrate_path }}'
become: true
ansible.builtin.file:
path: '{{ baseline_second_disk_migrate_path }}.old'
state: absent

View file

@ -1,10 +1,12 @@
---
- name: DNS Resolver | PATCH | Install systemd-resolved
become: true
ansible.builtin.dnf:
name: systemd-resolved
state: latest
- name: DNS Resolver | PATCH | Ensure systemd-resolved is in use
become: true
ansible.builtin.systemd_service:
name: systemd-resolved
state: started
@ -12,12 +14,14 @@
masked: false
- name: DNS Resolver | PATCH | Remove loopback address entries containing the hostname from /etc/hosts
become: true
ansible.builtin.lineinfile:
path: /etc/hosts
regexp: '^(127\.0\.0\.1|::1)\s.*{{ inventory_hostname }}'
state: absent
- name: DNS Resolver | PATCH | Enable DNSSEC and disable unwanted resolved features
become: true
ansible.builtin.copy:
src: resolved.conf
dest: /etc/systemd/resolved.conf
@ -25,9 +29,9 @@
group: root
mode: "0644"
notify: "Restart systemd-resolved"
become: true
- name: DNS Resolver | PATCH | Ensure /etc/systemd/system/systemd-resolved.service.d exists
become: true
ansible.builtin.file:
path: /etc/systemd/system/systemd-resolved.service.d
state: directory
@ -36,6 +40,7 @@
mode: "0755"
- name: DNS Resolver | PATCH | Disable resolved record synthesising
become: true
ansible.builtin.copy:
src: systemd-resolved-override.conf
dest: /etc/systemd/system/systemd-resolved.service.d/override.conf
@ -43,4 +48,3 @@
group: root
mode: "0644"
notify: "Restart systemd-resolved"
become: true

View file

@ -4,21 +4,28 @@
role: freeipa.ansible_freeipa.ipaclient
vars:
ipaclient_hostname: "{{ inventory_hostname }}"
when: ansible_user == "root" # We've already joined if we're using an unprivileged user
- name: FreeIPA Client | AUDIT | Check current authselect configuration
become: true
ansible.builtin.command: authselect current
register: _baseline_freeipa_authselect_status
changed_when: false
- name: FreeIPA Client | PATCH | Apply authselect profile with sssd, sudo, and mkhomedir if not set
ansible.builtin.command: authselect select sssd with-sudo with-mkhomedir with-subid --force
- name: FreeIPA Client | PATCH | Apply authselect profile with sssd, sudo, and more if not set
become: true
ansible.builtin.command: authselect select sssd with-sudo with-mkhomedir with-subid with-faillock with-pwhistory without-nullok --force
when: >
'Profile ID: sssd' not in _baseline_freeipa_authselect_status.stdout or
'with-sudo' not in _baseline_freeipa_authselect_status.stdout or
'with-mkhomedir' not in _baseline_freeipa_authselect_status.stdout or
'with-subid' not in _baseline_freeipa_authselect_status.stdout
'with-subid' not in _baseline_freeipa_authselect_status.stdout or
'with-faillock' not in _baseline_freeipa_authselect_status.stdout or
'with-pwhistory' not in _baseline_freeipa_authselect_status.stdout or
'without-nullok' not in _baseline_freeipa_authselect_status.stdout
- name: FreeIPA Client | PATCH | Enable oddjobd.service (for with-mkhomedir feature)
become: true
ansible.builtin.systemd_service:
name: oddjobd.service
state: started

View file

@ -1,13 +1,14 @@
---
- name: Lockdown | AUDIT | Check current authselect configuration
become: true
ansible.builtin.command: authselect current
register: baseline_lockdown_authselect_status
failed_when: false # Exit code is 2 when not configured
changed_when: false
- name: Lockdown | PATCH | Run Ansible Lockdown (RHEL9-CIS)
ansible.builtin.include_role:
name: RHEL9-CIS
ansible.builtin.import_role:
name: RHEL9-CIS # This is the SR2 fork that includes a patch to run all tasks with become: true
vars:
# Ensure message of the day is configured properly - we have our own MOTD to apply
rhel9cis_rule_1_7_1: false
@ -16,6 +17,7 @@
rhel9cis_rule_5_1_7: false
# Only disable root login once authselect is configured
rhel9cis_rule_5_1_20: "{{ baseline_lockdown_authselect_status.rc != 2 }}"
rhel9cis_rule_5_4_2_4: false # TODO: temporarily disable requirement for root password
# TODO: figure out boot password
rhel9cis_set_boot_pass: false
# TODO: We intend to later deploy a remote rsyslog sink

View file

@ -23,16 +23,19 @@
when: (baseline_epel_packages_allowed is defined) and (baseline_epel_packages_allowed | length > 0)
block:
- name: Baseline | PATCH | Install epel-release
become: true
ansible.builtin.dnf:
name: epel-release
state: present
- name: Baseline | PATCH | Restrict packages to be installed from EPEL
become: true
community.general.ini_file:
path: /etc/yum.repos.d/epel.repo
section: epel
option: includepkgs
value: "{{ baseline_epel_packages_allowed | join(',') }}"
- name: Baseline | PATCH | Disable EPEL openh264 repository
become: true
community.general.ini_file:
path: /etc/yum.repos.d/epel-cisco-openh264.repo
section: epel-cisco-openh264
@ -40,12 +43,14 @@
value: 0
- name: Baseline | PATCH | Remove EPEL repository
become: true
ansible.builtin.dnf:
name: epel-release
state: absent
when: (baseline_epel_packages_allowed is not defined) or (baseline_epel_packages_allowed | length == 0)
- name: Baseline | PATCH | Remove cockpit-ws
become: true
ansible.builtin.dnf:
name: cockpit-ws
state: absent
@ -59,6 +64,7 @@
when: baseline_lockdown
- name: Baseline | PATCH | Ensure message of the day is configured properly (CIS 1.7.1, 1.7.4)
become: true
ansible.builtin.template:
src: motd.j2
dest: /etc/motd
@ -67,6 +73,7 @@
mode: 'u-x,go-wx'
- name: Baseline | PATCH | Remove dhcpv6-client service from firewalld
become: true
ansible.posix.firewalld:
service: dhcpv6-client
state: disabled
@ -75,6 +82,7 @@
zone: public
- name: Baseline | PATCH | Remove mdns service from firewalld
become: true
ansible.posix.firewalld:
service: mdns
state: disabled
@ -83,6 +91,7 @@
zone: public
- name: Baseline | PATCH | Remove cockpit service from firewalld
become: true
ansible.posix.firewalld:
service: cockpit
state: disabled

View file

@ -1,6 +1,7 @@
---
# https://support.solusvm.com/hc/en-us/articles/21334950006807-How-to-install-Guest-Tools-manually-inside-a-VM-in-SolusVM-2
- name: SolusVM Guest | PATCH | Install required packages
become: true
ansible.builtin.dnf:
name:
- qemu-guest-agent
@ -8,27 +9,27 @@
- tuned
state: latest
update_cache: true
become: true
- name: SolusVM Guest | PATCH | Enable and start tuned
become: true
ansible.builtin.systemd_service:
name: tuned
enabled: true
state: started
become: true
- name: SolusVM Guest | AUDIT | Check for tuned profile
become: true
ansible.builtin.command: tuned-adm active
register: _baseline_solusvm_tuned_profile
become: true
changed_when: false
- name: SolusVM Guest | PATCH | Start tuned profile (virtual-guest)
ansible.builtin.command: tuned-adm profile virtual-guest
become: true
ansible.builtin.command: tuned-adm profile virtual-guest
when: "'virtual-guest' not in _baseline_solusvm_tuned_profile.stdout"
- name: SolusVM Guest | PATCH | Remove console=ttyS0,115200n8 from bootloader configurations
become: true
ansible.builtin.replace:
path: "{{ item }}"
regexp: 'console=ttyS0,115200n8'
@ -41,12 +42,14 @@
- Regenerate grub config
- name: SolusVM Guest | AUDIT | Find all vmlinuz-* files in /boot
become: true
ansible.builtin.find:
paths: /boot
patterns: 'vmlinuz-*'
register: baseline_solusvm_kernels
- name: SolusVM Guest | PATCH | Remove console=ttyS0,115200n8 from existing kernel bootloader entries
become: true
ansible.builtin.command:
cmd: "grubby --update-kernel={{ item.path }} --remove-args='console=ttyS0,115200n8'"
with_items: "{{ baseline_solusvm_kernels.files }}"

View file

@ -38,6 +38,14 @@
become_user: "{{ item }}"
with_items: "{{ podman_host_rootless_users }}"
- name: Podman Host | PATCH | Set XDG_RUNTIME_DIR in .bashrc for rootless users
ansible.builtin.lineinfile:
path: "/home/{{ item }}/.bashrc"
line: "export XDG_RUNTIME_DIR=/run/user/$(id -u)"
become: true
become_user: "{{ item }}"
with_items: "{{ podman_host_rootless_users }}"
- name: Podman Host | PATCH | Enable linger for rootless users
ansible.builtin.command:
argv: