[LZ 2.1] Discovery Before You Deploy Anything

The reproducible pre-deployment audit: subscriptions, address space, connectivity, access, Secure Score baseline, and the on-premises DNS forwarder check that saves you from the hardest problem to diagnose after go-live.

This is the companion to the starting-point article, and its job is narrow and non-negotiable: before you deploy a single management group, you inventory what already exists, because you cannot safely govern or migrate what you have not first understood. In the Microsoft 365-only case this pass is short. In the accidental-infrastructure and hybrid cases it is where you find the landmines, and the most dangerous one, a catch-all DNS forwarder, will not announce itself until a private endpoint silently resolves to the wrong address months after go-live. Run every step. Write the output down. The discovery document you produce here is the input to every decision that follows.

Prerequisites: Reader access to any existing Azure subscriptions, the Azure CLI signed in (az login), and, for the hybrid case, an account that can query the on-premises DNS servers. Everything here is read-only. You are looking, not changing.

Step 1: Inventory every subscription

Start with what subscriptions exist, who owns them, and how they are billed, because a pay-as-you-go subscription is a migration target and its billing needs to change before it becomes a permanent part of the estate. In the portal this is the Subscriptions blade. From the command line:

az account list --output table
az account list --query "[].{Name:name, State:state, Id:id}" --output table

For each subscription, record the offer type (whether it is pay-as-you-go, a Cloud Solution Provider subscription, or an Enterprise Agreement), the named owner, and a one-line description of what actually runs in it. You are building a table like this for the worked example, Northfork Supply Co.:

SubscriptionBillingOwnerContentsDisposition
Northfork-PAYGPay-as-you-goformer admin2 VMs, a VPN gateway, loose resource groupsMigrate, then retire
(none for non-prod)n/an/an/aCreate later on trigger

The disposition column is the point of the exercise. By the end of discovery you know which subscriptions become the foundation, which get migrated in, and which get retired.

Step 2: Map the network and its address space

The single most important fact discovery produces is the complete set of address ranges already in use, on both sides of the connection, because the foundation’s address plan must not overlap with any of them and overlap is expensive to fix once workloads are live. List every existing virtual network and its prefixes:

az network vnet list --query "[].{Name:name, RG:resourceGroup, Space:addressSpace.addressPrefixes}" --output table
az network vnet subnet list --resource-group RG-NAME --vnet-name VNET-NAME --output table

Then record the on-premises ranges by hand, because the CLI cannot see them: every subnet in the office, the datacenter, and any remote sites reachable across the existing tunnel. Write them into one address register alongside the Azure ranges. The check you are performing is simple and absolute: no proposed foundation range may overlap an existing range on either side. For Northfork, the on-premises estate uses 172.16.0.0/16 and the accidental Azure VNet sits at 10.0.0.0/24, which is why the foundation in later articles is planned into 10.40.0.0/16, clear of both.

Step 3: Record the connectivity in place

Document how on-premises and Azure are connected today, or whether they are connected at all. Note the connection type (site-to-site VPN or ExpressRoute), the on-premises device it terminates on and who manages it, and whether any client-side connectivity product such as a SASE service is in play. This matters because the network article treats client connectivity and server-to-server infrastructure connectivity as two separate problems, and you need to know which you already have.

ItemValueWhy it matters
On-prem to Azure linkSite-to-site VPN on a Fortinet applianceCarries infrastructure traffic; the on-prem side is configured by hand later
Client connectivitySASE agent, backhauls to the officeCandidate to re-home so clients stop hairpinning through the datacenter
ExpressRouteNoneVPN gateway is the correct choice at this scale

Step 4: Audit access assignments

In an accidental environment, role assignments were handed to individual people, and the identity article insists that access attach to groups instead. Find every direct user assignment now so you know the scope of the cleanup:

az role assignment list --all --include-inherited \
  --query "[?principalType=='User'].{User:principalName, Role:roleDefinitionName, Scope:scope}" \
  --output table

Flag anything at subscription scope, and flag every standing Owner. Both are corrected in the identity build. You are not fixing them here; you are counting them so the later remediation has a defined list rather than a vague intention.

Step 5: Capture the Secure Score baseline

Record the current Microsoft Defender for Cloud Secure Score before you change anything, because the value of the foundation is partly demonstrated by the movement of this number, and you cannot show movement from a baseline you never wrote down. The portal shows it on the Defender for Cloud overview. From the command line, with the account extension available:

az security secure-scores list --query "[].{Name:name, Current:properties.score.current, Max:properties.score.max}" --output table

Note the number and the date. Set a target and a review cadence in the operating article; the baseline is what makes that target meaningful.

Step 6: Inventory the managed detection provider

Many organizations at this scale already pay an external managed detection and response provider, and that provider is usually pulling from Microsoft signals already. Before you decide what your own Log Analytics workspace ingests, ask the provider two questions: which log sources do you collect, and how long do you retain them. The answer changes what you duplicate. It never changes the rule that you keep a local ninety-day floor regardless, but it does let you use cheaper tiers for anything the provider already retains long-term. Record the provider name, the collected sources, and the retention period.

Step 7: Audit on-premises DNS for catch-all forwarders

This is the step nobody runs and everybody should. In the hybrid case, once private endpoints exist, on-premises devices resolve Azure private names through conditional forwarders that point at the private DNS resolver. That chain breaks, silently and completely, if any on-premises DNS server already has a broad forwarder or stub zone for a Microsoft domain, because that broad rule intercepts the private DNS queries before your specific rules ever see them. The symptom appears months later as a private endpoint resolving to a public address, and it is the single hardest post-deployment problem to diagnose. So you find these entries before you deploy anything, not after.

On each on-premises DNS server, run the DNS Server PowerShell module and look for any conditional forwarder, stub zone, or manual record referencing windows.net, core.windows.net, azure.com, or microsoft.com:

Get-DnsServerZone | Where-Object { $_.ZoneType -eq 'Forwarder' } |
  Select-Object ZoneName, MasterServers

Get-DnsServerForwarder

Get-DnsServerZone | Where-Object {
  $_.ZoneName -match 'windows\.net|core\.windows\.net|azure\.com|microsoft\.com'
} | Select-Object ZoneName, ZoneType

The first command lists conditional forwarders. The second shows the server-level forwarders, where a single catch-all pointing all unknown queries at a device that mishandles Azure names does the most damage. The third catches stub zones and manual zones for the Microsoft domains. Record every match. If you find a broad forwarder for one of these domains, it has to be narrowed or removed before private endpoints go in, and that finding belongs at the top of the discovery document in bold, because the private DNS build depends on it.

Validation: the completed discovery document

Discovery is done when you can answer all of the following from a written document rather than from memory:

  • Every subscription, its billing model, owner, contents, and disposition.
  • A single address register listing every in-use range on both sides, with a proposed non-overlapping foundation range confirmed clear.
  • The connectivity in place, split into infrastructure and client connectivity.
  • A list of direct user role assignments and every standing Owner.
  • The Secure Score baseline value and date.
  • The managed detection provider’s collected sources and retention.
  • The result of the DNS forwarder audit, with any catch-all entries flagged for remediation.

End-to-end test

Two checks confirm the discovery is trustworthy. First, take the proposed foundation address range and compare it against every entry in the address register; if it overlaps nothing on either side, the range is safe to build on. Second, confirm the DNS audit came back either clean or with every catch-all entry explicitly listed for remediation. If both hold, you have removed the two failure modes that most often surface long after deployment, and the build can begin with the governance backbone.


Azure Landing Zones
‹ Previous: [LZ 2] Where You Are Starting From
Next: [LZ 3] The Governance Backbone