Skip to content

Platform: What It Is and How It Works

This section is for platform engineers: XMMS engineers in the managed model, or the customer's own platform team in the self-managed model (Operating models). It explains what the platform is technically, how it is deployed, and how to build, release and configure it.

I want to… Read
Understand the architecture This page. For the reasoning behind it, see the Architecture reference
Understand the order in which everything is deployed Platform deploy flow
Know which repository holds what Repo setup
Work on the code: tools, provisioning, new features, releases Code
Change a customer's configuration (hub or spoke) Config
Upgrade a customer to a new version What to do when a new version is released
Run the platform day to day Operations, Incident management, Monthly health check, Maintenance calendar
Organise firewall rules, regions, DNS, agents and VPN access Design guidance
Implement the platform in a new tenant (plan, prepare, deploy, validate, hand over) Implementing the platform
Handle a standard change step by step (operator and reviewer runbooks) Reviewer and operator runbooks
Maintain the template library Managed Templates
See what changed per version, do version-specific upgrade steps Releases and upgrade guidance, Release history
Understand and set up alerting Monitoring and alerting
Troubleshoot pipelines, agents and local access Troubleshooting how-tos
Know which Azure resources the platform deploys, and the switch for each What the platform deploys
Understand how customer copies of the code repository stay current Code synchronisation
Understand governance, roles and the DNS design Governance, Identity and access model, DNS design

What gets deployed

The platform consists of:

  • a hub: shared networking, security, governance and monitoring that every workload uses, and
  • spokes: one subscription per workload and spoke environment, pre-wired to the hub.

Everything is deployed with Terraform, orchestrated by a PowerShell module (src/Xebia.Mcp), and run from Azure DevOps pipelines or GitHub Actions workflows.

Management group structure

Tenant root
└── <organization management group>              (management_group_organization_id)
    └── cloudplatform
        ├── platform
        │   ├── platform_management   → Management subscription   (Log Analytics, Automation, Key Vault, storage)
        │   ├── platform_connectivity → Connectivity subscription (Virtual WAN, hub, Azure Firewall, gateways, DNS, App Gateway)
        │   └── platform_identity     → Identity subscription     (identity virtual network)
        ├── landingzones
        │   ├── landingzones_corp     → corp spoke subscriptions   (+ optional child groups)
        │   └── landingzones_online   → online spoke subscriptions (+ optional child groups)
        ├── shared                    (+ optional child groups)
        ├── sandbox
        └── decommissioned

The meaning of each level is explained in Architecture reference.

The tree is created by infra/templates/management_groups/main.tf. Names and IDs are set in <env-folder>/<primary region>/foundation.auto.tfvars (management_group_structure and the mgmtgrp_structure_under_customer_area_* maps).

Network

  • Virtual WAN with a virtual hub per region. The Virtual WAN is always created in the primary region; every region gets its own virtual hub. Azure Firewall is deployed into the virtual hub, which makes it a secured virtual hub.
  • Spokes connect with a virtual hub connection, not with classic VNet peering. With internet_security_enabled = true (the default), spoke internet traffic goes through the hub firewall.
  • Firewall rules and IP groups are JSON files in the configuration repository, deployed by the firewall layer. See Firewall rule organisation for how to structure them.
  • Private DNS: central private DNS zones for Private Endpoints and a Private DNS Resolver. An Azure Policy initiative registers Private Endpoint DNS records in the central zones automatically. See DNS design.
  • Optional: site-to-site VPN, point-to-site VPN, ExpressRoute, Application Gateway with WAF, Azure Bastion, DDoS protection, Azure Virtual Network Manager with IPAM. All switches are in the feature flags reference.

Governance

  • Built-in compliance initiatives at the cloudplatform management group: ISO 27001:2013, CIS 1.4.0, CIS 3.0.0, Microsoft cloud security benchmark and NIS2 (postdeployment layer).
  • Custom policy definitions and initiatives from JSON in the configuration repository (foundation layer).
  • Policy assignments and exemptions from JSON in the configuration repository (postdeployment layer).
  • Microsoft Defender for Cloud for the platform subscriptions, and optionally for spokes.

Monitoring

  • Action groups (ag-<company>-mgmtgeneral-… and ag-<company>-mgmtxpirit-…), created by the foundation layer.
  • Azure Monitor Baseline Alerts (AMBA): five initiatives (Service Health, Management, Connectivity, Identity, Landing Zone) assigned per management group by the postdeployment layer.
  • Alert processing rules route platform alerts to the action groups.
  • Optional hub 24/7 routing (hub_247_support) sends selected hub alerts to a webhook outside office hours (ADR-0007).

Spokes

For each spoke JSON file, the spoke pipeline creates or updates, in the spoke subscription:

  • subscription tags, name and management group placement
  • resource groups, virtual networks, subnets, NSGs and route tables
  • the virtual hub connection
  • a Log Analytics workspace, Key Vault and storage account (on by default)
  • Entra ID groups (Owners, Contributors, Readers, Support) with PIM settings
  • a service principal with role assignments
  • optionally an Azure DevOps repository and service connection

Deployment tooling

The pipelines run inside a container image (mcp) on self-hosted runners in the JobRunner subscription from mcp.json: a virtual network with NAT gateway, an Azure Container Registry, a Managed DevOps Pool, a Container Apps environment and a DNS resolver. Terraform state is stored in the storage accounts in mcp.json (Azure.TerraformState.Hub and .Spoke).

How it works, in one picture

flowchart LR
    subgraph code["xms-cloud-platform-code (one for all customers)"]
        tf["Terraform layers + modules"]
        mod["Xebia.Mcp PowerShell module"]
        tpl["Pipeline templates"]
    end
    subgraph cfg["Configuration repository (one per customer)"]
        json["mcp.json, tfvars, JSON"]
        entry["Entry pipelines (pinned version)"]
    end
    entry -- "checks out release/vX.Y" --> tpl
    tpl --> mod
    mod -- "terraform plan / apply" --> tf
    json -- "values" --> mod
    mod --> azure["Azure: canary, then prod"]

Why it is built this way

Design choice Reason
Code repository separate from configuration repository One shared, versioned codebase serves many tenants. Each tenant keeps only its own values.
Layers instead of one Terraform root Smaller blast radius, faster plans, a clear dependency order. See Deployment layers.
JSON files for rules, policies and spokes People who don't write Terraform can review changes. Schemas and config tests validate files before deployment.
Logic in a PowerShell module, thin YAML Azure DevOps and GitHub Actions behave the same, and every step can run locally (ADR-0011).
Canary platform environment Every code or config change is proven on a full copy of the hub before it reaches production.

See Platform philosophy for the principles behind these choices. The service types (core, direct, additional) and the spoke variants are described in Service types.