diff --git a/tools/gen_tags_v3_docx.py b/tools/gen_tags_v3_docx.py new file mode 100644 index 0000000..3b66f9a --- /dev/null +++ b/tools/gen_tags_v3_docx.py @@ -0,0 +1,184 @@ +"""Genere un fichier Word avec le tableau de correspondance Tag V3 -> Rule Type + QQL/Regex. + +Usage: + python tools/gen_tags_v3_docx.py [chemin_sortie.docx] +""" +import sys +from pathlib import Path + +try: + from docx import Document + from docx.shared import Pt, RGBColor, Inches, Cm + from docx.enum.table import WD_ALIGN_VERTICAL + from docx.oxml.ns import qn + from docx.oxml import OxmlElement +except ImportError: + print("[ERR] pip install python-docx") + sys.exit(1) + + +TAGS = [ + # (tag, rule_type, value, couleur) + ("OS-LIN", "Operating System", "Linux", "#4CAF50"), + ("OS-WIN", "Operating System", "Windows", "#2196F3"), + ("OS-WIN-SRV", "Operating System", "Windows Server", "#1976D2"), + ("OS-ESX", "Operating System", "ESXi", "#9C27B0"), + ("ENV-PRD", "Asset Search", 'name: vp* or name: sp* or name: lp* or name: ls-*', "#F44336"), + ("ENV-REC", "Asset Search", 'name: vr* or name: sr* or name: lr*', "#FF9800"), + ("ENV-PPR", "Asset Search", 'name: vi* or name: si* or name: vo*', "#FFC107"), + ("ENV-TST", "Asset Search", 'name: vv* or name: vt*', "#CDDC39"), + ("ENV-DEV", "Asset Search", 'name: vd* or name: sd*', "#8BC34A"), + ("EQT-VIR", "Asset Search", 'name: v*', "#00BCD4"), + ("EQT-SRV", "Asset Search", 'name: l* or name: s*', "#03A9F4"), + ("EQT-SWI", "Asset Search", 'name: n*', "#4DD0E1"), + ("POS-FL", "Asset Search", 'name: "*bot*" or name: "*boo*" or name: "*boc*" or name: "*afl*" or name: "*sup*"', "#009688"), + ("POS-INF", "Asset Search", 'name: "*dsi*" or name: "*cyb*" or name: "*iad*" or name: "*bur*" or name: "*ecm*" or name: "*log*" or name: "*vid*" or name: "*ges*" or name: "*mon*"', "#3F51B5"), + ("POS-PEA", "Asset Search", 'name: "*pea*" or name: "*osa*" or name: "*svp*" or name: "*adv*" or name: "*rpa*" or name: "*rpn*" or name: "ls-*"', "#673AB7"), + ("POS-TRA", "Asset Search", 'name: "*ame*" or name: "*tra*" or name: "*dai*" or name: "*pat*" or name: "*rau*" or name: "*dep*" or name: "*exp*" or name: "*sig*" or name: "*air*"', "#E91E63"), + ("POS-BI", "Asset Search", 'name: "*dec*" or name: "*sas*" or name: "*bip*" or name: "*apt*" or name: "*pbi*" or name: "*rep*"', "#FF5722"), + ("POS-GES", "Asset Search", 'name: "*int*" or name: "*agt*" or name: "*pin*" or name: "*ech*"', "#795548"), + ("POS-DMZ", "Asset Search", 'name: "*ssi*"', "#607D8B"), + ("TAG-OBS", "Operating System", r"Windows Server 2008|Windows Server 2012|CentOS release 6|Red Hat Enterprise Linux Server release 6", "#B71C1C"), + ("TAG-EMV", "Asset Search", 'name: "*emv*" or name: "*pci*"', "#D500F9"), +] + +STATIC_MANUAL = [ + ("TAG-SED", "Securite Exposition Directe — IP publique / NAT direct", "#C62828"), + ("TAG-SEI", "Securite Exposition Indirecte — derriere frontal", "#EF6C00"), + ("TAG-DEC", "Decommissionnement en cours", "#6D4C41"), + ("TAG-INT", "Integration / Implementation en cours", "#FDD835"), + ("TAG-SIC", "Zone SIC — Systeme Information Classifie", "#1A237E"), + ("TAG-SIA", "Zone SIA — Systeme Information Administration", "#283593"), +] + + +def _shade_cell(cell, hex_color): + """Ajoute une couleur de fond a une cellule (style surligneur).""" + tc_pr = cell._tc.get_or_add_tcPr() + shd = OxmlElement("w:shd") + shd.set(qn("w:val"), "clear") + shd.set(qn("w:color"), "auto") + shd.set(qn("w:fill"), hex_color.replace("#", "")) + tc_pr.append(shd) + + +def _set_col_widths(table, widths_cm): + for row in table.rows: + for i, cell in enumerate(row.cells): + if i < len(widths_cm): + cell.width = Cm(widths_cm[i]) + + +def main(): + out = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("SANEF_Qualys_Tags_V3_RuleTypes.docx") + + doc = Document() + # Marges reduites + for section in doc.sections: + section.left_margin = Cm(1.5) + section.right_margin = Cm(1.5) + section.top_margin = Cm(1.5) + section.bottom_margin = Cm(1.5) + + # Titre + h = doc.add_heading("Qualys Tags V3 — Correspondance Rule Type / Valeur", level=1) + + p = doc.add_paragraph() + r = p.add_run("Référence : SANEF DSI / Sécurité Opérationnelle — Plan d'action Qualys V3\n") + r.italic = True + r.font.size = Pt(9) + p.add_run("Chemin Qualys : AssetView > Tags > New Tag > cocher Dynamic, " + "puis choisir le Rule Type et copier la valeur.\n").font.size = Pt(10) + + # Section 1 : Tags dynamiques + doc.add_heading("1. Tags dynamiques (DYN) — à créer en console Qualys", level=2) + doc.add_paragraph("L'API Qualys ne permet pas de créer des tags dynamiques. " + "Ces 21 tags doivent être créés manuellement via la console web.").runs[0].font.size = Pt(10) + + table = doc.add_table(rows=1, cols=4) + table.style = "Light Grid Accent 1" + hdr = table.rows[0].cells + hdr[0].text = "Tag" + hdr[1].text = "Couleur" + hdr[2].text = "Rule Type" + hdr[3].text = "Valeur à saisir" + for c in hdr: + for p in c.paragraphs: + for r in p.runs: + r.bold = True + + for tag, rule, value, color in TAGS: + row = table.add_row().cells + row[0].text = tag + row[1].text = color + row[2].text = rule + row[3].text = value + # Font mono pour tag + valeur + for r in row[0].paragraphs[0].runs: + r.font.name = "Consolas" + r.bold = True + for r in row[3].paragraphs[0].runs: + r.font.name = "Consolas" + r.font.size = Pt(9) + _shade_cell(row[1], color) + # Texte couleur en blanc pour cellule sombre + for r in row[1].paragraphs[0].runs: + r.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF) + r.font.size = Pt(9) + + _set_col_widths(table, [2.5, 2.0, 3.5, 10.5]) + + # Section 2 : Tags statiques manuels + doc.add_paragraph() + doc.add_heading("2. Tags statiques manuels (STAT) — création via API ou SQATM", level=2) + doc.add_paragraph("Ces tags sont nominatifs et necessitent une decision humaine. " + "Ils peuvent être créés via PatchCenter (/qualys/tagsv3/gap) " + "ou via SQATM.").runs[0].font.size = Pt(10) + + table2 = doc.add_table(rows=1, cols=3) + table2.style = "Light Grid Accent 1" + h2 = table2.rows[0].cells + h2[0].text = "Tag" + h2[1].text = "Couleur" + h2[2].text = "Signification" + for c in h2: + for p in c.paragraphs: + for r in p.runs: + r.bold = True + + for tag, desc, color in STATIC_MANUAL: + row = table2.add_row().cells + row[0].text = tag + row[1].text = color + row[2].text = desc + for r in row[0].paragraphs[0].runs: + r.font.name = "Consolas" + r.bold = True + _shade_cell(row[1], color) + for r in row[1].paragraphs[0].runs: + r.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF) + r.font.size = Pt(9) + + _set_col_widths(table2, [2.5, 2.0, 13.5]) + + # Section 3 : Préfixes statiques à la demande + doc.add_paragraph() + doc.add_heading("3. Préfixes statiques à la demande", level=2) + for prefix, desc in [ + ("APP-xxx", "Application hebergee — APP-SAT, APP-JIRA, APP-GLPI..."), + ("BDD-xxx", "Type de base de donnees — BDD-ORA, BDD-PG, BDD-SQL..."), + ("VRF-xxx", "VRF reseau — VRF-TRAFIC, VRF-EMV..."), + ("MID-xxx", "Middleware — MID-TOMCAT, MID-HAPROXY..."), + ]: + p = doc.add_paragraph(style="List Bullet") + r = p.add_run(f"{prefix} ") + r.font.name = "Consolas" + r.bold = True + p.add_run(f"— {desc}") + + doc.save(out) + print(f"[OK] Genere: {out.resolve()}") + + +if __name__ == "__main__": + main()