first commit
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
---
|
||||
# Durcissement CIS Ubuntu 24.04 — AIDE (integrite fichiers) installe + verification quotidienne
|
||||
# (checks 35758, 35759)
|
||||
#
|
||||
# IMPORTANT : /var/lib/docker (images/layers/volumes), les donnees de bases de donnees
|
||||
# (postgresql, redis), wazuh-indexer, clamav et /var/log/audit sont exclus AVANT le premier
|
||||
# aideinit — sans ca, le scan initial serait tres long et generait des faux positifs
|
||||
# quotidiens (ces donnees changent en permanence par nature, leur integrite est geree par
|
||||
# leurs propres mecanismes, pas par un FIM au niveau fichier).
|
||||
#
|
||||
# `aideinit` peut prendre plusieurs minutes (hash de la quasi-totalite du systeme de
|
||||
# fichiers) — pas de reboot necessaire, mais consommation CPU/IO notable pendant le scan.
|
||||
#
|
||||
# `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-aide-hardening.yml --limit pre-prod-uber
|
||||
|
||||
- name: Durcissement AIDE - integrite fichiers (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:
|
||||
- name: Installer aide et aide-common
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- aide
|
||||
- aide-common
|
||||
state: present
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Deployer les exclusions specifiques infra (avant le premier scan)
|
||||
ansible.builtin.template:
|
||||
src: ../templates/72_aide_infra_excludes.j2
|
||||
dest: /etc/aide/aide.conf.d/72_aide_infra_excludes
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Verifier si une base AIDE existe deja
|
||||
ansible.builtin.stat:
|
||||
path: /var/lib/aide/aide.db
|
||||
register: aide_db
|
||||
|
||||
- name: Initialiser la base AIDE (aideinit) — peut prendre plusieurs minutes
|
||||
ansible.builtin.command:
|
||||
cmd: aideinit -y -f
|
||||
when: not aide_db.stat.exists
|
||||
changed_when: true
|
||||
|
||||
- name: Activer et demarrer la verification quotidienne (dailyaidecheck.timer)
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ item }}"
|
||||
masked: false
|
||||
enabled: true
|
||||
state: started
|
||||
loop:
|
||||
- dailyaidecheck.service
|
||||
- dailyaidecheck.timer
|
||||
|
||||
- name: Verifier l'etat final
|
||||
ansible.builtin.command:
|
||||
cmd: systemctl show dailyaidecheck.timer -p LoadState,ActiveState
|
||||
register: aide_timer_check
|
||||
changed_when: false
|
||||
failed_when: >
|
||||
'LoadState=loaded' not in aide_timer_check.stdout or
|
||||
'ActiveState=active' not in aide_timer_check.stdout
|
||||
|
||||
- name: Confirmer le succes pour cet host
|
||||
ansible.builtin.debug:
|
||||
msg: "✅ AIDE installé et vérification quotidienne active sur {{ inventory_hostname }}."
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
# Durcissement CIS Ubuntu 24.04 — AppArmor installe, active au boot, tous les profils enforcing
|
||||
# (checks 35536-35539)
|
||||
#
|
||||
# CONTEXTE (verifie manuellement avant deploiement) : sur cette infra, apparmor_status montre
|
||||
# des dizaines de profils en mode "unconfined"/"complain" qui correspondent tous a des paquets
|
||||
# desktop jamais utilises sur des serveurs headless (navigateurs, Discord, Steam, transmission,
|
||||
# runtimes conteneurs standalone comme runc/crun/podman non utilises directement — Docker confine
|
||||
# deja ses containers via le profil "docker-default", separe et deja enforce). Aucun process
|
||||
# reellement actif n'est concerne par le passage en enforce de ces profils inutilises.
|
||||
#
|
||||
# IMPORTANT GRUB : /etc/default/grub contient deja "audit=1 audit_backlog_limit=8192"
|
||||
# (playbook-coredump-auditd-hardening.yml) — ce playbook AJOUTE apparmor=1 security=apparmor
|
||||
# a la suite, ne remplace jamais la ligne existante.
|
||||
#
|
||||
# `aa-enforce /etc/apparmor.d/*` s'applique a chaud (pas de redemarrage necessaire pour le
|
||||
# check CIS lui-meme), mais comme pour audit=1, le parametre GRUB apparmor=1/security=apparmor
|
||||
# necessite un redemarrage pour etre reellement actif au niveau noyau (le check 35537 passe
|
||||
# immediatement car il inspecte /etc/default/grub, pas l'etat runtime).
|
||||
#
|
||||
# `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-apparmor-hardening.yml --limit pre-prod-uber
|
||||
|
||||
- name: Durcissement AppArmor (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:
|
||||
- name: Installer apparmor et apparmor-utils
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- apparmor
|
||||
- apparmor-utils
|
||||
state: present
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Sauvegarder /etc/default/grub avant modification
|
||||
ansible.builtin.copy:
|
||||
src: /etc/default/grub
|
||||
dest: /etc/default/grub.bak-cis-apparmor
|
||||
remote_src: true
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Ajouter apparmor=1 security=apparmor a GRUB_CMDLINE_LINUX (sans ecraser audit=1 existant)
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
if ! grep -q 'apparmor=1' /etc/default/grub; then
|
||||
sed -i 's/^\(GRUB_CMDLINE_LINUX="[^"]*\)"/\1 apparmor=1 security=apparmor"/' /etc/default/grub
|
||||
echo CHANGED
|
||||
fi
|
||||
register: grub_conf
|
||||
changed_when: "'CHANGED' in grub_conf.stdout"
|
||||
|
||||
- name: Regenerer grub.cfg si la config a change
|
||||
ansible.builtin.command:
|
||||
cmd: update-grub
|
||||
when: grub_conf.changed
|
||||
changed_when: true
|
||||
|
||||
- name: Forcer tous les profils AppArmor en mode enforce
|
||||
ansible.builtin.command:
|
||||
cmd: aa-enforce /etc/apparmor.d/*
|
||||
changed_when: true
|
||||
|
||||
- name: Verifier l'etat final (apparmor_status)
|
||||
ansible.builtin.command:
|
||||
cmd: apparmor_status
|
||||
register: aa_status
|
||||
changed_when: false
|
||||
failed_when: >
|
||||
'profiles are in complain mode' in aa_status.stdout and
|
||||
not (aa_status.stdout | regex_search('^0\s*profiles are in complain mode', multiline=True))
|
||||
|
||||
- name: Confirmer le succes pour cet host
|
||||
ansible.builtin.debug:
|
||||
msg: "✅ AppArmor durci sur {{ inventory_hostname }} — reboot requis pour apparmor=1/security=apparmor au niveau noyau."
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
# Regles d'audit detaillees restantes (CIS 6.2.3.4-6.2.3.19) — appliquees a chaud, pas de reboot
|
||||
#
|
||||
# PREREQUIS : hardening/playbook-coredump-auditd-hardening.yml (auditd) et
|
||||
# hardening/playbook-audit-rules-sudo-omnex.yml deja appliques.
|
||||
#
|
||||
# Couvre : date/heure, environnement reseau, acces fichier echoues, user/group (identity),
|
||||
# permissions DAC (chmod/chown/xattr), montages, sessions, login/logout, suppressions fichiers,
|
||||
# politique MAC (AppArmor), commandes chcon/setfacl/chacl/usermod, modules noyau.
|
||||
#
|
||||
# UID_MIN lu dynamiquement depuis /etc/login.defs de chaque host (1000 sur cette infra, mais
|
||||
# pas suppose en dur pour rester correct si un host differe).
|
||||
#
|
||||
# `augenrules --load` recharge a chaud : PAS de redemarrage necessaire tant que le mode
|
||||
# immutable (-e 2, check 35749) n'est pas active — volontairement PAS fait par ce playbook.
|
||||
#
|
||||
# `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-audit-rules-cis-rest.yml --limit pre-prod-uber
|
||||
|
||||
- name: Regles d'audit detaillees restantes CIS 6.2.3.x (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:
|
||||
- name: Lire UID_MIN depuis /etc/login.defs
|
||||
ansible.builtin.command:
|
||||
cmd: awk '/^\s*UID_MIN/{print $2}' /etc/login.defs
|
||||
register: uid_min_result
|
||||
changed_when: false
|
||||
|
||||
- name: Deployer les regles d'audit CIS restantes
|
||||
ansible.builtin.template:
|
||||
src: ../templates/audit-52-cis-rest.rules.j2
|
||||
dest: /etc/audit/rules.d/52-cis-rest.rules
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0640"
|
||||
vars:
|
||||
uid_min: "{{ uid_min_result.stdout }}"
|
||||
register: cis_rest_rules
|
||||
|
||||
- name: Charger les nouvelles regles d'audit (augenrules --load)
|
||||
ansible.builtin.command:
|
||||
cmd: augenrules --load
|
||||
when: cis_rest_rules.changed
|
||||
changed_when: true
|
||||
|
||||
- name: Verifier que les cles principales sont actives (auditctl -l)
|
||||
ansible.builtin.command:
|
||||
cmd: auditctl -l
|
||||
register: auditctl_check
|
||||
changed_when: false
|
||||
failed_when: >
|
||||
'time-change' not in auditctl_check.stdout or
|
||||
'system-locale' not in auditctl_check.stdout or
|
||||
'identity' not in auditctl_check.stdout or
|
||||
'perm_mod' not in auditctl_check.stdout or
|
||||
'mounts' not in auditctl_check.stdout or
|
||||
'session' not in auditctl_check.stdout or
|
||||
'logins' not in auditctl_check.stdout or
|
||||
'delete' not in auditctl_check.stdout or
|
||||
'MAC-policy' not in auditctl_check.stdout or
|
||||
'perm_chng' not in auditctl_check.stdout or
|
||||
'usermod' not in auditctl_check.stdout or
|
||||
'kernel_modules' not in auditctl_check.stdout
|
||||
|
||||
- name: Confirmer le succes pour cet host
|
||||
ansible.builtin.debug:
|
||||
msg: "✅ Règles d'audit CIS 6.2.3.x restantes actives sur {{ inventory_hostname }} (UID_MIN={{ uid_min_result.stdout }}, pas de reboot requis)."
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
# Regles d'audit detaillees (CIS 6.2.3.1-6.2.3.3) — surveillance sudo + surveillance dediee omnex
|
||||
#
|
||||
# PREREQUIS : necessite hardening/playbook-coredump-auditd-hardening.yml deja applique
|
||||
# (auditd installe et actif).
|
||||
#
|
||||
# - Regles CIS standard : changements /etc/sudoers(.d), toute action "en tant qu'un autre
|
||||
# utilisateur" (execve avec euid!=uid, couvre sudo/su), modifications de /var/log/sudo.log.
|
||||
# - Regle custom omnex : capture TOUTE commande executee par omnex (execve filtre sur auid,
|
||||
# qui persiste a travers sudo/su, donc suit omnex meme apres elevation) — uniquement sur
|
||||
# les hosts ou l'utilisateur omnex existe (absent sur bdd-redis-prod/backup-mln, root direct).
|
||||
# - `augenrules --load` recharge la config a chaud : PAS besoin de redemarrage ici (contrairement
|
||||
# a audit=1 dans GRUB) tant que le mode immutable (-e 2) n'est pas active — volontairement pas
|
||||
# configure par ce playbook (risque : plus aucune modif de regle possible sans reboot).
|
||||
#
|
||||
# `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-audit-rules-sudo-omnex.yml --limit pre-prod-uber
|
||||
|
||||
- name: Regles d'audit detaillees - sudo + omnex (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:
|
||||
- name: Deployer les regles d'audit sudo (CIS 6.2.3.1-6.2.3.3)
|
||||
ansible.builtin.template:
|
||||
src: ../templates/audit-50-sudo.rules.j2
|
||||
dest: /etc/audit/rules.d/50-sudo.rules
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0640"
|
||||
register: sudo_rules
|
||||
|
||||
- name: Verifier si l'utilisateur omnex existe sur cet host
|
||||
ansible.builtin.getent:
|
||||
database: passwd
|
||||
key: omnex
|
||||
ignore_errors: true
|
||||
register: omnex_getent
|
||||
|
||||
- name: Deployer la regle d'audit dediee omnex (uniquement si l'utilisateur existe)
|
||||
ansible.builtin.template:
|
||||
src: ../templates/audit-51-omnex.rules.j2
|
||||
dest: /etc/audit/rules.d/51-omnex.rules
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0640"
|
||||
vars:
|
||||
omnex_uid: "{{ ansible_facts.getent_passwd.omnex[1] }}"
|
||||
when: omnex_getent is succeeded
|
||||
register: omnex_rules
|
||||
|
||||
- name: Charger les nouvelles regles d'audit (augenrules --load)
|
||||
ansible.builtin.command:
|
||||
cmd: augenrules --load
|
||||
when: sudo_rules.changed or (omnex_rules is defined and omnex_rules.changed)
|
||||
changed_when: true
|
||||
|
||||
- name: Verifier que les regles sudo sont bien actives (auditctl -l)
|
||||
ansible.builtin.command:
|
||||
cmd: auditctl -l
|
||||
register: auditctl_check
|
||||
changed_when: false
|
||||
failed_when: >
|
||||
'scope' not in auditctl_check.stdout or
|
||||
'user_emulation' not in auditctl_check.stdout or
|
||||
'sudo_log_file' not in auditctl_check.stdout
|
||||
|
||||
- name: Verifier que la regle omnex est active (si applicable)
|
||||
ansible.builtin.command:
|
||||
cmd: auditctl -l
|
||||
register: auditctl_omnex_check
|
||||
changed_when: false
|
||||
when: omnex_getent is succeeded
|
||||
failed_when: "'omnex_actions' not in auditctl_omnex_check.stdout"
|
||||
|
||||
- name: Confirmer le succes pour cet host
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
✅ Règles d'audit sudo{{ ' + omnex' if omnex_getent is succeeded else '' }}
|
||||
actives sur {{ inventory_hostname }} (auditctl -l vérifié, pas de reboot requis).
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
# Durcissement CIS Ubuntu 24.04 — core dumps restreints, Apport désactivé, auditd installé/actif
|
||||
# (checks 35543, 35545, 35723-35726, 35756, 35757)
|
||||
#
|
||||
# IMPORTANT — REBOOT :
|
||||
# - audit=1 et audit_backlog_limit=8192 sont ajoutés à /etc/default/grub puis `update-grub`
|
||||
# régénère immédiatement /boot/grub/grub.cfg → les checks CIS 35725/35726 passent au VERT
|
||||
# dès ce playbook exécuté (ils inspectent le fichier grub.cfg généré, pas le noyau en cours
|
||||
# d'exécution).
|
||||
# - MAIS la protection réelle (auditer les process qui démarrent avant auditd) ne prend effet
|
||||
# qu'après un REDÉMARRAGE du serveur (le paramètre kernel n'est actif qu'au prochain boot).
|
||||
# Ce playbook NE redémarre PAS automatiquement les serveurs — décision à prendre séparément,
|
||||
# en fenêtre de maintenance, host par host (impact Docker/VPN/prod public à chaque reboot).
|
||||
#
|
||||
# - apport est PURGÉ (pas juste désactivé) : cohérent avec le choix déjà fait pour rsync/telnet/ftp
|
||||
# dans ce même chantier. apport-core-dump-handler et python3-apport partent avec (dépendances),
|
||||
# sans impact sur les services applicatifs de cette infra (aucun ne dépend d'apport).
|
||||
#
|
||||
# `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-coredump-auditd-hardening.yml --limit pre-prod-uber
|
||||
|
||||
- name: Durcissement core dumps + apport + auditd (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:
|
||||
# --- 1.5.3 Core dumps restreints ---
|
||||
- name: Deployer fs.suid_dumpable=0
|
||||
ansible.builtin.template:
|
||||
src: ../templates/60-cis-coredump-sysctl.conf.j2
|
||||
dest: /etc/sysctl.d/60-cis-coredump-sysctl.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
register: coredump_sysctl
|
||||
|
||||
- name: Appliquer fs.suid_dumpable
|
||||
ansible.builtin.command:
|
||||
cmd: sysctl --system
|
||||
when: coredump_sysctl.changed
|
||||
changed_when: true
|
||||
|
||||
- name: Deployer la limite hard core 0
|
||||
ansible.builtin.template:
|
||||
src: ../templates/60-cis-coredump-limits.conf.j2
|
||||
dest: /etc/security/limits.d/60-cis-coredump.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
# --- 1.5.5 Apport (Automatic Error Reporting) ---
|
||||
- name: Purger apport (et ses dependances python3-apport, apport-core-dump-handler)
|
||||
ansible.builtin.apt:
|
||||
name: apport
|
||||
state: absent
|
||||
purge: true
|
||||
|
||||
# --- 6.2.1.x auditd ---
|
||||
- name: Installer auditd et audispd-plugins
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- auditd
|
||||
- audispd-plugins
|
||||
state: present
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Demasquer, activer et demarrer auditd
|
||||
ansible.builtin.systemd:
|
||||
name: auditd
|
||||
masked: false
|
||||
enabled: true
|
||||
state: started
|
||||
|
||||
- name: Verifier la presence de audit=1 dans GRUB_CMDLINE_LINUX
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/default/grub
|
||||
regexp: '^GRUB_CMDLINE_LINUX='
|
||||
line: 'GRUB_CMDLINE_LINUX="audit=1 audit_backlog_limit=8192"'
|
||||
backup: true
|
||||
register: grub_conf
|
||||
|
||||
- name: Regenerer grub.cfg si la config a change
|
||||
ansible.builtin.command:
|
||||
cmd: update-grub
|
||||
when: grub_conf.changed
|
||||
changed_when: true
|
||||
|
||||
- name: Verifier que audit=1 est bien present dans grub.cfg genere
|
||||
ansible.builtin.command:
|
||||
cmd: grep -q 'audit=1' /boot/grub/grub.cfg
|
||||
changed_when: false
|
||||
|
||||
# --- 6.2.4.9 / 6.2.4.10 Ownership des outils d'audit ---
|
||||
- name: Proprietaire/groupe root:root sur les outils d'audit
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
owner: root
|
||||
group: root
|
||||
loop:
|
||||
- /sbin/auditctl
|
||||
- /sbin/aureport
|
||||
- /sbin/ausearch
|
||||
- /sbin/autrace
|
||||
- /sbin/auditd
|
||||
- /sbin/augenrules
|
||||
ignore_errors: true # certains binaires peuvent etre des symlinks vers /usr/sbin selon la distro
|
||||
|
||||
- name: Confirmer le succes pour cet host
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
✅ Core dumps/apport/auditd appliqués sur {{ inventory_hostname }}.
|
||||
REDÉMARRAGE requis pour que audit=1 protège les process pré-auditd (non fait par ce playbook).
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
# Durcissement CIS Ubuntu 24.04 — retrait rsync/telnet/ftp + permissions cron + cron.allow/at.allow
|
||||
# (checks 35573, 35585, 35587, 35594-35601)
|
||||
#
|
||||
# IMPORTANT :
|
||||
# - rsync/telnet/ftp verifies avant retrait sur cette infra : aucun daemon actif, aucun cron/script
|
||||
# n'en dependait (grep sur les crontabs + scripts de backup). Purge sans risque constate.
|
||||
# - Le paquet 'at' n'est PAS installe sur cette infra et ce playbook ne l'installe PAS : ajouter un
|
||||
# service juste pour le verrouiller ensuite serait contre-productif (surface d'attaque en plus
|
||||
# pour un compliance-checkbox). /etc/at.allow est quand meme cree en defense en profondeur, mais
|
||||
# le check CIS 35601 restera en echec par ce choix assume tant que 'at' n'est pas installe.
|
||||
# - /etc/cron.allow doit avoir owner:group EXACTEMENT root:root pour satisfaire le check automatise
|
||||
# 35600 — la documentation CIS mentionne le groupe "crontab" comme alternative acceptable, mais la
|
||||
# regex du check SCA (`r:^root root$`) n'accepte que root:root en pratique (verifie empiriquement).
|
||||
#
|
||||
# `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-cron-packages-hardening.yml --limit pre-prod-uber
|
||||
|
||||
- name: Durcissement cron/at + retrait paquets insecurises (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:
|
||||
- name: Purger rsync, telnet et ftp (clients/services insecurises)
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- rsync
|
||||
- telnet
|
||||
- inetutils-telnet
|
||||
- ftp
|
||||
- tnftp
|
||||
state: absent
|
||||
purge: true
|
||||
|
||||
- name: Permissions /etc/crontab (0600 root:root)
|
||||
ansible.builtin.file:
|
||||
path: /etc/crontab
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0600"
|
||||
|
||||
- name: Permissions repertoires cron (0700 root:root)
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0700"
|
||||
loop:
|
||||
- /etc/cron.hourly
|
||||
- /etc/cron.daily
|
||||
- /etc/cron.weekly
|
||||
- /etc/cron.monthly
|
||||
- /etc/cron.d
|
||||
|
||||
- name: Verifier si /etc/cron.deny existe
|
||||
ansible.builtin.stat:
|
||||
path: /etc/cron.deny
|
||||
register: cron_deny
|
||||
|
||||
- name: Creer /etc/cron.allow (crontab restreint aux utilisateurs autorises)
|
||||
ansible.builtin.file:
|
||||
path: /etc/cron.allow
|
||||
state: touch
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0640"
|
||||
access_time: preserve
|
||||
modification_time: preserve
|
||||
when: not cron_deny.stat.exists
|
||||
|
||||
- name: Permissions /etc/cron.deny si present
|
||||
ansible.builtin.file:
|
||||
path: /etc/cron.deny
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0640"
|
||||
when: cron_deny.stat.exists
|
||||
|
||||
- name: Creer /etc/at.allow (defense en profondeur, meme si 'at' non installe)
|
||||
ansible.builtin.file:
|
||||
path: /etc/at.allow
|
||||
state: touch
|
||||
owner: root
|
||||
group: daemon
|
||||
mode: "0640"
|
||||
access_time: preserve
|
||||
modification_time: preserve
|
||||
|
||||
- name: Confirmer le succes pour cet host
|
||||
ansible.builtin.debug:
|
||||
msg: "✅ Durcissement cron/paquets appliqué sur {{ inventory_hostname }}"
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
# Durcissement CIS Ubuntu 24.04 — modules noyau reseau/filesystem inutilises + sysctl reseau
|
||||
# (checks 35509, 35604-35607, 35608-35618)
|
||||
#
|
||||
# IMPORTANT :
|
||||
# - net.ipv4.ip_forward est laisse ACTIF sur la plupart des hosts (Docker gere le NAT des ports
|
||||
# publies, vpn-uber fait relais entre pairs WireGuard) — le desactiver casserait ces usages.
|
||||
# Seul load-balancer (pas de Docker, pas de relais VPN) le desactive, via la variable
|
||||
# `ip_forwarding_disabled` (group_vars, defaut false, true uniquement pour load-balancer).
|
||||
# Le check CIS 35608 restera donc en echec par necessite fonctionnelle sur la plupart des hosts.
|
||||
# - rp_filter est mis a 1 (strict) partout : verifie sans casse sur cette infra (Docker + WireGuard
|
||||
# coexistent sans probleme de routage asymetrique ici), mais a re-tester si la topologie change.
|
||||
# - Aucun des modules blacklistes n'est charge sur cette infra (verifie via lsmod avant deploiement) :
|
||||
# zero impact fonctionnel attendu. Exception : fat/fuse sont compiles en dur dans le noyau Ubuntu
|
||||
# (builtin) et resteront "disponibles" quoi qu'il arrive — check CIS 35509 restera en echec pour
|
||||
# ces deux modules specifiquement, cas documente par la CIS elle-meme comme sans remediation
|
||||
# possible ("if pre-compiled into the kernel, no remediation is necessary").
|
||||
#
|
||||
# `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-kernel-sysctl-hardening.yml --limit pre-prod-uber
|
||||
|
||||
- name: Durcissement kernel modules + sysctl reseau (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:
|
||||
- name: Deployer le blacklist des modules noyau inutilises
|
||||
ansible.builtin.template:
|
||||
src: ../templates/blacklist-unused-modules.conf.j2
|
||||
dest: /etc/modprobe.d/cis-blacklist-unused.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Deployer le durcissement sysctl reseau
|
||||
ansible.builtin.template:
|
||||
src: ../templates/60-cis-network-hardening.conf.j2
|
||||
dest: /etc/sysctl.d/60-cis-network-hardening.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
register: sysctl_conf
|
||||
|
||||
- name: Appliquer les parametres sysctl actifs
|
||||
ansible.builtin.command:
|
||||
cmd: sysctl --system
|
||||
when: sysctl_conf.changed
|
||||
changed_when: true
|
||||
register: sysctl_apply
|
||||
|
||||
- name: Verifier qu'aucune erreur n'est remontee par sysctl --system
|
||||
ansible.builtin.fail:
|
||||
msg: "Erreur sysctl --system sur {{ inventory_hostname }} : {{ sysctl_apply.stdout }}"
|
||||
when: sysctl_apply is defined and sysctl_apply.stdout is defined and 'error' in sysctl_apply.stdout | lower
|
||||
|
||||
- name: Verifier la valeur effective de ip_forward
|
||||
ansible.builtin.command:
|
||||
cmd: sysctl -n net.ipv4.ip_forward
|
||||
register: ip_forward_check
|
||||
changed_when: false
|
||||
failed_when: >
|
||||
(not (ip_forwarding_disabled | default(false)) and ip_forward_check.stdout != "1") or
|
||||
((ip_forwarding_disabled | default(false)) and ip_forward_check.stdout != "0")
|
||||
|
||||
- name: Confirmer le succes pour cet host
|
||||
ansible.builtin.debug:
|
||||
msg: "✅ Durcissement kernel/sysctl appliqué sur {{ inventory_hostname }} — ip_forward={{ ip_forward_check.stdout }}"
|
||||
@@ -0,0 +1,175 @@
|
||||
---
|
||||
# Durcissement PAM (CIS Ubuntu 24.04 — pam_faillock, pam_pwquality, pam_pwhistory)
|
||||
#
|
||||
# IMPORTANT — à lire avant d'exécuter :
|
||||
# - Ce playbook touche l'authentification (sudo/su) sur TOUS les hosts ciblés.
|
||||
# Une erreur dans un profil pam-auth-update peut casser sudo partout.
|
||||
# - `serial: 1` traite un host à la fois : si un host casse, le run s'arrête
|
||||
# avant de toucher les suivants (any_errors_fatal).
|
||||
# - La dernière tâche force un reset du cache sudo (`sudo -K`) puis revalide
|
||||
# un `become` réel, pour détecter une casse immédiatement plutôt que de la
|
||||
# découvrir 15 min plus tard quand le cache sudo normal expire.
|
||||
# - Volontairement AUCUNE expiration de mot de passe n'est appliquée sur les
|
||||
# comptes existants (omnex/root) : ces comptes se connectent en SSH par clé
|
||||
# (jamais par mot de passe), donc le mécanisme d'expiration PAM — qui ne se
|
||||
# déclenche qu'au moment d'un prompt de mot de passe au login — ne se
|
||||
# déclencherait jamais, et une expiration silencieuse casserait `sudo` sans
|
||||
# aucun moyen interactif de le corriger à distance. PASS_MAX_DAYS n'est posé
|
||||
# que dans /etc/login.defs (valeur par défaut pour les FUTURS comptes), pas
|
||||
# rétroactivement via chage.
|
||||
#
|
||||
# Usage recommandé : tester d'abord sur UN seul host avant le rollout complet :
|
||||
# ansible-playbook infra/playbook-pam-hardening.yml --limit pre-prod-uber
|
||||
#
|
||||
- name: Durcissement PAM (CIS Ubuntu 24.04)
|
||||
hosts: bdd-redis-prod
|
||||
become: true
|
||||
serial: 1
|
||||
any_errors_fatal: true
|
||||
vars:
|
||||
pam_faillock_deny: 5
|
||||
pam_faillock_unlock_time: 900
|
||||
pam_faillock_fail_interval: 900
|
||||
pam_pwquality_minlen: 16
|
||||
pam_pwquality_difok: 8
|
||||
pam_pwhistory_remember: 24
|
||||
|
||||
tasks:
|
||||
- name: Installer libpam-pwquality
|
||||
ansible.builtin.apt:
|
||||
name: libpam-pwquality
|
||||
state: present
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Sauvegarder l'état PAM actuel avant modification
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
BACKUP_DIR="/root/pam-backup-$(date +%Y%m%d%H%M%S)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
cp -a /etc/pam.d "$BACKUP_DIR/"
|
||||
cp -a /usr/share/pam-configs "$BACKUP_DIR/"
|
||||
cp /etc/login.defs "$BACKUP_DIR/" 2>/dev/null || true
|
||||
[ -f /etc/security/faillock.conf ] && cp /etc/security/faillock.conf "$BACKUP_DIR/" || true
|
||||
[ -f /etc/security/pwquality.conf ] && cp /etc/security/pwquality.conf "$BACKUP_DIR/" || true
|
||||
echo "$BACKUP_DIR"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
register: pam_backup
|
||||
|
||||
- name: Afficher le chemin de sauvegarde (rollback manuel possible)
|
||||
ansible.builtin.debug:
|
||||
msg: "Backup PAM : {{ pam_backup.stdout }}"
|
||||
|
||||
- name: Déployer le profil unix (retire nullok, garde use_authtok)
|
||||
ansible.builtin.template:
|
||||
src: ../templates/pam-configs-unix.j2
|
||||
dest: /usr/share/pam-configs/unix
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
register: pam_unix_profile
|
||||
|
||||
- name: Déployer le profil faillock (authfail)
|
||||
ansible.builtin.template:
|
||||
src: ../templates/pam-configs-faillock.j2
|
||||
dest: /usr/share/pam-configs/faillock
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
register: pam_faillock_profile
|
||||
|
||||
- name: Déployer le profil faillock_notify (preauth + account)
|
||||
ansible.builtin.template:
|
||||
src: ../templates/pam-configs-faillock-notify.j2
|
||||
dest: /usr/share/pam-configs/faillock_notify
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
register: pam_faillock_notify_profile
|
||||
|
||||
- name: Déployer le profil pwquality
|
||||
ansible.builtin.template:
|
||||
src: ../templates/pam-configs-pwquality.j2
|
||||
dest: /usr/share/pam-configs/pwquality
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
register: pam_pwquality_profile
|
||||
|
||||
- name: Déployer le profil pwhistory
|
||||
ansible.builtin.template:
|
||||
src: ../templates/pam-configs-pwhistory.j2
|
||||
dest: /usr/share/pam-configs/pwhistory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
register: pam_pwhistory_profile
|
||||
|
||||
- name: Déployer /etc/security/faillock.conf
|
||||
ansible.builtin.template:
|
||||
src: ../templates/faillock.conf.j2
|
||||
dest: /etc/security/faillock.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Déployer /etc/security/pwquality.conf
|
||||
ansible.builtin.template:
|
||||
src: ../templates/pwquality.conf.j2
|
||||
dest: /etc/security/pwquality.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Activer les profils PAM (regénère common-auth/common-account/common-password)
|
||||
ansible.builtin.command:
|
||||
cmd: pam-auth-update --enable faillock --enable faillock_notify --enable pwquality --enable pwhistory
|
||||
when: >
|
||||
pam_unix_profile.changed or pam_faillock_profile.changed or
|
||||
pam_faillock_notify_profile.changed or pam_pwquality_profile.changed or
|
||||
pam_pwhistory_profile.changed
|
||||
changed_when: true
|
||||
|
||||
- name: Configurer PASS_MAX_DAYS dans login.defs (nouveaux comptes uniquement)
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/login.defs
|
||||
regexp: '^PASS_MAX_DAYS'
|
||||
line: "PASS_MAX_DAYS\t365"
|
||||
|
||||
- name: Configurer PASS_MIN_DAYS dans login.defs
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/login.defs
|
||||
regexp: '^PASS_MIN_DAYS'
|
||||
line: "PASS_MIN_DAYS\t1"
|
||||
|
||||
- name: Configurer PASS_WARN_AGE dans login.defs
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/login.defs
|
||||
regexp: '^PASS_WARN_AGE'
|
||||
line: "PASS_WARN_AGE\t7"
|
||||
|
||||
- name: Verrouillage par défaut des comptes inactifs (nouveaux comptes)
|
||||
ansible.builtin.command:
|
||||
cmd: useradd -D -f 30
|
||||
changed_when: true
|
||||
|
||||
# --- Vérification critique : la stack PAM fonctionne-t-elle toujours ? ---
|
||||
# On invalide le cache sudo existant pour forcer une vraie ré-authentification
|
||||
# PAM, sinon un sudo déjà "chaud" masquerait une stack cassée pendant 15 min.
|
||||
- name: Invalider le cache sudo pour forcer une vraie revalidation PAM
|
||||
ansible.builtin.command:
|
||||
cmd: sudo -K
|
||||
become: false
|
||||
changed_when: false
|
||||
|
||||
- name: Vérifier que sudo fonctionne toujours avec la nouvelle stack PAM
|
||||
ansible.builtin.command:
|
||||
cmd: whoami
|
||||
register: pam_sudo_check
|
||||
failed_when: pam_sudo_check.stdout != "root"
|
||||
|
||||
- name: Confirmer le succès pour cet host
|
||||
ansible.builtin.debug:
|
||||
msg: "✅ PAM durci avec succès sur {{ inventory_hostname }} — sudo toujours fonctionnel."
|
||||
@@ -0,0 +1,76 @@
|
||||
- name: SSH HARDENNING
|
||||
hosts: load-balancer
|
||||
become: true
|
||||
gather_facts: true
|
||||
tasks:
|
||||
- name: Créer le groupe ssh
|
||||
ansible.builtin.group:
|
||||
name: ssh
|
||||
state: present
|
||||
|
||||
- ansible.builtin.user:
|
||||
name: "{{ user_ssh }}"
|
||||
shell: /bin/bash
|
||||
groups:
|
||||
- sudo
|
||||
- ssh
|
||||
append: true
|
||||
state: present
|
||||
password: "{{ password_user_ssh }}"
|
||||
update_password: on_create
|
||||
create_home: true
|
||||
home: /home/omnex
|
||||
no_log: true
|
||||
|
||||
- name: Check si la paire de clé SSH existe
|
||||
ansible.builtin.stat:
|
||||
path: "{{ playbook_dir }}/../../.ssh/{{ user_ssh }}"
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
register: ssh_key_check
|
||||
tags: [key]
|
||||
|
||||
- name: Générer la paire de clés SSH localement
|
||||
community.crypto.openssh_keypair:
|
||||
path: "{{ playbook_dir }}/../../.ssh/{{ user_ssh }}"
|
||||
type: ed25519
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
when: not ssh_key_check.stat.exists
|
||||
run_once: true
|
||||
tags: [key]
|
||||
|
||||
- ansible.posix.authorized_key:
|
||||
user: "{{ user_ssh }}"
|
||||
state: present
|
||||
key: "{{ lookup('file', playbook_dir + '/../../.ssh/' + user_ssh + '.pub') }}"
|
||||
|
||||
- name: Déployer la config sshd durcie
|
||||
ansible.builtin.template:
|
||||
src: ../templates/ssh_harden_conf.j2
|
||||
dest: /etc/ssh/sshd_config
|
||||
mode: "0644"
|
||||
owner: root
|
||||
group: root
|
||||
validate: /usr/sbin/sshd -t -f %s
|
||||
notify: restart ssh
|
||||
|
||||
- name: Delete cloud ssh config if exists
|
||||
ansible.builtin.file:
|
||||
path: /etc/ssh/sshd_config.d/60-cloudimg-settings.conf
|
||||
state: absent
|
||||
|
||||
- name: Déployer la config cloud-init durcie
|
||||
ansible.builtin.template:
|
||||
src: ../templates/cloud_harden.conf.j2
|
||||
dest: /etc/ssh/sshd_config.d/60-cloudimg-settings.conf
|
||||
mode: "0644"
|
||||
owner: root
|
||||
group: root
|
||||
notify: restart ssh
|
||||
|
||||
handlers:
|
||||
- name: restart ssh
|
||||
ansible.builtin.service:
|
||||
name: ssh
|
||||
state: restarted
|
||||
Reference in New Issue
Block a user