[LZ 6.1] Standing Up Posture and the Central Record

The central Log Analytics workspace, Defender for Cloud with the plan you chose, diagnostic settings pushed across the tree by policy, the identity signals routed in, the alerts that matter, and a test that proves a resource logs land in the record. The reproducible build for posture and central logging.


By the end of this you have the central Log Analytics workspace with a ninety-day floor and a daily cap, Defender for Cloud confirmed on with the plan you chose enabled at the subscription, resource diagnostic settings flowing into the workspace and an Azure Policy assignment pushing them across the tree so a resource created next year reports itself without anyone remembering, the Entra and Intune identity signals routed in on their own path, the handful of alerts that actually matter wired, and an end-to-end test that proves a resource’s logs land in the central record. The portal walk is the teaching spine; a consolidated set of commands reproduces each step. Northfork Supply Co. is the running example, with its single Production subscription under the tree.


Before Step 1: you need Owner on the Production subscription, or Contributor plus User Access Administrator, to create the workspace, enable Defender plans, and assign policy with a managed identity; the management-group tree from the governance build; a decision made on Defender for Servers Plan 1 versus Plan 2; and the Azure CLI. Set two identifiers once so the commands read cleanly: the Production subscription is PROD_SUB_ID, and the workspace resource ID that several steps consume is WORKSPACE_ID (Step 1 prints it). The management-group scope is /providers/Microsoft.Management/managementGroups/mg-northfork.

Step 1: Create the central workspace

Create one Log Analytics workspace and treat it as platform infrastructure, in the management resource group, named for what it is. Set the interactive retention to ninety days at creation rather than accepting the roughly one-month default, because the operational floor for investigating an incident is measured in weeks and a record that has aged out is not a record. Set a daily cap as a safety net, well above your expected volume, so a runaway ingestion spike cannot produce a runaway bill.

SettingValueWhy
Resource grouprg-management-prod-wus2-001The workspace is platform infrastructure, not a workload resource
Namelaw-platform-prod-wus2-001Named by the convention so its role is legible at a glance
Interactive retention90 daysThe investigation floor; about 31 days is included, the rest is a per-GB charge you accept deliberately
Daily capA ceiling above normal volume, with an alert before itA spike guard, not a budget; a capped workspace stops collecting and goes blind for the day
# Create the workspace with a 90-day interactive retention
az monitor log-analytics workspace create \
  --resource-group "rg-management-prod-wus2-001" \
  --workspace-name "law-platform-prod-wus2-001" \
  --location "westus2" \
  --retention-time 90

# Set the daily cap (dailyQuotaGb) as a safety net, e.g. 5 GB/day
az monitor log-analytics workspace update \
  --resource-group "rg-management-prod-wus2-001" \
  --workspace-name "law-platform-prod-wus2-001" \
  --quota 5

# Capture the workspace resource ID for later steps
az monitor log-analytics workspace show \
  --resource-group "rg-management-prod-wus2-001" \
  --workspace-name "law-platform-prod-wus2-001" \
  --query id -o tsv

Expected result: one workspace, ninety-day retention, a daily cap set. Save the resource ID the last command prints as WORKSPACE_ID. Failure mode to avoid: leaving retention at the default and discovering during an incident that the week you need aged out a month ago.

Step 2: Confirm posture is on, and enable the plan you chose

Defender for Cloud’s foundational posture tier is already enabled on the subscription and already scoring you against the Microsoft Cloud Security Benchmark; your job is to confirm it, not to switch it on. Then enable the one paid plan that earns its place on a hybrid estate, Defender for Servers, at the plan level you decided in the doctrine article. It is enabled at the subscription scope and covers every machine of that type, so this is the deliberate cost decision, made once.

