Skip to content

Deploy the Platform (Hub)

This page describes the first deployment of the hub: canary first, then prod. It assumes the prepare phase is complete (identity, repositories, state storage, job runners and the mcp image). The technical order is in the platform deploy flow; the layers are in Deployment layers.

Before you start

  • [ ] Prerequisites checked, identity in place
  • [ ] Repositories created; the configuration is on the initial branch
  • [ ] State storage account, hub and spoke state containers exist (Prepare agents)
  • [ ] infrastructure and container have run for canary (and later for prod) successfully
  • [ ] The IP plan is final
  • [ ] PIM is activated for the engineer who runs the deployment

1. Fill the configuration for canary

In the configuration repository, on the initial branch:

  1. Set environments/canary/mcp.json (Config): tenant, state backends, job runner, DevOps organization or GitHub App, service principal IDs, SpokeCommon.tenantinfo.
  2. Set global.auto.tfvars (regions, names, subscription IDs) and the region and layer tfvars, using the mapping.
  3. Search the whole repository for values of the template (its customer name, subscription IDs and resource IDs). Policy files contain Azure resource IDs.
  4. Check each firewall_rule_configuration folder: at least one JSON file must exist, even if the platform has no rules yet.
  5. Check that the DNS server address of the firewall policy matches the inbound endpoint address of the DNS private resolver of the same platform environment.
  6. In the entry pipelines, check the pinned version, the agent pool, the service connections or environments, and which mcp.json each entry targets.

Check mode and whatIf in the entry pipelines. The reference configuration repository applies the hub without approval (Pipelines). For the first run use Plan.

2. Register resource providers

Make sure all resource providers the platform needs are registered in every platform subscription. If your version includes the script scripts/register-az-providers.ps1 in the code repository, run it after connecting to the tenant:

Connect-AzAccount -TenantId <tenant-id>

Otherwise register the providers named in the errors of the first plan. This step is also part of Prerequisites.

3. Plan and apply the hub in canary

Run hub from the initial branch for the canary platform environment, first in Plan mode.

  1. Read the plan of every layer. On a first deployment everything is created. Check names, regions, address ranges and the feature switches against the design. A plan that wants to destroy anything on a first deployment means a wrong path or a wrong value. Stop and find out why (Config: a wrong path deletes resources).
  2. Run hub again in Apply (or ApproveModifications) mode.
  3. The pipeline runs the layers in the fixed order: foundation and connectivity in the primary region, then in the other regions, then firewall, identity and management in all regions, and postdeployment in the primary region (Deploy flow).
  4. When the pipeline finishes, run it again. A second plan must show no changes. Differences that keep reappearing (for example policy or Application Gateway attributes) are listed in Known issues.

Why the order matters on a first deployment

The layers depend on each other, for example on the virtual network. The pipeline handles the order. If you run layers or regions by hand, respect it: on a clean deployment, foundation and connectivity in the primary region first, then in the other regions, and only then firewall, identity and management, and postdeployment last. (Older runbooks ran foundation in all regions first and then connectivity, primary region first.)

Full or partial runs

What changed Run
A new layer, a global setting, several layers, or a new platform version The full hub (all layers, all regions)
One layer Only that layer, where your entry pipeline offers it, or the full hub and read that the other layers plan no changes
Region-specific settings Only that region, where your entry pipeline offers it

Older entry pipelines have the run-time parameters Environment, Region and Layer, each with an all value. Check which parameters your entry pipelines expose (Pipelines).

4. Allow the agents through the firewall

After the hub exists, the job runners reach Azure and the package sources through the hub firewall. If you set deployment_agents_private_network_range, the platform creates the rule collection group for them. Otherwise add rules by hand for the agent subnet (see Network access of the agents). In older layer-by-layer runs, the first layers run on temporary runners and the rest only after these rules exist.

5. Prepare prod from canary

When canary works, copy the canary configuration to prod and change the values that must differ:

  • every environment name and short name (canary / cnry) to the prod name,
  • all subscription IDs and management group IDs,
  • all IP addresses and ranges,
  • the service connection or credential, the state backend and the agent pool in mcp.json,
  • approvals and branch protection (these are for prod only, see Prepare repositories).

Run hub for prod in Plan mode, read all plans, then apply. Production always needs an approval: use an Approve* mode or an environment with required reviewers.

6. Merge and tidy up

  1. Create a pull request from initial to main, get it reviewed, and merge it. Set the default branch (GitHub) back to main and update the federated credential for the branch.
  2. Run hub once more from main for canary and prod and confirm that it plans no changes.
  3. Switch on the protections for main and for prod (Prepare repositories).
  4. Deploy a test spoke: Deploy the spoke canvas.

Older layer-by-layer runs

Pipelines before the hub pipeline (a single pipelines/main.yaml or .github/workflows/main.yaml, with the platform code as the repository resource xms-landing-zone-core) ran one layer at a time. The same preparation applies. In those versions:

  • The pipeline pointed at the pool (AzureDevOpsAgents_Prod or _Canary in the older agent set-up) and read the state location from a variable group (service connection, container, resource group, storage account, Terraform version and subscription of the state).
  • For the first deployment you ran, in canary: the foundation layer for all regions, the connectivity layer (main region, then the other regions), the full canary run for all regions and (on GitHub) the ghrunners layer. Then you switched the pipeline to the self-hosted or network-integrated runners and ran firewall, identity, management and postdeployment, then everything once more.
  • Prod followed the same order after the canary config was copied and changed.
  • Updates ran layer by layer in the order foundation, connectivity, identity, management, firewall, postdeployment (on GitHub with ghrunners first), for canary and then prod, and finished with a full run from main.

For updating a tenant on such a version, see What to do when a new version is released (legacy note) and Migrating from an older platform version.