<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Microsoft Sentinel on Brewed in the Cloud by Chris Hailes</title><link>https://blog.brewedinthecloud.com/tags/microsoft-sentinel/</link><description>Recent content in Microsoft Sentinel on Brewed in the Cloud by Chris Hailes</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Tue, 22 Sep 2026 00:00:00 +1000</lastBuildDate><atom:link href="https://blog.brewedinthecloud.com/tags/microsoft-sentinel/rss.xml" rel="self" type="application/rss+xml"/><item><title>Azure Security Telemetry: Start with the Control Plane</title><link>https://blog.brewedinthecloud.com/p/azure-security-telemetry-control-plane/</link><pubDate>Tue, 22 Sep 2026 00:00:00 +1000</pubDate><guid>https://blog.brewedinthecloud.com/p/azure-security-telemetry-control-plane/</guid><description>&lt;p&gt;Security telemetry programs often begin with tools, dashboards, and alert rules. That is understandable, but it can push teams into collecting data before they know what the data is supposed to prove. In Azure, the better starting point is the control plane: who changed what, where, when, and through which path.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you cannot explain control-plane activity, you do not yet have a defensible Azure security telemetry model.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This first post in the Azure Security Telemetry series sets the foundation. We are not trying to collect every possible log. We are defining the minimum trustworthy signal set that helps platform, security, and operations teams reason about Azure change.&lt;/p&gt;
&lt;h2 id="the-mental-model"&gt;The Mental Model
&lt;/h2&gt;&lt;p&gt;Think of Azure security telemetry as three connected layers. The first layer is intent: management operations, policy changes, role assignments, deployments, and configuration updates. The second layer is resource behavior: logs and metrics emitted by the workloads and services affected by those changes. The third layer is detection context: the alerts, incidents, investigations, and response actions that turn raw events into security decisions.&lt;/p&gt;
&lt;p&gt;The control plane sits in the intent layer. Azure Activity Log records subscription-level events such as administrative operations, service health events, and resource health changes. That makes it the audit backbone for questions like: who changed a network security group, who modified a key vault access model, who assigned a privileged role, or who deleted a diagnostic setting?&lt;/p&gt;
&lt;p&gt;The mistake is treating Activity Log as just another table. It is not simply &amp;ldquo;more logs.&amp;rdquo; It is the record of management authority being exercised. A denied data exfiltration attempt matters, but so does the control-plane change that opened the path for it. A risky deployment matters, but so does the identity and pipeline that submitted it.&lt;/p&gt;
&lt;p&gt;For senior cloud and security leaders, the mental model should be accountability before analytics. Start by mapping the decisions you must defend: privileged access, policy exceptions, logging coverage, network exposure, data protection posture, and incident response authority. Then collect the control-plane signals that let you prove those decisions are operating as intended.&lt;/p&gt;
&lt;h2 id="how-it-really-works"&gt;How It Really Works
&lt;/h2&gt;&lt;p&gt;Azure gives you some control-plane visibility by default, but durable security telemetry still requires deliberate routing. Platform metrics and activity logs exist automatically, while diagnostic settings are used to send activity logs, resource logs, and metrics to destinations such as Log Analytics workspaces, Event Hubs, or storage accounts. For security operations, the common pattern is to send security-relevant control-plane logs into a central Log Analytics workspace that is connected to Microsoft Sentinel.&lt;/p&gt;
&lt;div class="mermaid"&gt;flowchart LR
A[Azure Subscription] --&gt; B[Activity Log]
A --&gt; C[Resource Diagnostic Settings]
B --&gt; D[Central Log Analytics Workspace]
C --&gt; D
D --&gt; E[Microsoft Sentinel]
D --&gt; F[Security Dashboards]
E --&gt; G[Analytics Rules and Incidents]
&lt;/div&gt;
&lt;p&gt;The important implementation detail is scope. Activity Log helps at the subscription level, but many useful resource logs require diagnostic settings on the individual resource, resource group, or supported platform service. That means your logging design must account for scale. If diagnostic settings are configured by hand, they will drift. If they are configured through policy, infrastructure as code, and landing zone standards, they can become part of the platform contract.&lt;/p&gt;
&lt;p&gt;You also need to separate collection from interpretation. The collection design answers: what should be sent, where should it go, how long should it be retained, and which teams can read it? The interpretation design answers: which events matter, how should they be enriched, when should they alert, and which response path owns them?&lt;/p&gt;
&lt;p&gt;The control-plane baseline should include administrative operations, policy and initiative changes, role assignment changes, diagnostic setting changes, network control updates, key vault configuration changes, security control changes, and major resource lifecycle events. The exact list varies by environment, but the principle does not: if a change can materially alter security posture, it should leave a searchable trail.&lt;/p&gt;
&lt;h2 id="real-world-impact"&gt;Real-World Impact
&lt;/h2&gt;&lt;p&gt;The practical value of control-plane telemetry is speed and confidence during incidents. When something looks wrong, teams should not spend the first hour arguing whether the platform changed. They should be able to reconstruct the management timeline quickly.&lt;/p&gt;
&lt;p&gt;A common example is storage exposure. A storage account suddenly allows broader network access, public access is changed, or diagnostic coverage disappears. Without control-plane telemetry, the investigation starts with speculation. With it, the team can see the resource update, caller identity, caller IP, operation name, status, correlation ID, and timestamp. That does not solve the incident by itself, but it gives the response team a defensible timeline.&lt;/p&gt;
&lt;p&gt;Another example is privileged access. If a high-impact role assignment appears, the important question is not only whether the role exists. It is who assigned it, through which mechanism, whether it matched an approved change, whether Privileged Identity Management was involved, and whether related resources changed afterwards. Activity Log and identity telemetry together make that analysis possible.&lt;/p&gt;
&lt;p&gt;This also changes executive reporting. Instead of saying &amp;ldquo;we collect Azure logs,&amp;rdquo; the platform team can say &amp;ldquo;we can reconstruct privileged and security-relevant management changes across production subscriptions.&amp;rdquo; That is a stronger assurance statement because it is tied to decision quality, not data volume.&lt;/p&gt;
&lt;p&gt;Control-plane telemetry is also valuable for engineering discipline. When deployment pipelines, policy assignments, and manual portal actions are visible in the same workspace, teams can identify where change is automated, where exceptions happen, and where operational habits are creating risk. The telemetry becomes a feedback loop for platform maturity.&lt;/p&gt;
&lt;h2 id="gotchas-and-edge-cases"&gt;Gotchas and Edge Cases
&lt;/h2&gt;&lt;p&gt;The control plane looks simple until you operate it across many subscriptions, tenants, regions, and teams. The hard parts are not usually about whether Azure can emit logs. They are about consistency, ownership, cost, and retention.&lt;/p&gt;
&lt;p&gt;The first gotcha is assuming that default visibility is the same as a security telemetry design. Azure provides useful default signals, but default availability does not guarantee central retention, Sentinel integration, least-privilege access, or detection coverage. A log that exists somewhere but cannot be queried by the incident team is not operationally useful.&lt;/p&gt;
&lt;p&gt;The second gotcha is inconsistent diagnostic settings. Many Azure services require explicit diagnostic settings to export resource logs. If these are created manually, some resources will be covered and others will not. If your detection rules depend on a log category that only exists on half the resources, the rule creates false confidence.&lt;/p&gt;
&lt;p&gt;The third gotcha is treating every operation as equal. A noisy stream of benign write operations can bury the few events that matter. Control-plane telemetry needs classification. Privileged access changes, policy changes, network exposure changes, logging changes, and security tooling changes deserve a different review path from routine tag updates.&lt;/p&gt;
&lt;p&gt;Retention is another edge case. Security investigations often need to look beyond a short operational window, especially when a compromise is discovered late. Retention choices should be deliberate and risk-based. Sending everything to a premium workspace forever is rarely the answer, but neither is keeping only a few days of high-value administrative history.&lt;/p&gt;
&lt;p&gt;Finally, watch for cross-tenant and centralized operations. Enterprises often centralize logging, security operations, or event streaming. That is powerful, but it introduces permission, routing, and accountability questions. The target workspace or event hub must be protected as a security asset.&lt;/p&gt;
&lt;h2 id="best-practices"&gt;Best Practices
&lt;/h2&gt;&lt;p&gt;Begin with a written signal contract. Define the control-plane events that are security relevant for your organization, the subscriptions in scope, the destination workspace, the retention class, and the owning team. Make the contract understandable enough that cloud platform engineers and security analysts can both challenge it.&lt;/p&gt;
&lt;p&gt;Use Azure Policy or infrastructure as code to deploy diagnostic settings at scale wherever possible. Manual setup is acceptable for early discovery, but it should not become the operating model for production. Policy also helps detect drift when teams create new resources without the expected telemetry path.&lt;/p&gt;
&lt;p&gt;Design the workspace access model intentionally. Security analysts need enough access to investigate, but broad workspace access can expose sensitive operational data. Use role-based access control, table-level patterns where appropriate, and a clear distinction between readers, detection engineers, platform operators, and workspace administrators.&lt;/p&gt;
&lt;p&gt;Classify events before alerting. Not every write operation is an incident. Build analytic logic around high-impact operations, unexpected actors, unusual locations, after-hours changes, failed administrative attempts, and changes to logging, identity, network, and security controls. Use allow lists carefully and review them regularly.&lt;/p&gt;
&lt;p&gt;Correlate control-plane activity with identity and resource telemetry. An administrative operation becomes more meaningful when you can connect it to sign-in behavior, workload behavior, Defender findings, or Sentinel incidents. The goal is not a bigger query. It is a more reliable story.&lt;/p&gt;
&lt;h3 id="practical-control-plane-reconstruction-query"&gt;Practical control-plane reconstruction query
&lt;/h3&gt;&lt;p&gt;Use this as a starting point in Azure Monitor Logs or Sentinel when Azure Activity Log has been routed into the &lt;code&gt;AzureActivity&lt;/code&gt; table. It focuses on security-relevant management operations and returns the actor, correlation, operation, target, result, and time fields needed for a defensible change timeline.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;let lookback = 14d;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;let securityRelevantOperations = dynamic([
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Microsoft.Authorization/roleAssignments/write&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Microsoft.Authorization/roleAssignments/delete&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Microsoft.Authorization/policyAssignments/write&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Microsoft.Authorization/policyExemptions/write&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Microsoft.Insights/diagnosticSettings/write&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Microsoft.Insights/diagnosticSettings/delete&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Microsoft.Network/networkSecurityGroups/securityRules/write&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Microsoft.KeyVault/vaults/write&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Microsoft.Storage/storageAccounts/write&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Microsoft.Security/pricings/write&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AzureActivity
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| where TimeGenerated &amp;gt;= ago(lookback)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| where CategoryValue in (&amp;#34;Administrative&amp;#34;, &amp;#34;Policy&amp;#34;, &amp;#34;Security&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| where OperationNameValue in~ (securityRelevantOperations)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; or OperationNameValue has_any (&amp;#34;diagnosticSettings&amp;#34;, &amp;#34;roleAssignments&amp;#34;, &amp;#34;policyAssignments&amp;#34;, &amp;#34;networkSecurityGroups&amp;#34;, &amp;#34;keyVault&amp;#34;, &amp;#34;storageAccounts&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| extend AuthorizationAction = tostring(Authorization_d.action),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; AuthorizationScope = tostring(Authorization_d.scope),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; RequestMethod = tostring(HTTPRequest.method),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ClientRequestId = tostring(HTTPRequest.clientRequestId),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ClaimsAppId = tostring(Claims_d.appid),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ClaimsUpn = tostring(Claims_d.upn)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| project TimeGenerated, Caller, ClaimsUpn, ClaimsAppId, CallerIpAddress, CorrelationId, OperationId, OperationNameValue, ActivityStatusValue, ActivitySubstatusValue, SubscriptionId, ResourceGroup, ResourceProviderValue, ResourceId, AuthorizationAction, AuthorizationScope, RequestMethod, ClientRequestId
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| order by TimeGenerated desc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The assumption is that &lt;code&gt;AzureActivity&lt;/code&gt; contains subscription-level or management group level events routed to the workspace. Microsoft documents &lt;code&gt;CorrelationId&lt;/code&gt; as the field that groups events belonging to the same broader action, while &lt;code&gt;OperationNameValue&lt;/code&gt;, &lt;code&gt;ResourceId&lt;/code&gt;, &lt;code&gt;Caller&lt;/code&gt;, &lt;code&gt;CallerIpAddress&lt;/code&gt;, &lt;code&gt;ActivityStatusValue&lt;/code&gt;, and &lt;code&gt;TimeGenerated&lt;/code&gt; provide the core reconstruction frame. Validate provider-specific operations in your tenant before turning this into an alert.&lt;/p&gt;
&lt;div class="insight"&gt;
&lt;div class="insight-icon"&gt;🍺&lt;/div&gt;
&lt;div class="insight-content"&gt;
&lt;strong&gt;Brewed Insight:&lt;/strong&gt; The first real win I look for in an Azure security telemetry program isn&amp;rsquo;t the number of logs collected. It&amp;rsquo;s whether the team can explain a security-relevant change without relying on memory, screenshots, or tribal knowledge.
&lt;/div&gt;
&lt;/div&gt;
&lt;style&gt;
.insight {
display: flex;
align-items: center;
background-color: #0089e41c;
border-left: 10px solid #D69A2D;
padding: 10px;
margin: 20px 0;
border-radius: 4px;
}
.insight-icon {
font-size: 24px;
margin-right: 10px;
}
.insight-content {
flex: 1;
}
&lt;/style&gt;&lt;h2 id="learn-more"&gt;Learn More
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.brewedinthecloud.com/page/azure-security-telemetry-toolkit/" &gt;Azure Security Telemetry Toolkit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/azure/security/fundamentals/management-monitoring-overview" target="_blank" rel="noopener"
&gt;Azure security management and monitoring overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/azure/azure-monitor/essentials/diagnostic-settings" target="_blank" rel="noopener"
&gt;Diagnostic settings in Azure Monitor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/azure/azure-monitor/essentials/activity-log" target="_blank" rel="noopener"
&gt;Azure Activity Log&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/azure/sentinel/overview" target="_blank" rel="noopener"
&gt;Microsoft Sentinel overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>