22. Hardening systèmes et benchmarks CIS#

Le hardening consiste à réduire la surface d’attaque d’un système en appliquant un ensemble de configurations sécurisées, en désactivant les fonctionnalités inutiles et en renforçant les mécanismes d’authentification et de contrôle d’accès. Les benchmarks CIS (Center for Internet Security) fournissent la référence industrielle la plus utilisée pour guider ces efforts.

CIS Benchmarks#

Le CIS publie des guides de configuration pour plus de 100 technologies : systèmes d’exploitation, bases de données, navigateurs, cloud, conteneurs, équipements réseau.

Structure : Niveau 1 et Niveau 2#

Niveau

Profil

Description

Niveau 1

Pratique standard

Recommandations applicables à tout environnement, impact opérationnel minimal, conformité large

Niveau 2

Haute sécurité

Recommandations pour environnements à haute sensibilité (défense, finance), peut impacter l’usabilité

CIS Benchmark Ubuntu Linux — catégories principales#

Système de fichiers : montage avec options restrictives (noexec, nodev, nosuid), désactivation des systèmes de fichiers inutiles (cramfs, squashfs, udf).

Packages et services : suppression des services non nécessaires (CUPS, Avahi, NFS si non utilisé), désactivation du démarrage automatique.

Réseau : paramètres sysctl (désactivation du routage IP, protection SYN flood, désactivation des redirections ICMP), pare-feu UFW/nftables.

Authentification : politique de mots de passe (/etc/login.defs), verrouillage après échecs (PAM faillock), SSH durci (PermitRootLogin no, PasswordAuthentication no, Protocol 2).

Audit : auditd configuré pour tracer les accès privilégiés, modifications de fichiers sensibles, connexions.

Intégrité : AIDE (Advanced Intrusion Detection Environment) ou Tripwire pour la surveillance des modifications de fichiers.

CIS Benchmark Docker#

  • Image de base minimale (distroless ou Alpine)

  • Daemon Docker non exposé sur TCP sans TLS

  • Conteneurs exécutés sans --privileged

  • Utilisateur non-root dans le conteneur

  • Capabilities limitées (--cap-drop=ALL --cap-add=...)

  • Lecture seule du système de fichiers racine (--read-only)

  • Profil seccomp et AppArmor activés

  • Pas de montage du socket Docker dans les conteneurs

CIS Benchmark Kubernetes#

  • RBAC activé et principe du moindre privilège

  • Network Policies pour segmenter les pods

  • PodSecurityAdmission (successeur de PodSecurityPolicy)

  • Secrets chiffrés au repos dans etcd

  • Audit logging du serveur API

  • Rotation des certificats

  • Namespaces isolés par équipe/application


Lynis — audit de sécurité Linux#

Lynis est un outil d’audit de sécurité open-source pour les systèmes Unix/Linux. Il vérifie plusieurs centaines de points de contrôle et produit un score de durcissement (Hardening Index, 0 à 100).

# Installation
apt install lynis  # ou téléchargement depuis cisofy.com

# Audit système complet
lynis audit system

# Audit silencieux (pour scripts/CI)
lynis audit system --quiet --no-colors

# Audit avec profil personnalisé
lynis audit system --profile /etc/lynis/custom.prf

# Voir les résultats
lynis show details KRNL-5820  # Détails d'un test spécifique

Catégories auditées :

  • AUTH : authentification (PAM, sudo, SSH)

  • NETW : réseau (interfaces, services ouverts, pare-feu)

  • FILE : intégrité des fichiers et permissions

  • MALW : présence d’outils antimalware

  • CRYP : configuration TLS/SSL

  • KRNL : paramètres kernel (sysctl)

  • LOGG : configuration des logs et auditd

Interprétation du Hardening Index :

  • 0 – 49 : sécurité insuffisante

  • 50 – 74 : niveau acceptable pour environnement non critique

  • 75 – 89 : bon niveau, hardening avancé en place

  • 90 – 100 : niveau haute sécurité (rare en production)

Lynis en CI/CD