SettingValueWhy
Foundational postureOn (default), MCSB assignedSecure Score, recommendations, benchmark assessment, at no cost; confirm, never disable
Defender for ServersPlan 1 (EDR parity) or Plan 2 (posture + JIT)Plan 2 adds agentless scanning, FIM, just-in-time access, and 500 MB/machine/day of security ingestion
ScopeSubscriptionCovers all virtual machines in the subscription; a cost conversation before you flip it
# Confirm the free foundational tier is active across the subscription
az security pricing list --query "value[?pricingTier=='Free'].name" -o table

# Enable Defender for Servers at the plan you chose (subplan P1 or P2)
az security pricing create \
  --name "VirtualMachines" \
  --tier "Standard" \
  --subplan "P2"

# Verify the plan and subplan landed
az security pricing show --name "VirtualMachines" \
  --query "{tier:pricingTier, plan:subPlan}" -o table

Expected result: VirtualMachines shows Standard with your chosen subplan; the foundational tier remains on for everything else. The five-hundred-megabyte daily ingestion benefit that comes with Plan 2 applies automatically per workspace against the security tables, so it quietly offsets part of what Step 3 is about to start sending. Failure mode: enabling Plan 2 on a subscription full of virtual machines without doing the arithmetic first, then meeting the cost on the invoice instead of in the plan.

Step 3: Send diagnostics in, and make policy do it at scale

A resource sends its logs to the workspace through a diagnostic setting. Creating one by hand for a single resource is how you learn the shape; assigning a policy that creates them for you is how the estate stays covered without anyone remembering. Do both, in that order. First wire one resource directly so you can see the mechanism, then assign the built-in DeployIfNotExists initiative at the top of the tree so every current and future resource of the covered types reports itself, and run a remediation task to catch everything that already exists.

# Wire one resource directly, so you can see the mechanism (example: a Key Vault)
az monitor diagnostic-settings create \
  --name "diag-to-law" \
  --resource "RESOURCE_ID" \
  --workspace "WORKSPACE_ID" \
  --logs '[{"categoryGroup":"allLogs","enabled":true}]' \
  --metrics '[{"category":"AllMetrics","enabled":true}]'

# Then make it automatic across the tree: assign the built-in DINE initiative at MG scope.
# Find the initiative id (category-group diagnostic settings to a Log Analytics workspace):
az policy set-definition list --query "[?contains(displayName,'diagnostic settings') && contains(displayName,'Log Analytics')].{name:displayName, id:name}" -o table

# Assign it at the top of the tree with a system-assigned identity
az policy assignment create \
  --name "diag-to-law" \
  --display-name "Send diagnostics to central workspace" \
  --scope "/providers/Microsoft.Management/managementGroups/mg-northfork" \
  --policy-set-definition "INITIATIVE_ID" \
  --mi-system-assigned --location "westus2" \
  --params '{"logAnalytics":{"value":"WORKSPACE_ID"}}'

# Grant the assignment's managed identity the rights it needs, then remediate existing resources
az role assignment create --assignee "ASSIGNMENT_MI_OBJECT_ID" \
  --role "Log Analytics Contributor" --scope "/providers/Microsoft.Management/managementGroups/mg-northfork"
az role assignment create --assignee "ASSIGNMENT_MI_OBJECT_ID" \
  --role "Monitoring Contributor" --scope "/providers/Microsoft.Management/managementGroups/mg-northfork"
az policy remediation create --name "diag-to-law-remediation" \
  --policy-assignment "diag-to-law" \
  --management-group "mg-northfork"

Expected result: the single resource reports immediately, and within a remediation cycle the existing estate is covered while new resources are covered on creation. Failure mode to watch: assigning the initiative but forgetting the managed identity’s role assignments, which leaves the policy unable to create the settings it was assigned to create, so it reports non-compliant and silently deploys nothing. The identity needs Log Analytics Contributor and Monitoring Contributor at the scope it operates on.

Step 4: Route the identity and device signals on their own path

The identity signals do not arrive through Azure resource diagnostics, and this is the detail people miss until they go looking for a sign-in during an investigation and it is not there. Microsoft Entra ID exports its sign-in and audit logs through its own diagnostic settings, a separate surface, and the Conditional Access outcomes ride inside the sign-in records rather than in a category of their own. Microsoft Intune routes its audit, operational, and device-compliance logs the same separate way. Send both into the same central workspace so the identity timeline and the resource timeline line up.

