Skip to content

Spoke Canvas Module Reference

The spoke canvas Terraform has two root modules: deploy/subscription and deploy/spoke, both in src/Xebia.Mcp/Files/terraform/spoke-canvas/ of the code repository (layout). The pipelines fill their variables; you normally do not run them by hand. This page groups the inputs by purpose, lists the modules, and shows what the outputs hold. It is a reading guide: the generated tables in the README of each root module (made by terraform-docs) stay the exact source.

For what the result looks like, see Spoke canvas: what a deployment creates. For the JSON that drives it, see the Spoke JSON reference.

Subscription root (deploy/subscription)

The subscription layer prepares the subscription for a spoke: it is the step before the spoke canvas. It calls the subscription module and outputs the subscription ID that the canvas layer then uses. The design behind it is in Subscription provisioning.

Input Required Purpose
FileName yes Path of the spoke JSON file
IncrementName no (default 001) Increment value for generated names. The sources do not describe it further
TenantId yes Tenant of the subscription
xmscsp_billing_account_name, xmscsp_subscription, xmscsp_tenant, xmscspclient_id, xmscspclient_secret yes Billing account and service principal that are needed to create a subscription (CSP route)
Output Holds
subscriptionId The ID of the subscription for the spoke

The pipeline passes empty CSP values

The CSP inputs exist because the code can create a subscription when azureSubscriptionId is empty. The pipelines pass the five CSP values as empty strings, so the subscription must exist before the run (New spoke).

Spoke root (deploy/spoke)

Inputs by purpose

Purpose Input Required Description
Spoke definition FileName yes Path to the spoke configuration JSON file
subscriptionOutputFileName yes Path to the JSON file with the output of the subscription layer
subscription_id no Subscription ID, when it is given directly
IncrementName no (default 001) Increment value for generated names. The sources do not describe it further
spoke_canvas_version no Version identifier of the spoke canvas code. Written as the spoke_canvas_version tag
Deployment identity xmscsp_tenant, xmscsp_subscription yes Tenant and subscription the deployment runs against
xmscspclient_id, xmscspclient_secret yes Client ID and secret of the deployment identity
Name overrides overwrite_KeyVault, overwrite_KeyVaultPE, overwrite_StorageAccount, overwrite_StorageAccountPE, overwrite_LogAnalytics, overwrite_AutomationAccount, overwrite_DefaultNSGName, overwrite_VWanConnection, overwrite_SubscriptionName no Replace the generated name of one resource. null keeps the standard name
GitHub integration ghinfo no Object with BaseUrl, OrganizationName and OidcIssuer of the GitHub host
github_app_id no GitHub App ID, for app authentication of the GitHub providers. Passed as TF_VAR_github_app_id in CI/CD. Leave unset to use token authentication
github_app_installation_id no Installation ID of the GitHub App on the platform organisation
github_app_installation_id_workload no Installation ID on the organisation that holds the workload repository. Equals the platform installation when both are in the same organisation
github_token no Token for repository management. In CI/CD normally a short-lived GitHub App installation token, passed as TF_VAR_github_token
integration_module_source no Git source of the integration modules used by the GitHub and shared-service extensions. Has a default; override it when your platform syncs the modules elsewhere

Secrets as variables

xmscspclient_secret, github_token and the GitHub App credentials are secrets. Pass them from the pipeline's secret store through TF_VAR_* variables. Never put them in a spoke file or a tfvars file in the configuration repository.

Modules

The spoke root is a composition. Modules by area:

Area Modules What they do
Subscription subscription_managementgroup, subscription_rename, subscription_tags Place the subscription in the management group, rename it, apply tags
Identity and access privileges_adgroups, privileges_service_principal, privileges_roleassignments, pim_group_config, storespnsecret Create the Entra ID groups and the service principal, assign roles, configure PIM for the groups, store the service principal secret in the Key Vault
Resource groups resourcegroup, resourcegroup_networkwatcher The resource group per region, and the dedicated group for Network Watchers
Network virtualnetwork, virtualnetworkvhublink, networkwatcher Network, subnets, NSGs and route tables, the virtual hub connection, Network Watcher
Private DNS private_dns_zone, private_dns_zone_vnet_link_hub An optional private DNS zone for the spoke, linked to the hub DNS resolver network
Resources for the workload keyvault, storageaccount, loganalyticsworkspace Key Vault, storage account (with customer-managed key), Log Analytics workspace
Azure DevOps AzureDevOps Optional repository and service connection
Extensions apim_configuration, acr_configuration, servicebus_configuration, eventhub_configuration, github_repository_configuration, github_integration_configuration Optional use of shared services, and the GitHub repository with its federated credentials

Besides the modules, the root creates an Azure Monitor activity log alert for policy operations. The sources do not describe its trigger or action group.

Outputs

Outputs are the hand-over between the layers and the information a pipeline can show or pass on. The sources list the names only, without a description:

Output Reports on
workloadinfo The workload of the spoke
resourcegroup The resource groups
networking The network resources
keyvault The Key Vault
storage_account The storage account
loganalytics The Log Analytics workspace
groups The spoke Entra ID groups
ProductTeamGroups The team groups that were given access
privileges The role assignments
spn The service principal

Run terraform output on a spoke state to see the exact content for your version, and check it before you rely on it in a script. Treat the output of spn as sensitive until you know that it holds no secret.

Providers and versions

The spoke root pins exact provider versions, as every root module does (Tools).

Provider Used for
azurerm, azapi Azure resources
azuread Groups, service principals, PIM
azuredevops Repository and service connection
github Repository and federated credentials
external, time Supporting lookups and timing

At the time of the extraction, the spoke root required Terraform 1.9.2 or higher. The exact versions per release are in the README of the root module in the version you pin.

Settings shared by all spokes

Settings that are valid for every spoke are kept once and not repeated in each spoke file. In the current platform they are in mcp.json under SpokeCommon (mcp.json). In the older, separate spoke canvas they were in a common.tf file. The groups of settings are the same:

Group Holds
Tenant information (tenantinfo) Tenant, administrative unit ID, prefix for group names, validity of service principal secrets in days. Changing the validity creates new secrets for all spoke service principals
Networking The subscription of the central virtual hub, and optionally the Azure Virtual Network Manager IPAM pools that spoke files may allocate address space from
Regions Per region: Azure region name, friendly name, DNS server (normally the hub firewall in that region), resource ID of the virtual hub, resource ID of the central Log Analytics workspace
PIM configurations The named PIM profiles nopim, self-approve and approval
Overrides for the PIM role map Optional, see Data-plane access through PIM
GitHub host (ghinfo) Base URL, organisation and OIDC issuer of the GitHub host. For GitHub.com the OIDC issuer is https://token.actions.githubusercontent.com
Shared services The subscription of the shared services, used by the extensions

An IPAM pool is regional, so name the pool with its region when you have more than one region. Spoke files that do not use a pool keep their fixed address prefixes, which stays supported. A spoke file uses either addressPrefix or an ipamPool with numberOfIpAddresses, not both. When a virtual network uses a pool, its subnets inherit it and only give numberOfIpAddresses; a subnet in a network with a fixed address prefix cannot ask for a pool allocation.

Check the field names for your version

The names in this table are those of the older layout. Look in the Spoke JSON reference and in mcp.json of your configuration repository for the names your version uses.