← Volver al índice
🛡 Microsoft 365 — Informe mensual de protección

Protection Report

Script Python que genera un informe mensual HTML autocontenido con accesos bloqueados, detecciones de Identity Protection, alertas Microsoft Defender y usuarios en riesgo. Ejecutado desde security-monitor.

🌟 Python 3 standalone
Graph Security API
📈 Chart.js + mapa choropleth
📧 SMTP corporativo
En producción
4
Fuentes de datos Graph API
60
IDs por batch en dismiss
30
Días para dismiss automático
HTML
Salida autocontenida

Cómo funciona

Script Python standalone ejecutado mensualmente desde security-monitor. Sin Flask, sin base de datos. Consulta 4 endpoints Graph API, genera un HTML con Chart.js y lo envía por SMTP.

🔍 Recolección de datos

4 fuentes: auditLogs/signIns (bloqueos CA), riskDetections (Identity Protection), alerts_v2 (Defender), riskyUsers (usuarios en riesgo). Paginación automática.

📊 Informe HTML

HTML autocontenido: hero + KPIs, gráficos Chart.js (donut, stacked bar, horizontal bars), mapa mundial choropleth con distribución geográfica, tablas de detalle. Dark/light toggle.

🗑 Dismiss automático

Descarta en Entra ID usuarios en riesgo cuyo riskLastUpdatedDateTime supera N días. Batches de 60, manejo 429 con Retry-After, 403 graceful. Configurable con auto_dismiss_stale_days: 0 para deshabilitar.

Fuentes de datos

Cuatro endpoints de Graph API v1.0, todos con permisos Application (sin usuario interactivo).

SecciónEndpointPermiso requerido
Accesos bloqueados /auditLogs/signIns AuditLog.Read.All
Detecciones de riesgo /identityProtection/riskDetections IdentityRiskEvent.Read.All
Alertas Defender /security/alerts_v2 SecurityAlert.Read.All
Usuarios en riesgo + dismiss /identityProtection/riskyUsers IdentityRiskyUser.ReadWrite.All

🔑 App Registration (SisScripts)

Client ID250c7cb4-c8c7-4f9c-a393-5aa0b057dcc4
Tenantd78b7929-c2a3-4897-ae9a-7d8f8dc1a1cf
ThumbprintFC402921656C6BFE606980EB654C7A507883239E
Tipo permisosApplication (sin usuario interactivo)

Informe HTML generado

HTML autocontenido con Chart.js, chartjs-chart-geo y topojson-client incrustados. Funciona sin conexión a internet una vez generado.

📊 Secciones del informe

  • Hero con KPIs del mes (accesos bloqueados, detecciones, alertas, usuarios en riesgo)
  • Gráfico donut: tipos de bloqueo de acceso
  • Stacked bar: detecciones por día
  • Horizontal bars: alertas Defender por categoría
  • Mapa mundial choropleth: distribución geográfica de accesos
  • Tabla usuarios en riesgo con indicador de antigüedad

🕑 Antigüedad de riesgo

Los usuarios en riesgo se colorean según días desde último evento:

  • Verde — menos de 7 días (riesgo reciente, investigar)
  • Amarillo — 7-30 días (riesgo persistente)
  • Rojo — más de 30 días (candidato a dismiss)

Funciones principales

FunciónDescripción
fetch_blocked_signins() Consulta auditLogs/signIns con filtros de códigos de error CA/riesgo. Paginación automática hasta 1000/página
fetch_security_alerts() Chunking diario en alerts_v2 para evitar hard cap de 1000/query. Sleep 3s entre días (20 req/min). Avisa si algún día alcanza el límite
dismiss_stale_risky_users() Descarta usuarios con riesgo antiguo. Batches de 60 IDs, manejo 429 con Retry-After, 403 graceful sin error fatal
render_html() Genera el HTML completo autocontenido con Chart.js y topojson incrustados. Dark/light mode con prefers-color-scheme

Configuración y ejecución

📄 app-config.json

{ "graph": { "tenant_id": "d78b7929-...", "client_id": "250c7cb4-...", "cert_thumbprint": "FC402921..." }, "auto_dismiss_stale_days": 30, "email": { "smtp_host": "mail-s1.pro.es.sys.idealista", "smtp_port": 25, "from": "[email protected]", "to": ["[email protected]"] } }

💾 Assets y reports

Los assets JS (Chart.js, chartjs-chart-geo, topojson) se descargan desde jsDelivr/unpkg la primera vez y se cachean en assets/. Las ejecuciones posteriores los reutilizan sin acceso a internet.

  • assets/ — JS embebidos (ignorado en git)
  • reports/ — informes generados (ignorado en git)
  • config/app-config.json — credenciales (NO en git)

Limitaciones conocidas

🔞 Hard cap alerts_v2

security/alerts_v2 tiene un hard cap de 1000 alertas por query sin nextLink. El chunking diario lo mitiga. Si un día supera 1000, se avisa por stderr pero no se aborta la ejecución.

🔐 Cert store del usuario

Requiere acceso al cert store CurrentUser\My del usuario que ejecuta el script. Si el script corre como servicio de Windows, debe hacerlo bajo la misma cuenta donde está instalado el certificado.

🚫 Permiso ReadWrite requerido

Para el dismiss de usuarios en riesgo se requiere IdentityRiskyUser.ReadWrite.All, no el Read.All básico. Sin este permiso, el dismiss se omite con aviso graceful.

🌐 Sin internet primera ejecución

En entornos sin acceso a internet directo, copiar manualmente los assets JS a la carpeta assets/ antes de la primera ejecución: Chart.js, chartjs-chart-geo, topojson-client.