Skip to content

Repository files navigation

Microsoft Secure Enterprise Platform

Azure Bicep Sentinel Defender License


What this is

A complete, integrated Microsoft security architecture — 8 layers, from identity through AI-assisted operations — built as Infrastructure-as-Code, real detection content, and professional documentation. Read docs/PRD.md first: it states plainly what this proves and what it doesn't, before anything else in this repo.

Every Bicep file here is compiled with the real Bicep CLI before being committed — run scripts/validate_bicep.sh yourself to check.


Phase status

Phase Layer Status
1 Foundation (VNet, NSG, Key Vault) ✅ Complete
2 Identity + Endpoint (Entra ID, Conditional Access, Intune, Defender for Identity/Servers) ✅ Complete
3 SIEM / SOAR (Sentinel, Logic Apps, KQL, ATT&CK mapping) ✅ Complete
4 Cloud & Network Security (Defender for Cloud, Firewall, WAF, Front Door, DDoS) ✅ Complete
5 Email, CASB, Data Protection (Defender for O365, Defender for Cloud Apps, Purview) ✅ Complete
6 Threat Intelligence & AI (Defender TI, Security Copilot) ⏳ Planned
7 Attack Simulations & Runbooks (7 documented scenarios) ⏳ Planned
8 Documentation + polish ⏳ Planned

Phase 1 — Foundation

What's here:

Verified, not just written:

bash scripts/validate_bicep.sh
✅ PASS — bicep/foundation/keyvault.bicep
✅ PASS — bicep/foundation/main.bicep
✅ PASS — bicep/foundation/nsg.bicep
✅ PASS — bicep/foundation/vnet.bicep

4/4 Bicep files compiled clean.

Zero linter warnings across all 4 files as well.


Phase 2 — Identity + Endpoint