SourceCategories to sendWhere it is configured
Microsoft Entra IDSignInLogs, AuditLogs (add non-interactive and service-principal sign-ins if licensed)Entra admin center, Monitoring and health, Diagnostic settings
Microsoft IntuneAuditLogs, OperationalLogs, DeviceComplianceOrgIntune admin center, Reports, Diagnostics settings

The Entra diagnostic setting is portal-driven and also reachable through the tenant diagnostic-settings API when you want it scripted. There is no honest Azure CLI verb for it, so this is the one place a build sheet points you at the API rather than pretending a clean command exists.

# Route Entra sign-in and audit logs to the central workspace via the tenant diagnostic API
az rest --method put \
  --url "https://management.azure.com/providers/microsoft.aadiam/diagnosticSettings/entra-to-law?api-version=2017-04-01-preview" \
  --body '{
    "properties": {
      "workspaceId": "WORKSPACE_ID",
      "logs": [
        {"category": "SignInLogs", "enabled": true},
        {"category": "AuditLogs", "enabled": true},
        {"category": "NonInteractiveUserSignInLogs", "enabled": true},
        {"category": "ServicePrincipalSignInLogs", "enabled": true}
      ]
    }
  }'

Expected result: within about fifteen minutes the SigninLogs and AuditLogs tables in the workspace begin to populate. Failure mode: assuming Azure resource diagnostics covered identity and never configuring this path, so the sign-in evidence you most want during an account-compromise investigation is the one thing you never collected.

Step 5: Wire the alerts that matter

The record is queryable evidence; the alerts are the few signals no one should have to go looking for. Keep the set small and high-signal, because an alert that fires often is an alert people learn to ignore. Two of these close the loop from the identity article: the break-glass sign-in, which should never happen quietly, and a new Owner assignment appearing anywhere in the estate. The break-glass sign-in alert and the exclusion-group change alert are the same ones the Conditional Access framework asks you to keep, now landing in the platform’s own record.

AlertFires onUrgency
Break-glass sign-inAny sign-in by an emergency accountImmediate; these accounts are silent until used
New Owner assignmentA roleAssignments write granting OwnerImmediate; standing Owner should not appear unseen
Defender high severityA high-severity Defender for Cloud alertImmediate
Budget threshold80% and 100% of the monthly budgetCost control (set with the budget in the operating article)
Daily cap approachingIngestion nearing the workspace capBefore it trips, so the record never goes blind unnoticed
# Break-glass sign-in: a scheduled log-query alert on the emergency UPNs
az monitor scheduled-query create \
  --name "alert-breakglass-signin" \
  --resource-group "rg-management-prod-wus2-001" \
  --scopes "WORKSPACE_ID" \
  --condition "count 'placeholder' > 0" \
  --condition-query placeholder='SigninLogs | where UserPrincipalName in ("[email protected]","[email protected]")' \
  --description "Any emergency-account sign-in" \
  --evaluation-frequency 5m --window-size 5m \
  --action-groups "ACTION_GROUP_ID"

# New Owner assignment: an activity-log alert on role-assignment writes
az monitor activity-log alert create \
  --name "alert-owner-assignment" \
  --resource-group "rg-management-prod-wus2-001" \
  --scope "/subscriptions/PROD_SUB_ID" \
  --condition category=Administrative and operationName=Microsoft.Authorization/roleAssignments/write \
  --action-group "ACTION_GROUP_ID"

Expected result: the emergency-account query returns nothing on a normal day and pages you the moment it does not. Failure mode on the Owner alert: the activity-log condition fires on every role assignment, so route it to a channel you triage rather than a pager, or tighten it downstream to the Owner role definition, because an alert that cries on every Reader grant is one you will mute.

A worked example

Northfork runs one file-server virtual machine it administers directly, so it enabled Defender for Servers Plan 2 rather than Plan 1, specifically for just-in-time access, which let it close the machine’s management ports and stop planning for a bastion host. The workspace was created with ninety-day retention and a five-gigabyte daily cap. The diagnostic-settings initiative was assigned at mg-northfork, so the file-server’s resource logs, the Key Vault’s logs, and the network flow logs all began arriving without anyone touching each resource, and the flow logs were pointed at a Basic-tier table because they are forensic bulk nobody queries interactively. Entra sign-in and audit logs were routed in on the tenant path. The break-glass sign-in alert was wired to the operations mailbox. When Northfork later needed to patch the file server, an administrator raised a just-in-time request, the port opened for the window, the request and the sign-in both landed in the workspace, and the timeline of who reached the machine and when existed without anyone having planned to capture it. That is the record doing its job on an ordinary day.

Naming convention

The workspace follows the estate convention, law-platform-prod-wus2-001, so its role is obvious in any list. Name diagnostic-settings consistently, diag-to-law on each resource, so a glance tells you the destination. Name alerts for what they catch, alert-breakglass-signin, alert-owner-assignment, alert-daily-cap, so the alert rules read as a list of the things you decided were worth waking up for. Keep the data-collection choices, which table plan each high-volume source lands on, written down beside the rest of the foundation, because the cheap-tier decision for flow logs is invisible until someone wonders why the bill is what it is.

The end-to-end test

Prove the record actually records. Pick a resource covered by the diagnostic-settings policy, generate an event on it, wait a few minutes, and query the workspace for that event. If it is there, the fan-in works and the estate is keeping evidence. The cleanest proof uses activity that always exists: query the AzureActivity table for a recent operation, and separately confirm the identity path by querying SigninLogs for a recent sign-in. A workspace that returns rows for both an Azure operation and a sign-in is a workspace wired to both planes, which is the whole point.

# Prove resource-plane logging: recent Azure control-plane operations are landing
az monitor log-analytics query \
  --workspace "WORKSPACE_GUID" \
  --analytics-query "AzureActivity | where TimeGenerated > ago(1h) | summarize events=count()" -o table

# Prove identity-plane logging: recent sign-ins are landing (run after Step 4 has had time to flow)
az monitor log-analytics query \
  --workspace "WORKSPACE_GUID" \
  --analytics-query "SigninLogs | where TimeGenerated > ago(1h) | summarize signins=count()" -o table
# Expect: non-zero counts. WORKSPACE_GUID is the workspace customerId (GUID), not the full resource ID.

Before you scale it

  • One central workspace in rg-management, ninety-day interactive retention, a daily cap set as a safety net with an alert before it trips.
  • Defender for Cloud foundational tier confirmed on with MCSB assigned, and Defender for Servers enabled at the subscription at the plan you chose deliberately.
  • One resource wired to the workspace by hand, then the DeployIfNotExists initiative assigned at mg-northfork with its managed identity granted Log Analytics Contributor and Monitoring Contributor, and a remediation task run for existing resources.
  • Entra sign-in and audit logs and Intune device logs routed to the same workspace on the tenant diagnostic path, with the Conditional Access outcomes understood to ride inside the sign-in logs.
  • High-volume forensic data (VNet flow logs) sent to a Basic or Auxiliary table plan, not the Analytics plan.
  • The minimum alert set wired, break-glass sign-in and new-Owner first, routed to channels matched to their urgency.
  • End-to-end test passed: AzureActivity and SigninLogs both return recent rows in the central workspace.

With posture on and the record keeping itself, the foundation can now see itself and remember what happened to it. What remains is the layer that has been deferred since the first article, the one that turns all these good intentions into rules the estate actually enforces. The next article is policy: audit before deny, tags made mandatory, and the management-group tree finally doing the job it was shaped for.


Azure Landing Zones
‹ Previous: [LZ 6] The Estate You Can See
Next: [LZ 7] Where the Tree Starts Saying No