Intégrer Lynis dans un pipeline CI pour valider les images de base avant déploiement. Un score en dessous d’un seuil configuré bloque le déploiement. Utilisez lynis audit system --pentest pour une analyse non-root plus complète.


OpenSCAP — conformité automatisée#

SCAP (Security Content Automation Protocol) est un standard NIST pour l’automatisation de la vérification de conformité.

Composants SCAP :

  • XCCDF (Extensible Configuration Checklist Description Format) : liste de vérification structurée

  • OVAL (Open Vulnerability and Assessment Language) : tests de vérification automatisés

  • CPE (Common Platform Enumeration) : identification standardisée des plateformes

# Installation
dnf install openscap-scanner scap-security-guide  # RHEL/Fedora
apt install libopenscap8 ssg-debderived            # Debian/Ubuntu

# Lister les profils disponibles
oscap info /usr/share/xml/scap/ssg/content/ssg-ubuntu2204-ds.xml

# Évaluation contre le profil CIS Niveau 1
oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis_level1_server \
  --results /tmp/scan-results.xml \
  --report /tmp/scan-report.html \
  /usr/share/xml/scap/ssg/content/ssg-ubuntu2204-ds.xml

# Évaluation DISA STIG
oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_stig \
  --results /tmp/stig-results.xml \
  --report /tmp/stig-report.html \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

# Générer un script de remédiation Bash
oscap xccdf generate fix \
  --fix-type bash \
  --result-id "" \
  --output /tmp/remediation.sh \
  /tmp/scan-results.xml

Cycle de gestion des vulnérabilités#

La gestion des vulnérabilités est un processus continu, pas ponctuel.

Les cinq phases#

1. Discovery (Découverte) Inventaire complet des actifs (CMDB) et scan de vulnérabilités : Nessus, Qualys, OpenVAS/GVM, Trivy (conteneurs).

2. Assessment (Évaluation) Identification et qualification des vulnérabilités : CVE, score CVSS v3.1, contexte de l’actif, exposition réseau.

3. Prioritization (Priorisation) Tri par criticité réelle (CVSS + EPSS + contexte business), pas seulement par score brut.

4. Remediation (Remédiation) Patch, workaround, ou acceptation de risque documentée. Suivi des SLA par sévérité.

5. Verification (Vérification) Re-scan post-patch pour confirmer la résolution. Fermeture du ticket de vulnérabilité.


EPSS — Exploit Prediction Scoring System#

L’EPSS (Exploit Prediction Scoring System), maintenu par FIRST, estime la probabilité qu’une vulnérabilité soit activement exploitée dans les 30 prochains jours.

Complémentarité CVSS / EPSS :

Situation

CVSS

EPSS

Action

Score élevé, forte probabilité

9.8

0.92

Patch immédiat (P1)

Score élevé, faible probabilité

9.1

0.003

Patch planifié (P2)

Score moyen, forte probabilité

6.5

0.78

Remonter en priorité

Score moyen, faible probabilité

6.2

0.001

Patch lors de la prochaine fenêtre

Le CVSS mesure la sévérité potentielle ; l’EPSS mesure l’imminence de l’exploitation. Les deux dimensions sont nécessaires pour une priorisation rationnelle.


Gestion des patchs#

SLA par sévérité (bonnes pratiques)#

CVSS CRITICAL (9.0-10.0) : patch ou workaround sous 24 heures
CVSS HIGH (7.0-8.9)      : patch sous 7 jours
CVSS MEDIUM (4.0-6.9)    : patch sous 30 jours
CVSS LOW (0.1-3.9)       : patch lors de la prochaine fenêtre planifiée

Stratégies de déploiement#

Canary patching : déploiement du patch sur 5 % des systèmes, surveillance 24-48h, déploiement progressif si pas de régression.

Fenêtres de maintenance : créneaux planifiés (souvent dimanche 02h-06h) pour minimiser l’impact opérationnel. Certains patchs critiques peuvent nécessiter une fenêtre d’urgence.

Rollback plan : chaque patch doit avoir un plan de retour arrière documenté et testé. Pour les systèmes critiques, snapshot VM avant chaque patch.

