The problem.
An SMB on Microsoft 365 without a security team never notices a forwarding rule to an external mailbox, a risky sign-in, a new global admin or a USB stick draining files. The signals are in Microsoft's logs, but nobody looks at them.
What I built.
01
Ingestion
- Message traces (Get-MessageTraceV2), unified audit log, Entra ID sign-ins and Defender for Endpoint advanced hunting (USB exfiltration).
- Automatic cycle every 30 minutes per tenant, resuming where the previous cycle stopped.
02
Detection and visualisation
- 8 detections: brute force, new global admin, MFA disabled, risky sign-in, forwarding rule, app consent, password reset bursts, transport rule change.
- 19 dashboards: mail threats, sign-ins, exfiltration and forwarding, compromised accounts, privileged access, external sharing, unused licences…
- Teams, Slack or e-mail alerts and an automatic monthly security report.
03
From lab to platform
- FastAPI + PostgreSQL web portal: accounts, organisations, tenants, sync status, guided tenant onboarding.
- Per-customer data isolation with OpenSearch document-level security (DLS); dashboards only reachable through the portal (nginx auth proxy).
- Deployed on a Linux VPS behind a Cloudflare Tunnel: no port directly exposed to the Internet; daily backups.
The architecture.
Exchange Onlinetraces · unified audit
Entra IDsign-ins
Defender for Endpointadvanced hunting
PowerShell ingestionevery 30 min
OpenSearchper-customer DLS
8 detectionsTeams / e-mail alerts
19 dashboardsvia FastAPI portal
Security & guardrails.
- Internal ports bound to 127.0.0.1; all external traffic goes through Cloudflare.
- Customers only see their own documents (filtered in the engine, not just in the UI).
- Secrets kept out of the repository; daily backup of the database and critical files.
The results.
- Nearly 290 commits: from a lab script to a multi-organisation platform.
- Foundation of a managed SOC offer for SMBs, with quote, contract and onboarding path written.