<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Azure Virtual Network on Brewed in the Cloud by Chris Hailes</title><link>https://blog.brewedinthecloud.com/tags/azure-virtual-network/</link><description>Recent content in Azure Virtual Network on Brewed in the Cloud by Chris Hailes</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Tue, 07 Apr 2026 00:00:00 +1100</lastBuildDate><atom:link href="https://blog.brewedinthecloud.com/tags/azure-virtual-network/rss.xml" rel="self" type="application/rss+xml"/><item><title>Defining Blast Radius in Azure Networks</title><link>https://blog.brewedinthecloud.com/p/assume-breach-defining-blast-radius/</link><pubDate>Tue, 07 Apr 2026 00:00:00 +1100</pubDate><guid>https://blog.brewedinthecloud.com/p/assume-breach-defining-blast-radius/</guid><description>&lt;p&gt;Most Azure networks aren’t designed to fail gracefully.&lt;/p&gt;
&lt;p&gt;They’re designed to be &lt;em&gt;convenient&lt;/em&gt;: easy peering, wide address space, few hard edges. Everything works, deployments are fast, nobody blocks progress.&lt;/p&gt;
&lt;p&gt;Until something breaks in the worst possible way, a compromised workload already inside the network and you discover that “convenient” and “contained” are rarely the same thing.&lt;/p&gt;
&lt;p&gt;In an assume‑breach model, blast radius isn’t theoretical. It’s the difference between an incident and an outage‑shaped investigation.&lt;/p&gt;
&lt;h2 id="the-mental-model"&gt;The Mental Model
&lt;/h2&gt;&lt;h3 id="the-common-assumption"&gt;The common assumption
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;VNets are boundaries. If we didn’t mean for things to talk, security controls will handle it.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This model treats:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Address space as neutral&lt;/li&gt;
&lt;li&gt;Peering as low‑risk plumbing&lt;/li&gt;
&lt;li&gt;Routing as an implementation detail&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Security, in this framing, lives elsewhere.&lt;/p&gt;
&lt;h3 id="why-it-breaks"&gt;Why it breaks
&lt;/h3&gt;&lt;p&gt;Azure networking is opinionated in one quiet but important way:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If traffic is routable, the platform assumes it’s legitimate.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;VNets, peerings, and routes don’t express &lt;em&gt;intent&lt;/em&gt;. They express &lt;em&gt;possibility&lt;/em&gt;. Once a packet has a valid path, Azure does not ask whether that path aligns with your threat model.&lt;/p&gt;
&lt;p&gt;In an incident, possibility always beats intent.&lt;/p&gt;
&lt;h2 id="how-it-really-works"&gt;How It Really Works
&lt;/h2&gt;&lt;p&gt;Blast radius in Azure networks is shaped by &lt;strong&gt;structural reachability&lt;/strong&gt;, not by how carefully your firewall rules are written.&lt;/p&gt;
&lt;p&gt;Three mechanics matter most.&lt;/p&gt;
&lt;h3 id="address-space-sets-the-outer-limit"&gt;Address space sets the outer limit
&lt;/h3&gt;&lt;p&gt;CIDR ranges define what &lt;em&gt;could ever&lt;/em&gt; be reached.&lt;/p&gt;
&lt;p&gt;If two workloads sit in address spaces that can be routed between:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They are part of the same potential blast radius&lt;/li&gt;
&lt;li&gt;Any containment relies on controls outside the network layer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Addressing is not bookkeeping. It’s scope definition.&lt;/p&gt;
&lt;h3 id="peering-collapses-assumed-boundaries"&gt;Peering collapses assumed boundaries
&lt;/h3&gt;&lt;p&gt;VNet peering creates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full IP reachability between address spaces&lt;/li&gt;
&lt;li&gt;No inherent notion of trust direction&lt;/li&gt;
&lt;li&gt;No concept of “only for these workloads”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From a routing perspective, peered VNets behave like a single, larger network unless you deliberately constrain paths.&lt;/p&gt;
&lt;p&gt;That’s efficient. It’s also expansive.&lt;/p&gt;
&lt;h3 id="routing-decides-how-compromise-spreads"&gt;Routing decides how compromise spreads
&lt;/h3&gt;&lt;p&gt;User Defined Routes (UDRs), system routes, and propagated paths answer one question during an incident:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Where can packets actually go right now?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The answer is often broader and less remembered than architects expect.&lt;/p&gt;
&lt;h2 id="realworld-impact"&gt;Real‑World Impact
&lt;/h2&gt;&lt;p&gt;Under assume breach, blast radius isn’t an abstract risk. It shows up as very concrete outcomes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Non‑Prod compromise that suddenly has line‑of‑sight to Prod&lt;/li&gt;
&lt;li&gt;A “small” spoke that can reach far more than its owners realise&lt;/li&gt;
&lt;li&gt;An incident response slowed down by surprise connectivity&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pattern is consistent: &lt;strong&gt;networks optimised for convenience quietly optimise for spread&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="blast-radius-smell-tests"&gt;Blast Radius Smell Tests
&lt;/h2&gt;&lt;p&gt;These aren’t best practices. They’re gut checks you can run against a real estate &lt;em&gt;as it exists today&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="1-reachability-without-intent"&gt;1. Reachability Without Intent
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Question to ask:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Can this workload reach IP ranges it was never explicitly designed to talk to simply because routing allows it?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If the answer is yes, that reachability is part of your blast radius, regardless of firewall posture.&lt;/p&gt;
&lt;p&gt;This smell commonly comes from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Just in case” peering&lt;/li&gt;
&lt;li&gt;Broad, loosely allocated address space&lt;/li&gt;
&lt;li&gt;Default routes no one has reviewed in years&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Under breach conditions, attackers care about what’s reachable, not what was intended.&lt;/p&gt;
&lt;h3 id="2-environment-boundaries-that-only-exist-in-diagrams"&gt;2. Environment Boundaries That Only Exist in Diagrams
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Question to ask:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;If I ignore names, subscriptions, and tags, are Prod and Non‑Prod actually isolated at the routing layer?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If environments are routable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They are not isolated&lt;/li&gt;
&lt;li&gt;They simply rely on convention to stay apart&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Attackers don’t see environments. They see IP ranges and next hops.&lt;/p&gt;
&lt;p&gt;If a Non‑Prod workload is compromised, the network decides whether that incident stays there, not your naming standards.&lt;/p&gt;
&lt;h3 id="3-temporary-connectivity-that-never-left"&gt;3. Temporary Connectivity That Never Left
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Question to ask:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Which peerings or routes would surprise you if they appeared in an incident review?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Migration links, troubleshooting routes, one‑off access that “we’ll remove later” these quietly accumulate.&lt;/p&gt;
&lt;p&gt;They are dangerous because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They’re forgotten&lt;/li&gt;
&lt;li&gt;They’re rarely monitored&lt;/li&gt;
&lt;li&gt;They aren’t defended in anyone’s mental model&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Routing doesn’t care how old a decision is.&lt;/p&gt;
&lt;h2 id="implementation-examples"&gt;Implementation Examples
&lt;/h2&gt;&lt;h3 id="visualising-accidental-blast-radius"&gt;Visualising accidental blast radius
&lt;/h3&gt;&lt;div class="mermaid"&gt;graph TD
Shared["Shared Services VNet&lt;br/&gt;10.0.0.0/16"]
Prod["Prod VNet&lt;br/&gt;10.1.0.0/16"]
NonProd["Non‑Prod VNet&lt;br/&gt;10.2.0.0/16"]
Shared --- Prod
Shared --- NonProd
&lt;/div&gt;
&lt;p&gt;This looks segmented.&lt;/p&gt;
&lt;p&gt;From a routing perspective, it often isn’t. Shared services become an implicit bridge unless paths are deliberately constrained.&lt;/p&gt;
&lt;h3 id="a-peering-that-widens-scope-by-default"&gt;A peering that widens scope by default
&lt;/h3&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;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bicep" data-lang="bicep"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nonProdToShared&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2023-11-01&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;nonprod-to-shared&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nonProdVnet&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;allowVirtualNetworkAccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;allowForwardedTraffic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&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;Nothing here is misconfigured.&lt;/p&gt;
&lt;p&gt;But combined with similar peerings elsewhere, this enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lateral reach that wasn’t consciously designed&lt;/li&gt;
&lt;li&gt;Incident paths that rely entirely on downstream controls to stop spread&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s blast radius expressed as configuration.&lt;/p&gt;
&lt;h2 id="gotchas--edge-cases"&gt;Gotchas &amp;amp; Edge Cases
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Subscription boundaries don’t limit routing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Address space reuse hides, rather than reduces, blast radius&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Old peerings are rarely re‑evaluated&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Default system routes often enable more reach than diagrams suggest&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you haven’t inspected effective routes during a failure scenario, you don’t actually know your containment story.&lt;/p&gt;
&lt;h2 id="best-practices"&gt;Best Practices
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Treat &lt;strong&gt;every routable path as an explicit trust decision&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Align address space with &lt;strong&gt;containment goals&lt;/strong&gt;, not just growth&lt;/li&gt;
&lt;li&gt;Periodically review &lt;strong&gt;reachable IP ranges&lt;/strong&gt;, not just VNets&lt;/li&gt;
&lt;li&gt;Remove connectivity that no one can clearly justify today&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is architectural discipline, not extra tooling.&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; Blast radius is rarely expanded by bold decisions.&lt;br&gt;
It’s expanded by quiet ones no one revisits.
&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://learn.microsoft.com/azure/virtual-network/virtual-network-peering-overview" target="_blank" rel="noopener"
&gt;Azure Virtual Network Peering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/azure/virtual-network/virtual-networks-udr-overview" target="_blank" rel="noopener"
&gt;Azure Routing Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/azure/virtual-network/diagnose-network-routing-problem" target="_blank" rel="noopener"
&gt;Effective Routes in Azure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>