What's here:

  • bicep/identity/defender-for-identity.bicep — enables Defender for Identity at subscription scope
  • bicep/endpoint/defender-for-servers.bicep — enables Defender for Servers Plan 2 (the plan that actually includes EDR — P1 doesn't)
  • conditional-access/ — 3 real Microsoft Graph-schema Conditional Access policies (require MFA, block legacy auth, require compliant device for privileged roles) plus a PowerShell deployment script. Documented distinctly from the Bicep resources above: Conditional Access lives in Microsoft Graph/Entra ID, a different control plane from Azure Resource Manager — that distinction is stated, not blurred for a cleaner story
  • intune/windows-compliance-baseline.json — the compliance policy CA003 actually depends on (BitLocker, Secure Boot, Defender status, password policy)
  • detections/kql/ — 2 KQL detections for this phase: privileged sign-in from a non-compliant device, and Defender tamper/AV-disable attempts (T1562.001)
  • architecture/diagrams/lld-identity-endpoint.svg — low-level design for this phase

A real correction made during this phase, not glossed over: Defender plan resources (Microsoft.Security/pricings) initially failed to compile at resource-group scope — the Bicep CLI rejected it with error BCP135, which is how the subscription-scope requirement was caught and fixed, not assumed correct from the start.

Verified, not just written:

bash scripts/validate_bicep.sh
✅ PASS — bicep/endpoint/defender-for-servers.bicep
✅ PASS — bicep/endpoint/main.bicep
✅ PASS — bicep/foundation/keyvault.bicep
✅ PASS — bicep/foundation/main.bicep
✅ PASS — bicep/foundation/nsg.bicep
✅ PASS — bicep/foundation/vnet.bicep
✅ PASS — bicep/identity/defender-for-identity.bicep
✅ PASS — bicep/identity/main.bicep

8/8 Bicep files compiled clean.

All 4 JSON policy files (3 Conditional Access + 1 Intune) parse and validate against their documented Microsoft Graph schema fields.


Phase 3 — SIEM / SOAR core

What's here:

  • bicep/siem-soar/sentinel-workspace.bicep — Log Analytics workspace + Sentinel onboarding deployed together (Sentinel is a solution enabled on a workspace, not a standalone resource — the module reflects that instead of treating them as separate layers)
  • detections/kql/ — 17 more KQL detections added this phase (19 total across the project), spanning identity, endpoint, cloud/container, email, and data-protection sources — because Sentinel is the central SIEM regardless of which layer a signal originates from
  • detections/generate_attack_coverage.py — parses every rule's ATT&CK header and generates a real Navigator layer, run and verified: 15 techniques covered, 2 rules intentionally excluded and named (one uses a NIST CSF tag instead since it detects posture drift, not an attack technique; one is a Conditional-Access control-effectiveness check)
  • soar/playbooks/ — 2 real Logic App templates:
    • playbook-enrich-and-respond.json — the documented enrichment chain (VirusTotal → AbuseIPDB → Whois → Teams → ServiceNow), with device isolation gated behind confirmed-malicious enrichment results, not the raw incident alone
    • playbook-disable-compromised-user.json — gated on the specific source detection rule (password spray / lateral movement / guest privilege escalation), not any generic incident, matching the "Impossible Travel → Disable User" scenario from the original brief

Verified, not just written:

bash scripts/validate_bicep.sh          # 10/10 Bicep files compiled clean
python3 detections/generate_attack_coverage.py   # 15 techniques extracted, real Navigator layer written

Both SOAR playbook JSON files parse and validate; both are deliberately gated on high-confidence conditions rather than auto-acting on a raw incident, matching the "human-in-the-loop for destructive actions" discipline used throughout the rest of this profile's SOAR work.


Phase 4 — Cloud & Network Security

What's here:

  • bicep/cloud-network-security/firewall-rules.bicep — Azure Firewall Premium, deployed into the exact AzureFirewallSubnet reserved back in Phase 1 (this is what that reservation was for). Policy-based rule management with real network + application rule collections, threat intel in Alert-only mode as the starting posture — same "don't hard-block on day one" discipline used for Conditional Access in Phase 2
  • front-door-waf.bicep — Front Door Premium with a WAF policy running Microsoft's Default Ruleset (OWASP coverage) in Prevention mode — a deliberately different posture than the Firewall's Alert-only threat intel, reasoned about explicitly in the file's comments, not just copy-pasted
  • ddos-protection.bicep — DDoS Protection Plan, with the VNet-association step correctly identified as living on the Phase 1 VNet resource rather than modeled as a separate (nonexistent) attachment resource
  • bastion.bicep — Azure Bastion into the reserved AzureBastionSubnet — the actual service that makes Phase 1's "RDP/SSH from Bastion subnet only" NSG rules meaningful, rather than a rule pointing at nothing
  • defender-for-cloud.bicep — Defender for Storage (with on-upload malware scanning, wired to Phase 3's storage-malware-upload.kql), SQL, Containers, and the CSPM plan tier

Two orchestrators, not one — and that's deliberate: main.bicep (resource-group scope: Firewall, Front Door, DDoS, Bastion) and main-defender.bicep (subscription scope: Defender plans), matching the exact scope split Azure itself enforces — the same reasoning already established in Phase 2 for identity/endpoint.

Bugs the real Bicep CLI actually caught during this build (kept here rather than quietly fixed and forgotten):

  • Two hardcoded-URL linter warnings on the Firewall's allow-listed management FQDNs — properly suppressed with a documented reason rather than reworded to dodge the linter
  • An unused location parameter on the Front Door module — removed outright once traced to Front Door resources all being Global scope, not resource-group-scoped
  • An unused vnetId parameter on the DDoS module — fixed by actually threading it through to an output instead of leaving dead code

Verified, not just written:

bash scripts/validate_bicep.sh   # 17/17 Bicep files compiled clean, project-wide

Deploying (once you have a subscription)

# Phase 1 — resource-group scoped
az group create --name rg-mse-platform --location eastus
az deployment group create \
  --resource-group rg-mse-platform \
  --template-file bicep/foundation/main.bicep

# Phase 2 — subscription scoped (Defender plans apply subscription-wide)
az deployment sub create --location eastus --template-file bicep/identity/main.bicep
az deployment sub create --location eastus --template-file bicep/endpoint/main.bicep

# Conditional Access + Intune (Microsoft Graph, not Bicep)
pwsh conditional-access/deploy-conditional-access.ps1

# Phase 3 — resource-group scoped (Sentinel workspace)
az deployment group create \
  --resource-group rg-mse-platform \
  --template-file bicep/siem-soar/main.bicep

# Logic Apps playbooks require an existing Sentinel workspace + API connections —
# see soar/playbooks/*.json "metadata.note" for the exact permissions each needs

# Phase 4 — resource-group scoped (Firewall, Front Door, DDoS, Bastion) —
# requires Phase 1's subnet/VNet output IDs as parameters
az deployment group create \
  --resource-group rg-mse-platform \
  --template-file bicep/cloud-network-security/main.bicep \
  --parameters firewallSubnetId=<phase1-output> bastionSubnetId=<phase1-output> vnetId=<phase1-output>

# Phase 4 — subscription scoped (Defender for Storage/SQL/Containers/CSPM)
az deployment sub create --location eastus --template-file bicep/cloud-network-security/main-defender.bicep

# Phase 5 — no Bicep; three separate deployment surfaces
pwsh email-security/deploy-email-security.ps1
python3 casb/deploy_casb_policies.py          # set CLOUDAPPS_TENANT_URL + CLOUDAPPS_API_TOKEN to deploy for real
pwsh data-protection/deploy-purview-policies.ps1

No subscription was available at build time — see docs/PRD.md Section 4 for the exact, honest boundary on what that means for what this repo does and doesn't prove.


Phase 5 — Email, CASB, Data Protection

A deliberately different deployment shape than Phases 1-4 — worth explaining directly, since it's a real architectural fact, not a gap: none of Defender for Office 365, Defender for Cloud Apps, or Purview are ARM resources. They're licensed M365/Security-portal-configured products with their own control planes, so this phase has zero Bicep files and that's correct, not incomplete.

What's here, across three genuinely distinct deployment surfaces:

Layer Deployment surface Files
Email security (Defender for O365) Exchange Online PowerShell email-security/ — Safe Links (click-through disabled, not just warned), Safe Attachments (dynamic delivery, fail-closed on scan error)
CASB (Defender for Cloud Apps) Cloud Apps REST API casb/ — anomaly detection (impossible travel/mass download for SaaS apps) + OAuth app governance (flagged for review, never auto-revoked)
Data protection (Purview) Security & Compliance PowerShell data-protection/ — 4-tier sensitivity label taxonomy + a DLP policy that actually references those labels, deployed in the correct dependency order

Each policy ties back to a specific detection, not built in isolation:

  • Safe Links → safelinks-clickthrough-despite-warning.kql (the policy blocks outright; the detection catches the edge case where it didn't)
  • CASB anomaly policy → identity-lateral-movement-enriched.kql (same lateral-movement concept, SaaS-app side instead of Azure AD sign-in side)
  • Purview DLP → purview-confidential-file-external-share.kql (policy blocks the share; detection catches labeling gaps)

Verified, not just written:

python3 casb/deploy_casb_policies.py   # dry-run, prints the exact request each policy would send

Both CASB policies print a real, correctly-shaped API request in dry-run mode. All 7 new JSON files across email-security/casb/data-protection parse and validate.


Phase 6 — Threat Intelligence & AI (next)

Not yet built — Defender Threat Intelligence integration and Security Copilot use-case documentation (KQL generation, incident summarization, MITRE mapping).


License

MIT — see LICENSE.

About

Microsoft Secure Enterprise Platform — an integrated 8-layer Microsoft security architecture, built as real, compiled Bicep, detection content, and documentation.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages