ui(qualys/agents): renomme 'Suggestions' en 'Diagnostic' + reformulation orientee constat (pas de cmds shell, oriente vers ticket support)

This commit is contained in:
Pierre & Lumière 2026-04-28 01:23:56 +02:00
parent 5abc474805
commit 7f8c2c710b
2 changed files with 49 additions and 78 deletions

View File

@ -677,49 +677,34 @@ def _analyze_qualys_audit(r):
s_lvm = (r.get("lvm_info") or "") s_lvm = (r.get("lvm_info") or "")
s_lrt = (r.get("logrotate_config") or "").lower() s_lrt = (r.get("logrotate_config") or "").lower()
# Disque saturé / agent ne peut écrire — multi-suggestions selon contexte # Disque saturé / agent ne peut écrire
disk_full = " 100%" in s_disk or "no space left" in (s_log + s_sys) disk_full = " 100%" in s_disk or "no space left" in (s_log + s_sys)
if disk_full: if disk_full:
# 1. Cleanup des vieux logs (action sûre, à proposer en premier)
suggestions.append({ suggestions.append({
"severity": "critical", "severity": "critical",
"title": "Partition /var/log saturée — cleanup vieux logs (action sûre)", "title": "Partition /var/log saturée",
"fix": "Libérer l'espace en supprimant les .log archivés du crash loop :\n" "fix": "Cause : disque 100% rempli, l'agent ne peut plus écrire ses logs et crashe.\n"
"sudo find /var/log/qualys -name '*.log.[0-9]*' -mtime +7 -delete\n" "Pistes possibles : cleanup logs anciens (.log.0/1/2 du crash loop), "
"sudo find /var/log -name 'messages-*' -mtime +30 -delete\n" "extension du FS si LVM avec espace libre dans le VG (voir bloc LVM ci-dessous)."
"sudo journalctl --vacuum-size=200M\n"
"Puis : sudo systemctl restart qualys-cloud-agent"
}) })
# 2. Si LVM avec free dans VG -> extend FS # Si LVM avec free dans VG -> note diagnostic
# Cherche pattern : "vg_name size free" où free > 0
m_vg = re.search(r"(\S+)\s+([\d.]+)g\s+([\d.]+)g", s_lvm.lower()) m_vg = re.search(r"(\S+)\s+([\d.]+)g\s+([\d.]+)g", s_lvm.lower())
if m_vg and float(m_vg.group(3)) > 0.5: if m_vg and float(m_vg.group(3)) > 0.5:
vg_name = m_vg.group(1) vg_name = m_vg.group(1)
free_gb = float(m_vg.group(3)) free_gb = float(m_vg.group(3))
# Trouver le LV /var/log
m_lv = re.search(r"(varloglv|var_log|log)\s+(\S+)\s+([\d.]+)g", s_lvm.lower())
lv_name = m_lv.group(1) if m_lv else "varloglv"
extend_size = min(2.0, free_gb) # +2G max ou tout ce qui reste
suggestions.append({ suggestions.append({
"severity": "high", "severity": "high",
"title": f"LVM : VG {vg_name} a {free_gb}G libres — étendre /var/log", "title": f"LVM : extension FS possible (VG {vg_name} a {free_gb}G libres)",
"fix": f"⚠ SNAPSHOT vCenter de la VM AVANT TOUTE ACTION (rollback en cas de souci)\n\n" "fix": f"Le VG {vg_name} dispose de {free_gb}G non alloués → extension du LV /var/log faisable. "
f"1. Extension du LV :\n" f"⚠ Snapshot vCenter de la VM obligatoire avant toute action de redimensionnement."
f"sudo lvextend -L +{extend_size}G /dev/{vg_name}/{lv_name}\n\n"
f"2. Grow du FS (selon type — voir bloc LVM ci-dessous) :\n"
f"sudo xfs_growfs /var/log # si XFS\n"
f"sudo resize2fs /dev/{vg_name}/{lv_name} # si ext4\n\n"
f"3. Vérif :\n"
f"df -h /var/log\n"
f"sudo systemctl restart qualys-cloud-agent"
}) })
if "cannot write file" in s_sys or "logger initialization failed" in s_sys: if "cannot write file" in s_sys or "logger initialization failed" in s_sys:
suggestions.append({ suggestions.append({
"severity": "critical", "severity": "critical",
"title": "Agent ne peut pas écrire son log", "title": "Agent ne peut pas écrire son log",
"fix": "Vérifier permissions /var/log/qualys (drwxrwx--- root:root) ET espace dispo. " "fix": "Cause : permissions /var/log/qualys cassées, ou disque saturé. "
"Si /var/log saturé : libérer l'espace puis restart agent." "L'agent fail-fast à l'init du logger."
}) })
# Crash loop # Crash loop
@ -727,11 +712,10 @@ def _analyze_qualys_audit(r):
if m and int(m.group(1)) > 50: if m and int(m.group(1)) > 50:
suggestions.append({ suggestions.append({
"severity": "high", "severity": "high",
"title": f"Crash loop ({m.group(1)} restarts)", "title": f"Crash loop ({m.group(1)} restarts depuis la dernière stabilité)",
"fix": "Stopper l'agent pour éviter d'amplifier le problème :\n" "fix": "Le service est en boucle de redémarrage permanente. "
"sudo systemctl stop qualys-cloud-agent\n" "À stopper temporairement (sudo systemctl stop qualys-cloud-agent) "
"Corriger la cause racine (voir suggestions ci-dessus), puis :\n" "le temps que le problème racine soit traité — sinon il pollue les logs et stresse le système."
"sudo systemctl reset-failed qualys-cloud-agent && sudo systemctl start qualys-cloud-agent"
}) })
# Connectivité KO # Connectivité KO
@ -740,21 +724,17 @@ def _analyze_qualys_audit(r):
suggestions.append({ suggestions.append({
"severity": "high", "severity": "high",
"title": "Connectivité Qualys cloud KO (flux direct bloqué)", "title": "Connectivité Qualys cloud KO (flux direct bloqué)",
"fix": "L'agent Qualys SANEF se connecte EN DIRECT (pas via proxy) à " "fix": "L'agent doit joindre qagpublic.qg1.apps.qualys.eu:443 en direct (pas via proxy). "
"qagpublic.qg1.apps.qualys.eu:443 (pod EU1). Si la connexion échoue :\n\n" "Le test échoue → flux 443 sortant probablement bloqué côté firewall périmétrique. "
"1. Vérifier route directe sortante 443/TCP depuis ce serveur vers cet endpoint.\n" "Comparer avec un serveur où l'agent fonctionne pour confirmer "
"2. Test depuis le serveur :\n" "que les mêmes règles de flux sont appliquées."
" curl -v --connect-timeout 5 https://qagpublic.qg1.apps.qualys.eu/\n"
"3. Comparer avec un serveur où l'agent fonctionne (mêmes flux ouverts ?).\n"
"4. Si bloqué côté infra : ouvrir ticket réseau pour ouvrir 443/TCP "
"vers *.apps.qualys.eu (ou IP 64.39.x.x range Qualys EU)."
}) })
if "certificate verify failed" in s_conn or "ssl" in s_conn and "verify" in s_conn: if "certificate verify failed" in s_conn or ("ssl" in s_conn and "verify" in s_conn):
suggestions.append({ suggestions.append({
"severity": "high", "severity": "high",
"title": "Erreur TLS/SSL", "title": "Erreur TLS/SSL",
"fix": "Possible interception SSL (proxy MITM) ou bundle CA obsolète. " "fix": "Cause possible : interception SSL par un proxy MITM, ou bundle CA système obsolète. "
"Vérifier proxy d'entreprise et chaîne de certificats du serveur." "À investiguer avec l'équipe réseau/sécu."
}) })
# Service désactivé / arrêté # Service désactivé / arrêté
@ -762,31 +742,30 @@ def _analyze_qualys_audit(r):
suggestions.append({ suggestions.append({
"severity": "medium", "severity": "medium",
"title": "Service masked", "title": "Service masked",
"fix": "sudo systemctl unmask qualys-cloud-agent && sudo systemctl enable --now qualys-cloud-agent" "fix": "Le service Qualys a été explicitement masqué. À unmask + enable une fois la cause identifiée."
}) })
elif "disabled" in s_status: elif "disabled" in s_status:
suggestions.append({ suggestions.append({
"severity": "medium", "severity": "medium",
"title": "Service disabled au boot", "title": "Service disabled au boot",
"fix": "sudo systemctl enable --now qualys-cloud-agent" "fix": "Le service ne démarrera pas au prochain reboot. "
"Soit voulu (serveur en décom), soit oubli post-intervention — à clarifier."
}) })
elif any(k in s_status for k in ["inactive (dead)", "stopped", "not running"]) \ elif any(k in s_status for k in ["inactive (dead)", "stopped", "not running"]) \
and "active" not in s_status: and "active" not in s_status:
suggestions.append({ suggestions.append({
"severity": "medium", "severity": "medium",
"title": "Service arrêté", "title": "Service arrêté",
"fix": "sudo systemctl start qualys-cloud-agent\n" "fix": "L'agent n'est plus en cours d'exécution. Voir les logs ci-dessous pour la cause de l'arrêt."
"Si crash immédiat, consulter les logs ci-dessous pour la cause."
}) })
# Agent obsolète # Agent obsolète
if re.match(r"^qualys-cloud-agent-([0-5]\.|6\.[01]\.)", s_ver): if re.match(r"^qualys-cloud-agent-([0-5]\.|6\.[01]\.)", s_ver):
suggestions.append({ suggestions.append({
"severity": "low", "severity": "low",
"title": "Agent obsolète", "title": f"Agent obsolète ({s_ver.strip()})",
"fix": f"Version installée: {s_ver.strip()}. Mettre à jour vers la dernière version " "fix": "Version ancienne, plus supportée par Qualys. "
f"stable (7.x) — Activation Key et package depuis console Qualys " "À planifier en upgrade vers 7.x dans le cadre des MAJ de l'agent."
f"(https://qualysguard.qualys.eu)."
}) })
# Logrotate Qualys mal configuré # Logrotate Qualys mal configuré
@ -796,18 +775,14 @@ def _analyze_qualys_audit(r):
suggestions.append({ suggestions.append({
"severity": "medium", "severity": "medium",
"title": "Logrotate Qualys : compression désactivée", "title": "Logrotate Qualys : compression désactivée",
"fix": "Logrotate sans compression = vieux logs prennent 5-10x plus de place. " "fix": "Sans compression, les logs archivés occupent 5-10× plus de place — "
"Editer /etc/logrotate.d/qualys-cloud-agent et ajouter (ou décommenter) :\n" "contribution potentielle à la saturation de /var/log."
"compress\ndelaycompress\nrotate 7\n"
"Puis : sudo logrotate -f /etc/logrotate.d/qualys-cloud-agent"
}) })
if "rotate" not in s_lrt: if "rotate" not in s_lrt:
suggestions.append({ suggestions.append({
"severity": "low", "severity": "low",
"title": "Logrotate Qualys : pas de directive rotate", "title": "Logrotate Qualys : pas de directive rotate",
"fix": "Ajouter une politique de rétention dans /etc/logrotate.d/qualys-cloud-agent :\n" "fix": "Pas de politique de rétention définie → les logs s'accumulent indéfiniment."
"rotate 7 # 7 fichiers archives max\n"
"size 100M # rotation auto a 100M"
}) })
# Core dump + package absent = installation incomplète / corrompue # Core dump + package absent = installation incomplète / corrompue
@ -816,28 +791,18 @@ def _analyze_qualys_audit(r):
suggestions.append({ suggestions.append({
"severity": "critical", "severity": "critical",
"title": "Installation Qualys cassée (core dump + package absent du RPM)", "title": "Installation Qualys cassée (core dump + package absent du RPM)",
"fix": "Le service systemd existe mais le binaire est manquant ou corrompu " "fix": "Le service systemd existe mais le binaire est manquant ou corrompu — "
"→ core dump en boucle. Désinstaller proprement puis réinstaller :\n\n" "core dump systématique au démarrage. Désinstallation incomplète probable. "
"1. Cleanup :\n" "Nécessite cleanup complet (service unit + fichiers) puis réinstallation "
"sudo systemctl stop qualys-cloud-agent\n" "via le RPM SANEF (/root/QualysCloudAgent.rpm) avec ré-activation."
"sudo systemctl disable qualys-cloud-agent\n"
"sudo rpm -e qualys-cloud-agent 2>/dev/null # si package partiel\n"
"sudo rm -rf /usr/local/qualys /var/log/qualys /etc/qualys\n"
"sudo rm -f /usr/lib/systemd/system/qualys-cloud-agent.service\n"
"sudo systemctl daemon-reload && sudo systemctl reset-failed\n\n"
"2. Réinstall (procédure SANEF) :\n"
"sudo rpm -ivh /root/QualysCloudAgent.rpm\n\n"
"3. Activation (script Qualys avec ActivationId + CustomerId depuis console qualysguard.qg2.apps.qualys.eu)."
}) })
elif "core-dump" in s_sys or "core dumped" in s_sys: elif "core-dump" in s_sys or "core dumped" in s_sys:
suggestions.append({ suggestions.append({
"severity": "high", "severity": "high",
"title": "Agent Qualys core dumps en boucle", "title": "Agent Qualys core dumps en boucle",
"fix": "Vérifier dépendances binaire :\n" "fix": "Le binaire crashe au démarrage (signal SIGABRT). "
"ldd /usr/local/qualys/cloud-agent/bin/qualys-cloud-agent\n" "Cause possible : lib système cassée (ldd manquant), bug version agent vs OS, "
"Voir le coredump pour la cause :\n" "ou conflit avec autre package."
"sudo coredumpctl info qualys-cloud-agent | head -50\n"
"Si lib cassée → réinstaller agent. Si bug Qualys → ouvrir ticket support."
}) })
# OS EOL (RHEL 5/6) # OS EOL (RHEL 5/6)
@ -846,8 +811,8 @@ def _analyze_qualys_audit(r):
suggestions.append({ suggestions.append({
"severity": "low", "severity": "low",
"title": "OS en fin de vie", "title": "OS en fin de vie",
"fix": "RHEL 5/6 EOL — agent Qualys 7.x non supporté. Migrer vers RHEL 8/9 " "fix": "RHEL 5/6 EOL — l'agent Qualys 7.x n'est plus supporté sur ces versions. "
"ou conserver l'agent legacy en attendant la décom du serveur." "À traiter dans le plan de migration / décom du serveur."
}) })
return suggestions return suggestions

View File

@ -61,9 +61,9 @@
{% if audit.status == 'OK' %} {% if audit.status == 'OK' %}
{% if audit.suggestions %} {% if audit.suggestions %}
<!-- Suggestions de résolution --> <!-- Diagnostic -->
<div class="card p-4 mb-4" style="border:1px solid #00ffc8;background:rgba(0,255,200,0.05)"> <div class="card p-4 mb-4" style="border:1px solid #00ffc8;background:rgba(0,255,200,0.05)">
<h3 class="text-sm font-bold text-cyber-accent mb-3">💡 Suggestions de résolution ({{ audit.suggestions|length }})</h3> <h3 class="text-sm font-bold text-cyber-accent mb-3">🔍 Diagnostic ({{ audit.suggestions|length }} problème(s) détecté(s))</h3>
<div style="display:flex;flex-direction:column;gap:10px"> <div style="display:flex;flex-direction:column;gap:10px">
{% for s in audit.suggestions %} {% for s in audit.suggestions %}
<div style="border-left:3px solid {% if s.severity == 'critical' %}#ef4444{% elif s.severity == 'high' %}#f97316{% elif s.severity == 'medium' %}#f59e0b{% else %}#3b82f6{% endif %};padding:8px 12px;background:#0b0f1a;border-radius:4px"> <div style="border-left:3px solid {% if s.severity == 'critical' %}#ef4444{% elif s.severity == 'high' %}#f97316{% elif s.severity == 'medium' %}#f59e0b{% else %}#3b82f6{% endif %};padding:8px 12px;background:#0b0f1a;border-radius:4px">
@ -75,6 +75,12 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
<div class="mt-3 pt-3" style="border-top:1px solid #1f2937">
<p class="text-xs text-gray-400">
<span class="text-cyber-accent font-bold">→ Action :</span>
ouvrir un ticket support avec ces éléments de diagnostic + l'export complet de cette page (capture/PDF) pour traçabilité.
</p>
</div>
</div> </div>
{% endif %} {% endif %}