<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Security Architecture on Brewed in the Cloud by Chris Hailes</title><link>https://blog.brewedinthecloud.com/tags/security-architecture/</link><description>Recent content in Security Architecture on Brewed in the Cloud by Chris Hailes</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Thu, 21 May 2026 00:00:00 +1000</lastBuildDate><atom:link href="https://blog.brewedinthecloud.com/tags/security-architecture/rss.xml" rel="self" type="application/rss+xml"/><item><title>Routing Decisions That Quietly Create Security Gaps</title><link>https://blog.brewedinthecloud.com/p/network-fails-routing-decisions-security-gaps/</link><pubDate>Thu, 21 May 2026 00:00:00 +1000</pubDate><guid>https://blog.brewedinthecloud.com/p/network-fails-routing-decisions-security-gaps/</guid><description>&lt;p&gt;Routing still feels like plumbing.&lt;/p&gt;
&lt;p&gt;You change where packets go, traffic flows again, and the incident closes. Nothing &lt;em&gt;looks&lt;/em&gt; less secure. No rules changed. No alerts fired. Yet something fundamental may have shifted not availability, but &lt;strong&gt;who is now allowed to talk to whom&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This post is about routing decisions that don’t break connectivity, they quietly break &lt;strong&gt;trust boundaries&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="the-mental-model"&gt;The Mental Model
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Common assumption:&lt;/strong&gt;&lt;br&gt;
Routing is a connectivity concern. Security is enforced elsewhere.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why it breaks:&lt;/strong&gt;&lt;br&gt;
In Azure, routing determines the &lt;em&gt;effective security perimeter&lt;/em&gt;. If a route expands reachability beyond the documented trust boundary, that expansion &lt;strong&gt;is a security failure&lt;/strong&gt;, regardless of intent.&lt;/p&gt;
&lt;p&gt;Security controls only matter if traffic actually traverses them. Routing decides whether they ever get the chance.&lt;/p&gt;
&lt;h2 id="how-it-really-works"&gt;How It Really Works
&lt;/h2&gt;&lt;p&gt;Azure evaluates routing before most security controls can apply policy.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User‑defined routes (UDRs) override platform defaults.&lt;/li&gt;
&lt;li&gt;Peering enables reachability that security rules often assume is constrained.&lt;/li&gt;
&lt;li&gt;Abstractions hide the effective path until it matters.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Azure will faithfully forward packets along any valid route. It does not validate whether that path aligns with your security intent or whether it expands trust beyond what was ever reviewed.&lt;/p&gt;
&lt;p&gt;Routing doesn’t just connect networks.&lt;br&gt;
It &lt;strong&gt;redefines the trust model the rest of your security stack assumes&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="routing-as-an-unreviewed-trust-expansion"&gt;Routing as an Unreviewed Trust Expansion
&lt;/h2&gt;&lt;h3 id="convenience-routes"&gt;Convenience Routes
&lt;/h3&gt;&lt;p&gt;A common change request:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“We just need workload A to reach service B.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The route gets added. The problem is solved. But if that route enables A to reach &lt;em&gt;everything&lt;/em&gt; B can reach, the trust boundary has already expanded.&lt;/p&gt;
&lt;p&gt;No firewall rule changed.&lt;br&gt;
But the security posture did.&lt;/p&gt;
&lt;p&gt;If reachability grows beyond what was explicitly documented and approved, the routing change itself is the failure not the firewall configuration.&lt;/p&gt;
&lt;h3 id="asymmetric-paths-invisible-impact"&gt;Asymmetric Paths, Invisible Impact
&lt;/h3&gt;&lt;p&gt;Azure does not enforce symmetric routing.&lt;/p&gt;
&lt;p&gt;It’s easy to create designs where traffic passes through inspection on the way out, but returns via a different path governed by system routes or peering behaviour.&lt;/p&gt;
&lt;p&gt;From a security perspective, this means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enforcement becomes partial&lt;/li&gt;
&lt;li&gt;Logs represent only a subset of reality&lt;/li&gt;
&lt;li&gt;Policy confidence decays over time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you can’t explain the full bidirectional path, you can’t reliably define the trust boundary.&lt;/p&gt;
&lt;h3 id="accidental-transitivity"&gt;Accidental Transitivity
&lt;/h3&gt;&lt;p&gt;Routing plus peering enables &lt;strong&gt;implicit trust chains&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Network A can reach B.&lt;br&gt;
B can reach C.&lt;br&gt;
A can now often reach C even if nobody intended that relationship to exist.&lt;/p&gt;
&lt;p&gt;No new security rule was added.&lt;br&gt;
But effective reachability expanded anyway.&lt;/p&gt;
&lt;h2 id="realworld-impact"&gt;Real‑World Impact
&lt;/h2&gt;&lt;p&gt;This failure mode shows up operationally, not at design time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Security reviews pass while posture degrades&lt;/strong&gt;&lt;br&gt;
Controls are correct, the path is not.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Visibility becomes misleading&lt;/strong&gt;&lt;br&gt;
Logs show inspected traffic, not &lt;em&gt;all possible traffic&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Change risk compounds silently&lt;/strong&gt;&lt;br&gt;
Each routing change inherits and extends existing trust relationships.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Security ownership blurs&lt;/strong&gt;&lt;br&gt;
Routing changes feel “network‑only”, but their impact is architectural.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This changes how routing should be treated in production:&lt;br&gt;
&lt;strong&gt;as a security‑significant change, not a connectivity tweak.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="implementation-example-a-route-that-expands-trust"&gt;Implementation Example: A Route That Expands Trust
&lt;/h2&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;/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;appRouteTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Microsoft.Network/routeTables@2023-09-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;rt-app-subnet&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;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;resourceGroup&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nv"&gt;location&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;routes&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="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;to-shared-services&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;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;addressPrefix&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;10.40.0.0/16&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;nextHopType&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;VirtualAppliance&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;nextHopIpAddress&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;10.20.0.4&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="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;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;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;On paper, this sends app traffic through an inspection point.&lt;/p&gt;
&lt;p&gt;In practice, this route should be treated as a &lt;strong&gt;security failure&lt;/strong&gt; if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;10.40.0.0/16&lt;/code&gt; contains more than the explicitly intended services&lt;/li&gt;
&lt;li&gt;It enables reachability beyond the documented trust boundary&lt;/li&gt;
&lt;li&gt;The return path does not traverse the same enforcement points&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The route may be technically correct and still security‑incorrect.&lt;/p&gt;
&lt;h2 id="visualising-the-trust-shift"&gt;Visualising the Trust Shift
&lt;/h2&gt;&lt;div class="mermaid"&gt;flowchart LR
A[App Subnet] --&gt;|UDR| F[Inspection Point]
F --&gt; B[Shared Services]
B --&gt; C[Additional Networks]
C -. Implicit Reachability .-&gt; A
&lt;/div&gt;
&lt;p&gt;The security gap is not the firewall.&lt;br&gt;
It’s the &lt;strong&gt;unreviewed expansion of reachability beyond intent&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="gotchas--edge-cases"&gt;Gotchas &amp;amp; Edge Cases
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Platform‑managed routes may expand reachability without obvious configuration changes.&lt;/li&gt;
&lt;li&gt;Multiple route tables create inconsistent trust enforcement across subnets.&lt;/li&gt;
&lt;li&gt;Security tooling reports where traffic was &lt;em&gt;seen&lt;/em&gt;, not everywhere it &lt;em&gt;could go&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="best-practices"&gt;Best Practices
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Treat routing changes as &lt;strong&gt;trust boundary changes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Document intended reachability, not just IP ranges&lt;/li&gt;
&lt;li&gt;Review routes for &lt;strong&gt;what they enable&lt;/strong&gt;, not what they fix&lt;/li&gt;
&lt;li&gt;Assume transitivity unless explicitly disproven&lt;/li&gt;
&lt;li&gt;If intent and reachability diverge, classify it as a security issue&lt;/li&gt;
&lt;/ul&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; If routing expands reachability beyond what you can explicitly justify, the design is already insecure even if every security control still looks correct.
&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-networks-udr-overview" target="_blank" rel="noopener"
&gt;Azure virtual network traffic routing&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;li&gt;&lt;a class="link" href="https://learn.microsoft.com/azure/security/fundamentals/network-overview" target="_blank" rel="noopener"
&gt;Azure network security fundamentals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>