<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Data Exfiltration on Brewed in the Cloud by Chris Hailes</title><link>https://blog.brewedinthecloud.com/tags/data-exfiltration/</link><description>Recent content in Data Exfiltration on Brewed in the Cloud by Chris Hailes</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Tue, 16 Jun 2026 00:00:00 +1000</lastBuildDate><atom:link href="https://blog.brewedinthecloud.com/tags/data-exfiltration/rss.xml" rel="self" type="application/rss+xml"/><item><title>Private Link Doesn’t Stop Exfiltration. It Just Changes the Route</title><link>https://blog.brewedinthecloud.com/p/pe-attacks-exfiltration/</link><pubDate>Tue, 16 Jun 2026 00:00:00 +1000</pubDate><guid>https://blog.brewedinthecloud.com/p/pe-attacks-exfiltration/</guid><description>&lt;p&gt;You can disable public network access, tighten internet egress, and still leave a perfectly usable path for data to leave the workload.&lt;/p&gt;
&lt;p&gt;That is the trap with Private Link. It reduces one kind of exposure while making another kind of path feel safe by default. Once a service is reachable over a Private Endpoint, it starts behaving like trusted internal plumbing. In a lot of estates, that trust arrives long before anybody has defined whether the path should exist, who should own it, or how broadly it should resolve.&lt;/p&gt;
&lt;p&gt;That is why this post treats Private Endpoints as part of the internal attack surface, not as a security boundary.&lt;/p&gt;
&lt;p&gt;The practical question is not whether the traffic stays private.&lt;/p&gt;
&lt;p&gt;It is whether the trust relationship created by that private path is explicit, constrained, and observable enough to rely on.&lt;/p&gt;
&lt;h2 id="the-mental-model"&gt;The Mental Model
&lt;/h2&gt;&lt;p&gt;The common assumption is familiar:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“If the service has no public endpoint and is only reachable over Private Endpoint, then exfiltration risk is largely removed.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That sounds neat on a slide. It breaks in real estates.&lt;/p&gt;
&lt;p&gt;Private Endpoint does not mean data cannot leave. It means data can leave through a path that now looks internal, often carries less scrutiny, and is easier to describe as “approved” without proving what that approval actually covers.&lt;/p&gt;
&lt;p&gt;The more useful mental model is this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A Private Endpoint is a trust edge.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is not just a private IP for a platform service. It is a decision to make a managed service reachable from a specific network context under a specific name-resolution model, with all the downstream service behaviour and authorisation complexity that implies.&lt;/p&gt;
&lt;p&gt;That should change how you design, deploy, and operate. You should review a new Private Endpoint the way you would review any new trust relationship, not the way you would review a harmless network attachment.&lt;/p&gt;
&lt;h2 id="how-it-really-works"&gt;How It Really Works
&lt;/h2&gt;&lt;p&gt;Private Link gives your workload a private network path to a supported Azure platform service. DNS resolution typically steers the client to the Private Endpoint IP, and the Azure fabric carries the traffic to the target service.&lt;/p&gt;
&lt;p&gt;That changes the shape of the path, but not the need to govern it.&lt;/p&gt;
&lt;p&gt;A Private Endpoint by itself does &lt;strong&gt;not&lt;/strong&gt; grant meaningful data access. The service behind it still enforces its own authentication and authorisation model. That matters, because the real exfiltration risk appears when three things combine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;private reachability&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;broad or inherited name resolution&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;service permissions that allow data use, storage, or onward movement&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That combination is where an unexamined data path emerges.&lt;/p&gt;
&lt;p&gt;So the real issue is not “Private Link secretly bypasses all security”. It does not.&lt;/p&gt;
&lt;p&gt;The issue is that many teams govern the endpoint object, but not the trust relationship around it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;which workloads can resolve the name&lt;/li&gt;
&lt;li&gt;which subnets can reach the interface&lt;/li&gt;
&lt;li&gt;which identities can use the service meaningfully&lt;/li&gt;
&lt;li&gt;which service instance sits behind the endpoint&lt;/li&gt;
&lt;li&gt;which downstream service behaviours are now in scope&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is the operational gap. The platform gives you private transport. It does not tell you whether the resulting path should be trusted.&lt;/p&gt;
&lt;h2 id="the-architectural-blind-spot"&gt;The Architectural Blind Spot
&lt;/h2&gt;&lt;p&gt;A lot of Azure estates now have strong language around “no public access” and “private-only service consumption”. Both can be sensible controls. But they often create an unhelpful shortcut in architecture reviews:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;public endpoint disabled&lt;/li&gt;
&lt;li&gt;Private Endpoint deployed&lt;/li&gt;
&lt;li&gt;issue considered solved&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is not solved. It has moved.&lt;/p&gt;
&lt;p&gt;If a workload can privately reach a storage account, database, or messaging service and has the service-level permissions to use it, then you already have a sanctioned outbound data path. The fact that the packet did not hit the public internet does not make that path harmless.&lt;/p&gt;
&lt;p&gt;This is where the trust-edge model matters. A Private Endpoint should not be assessed as “more secure networking” in the abstract. It should be assessed as a concrete relationship between:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a source workload&lt;/li&gt;
&lt;li&gt;a resolution path&lt;/li&gt;
&lt;li&gt;a destination service&lt;/li&gt;
&lt;li&gt;a set of service permissions&lt;/li&gt;
&lt;li&gt;a trust boundary&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If one of those is undefined, the path is probably being trusted implicitly.&lt;/p&gt;
&lt;h2 id="dns-is-where-trust-quietly-expands"&gt;DNS Is Where Trust Quietly Expands
&lt;/h2&gt;&lt;p&gt;In many Azure estates, the most important policy decision behind a Private Endpoint is not the endpoint itself.&lt;/p&gt;
&lt;p&gt;It is which networks are allowed to resolve the name.&lt;/p&gt;
&lt;p&gt;This is one of the easiest places for accidental trust expansion to happen. A Private Endpoint may be created for one application or subnet, but the corresponding private DNS zone is often linked far more broadly than the original use case required. Once that happens, reachability stops being a narrow application decision and starts becoming a platform-wide convenience feature.&lt;/p&gt;
&lt;p&gt;That changes something important operationally.&lt;/p&gt;
&lt;p&gt;A service that was supposed to be privately reachable by one workload can become resolvable by many workloads. If network paths and service permissions also line up, you have quietly widened the set of systems that can use that service as a data path.&lt;/p&gt;
&lt;p&gt;That is not a DNS hygiene problem. It is an architecture problem with DNS symptoms.&lt;/p&gt;
&lt;h2 id="a-typical-exfiltration-pattern-without-the-hype"&gt;A Typical Exfiltration Pattern Without the Hype
&lt;/h2&gt;&lt;p&gt;We do not need to get into malware behaviour or offensive detail to see the design issue.&lt;/p&gt;
&lt;p&gt;A common pattern looks like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an application subnet can resolve a private service name&lt;/li&gt;
&lt;li&gt;the subnet can reach the Private Endpoint&lt;/li&gt;
&lt;li&gt;the workload has valid service credentials or managed identity access&lt;/li&gt;
&lt;li&gt;the destination service is treated as inherently safe because it has no public endpoint&lt;/li&gt;
&lt;li&gt;the path is not reviewed as an outbound trust relationship&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At that point, the environment has not eliminated outbound data movement. It has created a low-friction private route for it.&lt;/p&gt;
&lt;p&gt;The most common examples are not exotic:&lt;/p&gt;
&lt;h3 id="private-storage-as-an-internal-sink"&gt;Private storage as an internal sink
&lt;/h3&gt;&lt;p&gt;A private-only storage account can become an internal drop location simply because it is reachable, resolvable, and writable from more places than intended.&lt;/p&gt;
&lt;h3 id="east-adjacent-movement-across-landing-zones"&gt;East-adjacent movement across landing zones
&lt;/h3&gt;&lt;p&gt;A workload in one application trust zone may be able to write data to a private service hosted in another platform, subscription, or spoke. The traffic stays private, but the trust boundary crossing is real.&lt;/p&gt;
&lt;h3 id="service-mediated-onward-movement"&gt;Service-mediated onward movement
&lt;/h3&gt;&lt;p&gt;The first hop may be private, but once data lands in the service, downstream platform behaviours matter. Export, replication, integration, or secondary consumers may extend the effective data path well beyond the source workload’s original boundary.&lt;/p&gt;
&lt;p&gt;The mistake is not using these services. The mistake is reviewing only the transport path and ignoring what the service is now allowed to do in the broader design.&lt;/p&gt;
&lt;h2 id="visualising-the-problem"&gt;Visualising the Problem
&lt;/h2&gt;&lt;div class="mermaid"&gt;flowchart LR
A[Source workload] --&gt; B[Private DNS resolution]
B --&gt; C[Private Endpoint]
C --&gt; D[Azure PaaS service]
D --&gt; E[Data written or staged]
D --&gt; F[Service-side downstream behaviour]
D --&gt; G[Consumer in another trust zone]
H[Shared DNS zone links] --&gt; B
I[Service permissions] --&gt; D
style C fill:#d9edf7,stroke:#31708f
style D fill:#fcf8e3,stroke:#8a6d3b
style E fill:#f2dede,stroke:#a94442
style F fill:#f2dede,stroke:#a94442
style G fill:#f2dede,stroke:#a94442
style H fill:#f5f5f5,stroke:#666666
style I fill:#f5f5f5,stroke:#666666
&lt;/div&gt;
&lt;p&gt;The useful takeaway here is that the Private Endpoint is not the whole story. The meaningful risk sits in the combination of resolution scope, network reachability, service authorisation, and downstream service behaviour.&lt;/p&gt;
&lt;h2 id="why-no-public-endpoint-can-become-a-blind-spot"&gt;Why “No Public Endpoint” Can Become a Blind Spot
&lt;/h2&gt;&lt;p&gt;Disabling public access is often the right move. It removes a class of exposure cleanly.&lt;/p&gt;
&lt;p&gt;But there is a difference between &lt;strong&gt;reducing exposure&lt;/strong&gt; and &lt;strong&gt;controlling data paths&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;“No public endpoint” can create false confidence because it sounds like a complete answer. In practice, it often just shifts scrutiny away from the remaining path. The service is now considered private, the traffic looks internal, and the path gets less attention precisely because it appears more controlled.&lt;/p&gt;
&lt;p&gt;That is how unmanaged trust grows in mature environments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the path is real&lt;/li&gt;
&lt;li&gt;the path is approved in principle&lt;/li&gt;
&lt;li&gt;the scope of that approval is unclear&lt;/li&gt;
&lt;li&gt;visibility is fragmented&lt;/li&gt;
&lt;li&gt;ownership is diluted across networking, platform, and application teams&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The end state is not a dramatic security failure. It is something more common and more dangerous: a private data path that nobody is actively governing.&lt;/p&gt;
&lt;h2 id="how-this-changes-design-deployment-and-operations"&gt;How This Changes Design, Deployment, and Operations
&lt;/h2&gt;&lt;p&gt;This is the practical anchor.&lt;/p&gt;
&lt;h3 id="design"&gt;Design
&lt;/h3&gt;&lt;p&gt;Treat each Private Endpoint as a trust-edge decision.&lt;/p&gt;
&lt;p&gt;Do not stop at “the app needs private access to Storage”. Define:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;which workload needs it&lt;/li&gt;
&lt;li&gt;which exact service instance it should reach&lt;/li&gt;
&lt;li&gt;which networks should resolve the name&lt;/li&gt;
&lt;li&gt;which trust boundaries are being crossed&lt;/li&gt;
&lt;li&gt;which downstream service behaviours are acceptable&lt;/li&gt;
&lt;li&gt;which cases are explicitly out of scope&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That changes design because you stop modelling Private Endpoints as generic network plumbing and start modelling them as approved service relationships.&lt;/p&gt;
&lt;h3 id="deployment"&gt;Deployment
&lt;/h3&gt;&lt;p&gt;Treat creation of a Private Endpoint as introduction of a new sanctioned private data path.&lt;/p&gt;
&lt;p&gt;That means the deployment is not complete when the resource exists. It is complete when the trust conditions around it are also understood:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;source scope&lt;/li&gt;
&lt;li&gt;DNS scope&lt;/li&gt;
&lt;li&gt;destination ownership&lt;/li&gt;
&lt;li&gt;expected service use&lt;/li&gt;
&lt;li&gt;reviewability&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If those are missing, the deployment is technically correct but architecturally incomplete.&lt;/p&gt;
&lt;h3 id="operations"&gt;Operations
&lt;/h3&gt;&lt;p&gt;Review Private Endpoints the way you would review long-lived firewall rules or peering relationships: as objects that outlast the project that created them.&lt;/p&gt;
&lt;p&gt;That changes operations because your questions become sharper:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;which workloads can resolve this service name today&lt;/li&gt;
&lt;li&gt;which trust zones can reach this endpoint now&lt;/li&gt;
&lt;li&gt;does the destination still have a valid owner&lt;/li&gt;
&lt;li&gt;would anybody notice if a workload started using this path differently&lt;/li&gt;
&lt;li&gt;does the current DNS linkage still match the original design intent&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is far more useful than simply counting how many Private Endpoints exist.&lt;/p&gt;
&lt;h2 id="governance-query-example"&gt;Governance Query Example
&lt;/h2&gt;&lt;p&gt;For this kind of article, deployment syntax is not the interesting artefact. The harder problem is whether the estate can identify Private Endpoints that have become unmanaged trust relationships.&lt;/p&gt;
&lt;p&gt;A governance-oriented query is more useful than a create example because it tests whether your environment can answer basic architectural questions at scale.&lt;/p&gt;
&lt;p&gt;The Azure Resource Graph query below looks for Private Endpoints and surfaces signals that deserve review:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;missing ownership tags&lt;/li&gt;
&lt;li&gt;missing business-purpose tags&lt;/li&gt;
&lt;li&gt;the subnet hosting the endpoint&lt;/li&gt;
&lt;li&gt;the target resource behind the connection&lt;/li&gt;
&lt;/ul&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;/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;resources
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| where type =~ &amp;#39;microsoft.network/privateendpoints&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| extend peSubnetId = tostring(properties.subnet.id)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| extend connections = properties.privateLinkServiceConnections
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| mv-expand conn = connections
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| extend targetResourceId = tostring(conn.properties.privateLinkServiceId)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| project
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; subscriptionId,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; resourceGroup,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; privateEndpoint = name,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; location,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; peSubnetId,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; targetResourceId,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; owner = tostring(tags.Owner),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; businessPurpose = tostring(tags.BusinessPurpose)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| extend ownerState = iif(isempty(owner), &amp;#39;Missing&amp;#39;, &amp;#39;Present&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| extend purposeState = iif(isempty(businessPurpose), &amp;#39;Missing&amp;#39;, &amp;#39;Present&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| order by ownerState desc, purposeState desc, subscriptionId asc
&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;This does not prove exfiltration risk by itself, and it should not be oversold. What it &lt;em&gt;does&lt;/em&gt; show is whether your estate can identify private service paths that lack even basic ownership and intent metadata.&lt;/p&gt;
&lt;p&gt;That matters because unmanaged trust tends to appear before confirmed misuse does.&lt;/p&gt;
&lt;p&gt;If your platform team cannot quickly answer who owns a Private Endpoint, why it exists, and which service it reaches, then your “private-only” posture is probably carrying more implicit trust than you think.&lt;/p&gt;
&lt;h2 id="indicators-that-the-data-path-is-being-trusted-implicitly"&gt;Indicators That the Data Path Is Being Trusted Implicitly
&lt;/h2&gt;&lt;p&gt;These are the signs I would look for in a real environment.&lt;/p&gt;
&lt;h3 id="private-dns-zone-links-are-broader-than-the-application-need"&gt;Private DNS zone links are broader than the application need
&lt;/h3&gt;&lt;p&gt;This is one of the strongest indicators that convenience has overtaken design intent.&lt;/p&gt;
&lt;h3 id="private-endpoints-exist-without-clear-ownership-metadata"&gt;Private Endpoints exist without clear ownership metadata
&lt;/h3&gt;&lt;p&gt;If the object is live but nobody clearly owns the path, it is already under-governed.&lt;/p&gt;
&lt;h3 id="shared-services-are-reachable-across-multiple-trust-zones-by-default"&gt;Shared services are reachable across multiple trust zones by default
&lt;/h3&gt;&lt;p&gt;That may be intentional, but it should be visible and explicitly defended, not inherited silently.&lt;/p&gt;
&lt;h3 id="architecture-documents-describe-private-access-but-not-approved-data-destinations"&gt;Architecture documents describe “private access” but not “approved data destinations”
&lt;/h3&gt;&lt;p&gt;That wording usually means the transport decision was reviewed but the data-path decision was not.&lt;/p&gt;
&lt;h3 id="public-access-is-disabled-and-that-is-treated-as-the-end-of-the-conversation"&gt;Public access is disabled and that is treated as the end of the conversation
&lt;/h3&gt;&lt;p&gt;This is the most common mental shortcut. It reduces one risk and masks another.&lt;/p&gt;
&lt;h2 id="gotchas--edge-cases"&gt;Gotchas &amp;amp; Edge Cases
&lt;/h2&gt;&lt;h3 id="private-reachability-is-not-the-same-as-authorised-use"&gt;Private reachability is not the same as authorised use
&lt;/h3&gt;&lt;p&gt;A workload still needs valid service-level permissions. The risk comes from the combination of path and permission, not from private transport alone.&lt;/p&gt;
&lt;h3 id="dns-scope-can-widen-faster-than-endpoint-deployment"&gt;DNS scope can widen faster than endpoint deployment
&lt;/h3&gt;&lt;p&gt;You can accidentally expand reachability through name resolution changes without creating any new Private Endpoint resources.&lt;/p&gt;
&lt;h3 id="cross-subscription-does-not-mean-cross-trust-is-understood"&gt;Cross-subscription does not mean cross-trust is understood
&lt;/h3&gt;&lt;p&gt;Administrative boundaries are not the same as trust boundaries. A private path into another team’s service is still a trust decision even if it lives inside the same tenant.&lt;/p&gt;
&lt;h3 id="service-subresources-matter"&gt;Service subresources matter
&lt;/h3&gt;&lt;p&gt;Different subresources can expose materially different capabilities. Reviewing access only at the service label level is often too coarse.&lt;/p&gt;
&lt;h2 id="best-practices"&gt;Best Practices
&lt;/h2&gt;&lt;h3 id="1-review-private-endpoints-as-trust-edges"&gt;1. Review Private Endpoints as trust edges
&lt;/h3&gt;&lt;p&gt;Make this the default posture. If a new endpoint creates a new path to a managed service, it deserves trust-boundary review.&lt;/p&gt;
&lt;h3 id="2-keep-dns-scope-as-narrow-as-the-use-case"&gt;2. Keep DNS scope as narrow as the use case
&lt;/h3&gt;&lt;p&gt;Private resolution should be deliberate. Broad inherited zone links are one of the easiest ways to create accidental trust expansion.&lt;/p&gt;
&lt;h3 id="3-separate-transport-approval-from-data-path-approval"&gt;3. Separate transport approval from data-path approval
&lt;/h3&gt;&lt;p&gt;A service being reachable privately does not automatically make it an approved destination for sensitive or high-value data.&lt;/p&gt;
&lt;h3 id="4-require-ownership-and-business-purpose-for-every-private-endpoint"&gt;4. Require ownership and business purpose for every Private Endpoint
&lt;/h3&gt;&lt;p&gt;If the relationship matters, it should be attributable. If it is not attributable, it should not be trusted by default.&lt;/p&gt;
&lt;h3 id="5-review-by-trust-boundary-not-just-by-subscription-or-vnet"&gt;5. Review by trust boundary, not just by subscription or VNet
&lt;/h3&gt;&lt;p&gt;The real question is who can now reach which service under which name and permissions, not which administrative container the resource lives in.&lt;/p&gt;
&lt;h3 id="6-assume-private-paas-traffic-is-under-observed-until-proven-otherwise"&gt;6. Assume private PaaS traffic is under-observed until proven otherwise
&lt;/h3&gt;&lt;p&gt;Do not assume your visibility model kept up with your connectivity model.&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; Private Link is very good at removing public exposure. That is exactly why it can hide bad assumptions so well.
If the service is private, broadly resolvable, and meaningfully usable, then you do not have “no exfiltration path”. You have a trusted one.
&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/private-link/private-endpoint-overview" target="_blank" rel="noopener"
&gt;Azure Private Endpoint documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/azure/private-link/private-link-overview" target="_blank" rel="noopener"
&gt;What is Azure Private Link?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/azure/private-link/private-endpoint-dns" target="_blank" rel="noopener"
&gt;Azure Private Endpoint DNS configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/azure/governance/resource-graph/overview" target="_blank" rel="noopener"
&gt;Azure Resource Graph overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/azure/storage/common/storage-network-security" target="_blank" rel="noopener"
&gt;Azure Storage networking for secure access&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>