CIS Microsoft Azure Foundations Benchmark — SnowOps Control Mapping¶
Framework: CIS Microsoft Azure Foundations Benchmark v2.0.0 Type: Configuration benchmark (not a certification — no audit firm required) Assessment tool: Microsoft Defender for Cloud (MCSB) + Discovery Audit Suite (
G0–G7) discovery audit SnowOps package: Baseline "Cloud Secure" [B] covers the majority of CIS Azure controls
Coverage Legend¶
| Symbol | Meaning |
|---|---|
| ✅ | Automated — SnowOps asset enforces the control with Terraform/Azure Policy |
| 🔧 | Partial — Technical control exists; supplemental Entra/portal configuration required |
| 📋 | Manual — Configuration in Entra admin centre or Azure portal (no ARM/TF resource) |
| ⏳ | Roadmap — Planned in M4 |
| ❌ | Not applicable / Azure-managed |
Section 1 — Identity and Access Management¶
| CIS ID | Recommendation | Coverage | Asset | Notes |
|---|---|---|---|---|
| 1.1.1 | Ensure Security Defaults are disabled (MFA via CA instead) | 🔧 Partial | Azure Baseline Module (F1), Entra PIM Templates Module (H3) |
Entra Conditional Access MFA is the secure path; Security Defaults toggle is a portal action |
| 1.1.2 | Ensure MFA is required for all users with admin roles | ✅ | Entra PIM Templates Module (H3) (CA policy) |
Conditional Access MFA for directory roles |
| 1.1.3 | Ensure MFA is required for all users | 📋 Manual | — | Conditional Access policy scope; Entra admin centre |
| 1.2.1 | Ensure guest user access restrictions | 📋 Manual | — | Entra external collaboration settings; not a TF resource |
| 1.2.2 | Ensure guest invitations are restricted | 📋 Manual | — | Entra external collaboration settings |
| 1.2.3 | Ensure guest users are reviewed monthly | ⏳ Roadmap | guest-review automation (M4; nearest analogue: Service Principal Inventory) | H5 covers SP credential inventory; a dedicated guest-user review tool is not yet built |
| 1.3.1 | Ensure Azure AD Password Protection is enabled | 📋 Manual | — | Entra password protection; not a TF resource |
| 1.3.3 | Ensure password protection lockout duration ≥ 1 min | 📋 Manual | — | Entra smart lockout policy |
| 1.4 | Ensure Azure AD no longer has legacy authentication | 🔧 Partial | Entra PIM Templates Module (H3) (CA policy) |
Block legacy auth via Conditional Access policy |
| 1.5 | Ensure all subscription owners have MFA | ✅ | Azure Resource PIM Module (B5), Entra PIM Templates Module (H3) |
PIM eligible owner assignments + CA MFA enforcement |
| 1.6 | Ensure access to Azure resources is managed via identities | ✅ | Azure Baseline Module (F1), Entra ID Baseline Module (H1)/Conditional Access Module (H2) |
Managed identity preferred; no local accounts |
| 1.7 | Ensure guest accounts have least privilege | 🔧 Partial | Conditional Access Module (H2) |
RBAC custom roles; guest account policy is manual |
| 1.8 | Ensure that there are no more than 3 global admins | 📋 Manual | — | Review via Entra PIM; Break-Glass Account Module (H7) manages break-glass count |
| 1.9 | Ensure global admin is not used for day-to-day | ✅ | Break-Glass Account Module (H7), Azure Resource PIM Module (B5) |
Break-glass accounts for emergency only; PIM for daily admin |
| 1.21 | Ensure user who can create new service principals is restricted | 📋 Manual | — | Entra app registration restriction policy |
| 1.22 | Ensure service principal certificates/secrets expiry is < 180 days | ✅ | Service Principal Inventory (H5) |
SP inventory + rotation PR at 90 days threshold |
| 1.23 | Ensure Microsoft Entra ID P2 licensing | 🔧 Partial | Client Prerequisite Checker (B6) (prerequisite check) |
Client Prerequisite Checker (B6) validates P2 presence pre-engagement; licensing is purchased by client |
Section 2 — Microsoft Defender for Cloud¶
| CIS ID | Recommendation | Coverage | Asset | Evidence |
|---|---|---|---|---|
| 2.1.1 | Ensure Defender for Servers is enabled (Standard) | ✅ | Subscription Baseline Module (B3) (MCSB assign) |
MCSB assignment enables Defender for Servers |
| 2.1.2 | Ensure Defender for App Service is enabled | ✅ | Subscription Baseline Module (B3) |
MCSB assignment |
| 2.1.3 | Ensure Defender for SQL Servers on machines | ✅ | Subscription Baseline Module (B3) |
MCSB |
| 2.1.4 | Ensure Defender for SQL Servers (Azure) | ✅ | Subscription Baseline Module (B3) |
MCSB |
| 2.1.5 | Ensure Defender for Storage is enabled | ✅ | Subscription Baseline Module (B3) |
MCSB |
| 2.1.6 | Ensure Defender for Kubernetes | ✅ | Subscription Baseline Module (B3) |
MCSB |
| 2.1.7 | Ensure Defender for Container Registries | ✅ | Subscription Baseline Module (B3) |
MCSB |
| 2.1.8 | Ensure Defender for Key Vault | ✅ | Subscription Baseline Module (B3) |
MCSB |
| 2.1.9 | Ensure Defender for DNS | ✅ | Subscription Baseline Module (B3) |
MCSB |
| 2.1.10 | Ensure Defender for Resource Manager | ✅ | Subscription Baseline Module (B3) |
MCSB |
| 2.1.15 | Ensure Microsoft Defender for Endpoint integrated with Defender | ✅ | Subscription Baseline Module (B3) |
MCSB auto-provisions MDE |
| 2.2 | Ensure auto-provisioning of agents | ✅ | Subscription Baseline Module (B3) |
MCSB assignment enables MMA/AMA auto-provisioning |
| 2.3 | Ensure ASC integration with Microsoft Cloud App Security | 📋 Manual | — | Defender for Cloud Apps integration is a portal setting |
| 2.4 | Ensure Azure Policy Add-on for Kubernetes | ✅ | Subscription Baseline Module (B3), Kyverno AKS Policy Bundle (D4) |
MCSB enables AKS policy add-on; Kyverno is layered on top |
| 2.6 | Ensure Defender for Cloud email is configured | 🔧 Partial | Subscription Baseline Module (B3) |
Email alert configuration is a Defender setting |
| 2.7 | Ensure email set for subscription owners | 📋 Manual | — | Defender Security contacts — portal only |
| 2.13 | Ensure MDfC compliance score < 30 days | ✅ | Compliance Snapshot Collector (E0), Compliance Dashboard (S2) |
E0 collects Defender score; S2 trends + regresses on it |
Section 3 — Storage Accounts¶
| CIS ID | Recommendation | Coverage | Asset | Notes |
|---|---|---|---|---|
| 3.1 | Ensure "Secure transfer required" is enabled | ✅ | State Backend Module (F6), Private Endpoint Policy Module (N5) |
enable_https_traffic_only = true in F6; public-access deny (N5) |
| 3.2 | Ensure storage account access keys are not used by default | ✅ | State Backend Module (F6), Client State Backend Module (B4), State-backend data-plane access decision D22 |
shared_access_key_enabled = false; AAD-only auth |
| 3.3 | Ensure storage account minimum TLS is 1.2 | ✅ | State Backend Module (F6) |
min_tls_version = "TLS1_2" in F6 |
| 3.5 | Ensure shared access signature tokens expire within 1 hour | 📋 Manual | — | SAS token policy is application-layer |
| 3.6 | Ensure storage account public access is disabled | ✅ | Private Endpoint Policy Module (N5), State Backend Module (F6) |
Public-access deny policy (N5); F6 default off |
| 3.7 | Ensure default action is Deny for storage account network rules | ✅ | State Backend Module (F6), State-backend data-plane access decision D22 |
default_action = "Deny" + network rules (opt-in per decision D22) |
| 3.9 | Ensure private endpoints are used | ✅ | State Backend Module (F6) (private endpoint support) |
F6 supports private endpoints; OPT-IN per decision D22 |
| 3.10 | Ensure blob versioning is enabled | 🔧 Partial | State Backend Module (F6), Audit Log Archive Module (J6) |
J6 = WORM; blob versioning is F6 optional toggle |
| 3.11 | Ensure storage logging is enabled | ✅ | Policy Diagnostics Module (J2) |
DINE diagnostic settings for storage accounts |
| 3.15 | Ensure Storage is encrypted with CMK | ✅ | Customer-Managed Key Module (M2), Key Vault Module (F5) |
CMK with HSM-backed AKV key |
Section 4 — Database Services¶
| CIS ID | Recommendation | Coverage | Asset | Notes |
|---|---|---|---|---|
| 4.1.1 | Ensure SQL server auditing is enabled | ✅ | Policy Diagnostics Module (J2) |
DINE diagnostic settings auto-wire SQL audit |
| 4.1.2 | Ensure SQL audit retention ≥ 90 days | ✅ | Log Analytics Module (J1), Audit Log Archive Module (J6) |
LAW retention; WORM blob for immutable audit |
| 4.1.3 | Ensure SQL server firewall does not allow 0.0.0.0 | ✅ | Private Endpoint Policy Module (N5) |
Public-network-access deny policy |
| 4.2.1 | Ensure no PostgreSQL server allows ingress 0.0.0.0/0 | ✅ | Private Endpoint Policy Module (N5) |
Same public-access deny initiative |
| 4.2.2 | Ensure PostgreSQL SSL is enabled | ✅ | TLS Policy Module (M3) |
TLS deny policy enforces ssl_enforcement_enabled |
| 4.3.1 | Ensure MySQL SSL is enabled | ✅ | TLS Policy Module (M3) |
TLS deny policy |
| 4.4 | Ensure Cosmos DB firewall rules configured | ✅ | Private Endpoint Policy Module (N5) |
Public-network-access deny |
| 4.5 | Ensure Azure SQL Database transparent data encryption | ✅ | Encryption Policy Module (M1) |
Encryption deny initiative includes SQL TDE |
Section 5 — Logging and Monitoring¶
| CIS ID | Recommendation | Coverage | Asset | Notes |
|---|---|---|---|---|
| 5.1.1 | Ensure Azure Monitor Diagnostic Setting captures all activity log categories | ✅ | Policy Diagnostics Module (J2) |
DINE diagnostic settings for subscription activity log |
| 5.1.2 | Ensure the activity retention is set to ≥ 1 year | ✅ | Log Analytics Module (J1) |
LAW workspace retention configured ≥ 365 days |
| 5.1.3 | Ensure Audit Profile captures all categories | ✅ | Policy Diagnostics Module (J2) |
DINE policy covers Administrative, Security, Alert, Policy |
| 5.1.4 | Ensure activity log alert exists for Create Policy Assignment | ✅ | Budget Alert Module (U1) |
Action group + alert rule configured by U1 |
| 5.1.5 | Ensure alert for Delete Policy Assignment | ✅ | Budget Alert Module (U1) |
Alert rule for policy delete operations |
| 5.1.6 | Ensure alert for Create/Update/Delete Network Security Groups | ✅ | Budget Alert Module (U1) |
NSG change alert |
| 5.1.7 | Ensure alert for Create/Update/Delete Network Security Group Rules | ✅ | Budget Alert Module (U1) |
NSG rule change alert |
| 5.1.8 | Ensure alert for Create/Update/Delete Security Solution | ✅ | Budget Alert Module (U1) |
Security solution change alert |
| 5.1.9 | Ensure alert for Create/Update/Delete SQL Server Firewall Rule | ✅ | Budget Alert Module (U1) |
SQL firewall change alert |
| 5.1.10 | Ensure alert for Update Security Policy | ✅ | Budget Alert Module (U1) |
Security policy update alert |
| 5.2 | Ensure Azure KeyVault logging is enabled | ✅ | Policy Diagnostics Module (J2), Key Vault Module (F5) |
DINE includes Key Vault diagnostic settings |
| 5.3 | Ensure network watcher is enabled | 🔧 Partial | NSG Baseline Module (N6) |
N6 optionally enables flow logs (requires Network Watcher) |
| 5.4 | Ensure storage container holding Activity logs is private | ✅ | Audit Log Archive Module (J6), State Backend Module (F6) |
WORM storage with private access; public-access deny |
Section 6 — Networking¶
| CIS ID | Recommendation | Coverage | Asset | Notes |
|---|---|---|---|---|
| 6.1 | Ensure that RDP access is restricted | ✅ | NSG Baseline Module (N6), Private Endpoint Policy Module (N5) |
NSG hardening (N6); public-access deny (N5) |
| 6.2 | Ensure that SSH access is restricted | ✅ | NSG Baseline Module (N6), Private Endpoint Policy Module (N5) |
Same NSG + public-access controls |
| 6.3 | Ensure VMs are using managed disks | 📋 Manual | — | VM resource configuration; not enforced by current OPA rules |
| 6.4 | Ensure web application firewall (WAF) is configured | ✅ | WAF Policy Module (N3) |
WAF Policy Module — AppGw WAF v2 / Front Door policy with OWASP 3.2 managed rules + custom block/rate-limit rules |
| 6.5 | Ensure DDoS Standard protection is enabled | ✅ | DDoS Protection (N4), Network Hub Module (F2) |
DDoS Protection module provisions a DDoS Network Protection plan; F2 VNets associate via the exported plan_id |
| 6.6 | Ensure Network Watcher is enabled | 🔧 Partial | NSG Baseline Module (N6) |
N6 uses flow logs which require Network Watcher |
Section 7 — Virtual Machines¶
| CIS ID | Recommendation | Coverage | Asset | Notes |
|---|---|---|---|---|
| 7.1 | Ensure VMs use managed disks | 📋 Manual | — | VM resource config; add to OPA rules as a future enhancement |
| 7.2 | Ensure OS/data disks are encrypted with CMK | ✅ | Encryption Policy Module (M1), Customer-Managed Key Module (M2) |
Encryption deny initiative + CMK module |
| 7.3 | Ensure trusted launch is enabled for VMs | 📋 Manual | — | VM resource property; no current SnowOps module |
| 7.4 | Ensure Azure Backup is enabled for VMs | ✅ | Azure Backup Policy Module (L1) |
Azure Backup policy module (L1) includes VM backup policy |
| 7.5 | Ensure only approved VM extensions installed | ✅ | Terraform OPA Policy Bundle (D3)/Conftest Test Suite (X3) |
OPA rules can gate VM extension resources in plan |
| 7.6 | Ensure endpoint protection is installed | ✅ | Subscription Baseline Module (B3) |
MCSB enables Defender for Endpoint via MDE auto-provisioning |
| 7.7 | Ensure MFA is required for VM management | ✅ | Entra PIM Templates Module (H3), Azure Resource PIM Module (B5) |
CA MFA for ARM; PIM for privileged VM operations |
Section 8 — Key Vault¶
| CIS ID | Recommendation | Coverage | Asset | Notes |
|---|---|---|---|---|
| 8.1 | Ensure Key Vault is recoverable | ✅ | Key Vault Module (F5) |
soft_delete_retention_days = 90; purge_protection_enabled = true |
| 8.2 | Ensure Key Vault keys have an expiration date | ✅ | Customer-Managed Key Module (M2) |
CMK with rotation_policy enforcing expiry + auto-rotate |
| 8.3 | Ensure Key Vault secrets have an expiration date | 🔧 Partial | Service Principal Inventory (H5) |
SP secrets tracked by H5; KV secret expiry is set by producer |
| 8.4 | Ensure Key Vault is not publicly accessible | ✅ | Key Vault Module (F5) |
public_network_access_enabled = false in F5; private endpoint support |
| 8.5 | Ensure Key Vault logging is enabled | ✅ | Policy Diagnostics Module (J2) |
DINE diagnostic settings include Key Vault |
| 8.7 | Ensure automatic key rotation is enabled within 90 days | ✅ | Customer-Managed Key Module (M2) |
rotation_policy in M2 (CMK) with ≤ 90-day rotation interval |
Section 9 — AppService¶
| CIS ID | Recommendation | Coverage | Asset | Notes |
|---|---|---|---|---|
| 9.1 | Ensure App Service authentication is enabled | 📋 Manual | — | App Service EasyAuth; application configuration |
| 9.2 | Ensure App Service uses the latest TLS version | ✅ | TLS Policy Module (M3) |
TLS deny initiative includes App Service minimum TLS |
| 9.3 | Ensure web app redirects HTTP to HTTPS | ✅ | TLS Policy Module (M3) |
HTTPS-only policy |
| 9.4 | Ensure web app is using managed identity | ✅ | Azure Baseline Module (F1) |
Managed identity module; no client secrets |
| 9.5 | Ensure App Service has a registered Managed Identity | ✅ | Azure Baseline Module (F1) |
Same |
| 9.10 | Ensure FTP/FTPS is disabled | 📋 Manual | — | App Service FTP state; no current SnowOps OPA rule |
| 9.11 | Ensure SCM requires same auth as app | 📋 Manual | — | App Service SCM authentication setting |
Running a CIS Assessment¶
# 1. Run G-series (G0-G7) discovery audit — maps each finding to CIS control IDs
node apps/discovery-auditor/dist/index.js \
--subscription-id <sub-id> \
--report-format markdown \
--out /tmp/cis-assessment.md
# 2. Check Defender for Cloud CIS benchmark recommendation state
az security assessment list --subscription <sub-id> \
--query "[?contains(name, 'cis')].[name, status.code]" -o table
# 3. E0 compliance snapshot (includes Defender score + policy compliance %)
node apps/evidence-collector/dist/index.js \
--subscription-id <sub-id> \
--tenant-id <tenant-id> \
--out-dir compliance/snapshots/
# 4. View S2 dashboard trend across snapshots
node apps/compliance-dashboard/dist/index.js \
--snapshots-dir compliance/snapshots/ \
--out compliance/cis-dashboard/
What SnowOps Does NOT Automate for CIS Azure¶
These benchmark items require Entra admin centre / Azure portal configuration or organizational follow-through that sits outside Terraform/Azure Policy automation. What to do about each:
| Control Area | Who | What the manual step is | Notes |
|---|---|---|---|
| Entra ID settings (MFA, legacy auth, guest access) | Client | In the Entra admin centre, scope Conditional Access policies to "All users" for MFA (1.1.3), block legacy authentication protocols, and configure external-collaboration settings to restrict guest invitations and access (1.2.1–1.2.2) | These are tenant-level Entra settings with no Terraform/ARM resource — Entra PIM Templates Module (H3) ships the policy templates to clone from, but applying/scoping them in the admin centre is a one-time manual step per tenant |
| Password protection + smart lockout (1.3.1, 1.3.3) | Client | In Entra ID > Security > Authentication methods, enable Azure AD Password Protection and set the smart-lockout threshold/duration to ≥ 1 minute | Tenant-wide authentication setting; no ARM/TF resource exposes it |
| Global admin count + usage review (1.8) | Client | Periodically review Entra ID > Roles and administrators > Global Administrator and confirm the assigned count is ≤ 3, with all but break-glass accounts using PIM-eligible (not permanent) assignment | Break-Glass Account Module (H7) provisions and counts the emergency-access accounts; the periodic review of who holds standing Global Admin is a recurring access-review task — see Access Review Automation (E6) for the closest automation |
| App registration restriction (1.21) | Client | In Entra ID > User settings, restrict "Users can register applications" to a designated admin group | Tenant-level toggle with no Terraform resource; document the chosen group in the access-control policy |
| VM trusted launch + VM extensions (6.3, 7.1, 7.3, 7.5) | Client (🔧 D3/X3 partial on 7.5) | For each VM/VMSS deployment, set trusted_launch_enabled = true, use managed disks, and restrict the extension allow-list at the resource definition |
No current SnowOps module provisions VMs directly (the platform is AKS/PaaS-first via Secure AKS Module F3); 7.5 can be partially gated today via Terraform OPA Policy Bundle (D3)/Conftest Test Suite (X3) plan-time checks; a dedicated VM baseline module is a roadmap candidate |
| AppService FTP disable, SCM auth (9.1, 9.10, 9.11) | Client | In each App Service's Configuration > General settings, enable EasyAuth, set FTP state to "Disabled" (or "FTPS Only"), and require the SCM site to use the same authentication as the main site | App Service–specific resource properties with no current SnowOps OPA rule gating them; add to the Terraform OPA Policy Bundle (D3) backlog if the client runs App Service workloads |
| Network Watcher provisioning (5.3, 6.6) | Client | Enable Network Watcher in every region where VNets are deployed (Azure enables it by default in most regions, but verify and re-enable if previously disabled) | Prerequisite for NSG Baseline Module (N6) flow logs — a one-time per-region toggle, not a resource the module itself manages |
| SAS token expiry policy (3.5) | Client | Configure the storage account's default SAS expiration policy (and enforce it in application code that issues SAS tokens) to expire within 1 hour | Application-layer concern — the token-issuing code path is outside infrastructure-as-code; State Backend Module (F6) already disables shared-key auth entirely (decision D22) which removes the SAS attack surface for Terraform state, but app-issued SAS tokens for other storage accounts remain a manual policy |
| Defender for Cloud Apps integration + security contact email (2.3, 2.7) | Client | In Defender for Cloud > Environment settings > Email notifications, add the subscription-owner email and enable the Microsoft Defender for Cloud Apps connector | Portal-only settings (Subscription Baseline Module B3 configures the MCSB plans themselves, but these two integration toggles sit outside the Terraform-exposed Defender API) |
| Remediation register / formal tracking | Client | Stand up a remediation tracker (issue board, GRC tool, or spreadsheet) that converts each gap into a ticket with an owner, target date, and verification step | Discovery Audit Suite (G0–G7) and Compliance Dashboard (S2) identify and trend the gaps; converting that into a managed register with accountable owners and due dates is a process the client (or SnowOps in an ongoing-engagement role) must run |