Dépendance entre patchs et tests

Un patch système peut briser des applications. Établir un environnement de staging représentatif et une suite de tests de non-régression automatisés avant de déployer en production.


Hardening vs usabilité : compromis opérationnels#

Chaque mesure de hardening a un coût opérationnel. La matrice de décision aide à prioriser les contrôles.

Contrôle

Sécurité gagnée

Coût opérationnel

Recommandé

MFA sur comptes admin

Très élevée

Faible

Oui, toujours

Désactivation USB

Élevée

Moyen (shadow IT)

Selon contexte

/tmp noexec

Élevée

Faible

Oui

AppArmor/SELinux

Élevée

Élevé (tuning)

Oui, avec planning

Audit syscalls complet

Moyenne

Élevé (I/O)

Sélectif

Pare-feu applicatif WAF

Élevée

Moyen

Oui (web)

Chiffrement swap

Moyenne

Faible

Oui

ASLR + PIE

Élevée

Nul

Oui, toujours


Cellule 1 — Simulation scoring CIS Benchmark avec radar chart#

Hide code cell source

import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import seaborn as sns
from math import pi

sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)
np.random.seed(42)
# Checklist CIS Benchmark simulée — 20 contrôles, 5 catégories
controles = [
    # (id, nom, catégorie, poids, statut: 0/0.5/1)
    ("C01", "SSH PermitRootLogin désactivé",           "Authentification", 3, 1.0),
    ("C02", "MFA sur comptes privilégiés",             "Authentification", 4, 1.0),
    ("C03", "Politique mot de passe renforcée",        "Authentification", 3, 0.5),
    ("C04", "Verrouillage après 5 échecs",             "Authentification", 2, 1.0),
    ("C05", "UFW activé, règles restrictives",         "Réseau",           4, 1.0),
    ("C06", "sysctl IPv4 forwarding désactivé",        "Réseau",           3, 0.0),
    ("C07", "Ports inutilisés fermés",                 "Réseau",           3, 0.5),
    ("C08", "TCP SYN cookies activés",                 "Réseau",           2, 1.0),
    ("C09", "auditd installé et configuré",            "Audit",            4, 1.0),
    ("C10", "Logs centralisés (syslog distant)",       "Audit",            3, 0.5),
    ("C11", "Rotation des logs activée",               "Audit",            2, 1.0),
    ("C12", "Surveillance /etc/passwd et /etc/shadow", "Audit",            3, 0.0),
    ("C13", "AIDE — baseline créée",                   "Intégrité",        4, 0.5),
    ("C14", "Permissions /etc corrects",               "Intégrité",        3, 1.0),
    ("C15", "SUID/SGID non autorisés supprimés",       "Intégrité",        3, 0.5),
    ("C16", "/tmp et /var/tmp noexec,nosuid",          "Intégrité",        3, 1.0),
    ("C17", "Mise à jour automatique sécurité active", "Patchs",           4, 1.0),
    ("C18", "Délai max patch CRITICAL ≤ 24h respecté", "Patchs",           4, 0.5),
    ("C19", "Inventaire actifs à jour",                "Patchs",           3, 0.5),
    ("C20", "Scan vulnérabilités mensuel",             "Patchs",           3, 1.0),
]

df_cis = pd.DataFrame(controles, columns=["id", "nom", "catégorie", "poids", "statut"])
df_cis["score_contrôle"] = df_cis["poids"] * df_cis["statut"]
df_cis["score_max"] = df_cis["poids"]

# Score par catégorie
df_cat = df_cis.groupby("catégorie").agg(
    score=("score_contrôle", "sum"),
    max_score=("score_max", "sum")
).reset_index()
df_cat["pct"] = df_cat["score"] / df_cat["max_score"] * 100
score_global = df_cis["score_contrôle"].sum() / df_cis["score_max"].sum() * 100

# --- Radar chart ---
categories = df_cat["catégorie"].tolist()
valeurs = df_cat["pct"].tolist()
N = len(categories)
angles = [n / float(N) * 2 * pi for n in range(N)]
angles += angles[:1]
valeurs_plot = valeurs + valeurs[:1]

fig = plt.figure(figsize=(13, 5))

# Radar
ax1 = fig.add_subplot(121, polar=True)
ax1.set_theta_offset(pi / 2)
ax1.set_theta_direction(-1)
ax1.set_xticks(angles[:-1])
ax1.set_xticklabels(categories, size=10)
ax1.set_ylim(0, 100)
ax1.set_yticks([20, 40, 60, 80, 100])
ax1.set_yticklabels(["20", "40", "60", "80", "100"], size=7, color="gray")
ax1.plot(angles, valeurs_plot, "o-", color="#2196F3", linewidth=2, markersize=6)
ax1.fill(angles, valeurs_plot, alpha=0.2, color="#2196F3")
ax1.set_title(f"Score CIS par catégorie\nScore global : {score_global:.1f}/100",
              fontweight="bold", pad=20)

# Barplot détaillé
ax2 = fig.add_subplot(122)
colors = ["#4CAF50" if s >= 75 else "#FF9800" if s >= 50 else "#F44336" for s in df_cat["pct"]]
bars = ax2.barh(df_cat["catégorie"], df_cat["pct"], color=colors, alpha=0.85)
ax2.axvline(x=75, color="gray", linestyle="--", linewidth=1, label="Seuil 75%")
ax2.set_xlim(0, 110)
ax2.set_xlabel("Score (%)")
ax2.set_title("Score CIS par catégorie", fontweight="bold")
for bar, val in zip(bars, df_cat["pct"]):
    ax2.text(val + 1, bar.get_y() + bar.get_height() / 2,
             f"{val:.0f}%", va="center", fontsize=10)
ax2.legend(fontsize=9)

plt.suptitle("Simulation CIS Benchmark Ubuntu — État de conformité", fontsize=13, fontweight="bold")
plt.subplots_adjust(wspace=0.4)
plt.show()

print(f"Score global CIS Benchmark : {score_global:.1f}/100")
print("\nDétail par catégorie :")
for _, row in df_cat.iterrows():
    etat = "OK" if row["pct"] >= 75 else "À améliorer"
    print(f"  {row['catégorie']:18s} : {row['pct']:.0f}% — {etat}")
_images/5dacf78c960aaee4fd9f5025d52d55fdfbb4de6e403466eed28c6d3ca097e528.png
Score global CIS Benchmark : 72.2/100

Détail par catégorie :
  Audit              : 62% — À améliorer
  Authentification   : 88% — OK
  Intégrité          : 73% — À améliorer
  Patchs             : 75% — OK
  Réseau             : 62% — À améliorer

Cellule 2 — Scatter EPSS vs CVSS : priorisation des CVEs#

# Génération de 200 CVEs synthétiques
np.random.seed(13)

n_cves = 200
cvss = np.random.beta(2.5, 2.0, n_cves) * 10
# EPSS corrélé faiblement avec CVSS + bruit
epss_base = 0.05 + 0.08 * (cvss / 10)
epss = np.clip(epss_base + np.random.beta(0.5, 5, n_cves) * 0.6, 0.001, 0.999)

# Quelques CVEs critiques connus (simulés)
idx_critiques = np.argsort(cvss)[-15:]
epss[idx_critiques[:8]] = np.random.uniform(0.7, 0.98, 8)
epss[idx_critiques[8:]] = np.random.uniform(0.001, 0.02, 7)

df_cve = pd.DataFrame({"cvss": cvss, "epss": epss})

def quadrant(row):
    if row["cvss"] >= 7 and row["epss"] >= 0.1:
        return "Critique — patch immédiat"
    elif row["cvss"] >= 7 and row["epss"] < 0.1:
        return "Sévère — patch planifié"
    elif row["cvss"] < 7 and row["epss"] >= 0.1:
        return "Exploitabilité haute — remonter"
    else:
        return "Standard — fenêtre normale"

df_cve["quadrant"] = df_cve.apply(quadrant, axis=1)

sns.set_theme(style="whitegrid", palette="muted", font_scale=1.1)

palette_q = {
    "Critique — patch immédiat": "#F44336",
    "Sévère — patch planifié": "#FF9800",
    "Exploitabilité haute — remonter": "#9C27B0",
    "Standard — fenêtre normale": "#4CAF50",
}

fig, ax = plt.subplots(figsize=(11, 7))
for quad, grp in df_cve.groupby("quadrant"):
    ax.scatter(grp["cvss"], grp["epss"], label=f"{quad} (n={len(grp)})",
               alpha=0.7, s=55, color=palette_q[quad], edgecolors="none")

ax.axhline(y=0.1, color="gray", linestyle="--", linewidth=1, alpha=0.7)
ax.axvline(x=7.0, color="gray", linestyle="--", linewidth=1, alpha=0.7)

ax.text(8.5, 0.92, "PATCH IMMÉDIAT", fontsize=9, color="#F44336", fontweight="bold", alpha=0.8)
ax.text(1.0, 0.92, "REMONTER EN\nPRIORITÉ", fontsize=9, color="#9C27B0", fontweight="bold", alpha=0.8)
ax.text(8.5, 0.02, "PATCH\nPLANIFIÉ", fontsize=9, color="#FF9800", fontweight="bold", alpha=0.8)
ax.text(1.0, 0.02, "FENÊTRE\nNORMALE", fontsize=9, color="#4CAF50", fontweight="bold", alpha=0.8)

ax.set_xlabel("Score CVSS v3.1 (sévérité potentielle)")
ax.set_ylabel("Score EPSS (probabilité d'exploitation sur 30 jours)")
ax.set_title("Priorisation des CVEs : CVSS × EPSS\n(200 vulnérabilités synthétiques)", fontweight="bold")
ax.legend(loc="upper left", fontsize=9)
ax.set_xlim(0, 10.2)
ax.set_ylim(-0.02, 1.05)
plt.show()

print("Distribution par quadrant :")
for q, n in df_cve["quadrant"].value_counts().items():
    print(f"  {q:40s} : {n} CVEs ({100*n/n_cves:.0f}%)")
_images/f29d788ae4e2e2e40f6184058f80e77d593bb85c074ff0acaa768ca0c77bc45d.png
Distribution par quadrant :
  Exploitabilité haute — remonter          : 97 CVEs (48%)
  Standard — fenêtre normale               : 53 CVEs (26%)
  Critique — patch immédiat                : 43 CVEs (22%)
  Sévère — patch planifié                  : 7 CVEs (4%)

Cellule 3 — Heatmap risque résiduel : contrôles × menaces#

# Heatmap d'efficacité des contrôles de hardening contre les menaces
menaces = [
    "Brute force SSH",
    "Escalade privilèges",
    "Persistance malware",
    "Exfiltration données",
    "Mouvement latéral",
    "Exploitation vuln.",
    "Injection commande",
    "Accès physique"
]

controles_h = [
    "MFA + SSH keys",
    "SELinux/AppArmor",
    "auditd + AIDE",
    "Pare-feu + segmentation",
    "Least privilege RBAC",
    "Patch management",
    "noexec /tmp",
    "Chiffrement disque"
]

# Matrice d'efficacité du contrôle (0 = inefficace, 3 = très efficace)
efficacite = np.array([
    # MFA  SEL  AUD  FW   RBAC PATCH NEXEC CRYPT
    [3,    1,   1,   2,   1,   0,    0,    0],   # Brute force SSH
    [1,    3,   2,   0,   3,   1,    1,    0],   # Escalade privilèges
    [0,    2,   3,   1,   1,   2,    3,    0],   # Persistance malware
    [1,    1,   2,   3,   2,   0,    0,    2],   # Exfiltration données
    [2,    1,   2,   3,   3,   1,    0,    0],   # Mouvement latéral
    [0,    2,   1,   2,   1,   3,    2,    0],   # Exploitation vuln.
    [0,    3,   1,   1,   2,   1,    3,    0],   # Injection commande
    [0,    0,   1,   0,   1,   0,    0,    3],   # Accès physique
])

