From 76592a5c127f3305d228cc76a61d2949ec63d716 Mon Sep 17 00:00:00 2001 From: Nuxgrid Date: Wed, 29 Jul 2026 19:00:53 +0200 Subject: [PATCH] chore: update hardening --- .../playbook-journald-rsyslog-chrony.yml | 165 ++++++++++++++++++ templates/60-journald.conf.j2 | 7 + templates/60-rsyslog-filecreatemode.conf.j2 | 2 + templates/60-timesyncd.conf.j2 | 6 + templates/fix_logfile_perms.sh.j2 | 50 ++++++ 5 files changed, 230 insertions(+) create mode 100644 hardening/playbook-journald-rsyslog-chrony.yml create mode 100644 templates/60-journald.conf.j2 create mode 100644 templates/60-rsyslog-filecreatemode.conf.j2 create mode 100644 templates/60-timesyncd.conf.j2 create mode 100644 templates/fix_logfile_perms.sh.j2 diff --git a/hardening/playbook-journald-rsyslog-chrony.yml b/hardening/playbook-journald-rsyslog-chrony.yml new file mode 100644 index 0000000..e833659 --- /dev/null +++ b/hardening/playbook-journald-rsyslog-chrony.yml @@ -0,0 +1,165 @@ +--- +# Durcissement CIS Ubuntu 24.04 — journald, rsyslog, synchronisation temps (timesyncd/chrony) +# (checks 35588, 35708, 35719 — 35591/35592/35720/35722 exceptions documentees ci-dessous) +# +# IMPORTANT — DECOUVERT EN TESTANT SUR pre-prod-uber : +# Les checks Wazuh SCA correspondants exigent le reglage a la fois dans le fichier de BASE +# et dans le repertoire conf.d (condition "all" combinant les deux emplacements) : +# - 35708 (journald) : les 5 valeurs doivent apparaitre litteralement dans +# /etc/systemd/journald.conf ET dans un fichier de /etc/systemd/journald.conf.d/*.conf +# - 35719 (rsyslog) : $FileCreateMode doit apparaitre dans /etc/rsyslog.conf ET dans un +# fichier de /etc/rsyslog.d/*.conf +# - 35588 (timesyncd) est different : condition "any", donc NTP=/FallbackNTP= dans le +# seul fichier de BASE /etc/systemd/timesyncd.conf suffit (le conf.d est deploye quand +# meme, mais n'est pas strictement necessaire pour ce check precis) +# Une premiere tentative "conf.d seul, base si absent" a echoue au rescan — deployer +# systematiquement aux DEUX emplacements evite ce piege. +# +# CONTEXTE : +# - Cette infra utilise systemd-timesyncd (chrony non installe). Les checks 35591/35592 +# (chrony actif / user _chrony) incluent tous deux la condition +# `not systemd-timesyncd LoadState=loaded|ActiveState=active` dans un "condition: all" — +# ils resteront donc TOUJOURS en echec tant que timesyncd est actif, quelle que soit la +# config. Exception structurelle assumee (equivalent du choix CIS "2.3.2 timesyncd OU +# 2.3.3 chrony", Wazuh evalue les deux blocs sans les rendre mutuellement exclusifs). +# - 35710 (systemd-journal-upload) est "not applicable" tant que rsyslog est actif — non +# traite ici. +# - 35720 (rsyslog vers un host de log distant) est VOLONTAIREMENT NON TRAITE : decision +# d'architecture (necessite un serveur cible + ouverture firewall), pas un simple reglage. +# Wazuh joue deja ce role de centralisation via son propre protocole agent. +# - 35722 (permissions /var/log) : wtmp/btmp/lastlog conservent group-write (groupe utmp) +# car necessaire au bon fonctionnement de last/who/lastlog — plus strict casserait ces +# commandes. Le reste de /var/log est corrige (apt logs, README, fichiers generiques). +# +# Aucune tache de ce playbook ne necessite de redemarrage serveur — tout s'applique via +# `systemctl reload-or-restart` des services concernes. +# +# `serial: 1` + `any_errors_fatal` : un host a la fois, arret immediat si un host casse. +# +# Usage recommande : tester sur un host avant le rollout complet : +# ansible-playbook hardening/playbook-journald-rsyslog-chrony.yml --limit pre-prod-uber + +- name: Durcissement journald/rsyslog/timesyncd (CIS Ubuntu 24.04) + hosts: prod,pre-prod,bdd-redis-prod,replica-prod,infra,infra-runner,infra-utils,load-balancer + become: true + serial: 1 + any_errors_fatal: true + + tasks: + # --- 6.1.1.3 Rotation des logs journald (base ET conf.d) --- + - name: journald - fixer les 5 parametres dans le fichier de base + ansible.builtin.lineinfile: + path: /etc/systemd/journald.conf + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + insertafter: '^\[Journal\]' + loop: + - { regexp: '^#?SystemMaxUse=', line: 'SystemMaxUse=1G' } + - { regexp: '^#?SystemKeepFree=', line: 'SystemKeepFree=500M' } + - { regexp: '^#?RuntimeMaxUse=', line: 'RuntimeMaxUse=200M' } + - { regexp: '^#?RuntimeKeepFree=', line: 'RuntimeKeepFree=50M' } + - { regexp: '^#?MaxFileSec=', line: 'MaxFileSec=1month' } + register: journald_base + + - name: journald - deployer aussi en conf.d + ansible.builtin.template: + src: ../templates/60-journald.conf.j2 + dest: /etc/systemd/journald.conf.d/60-journald.conf + owner: root + group: root + mode: "0644" + register: journald_confd + + - name: journald - recharger si config changee + ansible.builtin.command: + cmd: systemctl reload-or-restart systemd-journald + when: journald_base.changed or journald_confd.changed + changed_when: true + + # --- 2.3.2.1 Serveur NTP explicite (timesyncd) — fichier de BASE obligatoire --- + - name: Verifier si chrony est actif (dans ce cas ne pas toucher timesyncd) + ansible.builtin.command: + cmd: systemctl is-active chrony.service + register: chrony_active + changed_when: false + failed_when: false + + - name: timesyncd - fixer NTP/FallbackNTP dans le fichier de base + ansible.builtin.lineinfile: + path: /etc/systemd/timesyncd.conf + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + insertafter: '^\[Time\]' + loop: + - { regexp: '^#?NTP=', line: 'NTP=ntp.ubuntu.com' } + - { regexp: '^#?FallbackNTP=', line: 'FallbackNTP=0.ubuntu.pool.ntp.org 1.ubuntu.pool.ntp.org 2.ubuntu.pool.ntp.org 3.ubuntu.pool.ntp.org' } + when: chrony_active.stdout != "active" + register: timesyncd_base + + - name: timesyncd - deployer aussi en conf.d + ansible.builtin.template: + src: ../templates/60-timesyncd.conf.j2 + dest: /etc/systemd/timesyncd.conf.d/60-timesyncd.conf + owner: root + group: root + mode: "0644" + when: chrony_active.stdout != "active" + register: timesyncd_confd + + - name: timesyncd - recharger si config changee + ansible.builtin.command: + cmd: systemctl reload-or-restart systemd-timesyncd + when: timesyncd_base is defined and (timesyncd_base.changed or timesyncd_confd.changed) + changed_when: true + + # --- 6.1.3.4 Mode de creation des fichiers rsyslog (base ET conf.d) --- + - name: rsyslog - fixer FileCreateMode dans le fichier de base + ansible.builtin.lineinfile: + path: /etc/rsyslog.conf + regexp: '^\$FileCreateMode' + line: '$FileCreateMode 0640' + register: rsyslog_base + + - name: rsyslog - deployer aussi en conf.d + ansible.builtin.template: + src: ../templates/60-rsyslog-filecreatemode.conf.j2 + dest: /etc/rsyslog.d/60-rsyslog-filecreatemode.conf + owner: root + group: root + mode: "0644" + register: rsyslog_confd + + - name: rsyslog - recharger si config changee + ansible.builtin.command: + cmd: systemctl reload-or-restart rsyslog + when: rsyslog_base.changed or rsyslog_confd.changed + changed_when: true + + # --- 6.1.4.1 Permissions et ownership sur /var/log --- + - name: Deployer le script de correction des permissions /var/log + ansible.builtin.template: + src: ../templates/fix_logfile_perms.sh.j2 + dest: /tmp/fix_logfile_perms.sh + owner: root + group: root + mode: "0700" + + - name: Executer la correction des permissions /var/log (ne fait que restreindre) + ansible.builtin.command: + cmd: bash /tmp/fix_logfile_perms.sh + register: logperm_fix + changed_when: "'OK' in logperm_fix.stdout" + + - name: Retirer other-read sur les logs apt et README + ansible.builtin.shell: | + chmod o-r /var/log/README /var/log/apt/*.log /var/log/apt/*.log.*.gz /var/log/apt/*.xz 2>/dev/null || true + changed_when: true + + - name: Supprimer le script temporaire + ansible.builtin.file: + path: /tmp/fix_logfile_perms.sh + state: absent + + - name: Confirmer le succes pour cet host + ansible.builtin.debug: + msg: "✅ journald/rsyslog/timesyncd durcis sur {{ inventory_hostname }} (aucun reboot requis)." diff --git a/templates/60-journald.conf.j2 b/templates/60-journald.conf.j2 new file mode 100644 index 0000000..60d5d3a --- /dev/null +++ b/templates/60-journald.conf.j2 @@ -0,0 +1,7 @@ +# CIS Ubuntu 24.04 - rotation des logs journald (6.1.1.3) +[Journal] +SystemMaxUse=1G +SystemKeepFree=500M +RuntimeMaxUse=200M +RuntimeKeepFree=50M +MaxFileSec=1month diff --git a/templates/60-rsyslog-filecreatemode.conf.j2 b/templates/60-rsyslog-filecreatemode.conf.j2 new file mode 100644 index 0000000..24dcd40 --- /dev/null +++ b/templates/60-rsyslog-filecreatemode.conf.j2 @@ -0,0 +1,2 @@ +# CIS Ubuntu 24.04 - mode de creation des fichiers de log rsyslog (6.1.3.4) +$FileCreateMode 0640 diff --git a/templates/60-timesyncd.conf.j2 b/templates/60-timesyncd.conf.j2 new file mode 100644 index 0000000..f381f7f --- /dev/null +++ b/templates/60-timesyncd.conf.j2 @@ -0,0 +1,6 @@ +# CIS Ubuntu 24.04 - serveur NTP autorise explicite (2.3.2.1) +# Rend explicite le serveur deja utilise par defaut sur Ubuntu (ntp.ubuntu.com), +# aucun changement de comportement reel, juste rendu auditable pour le check CIS. +[Time] +NTP=ntp.ubuntu.com +FallbackNTP=0.ubuntu.pool.ntp.org 1.ubuntu.pool.ntp.org 2.ubuntu.pool.ntp.org 3.ubuntu.pool.ntp.org diff --git a/templates/fix_logfile_perms.sh.j2 b/templates/fix_logfile_perms.sh.j2 new file mode 100644 index 0000000..e93d459 --- /dev/null +++ b/templates/fix_logfile_perms.sh.j2 @@ -0,0 +1,50 @@ +#!/bin/bash +# CIS Ubuntu 24.04 - 6.1.4.1 Ensure access to all logfiles has been configured. +# Adaptation simplifiee du script officiel CIS pour Ubuntu (retire les cas RHEL/SSSD/gdm +# non pertinents ici). Ne fait que RESTREINDRE les permissions, jamais les elargir. + +set -u + +fix_file() { + local f="$1" perm_mask="$2" rperms="$3" auser="$4" agroup="$5" + local mode user group + read -r mode user group < <(stat -Lc '%#a %U %G' "$f" 2>/dev/null) + [ -z "${mode:-}" ] && return + if [ $(( mode & perm_mask )) -gt 0 ]; then + chmod "$rperms" "$f" + fi + if [[ ! "$user" =~ ^($auser)$ ]]; then + chown root "$f" + fi + if [[ ! "$group" =~ ^($agroup)$ ]]; then + chgrp root "$f" + fi +} + +while IFS= read -r -d '' file; do + base="$(basename "$file")" + dir="$(dirname "$file")" + case "$base" in + lastlog|lastlog.*|wtmp|wtmp.*|wtmp-*|btmp|btmp.*|btmp-*) + # group-write tolere : necessaire au bon fonctionnement de last/who/lastlog + # (groupe utmp) — plus strict casserait ces commandes, ecart assume vs le + # check SCA generique qui ne distingue pas ces fichiers. + fix_file "$file" 0113 "ug-x,o-wx" "root" "root|utmp" + ;; + README) + fix_file "$file" 0137 "u-x,g-wx,o-rwx" "root" "root|adm" + ;; + *.journal|*.journal~) + fix_file "$file" 0137 "u-x,g-wx,o-rwx" "root" "root|systemd-journal" + ;; + *) + if [[ "$dir" == *"/apt" ]]; then + fix_file "$file" 0137 "u-x,g-wx,o-rwx" "root" "root|adm" + else + fix_file "$file" 0137 "u-x,g-wx,o-rwx" "root|syslog" "root|adm" + fi + ;; + esac +done < <(find -L /var/log -type f \( -perm /0137 -o ! -user root -o ! -group root \) -print0 2>/dev/null) + +echo "OK"