From Finding to Path: Model Azure Exposure as Reachability

Turn a prioritized Azure finding into a bounded path record, a remediation hypothesis and a falsifiable test.

A finding can land at the top of the queue and still leave the engineer guessing.

“Restrict access to this storage account” sounds actionable. But access from where, using which identity, to do what? Without those answers, two teams can implement different fixes and both reasonably believe they have finished.

The earlier attack-path prioritization article explains why consequence should outrank finding volume. This series starts after that decision: what exactly should change, and how will we know the change worked?

I would not hand that finding to engineering until we can name the path and explain how the fix could fail its test. That adds work to triage. It also avoids the more expensive conversation later: the setting changed, so why is the unwanted operation still possible?

The Mental Model

Start with what the compromised workload can do, not where it sits on the diagram. An exposure path connects that capability to usable authority, a network path, a destination operation and its consequence.

Consider an application spoke whose workload needs to read objects from an approved private Blob destination. A second controlled destination represents somewhere it should not write. DNS, telemetry and responder access must keep working when we constrain that second path. This illustrative scenario runs through the series; the testing assumptions are collected below.

Can the workload connect to the second account? That is one question. Can its identity actually write there? That is another. And if we block the connection, can the workload or its deployment pipeline change a role assignment, public access setting or route to reopen it?

Those questions belong in the same record. Otherwise we risk closing the door while leaving the means to unlock it untouched.

flowchart LR S[Source workload capability] --> I[Effective identity authority] S --> N[DNS and network path] I --> O[Destination operation] N --> O O --> C[Reachable consequence] M[Control-plane change authority] -. can reopen .-> N M -. can widen .-> I R[Recovery and telemetry dependencies] --> V[Validation boundary]

The diagram expresses dependencies, not an Azure packet-processing order. A useful record names which edge a proposed change will constrain and which edges remain.

How It Really Works

Make the finding an engineering hypothesis

Give the path a stable ID, then describe it plainly: this workload, using this principal, can perform this operation against this service instance. Add the DNS answer, route and authorization scope that make the operation possible. Include who can change those conditions, not just who owns the account.

Then write a claim that can fail:

After change C, source S using principal P cannot perform operation O against controlled destination D; the approved dependency and responder path still work.

That is less impressive than “the account is secure.” It is also something an engineer can challenge, implement and test.

The path-record module in the draft Azure Exposure Reduction Toolkit provides the technical companion. Its minimum fields are:

FieldDecision it supports
Path ID and scope versionComparing the same case across changes
Source, principal, destination, operationEstablishing which capability is being constrained
DNS, route and enforcement contextIdentifying where the network claim applies
Role scope and control-plane ownerFinding authority that can preserve or reopen access
Expected result and evidence referencesSeparating a hypothesis from a supported conclusion
Positive controls, residuals and retest triggersPreserving service and avoiding permanent assurance claims

Inventory gives you a starting point, not a verdict. This read-only Azure Resource Graph query identifies declared Private Endpoint targets:

1
2
3
4
5
6
7
8
resources
| where type =~ "microsoft.network/privateendpoints"
| mv-expand connection = properties.privateLinkServiceConnections
| project endpointId = id,
          subnetId = tostring(properties.subnet.id),
          targetId = tostring(connection.properties.privateLinkServiceId),
          groupIds = connection.properties.groupIds,
          location

Run it in Resource Graph, not a Log Analytics workspace. It covers the automatic connection property shown; manually requested connections use a different property and need separate inspection. Empty output may mean missing scope, permissions, delayed inventory or no matching resources. It does not mean no usable path exists.

Test authority and reachability separately

Run the checks where the workload runs. A successful CLI call from an administrator’s laptop may use a different resolver, route and identity. It answers a useful question, but not necessarily the one in the finding.

Use synthetic objects and scoped data permissions. The baseline must include an authorized, harmless operation that succeeds against the controlled unintended destination if the claim is that this path currently exists. If baseline access fails, investigate why; do not celebrate the same failure after the change as newly achieved reduction.

After a single approved lab change, repeat the identical operation, approved dependency probe and responder-access check. Preserve request identifiers, timestamps and configuration versions. A negative result is convincing only when the positive controls still work and the rejection can be attributed to the intended boundary.

Real-World Impact

The useful handoff is no longer “secure Storage.” It is “remove this write capability without breaking that read dependency.” Platform, identity and application owners can then divide the work without pretending one team owns every part of the path.

Choose the smaller defensible change

Suppose the application needs reads from account A but has inherited write authority to account B. Tightening the data role may be a smaller change than introducing a new centralized inspection dependency. Conversely, network restriction may be valuable where many identities share a reachable management surface.

I would compare those changes by the capability they remove and the dependency they preserve, not by how much infrastructure they introduce. The record gives the reviewer a way to make that choice and see what remains.

Leave responders something useful

A path record should survive the remediation ticket. During an incident, it tells responders which dependency they can constrain, which identity scope matters, and which recovery operation must remain possible.

That durability is worth the documentation burden when consequence is high. For a low-value isolated endpoint, a shorter record may be proportionate. The method should improve a decision, not create an exhaustive graph project before every change.

Gotchas and Edge Cases

A neat record can still describe the wrong path. The most important checks are the ones that catch a convincing explanation before it becomes a closure decision.

Reachable does not mean authorized

A successful TCP connection establishes transport, not Blob write authority. A service rejection might reflect authentication, authorization or a network policy; retain service error details rather than assigning every 403 to the firewall.

A snapshot can miss reopening authority

The principal used by the workload may not itself edit networking, while its deployment pipeline can. Record the separate automation identity and who can change that pipeline. The relevant authority graph includes deployment and recovery operations.

Context changes invalidate comparison

Changing resolver, test principal, destination subresource or token state between runs changes the experiment. Cached tokens and sessions require explicit handling. Use fresh connections and record token-acquisition context without recording tokens.

Unknown paths are not blocked paths

If role visibility or diagnostic access is incomplete, mark the path unknown. Removing an unknown record from the denominator does not improve security. It only improves the appearance of the report.

Best Practices

Start with the highest-consequence finding that has a controllable test boundary. Define one source, one principal, one destination operation and one proposed intervention. Expand only after the first record can be reviewed and reproduced.

Assumptions and evidence boundary

The proposed exercise uses synthetic objects and author-owned Blob destinations on supported general-purpose v2 Storage accounts. Service data access is separate from management-plane read access. Resource Graph needs visibility over the queried resources; the operation needs the appropriate scoped data role. Confirm CLI version, effective-route inspection support, resource API versions, region availability and diagnostic schema for the selected topology before deployment.

Microsoft documents Private Endpoint connectivity and unchanged service authorization mechanisms. This article proposes a validation exercise; it does not report Azure lab results. Keep those evidence categories separate in the final record.

I would close this as a removed path only when the baseline existed, the unwanted operation fails at the intended boundary, required service still works, and reopening authority is accounted for. If one of those is missing, call it a partial change or an inconclusive test. That is a useful engineering result too; it just is not the result we set out to prove.

🍺
Brewed Insight: A good remediation claim names the capability that disappears and the dependency that survives. A resource setting without those two statements is still an implementation task, not evidence of reduced consequence.

Learn More