303 lines
15 KiB
Python
303 lines
15 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""Generate SANEF Qualys V3 - resume execution + points de vigilance.docx"""
|
||
from docx import Document
|
||
from docx.shared import Pt, RGBColor, Inches, Cm
|
||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||
|
||
doc = Document()
|
||
|
||
style = doc.styles['Normal']
|
||
style.font.name = 'Calibri'
|
||
style.font.size = Pt(10)
|
||
|
||
# ===== Cover =====
|
||
title = doc.add_heading('SANEF — Qualys Taxonomie V3', 0)
|
||
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
|
||
sub = doc.add_paragraph()
|
||
sub.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
r = sub.add_run('Résumé d\'exécution + points de vigilance')
|
||
r.font.size = Pt(14)
|
||
r.italic = True
|
||
|
||
meta = doc.add_paragraph()
|
||
meta.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
r = meta.add_run('Date : 22 avril 2026\nRédacteur : Khalid MOUTAOUAKIL — SECOPS\nVersion : 1.0')
|
||
r.font.size = Pt(11)
|
||
|
||
doc.add_paragraph()
|
||
doc.add_paragraph('_' * 80)
|
||
doc.add_paragraph()
|
||
|
||
# ===== 1. Résumé =====
|
||
doc.add_heading('1. Résumé de la session', level=1)
|
||
doc.add_paragraph(
|
||
"Cette session a consisté à déployer la taxonomie V3 des tags Qualys SANEF, "
|
||
"définie dans le document « Processus d'affectation des Tags Qualys — Nomenclature V3 ». "
|
||
"L'ensemble des règles a été créé directement dans la console Qualys (module Asset Inventory) "
|
||
"et appliqué sur le parc actif (~3,22k assets sur 6,24k au total)."
|
||
)
|
||
|
||
doc.add_heading('1.1 Tags créés', level=2)
|
||
doc.add_paragraph('5 parents (containers organisationnels statiques) :', style='List Bullet')
|
||
for p in ['OS', 'EQT', 'ENV', 'POS', 'TAG']:
|
||
doc.add_paragraph(p, style='List Bullet 2')
|
||
|
||
doc.add_paragraph('23 tags dynamiques (Asset Inventory rule engine) :', style='List Bullet')
|
||
for line in [
|
||
'OS-LIN-SRV (729), OS-WIN-SRV (505), OS-WIN-WKS (~2056), OS-MAC (7), OS-ESX (2)',
|
||
'EQT-VIR (956), EQT-SRV (307), EQT-SWI (72)',
|
||
'ENV-PRD (~772), ENV-REC (~302), ENV-PPR (~76), ENV-TST (83), ENV-DEV (~21)',
|
||
'POS-FL, POS-INF, POS-PEA, POS-TRA, POS-BI, POS-GES (counts variables, voir console)',
|
||
'NOM-LEGACY (219) — KPI dette de conformité V3',
|
||
'TAG-EMV (~34) — zone PCI-DSS',
|
||
'TAG-OBS (~190+) — OS EOL liste explicite',
|
||
]:
|
||
doc.add_paragraph(line, style='List Bullet 2')
|
||
|
||
doc.add_paragraph('Tags statiques (bulk SQATM) :', style='List Bullet')
|
||
for line in [
|
||
'TAG-SED (10) — exposition directe Internet',
|
||
'TAG-SEI (22) — exposition indirecte derrière frontal',
|
||
'TAG-ELS (vide) — extension de licence (exclusion EOL)',
|
||
'TAG-DEC, TAG-INT, TAG-SIC, TAG-SIA — statiques manuels',
|
||
]:
|
||
doc.add_paragraph(line, style='List Bullet 2')
|
||
|
||
doc.add_heading('1.2 Découvertes techniques majeures', level=2)
|
||
findings = [
|
||
("Limites QQL Tag rule engine",
|
||
"Le moteur Asset Inventory pour la création de règles n'accepte que la syntaxe starts-with "
|
||
"(asset.name:vp*). Les opérateurs CONTAINS (*X*) et les guillemets (\"X\") échouent. La clé "
|
||
"tags.name peut être utilisée dans les recherches interactives mais PAS dans la création de "
|
||
"règles dynamiques (l'API rejette le commit avec « Error while committing transaction »)."),
|
||
("FQDN .sanef.groupe non env-spécifique",
|
||
"Découverte initialement supposée comme indicateur Production, le domaine AD interne "
|
||
".sanef.groupe est en réalité utilisé par tous les serveurs SANEF (PRD, REC, PPR, TST, DEV). "
|
||
"Utiliser comme filtre broad provoque des overlaps massifs entre tags ENV. Solution adoptée : "
|
||
"scoper FQDN par pattern hostname précis (ex : vmm*.sanef-int.adds pour les Win11 prod uniquement)."),
|
||
("Conflits de préfixes 5-char entre POS",
|
||
"Plusieurs préfixes hostname appartiennent à des domaines différents selon contexte applicatif "
|
||
"(ex : vppea* = FL pour BOOST + PEA pour SVP). Résolution par énumération 7-char spécifique "
|
||
"(vppeaab* BOOST = FL, vppeaaa*/ar*/ae* SVP = PEA) et clauses NOT exclusives."),
|
||
("Zone DMZ multi-subnet",
|
||
"La DMZ SANEF est segmentée en 15 sous-réseaux /24 différents. Pas de CIDR unique. "
|
||
"Impossible de faire une règle dynamique simple par IP. Tagging actuel TAG-SED/SEI en static "
|
||
"via SQATM bulk."),
|
||
("Tag built-in Qualys « Obsolete »",
|
||
"Qualys maintient automatiquement un tag « Obsolete » basé sur sa détection EOL. ~190 assets "
|
||
"SANEF sont taggés. Ce tag NE peut PAS être référencé dans une règle de tag custom (limitation "
|
||
"Qualys). On utilise une liste OS explicite pour TAG-OBS."),
|
||
("Postes Superviseur Péage (svp*) — exclusion ENV-TST et EQT-SRV",
|
||
"Le préfixe sv* visait initialement les serveurs physiques de test (svboomcla2, etc.). "
|
||
"Découverte : ~100 postes de travail Windows 11 (HP Elite Mini desktops SVP2xxxx + HP EliteBook "
|
||
"SVP1xxxx) commencent aussi par svp* — ce sont des postes Superviseur Péage, pas des serveurs. "
|
||
"Sans exclusion explicite, ils étaient ramassés par ENV-TST (~180 au lieu de 83) et "
|
||
"potentiellement par EQT-SRV. Correction : ajout de « and not asset.name:svp* » sur les deux "
|
||
"règles. ENV-TST passe à 83 assets, cohérent avec le périmètre attendu."),
|
||
]
|
||
for h, t in findings:
|
||
p = doc.add_paragraph()
|
||
p.add_run(h + ' : ').bold = True
|
||
p.add_run(t)
|
||
|
||
# ===== 2. Points de vigilance =====
|
||
doc.add_page_break()
|
||
doc.add_heading('2. Points de vigilance', level=1)
|
||
doc.add_paragraph(
|
||
"Les éléments suivants nécessitent une surveillance ou des actions futures pour maintenir "
|
||
"la cohérence et l'exhaustivité de la taxonomie V3."
|
||
)
|
||
|
||
doc.add_heading("2.1 POS-DMZ — à adapter une fois la DMZ normalisée", level=2)
|
||
doc.add_paragraph(
|
||
"Statut actuel : pas de tag POS-DMZ créé. La gestion DMZ est faite via TAG-SED (10 frontaux) "
|
||
"et TAG-SEI (22 backends), tous statiques."
|
||
)
|
||
p = doc.add_paragraph()
|
||
p.add_run('Problème : ').bold = True
|
||
p.add_run(
|
||
"la DMZ SANEF s'étend sur 15 sous-réseaux /24 différents (192.168.2/24, 192.168.20/24, "
|
||
"192.168.31/24, 10.41.20/24, 10.42.30/24, 10.205.0/24, etc.). Aucun CIDR unique ne permet "
|
||
"actuellement une règle dynamique simple."
|
||
)
|
||
p = doc.add_paragraph()
|
||
p.add_run('Action requise : ').bold = True
|
||
p.add_run(
|
||
"demander à l'équipe réseau SANEF de fournir soit (a) le CIDR DMZ consolidé (si réorganisation "
|
||
"envisagée), soit (b) une nomenclature IP DMZ-spécifique (par exemple un /20 dédié). Une fois "
|
||
"obtenu, basculer TAG-SED et TAG-SEI en règles dynamiques basées sur "
|
||
"asset.interface:(address: <CIDR>)."
|
||
)
|
||
p = doc.add_paragraph()
|
||
p.add_run('Alternative : ').bold = True
|
||
p.add_run(
|
||
"si la DMZ reste multi-subnet, garder TAG-SED/TAG-SEI en static. Documenter dans la procédure "
|
||
"patcheur SECOPS : tout nouveau serveur en zone DMZ doit être taggé manuellement via SQATM "
|
||
"selon son rôle (frontal = SED, backend = SEI)."
|
||
)
|
||
p = doc.add_paragraph()
|
||
p.add_run('Plages publiques connues pour TAG-SED dynamique : ').bold = True
|
||
p.add_run("83.68.96.0/24 (Juniper firewalls), 83.68.99.0/24 (F5 BIG-IP). Ces plages peuvent être "
|
||
"utilisées pour basculer TAG-SED en dynamique partiel dès aujourd'hui :")
|
||
doc.add_paragraph(
|
||
"asset.interface:(address: 83.68.96.0/24) or asset.interface:(address: 83.68.99.0/24)",
|
||
style='Intense Quote'
|
||
)
|
||
|
||
doc.add_heading('2.2 TAG-ELS — saisie manuelle au cas par cas', level=2)
|
||
doc.add_paragraph(
|
||
"TAG-ELS (Extended Life License) identifie les serveurs sous contrat de support sécurité "
|
||
"étendu payé (Microsoft ESU, Red Hat ELS, etc.). Ces serveurs ne doivent PAS être considérés "
|
||
"comme TAG-OBS car ils reçoivent encore des correctifs de sécurité."
|
||
)
|
||
p = doc.add_paragraph()
|
||
p.add_run('Statut actuel : ').bold = True
|
||
p.add_run("TAG-ELS créé (statique, vide). Aucun asset taggué.")
|
||
p = doc.add_paragraph()
|
||
p.add_run('Action requise : ').bold = True
|
||
p.add_run(
|
||
"lister les serveurs SANEF sous contrats ELS (vérifier avec la DSI / responsables applicatifs / "
|
||
"renouvellements de licence Microsoft/RedHat). Saisir manuellement via SQATM avec le tag TAG-ELS "
|
||
"sur chaque asset concerné."
|
||
)
|
||
p = doc.add_paragraph()
|
||
p.add_run('Workflow opérationnel : ').bold = True
|
||
p.add_run(
|
||
"lorsqu'un asset est ajouté à TAG-ELS, retirer manuellement TAG-OBS si présent (les deux tags "
|
||
"ne doivent pas coexister). Limitation : la chaîne de tag (tag rule excluant un autre tag) "
|
||
"n'est pas supportée par Qualys, donc le double-tagging doit être nettoyé manuellement."
|
||
)
|
||
p = doc.add_paragraph()
|
||
p.add_run('Reporting recommandé : ').bold = True
|
||
p.add_run("créer une « Saved Search » Qualys pour le reporting opérationnel :")
|
||
doc.add_paragraph('tags.name:"TAG-OBS" and not tags.name:"TAG-ELS"', style='Intense Quote')
|
||
doc.add_paragraph("Cette query, valide en recherche interactive, donne les « vrais EOL à patcher » "
|
||
"et est utilisable dans les dashboards.")
|
||
|
||
doc.add_heading("2.3 TAG-OBS — adapter la liste OS quand un nouvel OS devient obsolète", level=2)
|
||
doc.add_paragraph(
|
||
"TAG-OBS est défini en Option A (liste OS explicite) car la chaîne sur le tag built-in Qualys "
|
||
"« Obsolete » n'est pas supportée. La liste actuelle couvre 15 OS / familles."
|
||
)
|
||
p = doc.add_paragraph()
|
||
p.add_run('Liste OS actuelle (Ã maintenir) : ').bold = True
|
||
oses = [
|
||
"Windows XP (EOL 2014-04-08)",
|
||
"Windows Server 2003 (EOL 2015-07-14)",
|
||
"Windows Server 2008 / 2008 R2 (EOL 2020-01-14)",
|
||
"Windows Server 2012 / 2012 R2 (EOL 2023-10-10)",
|
||
"Windows 7 (EOL 2020-01-14)",
|
||
"Red Hat Enterprise Linux 5 (EOL 2017-03-31)",
|
||
"Red Hat Enterprise Linux 6 (EOL 2020-11-30)",
|
||
"CentOS 5 / 6 / 7 (CentOS 7 EOL 2024-06-30)",
|
||
"Ubuntu 14.04 / 16.04 / 18.04 (EOL 2019/2021/2023)",
|
||
"Debian 8 / 9 (EOL 2020/2022)",
|
||
]
|
||
for o in oses:
|
||
doc.add_paragraph(o, style='List Bullet')
|
||
|
||
p = doc.add_paragraph()
|
||
p.add_run('Surveillance recommandée : ').bold = True
|
||
p.add_run(
|
||
"vérifier au moins une fois par an (idéalement en début d'année) si de nouveaux OS sont passés EOL. "
|
||
"Sources fiables : endoflife.date, sites éditeurs (microsoft.com/lifecycle, redhat.com/support, "
|
||
"ubuntu.com/about/release-cycle)."
|
||
)
|
||
|
||
p = doc.add_paragraph()
|
||
p.add_run('OS Ã surveiller dans les 12-24 mois : ').bold = True
|
||
upcoming = [
|
||
"RHEL 7 — EOL 2024-06-30 (déjà à inclure si pas déjà fait)",
|
||
"Windows Server 2012 R2 ESU — EOL 2026-10-13",
|
||
"Ubuntu 20.04 — EOL 2025-04 standard, ESM jusqu'à 2030",
|
||
"Debian 10 — EOL 2024-06-30 standard, LTS jusqu'à 2024-06",
|
||
"CentOS Stream 8 — EOL 2024-05-31",
|
||
]
|
||
for o in upcoming:
|
||
doc.add_paragraph(o, style='List Bullet')
|
||
|
||
p = doc.add_paragraph()
|
||
p.add_run('Procédure de mise à jour TAG-OBS : ').bold = True
|
||
doc.add_paragraph("Ouvrir Qualys Console > AssetView > Configuration > Tags > TAG-OBS > Edit", style='List Number')
|
||
doc.add_paragraph('Ajouter la nouvelle clause OR Ã la query : or operatingSystem:"<nouvel OS>"', style='List Number')
|
||
doc.add_paragraph("Cliquer Test pour vérifier le count", style='List Number')
|
||
doc.add_paragraph("Save", style='List Number')
|
||
doc.add_paragraph("Mettre à jour le fichier de référence SANEF_Qualys_Tags_V3_RuleTypes_v2.xlsx", style='List Number')
|
||
|
||
doc.add_heading("2.4 Mécanisme natif Qualys « Obsolete » (à connaître)", level=2)
|
||
doc.add_paragraph(
|
||
"Qualys propose un tag système « Obsolete » auto-appliqué à partir d'une base de connaissance "
|
||
"interne sur les fins de support OS. Ce tag est maintenu par Qualys (pas par SANEF), s'applique "
|
||
"automatiquement aux assets quand leur OS bascule EOL."
|
||
)
|
||
p = doc.add_paragraph()
|
||
p.add_run("Couverture observée dans le parc SANEF : ").bold = True
|
||
p.add_run("~190 assets (181 dans l'export AssetView et 180 dans Cloud Agent au 22 avril 2026).")
|
||
|
||
p = doc.add_paragraph()
|
||
p.add_run("Pourquoi ne pas utiliser uniquement ce tag : ").bold = True
|
||
p.add_run(
|
||
"(1) il n'est PAS référençable dans une règle de tag dynamique custom (limitation Qualys "
|
||
"confirmée), donc impossible de créer un TAG-OBS = mirror du tag Qualys ; "
|
||
"(2) il n'inclut pas toujours toutes les variantes EOL (parfois décalage temporel ou critères "
|
||
"différents) ; "
|
||
"(3) il ne permet pas l'exclusion ELS via règle."
|
||
)
|
||
p = doc.add_paragraph()
|
||
p.add_run("Comment l'utiliser malgré ses limites : ").bold = True
|
||
p.add_run(
|
||
"via les Saved Searches dans la console Qualys. Exemple de query à sauvegarder pour le reporting :"
|
||
)
|
||
doc.add_paragraph('tags.name:"Obsolete" and not tags.name:"TAG-ELS"', style='Intense Quote')
|
||
p = doc.add_paragraph()
|
||
p.add_run("Comparaison TAG-OBS (Option A) vs Obsolete built-in : ").bold = True
|
||
p.add_run(
|
||
"TAG-OBS = liste explicite contrôlée par SECOPS, plus large potentiellement, mais nécessite "
|
||
"maintenance. Obsolete built-in = auto-update Qualys, sans maintenance, mais sans contrôle SANEF "
|
||
"et non chaînable. La meilleure approche est de conserver les deux et de les utiliser en croisant "
|
||
"leur intersection."
|
||
)
|
||
|
||
# ===== 3. Suite à faire =====
|
||
doc.add_page_break()
|
||
doc.add_heading('3. Suite à faire (TODO)', level=1)
|
||
todos = [
|
||
("Bulk SQATM TAG-SED, TAG-SEI",
|
||
"Appliqué aujourd'hui via SQATM (10 SED, 22 SEI). Vérifier à la prochaine revue qu'aucun nouveau "
|
||
"asset DMZ n'a été oublié."),
|
||
("Récupérer CIDR DMZ auprès équipe réseau",
|
||
"Pour basculer TAG-SED/TAG-SEI en dynamique IP-based. Voir section 2.1."),
|
||
("Saisir TAG-ELS sur les serveurs concernés",
|
||
"Inventaire des contrats ELS Ã faire avec la DSI. Voir section 2.2."),
|
||
("Nettoyer tags legacy concurrents dans Qualys",
|
||
"Plusieurs tags concurrents détectés dans les exports : TAG-SRVEXPOSEINTERNET, DMZ, SED, "
|
||
"ZONE-DMZ. Décision à prendre : garder en parallèle, supprimer ou consolider sur la nomenclature V3."),
|
||
("Documenter procédure SECOPS pour nouveaux serveurs",
|
||
"Procédure à intégrer dans le wiki DokuWiki SANEF (page infra:sanef_utiles:sanef_utiles:qualys_tagv3) : "
|
||
"tout nouveau serveur SANEF doit être taggé selon V3 dans les 48h après scan Qualys initial."),
|
||
("Dashboard Qualys « Conformité V3 »",
|
||
"Construire un dashboard avec : count NOM-LEGACY (KPI dette renommage), count TAG-OBS (hors ELS), "
|
||
"% serveurs avec OS-* + ENV-* + POS-* + EQT-* tags présents (couverture V3)."),
|
||
("Surveillance annuelle TAG-OBS",
|
||
"Revérifier la liste OS EOL en janvier 2027 et ajouter les nouveaux OS passés EOL. Voir 2.3."),
|
||
]
|
||
for title_, desc in todos:
|
||
p = doc.add_paragraph(style='List Bullet')
|
||
p.add_run(title_).bold = True
|
||
p.add_run(' : ' + desc)
|
||
|
||
doc.add_paragraph()
|
||
doc.add_paragraph('_' * 80)
|
||
p = doc.add_paragraph()
|
||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||
r = p.add_run("SANEF DSI / Sécurité Opérationnelle — Plan d'action Qualys V3")
|
||
r.italic = True
|
||
r.font.size = Pt(9)
|
||
|
||
out = r"C:\Claude\sanef\QL\docs\SANEF_Qualys_V3_Resume_Vigilance.docx"
|
||
doc.save(out)
|
||
print("Saved:", out)
|
||
import os
|
||
print("Size:", os.path.getsize(out), "bytes")
|