df_heat = pd.DataFrame(efficacite, index=menaces, columns=controles_h)

sns.set_theme(style="white", palette="muted", font_scale=1.1)
fig, ax = plt.subplots(figsize=(13, 7))

cmap = sns.color_palette("YlOrRd", as_cmap=True)
sns.heatmap(
    df_heat, annot=True, fmt="d", cmap=cmap,
    vmin=0, vmax=3, linewidths=0.5, linecolor="white",
    ax=ax, cbar_kws={"label": "Efficacité du contrôle (0=nul, 3=élevée)"}
)
ax.set_title("Efficacité des contrôles de hardening par menace", fontsize=13, fontweight="bold")
ax.set_xlabel("Contrôle de sécurité")
ax.set_ylabel("Menace")
ax.set_xticklabels(ax.get_xticklabels(), rotation=30, ha="right")

# Score de couverture global par menace
score_menace = df_heat.sum(axis=1) / (3 * len(controles_h)) * 100
for i, (menace, score) in enumerate(score_menace.items()):
    ax.text(len(controles_h) + 0.1, i + 0.5, f"{score:.0f}%",
            va="center", fontsize=9, color="#555")

ax.text(len(controles_h) + 0.1, -0.5, "Couv.", fontsize=9, color="#555", fontweight="bold")
plt.subplots_adjust(right=0.88)
plt.show()

print("Couverture des menaces par les contrôles de hardening :")
for menace, score in score_menace.items():
    etat = "Bonne" if score >= 50 else "Insuffisante"
    print(f"  {menace:30s} : {score:.0f}% — {etat}")
_images/8fd41e76fa55ce26b50649e74f97dd0b40bc67cef1f642ddb4ff351996403d6f.png
Couverture des menaces par les contrôles de hardening :
  Brute force SSH                : 33% — Insuffisante
  Escalade privilèges            : 46% — Insuffisante
  Persistance malware            : 50% — Bonne
  Exfiltration données           : 46% — Insuffisante
  Mouvement latéral              : 50% — Bonne
  Exploitation vuln.             : 46% — Insuffisante
  Injection commande             : 46% — Insuffisante
  Accès physique                 : 21% — Insuffisante

Résumé#

Ce chapitre a présenté les outils, référentiels et processus du hardening systèmes et de la gestion des vulnérabilités.

Points clés :

  1. CIS Benchmarks : référence industrielle pour la configuration sécurisée ; le Niveau 1 est applicable universellement, le Niveau 2 pour les environnements haute sécurité. Couvrent Linux, Docker, Kubernetes et plus de 100 technologies.

  2. Lynis : outil d’audit open-source produisant un Hardening Index (0-100) ; intégrable en CI/CD pour valider les images systèmes avant déploiement.

  3. OpenSCAP : automatise la vérification de conformité SCAP (XCCDF/OVAL) contre les profils CIS et DISA STIG ; génère des scripts de remédiation automatiques.

  4. Cycle de vulnérabilités : Discovery → Assessment → Prioritization → Remediation → Verification ; le processus est continu et doit être piloté par des SLA mesurables.

  5. EPSS : complément indispensable au CVSS ; une vulnérabilité CVSS 9.0 avec EPSS 0.001 est moins urgente qu’une CVSS 6.5 avec EPSS 0.85. La combinaison des deux évite la paralysie par l’exhaustivité.

  6. SLA patch management : CRITICAL ≤ 24h, HIGH ≤ 7j, MEDIUM ≤ 30j. Le canary patching réduit le risque de régression en production.

  7. Hardening vs usabilité : chaque contrôle a un coût opérationnel — MFA et /tmp noexec ont un rapport bénéfice/coût excellent ; SELinux/AppArmor nécessitent un investissement de tuning mais sont très efficaces contre l’escalade de privilèges.

  8. Visualisation de la couverture : la heatmap contrôles × menaces permet d’identifier rapidement les zones de risque résiduel élevé et de prioriser les investissements en sécurité.