Nieuwe spoke (workload / application landing zone)¶
Standaardwijziging: Nieuwe workload/spoke/application landing zone (spoke canvas)
Effect: een bestaande Azure subscription wordt een kant-en-klare landing zone. Hij wordt verplaatst naar de gekozen management group, getagd en hernoemd, verbonden met de hub, en krijgt de hieronder beschreven baseline voor netwerk, identity en RBAC.
De runbooks voor reviewers en operators zijn Spoke aanmaken, Review van de spoke pull request en Spoke deployment.
Aanvraagvelden¶
| Aanvraagveld | Waar het in de spoke-JSON komt | Opmerkingen |
|---|---|---|
| Naam | workloadShortName, plus azureSubscriptionName en de bestandsnaam |
workloadShortName is maximaal 6 tekens. Het wordt gebruikt in elke resourcenaam en in de Terraform state key. Kies zorgvuldig: wijzigen achteraf maakt een nieuwe spoke aan. |
| Onderbouwing | pull request / wijzigingsrecord | |
| Omgeving | environment |
dev, tst/test, acc/acc<n>, prd/prod, shrd/shared. De pipeline normaliseert de waarde alleen om spokes in stages te groeperen (acc2 → acc, prod → prd). Namen en de state key gebruiken de ruwe waarde, dus prod en prd zouden twee verschillende spokes zijn. Kies één schrijfwijze en houd je eraan. |
| Gebruikstype (productiedata ja/nee) | managementGroupId, en de tag pii als er persoonsgegevens bij betrokken zijn |
De JSON heeft geen veld voor productiedata. Druk het uit door een management group met de juiste policies te kiezen, bijvoorbeeld een …-prdlike child group in plaats van …-nonprd, als jouw structuur die heeft. |
| Blootstelling aan het publieke internet ja/nee | managementGroupId (boom landingzones_corp vs landingzones_online) en InternetSecurityEnabled |
Inkomende publicatie loopt via de hub Application Gateway (runbook). Uitgaand internet vereist firewallregels (runbook). |
| IP-range / IP-grootte | resourceconfiguration.network[].addressPrefix |
Wijs toe vanuit je IP-plan. De code controleert niet op overlap. Een /24 is een gangbare default. Wil je meer, spreek dat dan af met wie eigenaar is van het IP-plan. Leg het toegewezen bereik in dezelfde pull request vast in het plan. |
| Subnetnaam / -grootte | network[].subnets[].name / .addressPrefix |
|
| Subnet delegations | network[].subnets[].delegations[] |
name moet een van de waarden uit het schema zijn (bijvoorbeeld Microsoft.Web/serverFarms). |
| Subnet service endpoints | network[].subnets[].serviceEndpoints[] |
{ "service": "Microsoft.Storage" } |
| Welk team heeft toegang nodig | adInfo.ProductTeamGroupNames, adInfo.PIMGroupConfig |
Bestaande weergavenamen van Entra ID-groepen. |
| Opmerkingen | – |
Controleer de aanvraag¶
Controleer bij een binnenkomende aanvraag eerst of de informatie volledig en correct is. Stuur onduidelijke aanvragen terug tot ze duidelijk zijn.
| Onderdeel | Controle |
|---|---|
| Workload short name | Uniek over alle spokes. Maximaal 6 tekens. Alleen letters en cijfers: geen spaties of speciale tekens. |
| Omgeving | Een van de ondersteunde levenscyclusfasen (development, test, acceptatie, productie). Gebruik de afkortingen dev, tst, acc, prd consequent. |
| Tags | De vereiste governance-tags zijn aanwezig: owner, department, costcentre, pii (een tekstwaarde, zie de referentie), plus workload en environment. De spoke canvas-handleiding vraagt om kleine letters; controleer wat jouw tag policy vereist. Voeg de gereserveerde tag hidden-XebiaSpokeMetadata niet toe: de deployment voegt die zelf toe. |
| Teamgroep | De naam van de productteamgroep, precies zoals die in Entra ID staat. |
| Doelregio's | Regio's die in jouw platform bestaan. Gebruik de korte namen uit je regioninfo (Spoke common settings). Voorbeelden van korte namen: weu (West Europe), neu (North Europe). |
| Adresruimte | Een /24 (256 adressen) is het gebruikelijke minimum. Alles groter dan een /23 vraagt om een gesprek en een toelichting. Zie ook Netwerk-IP-dimensionering. |
| Subnets | Naam, grootte, delegations en service endpoints, volgens de Spoke JSON-referentie. |
| Management group | Gekozen uit de groepen in jouw structuur, zie hieronder. |
De management group kiezen¶
De spoke komt in een landing zone management group. Twee keuzes bepalen welke: of de workload bereikbaar is vanaf internet (Corp of Online) en of hij productie-achtige data verwerkt (PrdLike of NonPrd). Met een canary- en een productieplatformomgeving heeft elk een eigen boom, dus zijn er in totaal acht combinaties:
| Platformomgeving | Corp of Online | NonPrd of PrdLike | Management group (voorbeeldnaamgeving) |
|---|---|---|---|
| Canary | Corp | NonPrd | <canary>CorpNonPrd |
| Canary | Corp | PrdLike | <canary>CorpPrdLike |
| Canary | Online | NonPrd | <canary>OnlineNonPrd |
| Canary | Online | PrdLike | <canary>OnlinePrdLike |
| Productie | Corp | NonPrd | <platform>CorpNonPrd |
| Productie | Corp | PrdLike | <platform>CorpPrdLike |
| Productie | Online | NonPrd | <platform>OnlineNonPrd |
| Productie | Online | PrdLike | <platform>OnlinePrdLike |
De namen zijn een voorbeeld van één implementatie. Gebruik de ID's die in jouw management_group_structure bestaan
(Hub-configuratie).
Voordat je begint¶
Voor de eerste spoke van een nieuw platform, zie De spoke canvas uitrollen.
- De subscription moet al bestaan. De subscription-layer kan een subscription aanmaken, maar alleen als
azureSubscriptionId leeg is, en alleen met een CSP billing account (xmscsp_billing_account_name). De pipeline geeft de CSP-waarden
als lege strings door (Invoke-XebiaMcpSpokePlan.ps1), dus via de pipelines moet je een bestaande
subscription-ID opgeven. Maak de subscription eerst aan via je EA/MCA/CSP-proces.
- De spoke deployment identity (Azure.TerraformState.Spoke.ServicePrincipalId in mcp.json, gebruikt door de spoke
service connection) moet alles kunnen wat onder What gets created staat:
- de subscription tussen management groups verplaatsen;
- role assignments aanmaken op de subscription;
- een virtual hub connection aanmaken in de connectivity-subscription;
- Entra ID-groepen aanmaken in de administrative unit SpokeCommon.tenantinfo.AdministrativeUnitId;
- service principals aanmaken;
- PIM voor groepen configureren.
- De doel-managementGroupId moet voorkomen als id in <env-folder>/<targetRegions.primary of the spoke>/foundation.auto.tfvars,
anders weigert de configuratietest het bestand. De test accepteert elke id in management_group_structure en in de
corp/online child maps. Kies zelf een landing zone-groep; de test houdt je niet tegen als je bijvoorbeeld
de sandbox-groep kiest.
- De groepen in ProductTeamGroupNames moeten in Entra ID bestaan.
- De goedkeuringen die je organisatie vereist zijn geregeld, bijvoorbeeld van de product owner en van architectuur en security
voor een nieuwe workload, en een registratie van de workload in je asset register (CMDB) als je er een bijhoudt.
- Het adresbereik is gereserveerd in het IP-plan (zie de tabel hierboven) en het subnetplan laat ruimte voor nieuwe subnets.
Gebruik je in plaats daarvan een IPAM-pool, dan staat de pool in de common settings (hieronder).
- Maakt de spoke een Azure DevOps-repository of een GitHub-repository aan, dan is de voorbereiding daarvoor gedaan
(Spoke-integraties voorbereiden).
Stappen¶
1. Maak het spoke-bestand aan¶
Maak eerst een branch aan. Een standaard branchnaam maakt branches makkelijk terug te vinden, bijvoorbeeld
feature/SpokeNew-<request id>-<workload short name>-<environment>. Controleer je eigen conventies.
Maak daarna <env-folder>/spokes/<team-or-workload>/<file>.json aan. De makkelijkste start is een kopie van het template-spokebestand
dat bij de configuratierepository of de gepinde codeversie hoort. Templatebestanden voor veelvoorkomende patronen kunnen in
dezelfde repository staan, maar geef ze een andere extensie dan .json, of zet ze waar de glob niet matcht, zodat de
pipeline ze niet uitrolt.
- Gebruik een submap. De standaard-glob
**/*.jsonheeft een/nodig, dus bestanden die direct inspokes/staan worden niet gevonden. - Gebruik een unieke bestandsnaam over alle submappen heen. De bestandsnaam zonder
.jsonwordt de naam van de spoke in pipeline jobs en artifacts (spoke_<name>,subscription_output_<name>). Twee bestanden met dezelfde naam in verschillende mappen botsen in één run. - Een consistent patroon zoals
canvas_<workload>_<environment>.jsonmaaktspokeGlobmakkelijk te gebruiken. - De aparte spoke canvas-pipeline verwacht meer: de naam begint met
canvas_, eindigt op.jsonen bevat_prod_of_nonprod_(bijvoorbeeldcanvas_nonprod_<workload>-<environment>.json). Volg dit patroon als je die pipeline draait.
Minimaal voorbeeld (geldig volgens src/Xebia.Mcp/Files/json/spokeschema.json):
{
"workloadShortName": "app1",
"environment": "dev",
"azureSubscriptionId": "00000000-0000-0000-0000-000000000000",
"azureSubscriptionName": "sub-app1-dev",
"managementGroupId": "cloudplatform-landingzones-corp",
"tags": {
"owner": "Jane Doe",
"department": "Finance IT",
"workload": "Invoice Portal",
"pii": "no",
"costcentre": "CC-1234",
"environment": "dev"
},
"adInfo": {
"ProductTeamGroupNames": ["Team Invoice Portal"],
"PIMGroupConfig": {
"Readers": "nopim",
"Contributors": "self-approve",
"Owners": "approval"
}
},
"targetRegions": {
"primary": "weu",
"additional": []
},
"resourceconfiguration": {
"network": [
{
"name": "vnet-##wlshortname##-##environment##-##region##-001",
"region": "weu",
"addressPrefix": ["10.20.4.0/24"],
"peerHub": true,
"dnsServerOverwrite": "",
"subnets": [
{
"name": "snet-##wlshortname##-pe-##environment##-##region##-001",
"isprivatelinksubnet": true,
"addressPrefix": "10.20.4.0/27",
"privateEndpointNetworkPoliciesEnabled": false,
"serviceEndpoints": [],
"delegations": [],
"linkedroutetablename": null,
"linkednetworksecuritygroupname": "nsg-##wlshortname##-##environment##-##region##-001"
},
{
"name": "snet-##wlshortname##-app-##environment##-##region##-001",
"isprivatelinksubnet": false,
"addressPrefix": "10.20.4.64/26",
"privateEndpointNetworkPoliciesEnabled": false,
"serviceEndpoints": [{ "service": "Microsoft.Storage" }],
"delegations": [
{
"name": "Microsoft.Web/serverFarms",
"actions": ["Microsoft.Network/virtualNetworks/subnets/action"]
}
],
"linkedroutetablename": null,
"linkednetworksecuritygroupname": "nsg-##wlshortname##-##environment##-##region##-001"
}
],
"networksecuritygroups": [
{ "name": "nsg-##wlshortname##-##environment##-##region##-001", "rules": [] }
],
"routetables": []
}
]
}
}
De placeholders ##wlshortname##, ##environment## en ##region## worden vervangen in de namen van network, subnet, NSG en route table.
Twee structuurregels die het schema niet afdwingt, maar waar de Terraform wel op rekent:
- elke
network[]-entry heeft minstens één subnet met"isprivatelinksubnet": truenodig (modules/virtual_network/locals.tfpakt de eerste); - wanneer de Key Vault of het storage account wordt uitgerold (de default), heeft elke regio in
targetRegionseen VNet met zo'n subnet nodig. De private endpoints komen daar te staan. Alle velden, inclusief de optionele blokkenkeyvault,storageaccount,loganalytics,azdoenextensions, worden beschreven in de Spoke JSON-referentie.
Adresruimte uit een IPAM-pool¶
Heeft het platform IPAM-pools (Spoke common settings), dan kun je
addressPrefix weglaten en in plaats daarvan de poolnaam en de groottes opgeven. De pool kiest de adressen, en het
overlaprisico van handgeschreven bereiken verdwijnt. De velden en regels staan in de
Spoke JSON-referentie. Leg de toegewezen bereiken uit de
deployment-output daarna vast in je IP-plan.
2. Bepaal de optionele resources¶
Als je de blokken storageaccount, keyvault en loganalytics weglaat, worden er toch een storage account, een Key Vault en een Log
Analytics workspace aangemaakt met de module-defaults (deploy staat standaard op true in
spoke-canvas/deploy/spoke/locals.tf en main.tf). Een storage account forceert altijd een Key Vault, die de
customer-managed key bevat. Om ze over te slaan voeg je het blok toe met "deploy": false en alle keys die het schema voor dat
blok vereist (zie de referentie).
Maak het private endpoint van de Key Vault of het storage account (createprivateendpoint, CreatePrivateEndpoint) alleen aan
als de workload het gaat gebruiken. De Key Vault bevat het secret van de deployment service principal, tenzij de spoke federated
credentials gebruikt. Geef de voorkeur aan federated credentials (azdo.useFederatedCredentials bij het aanmaken van de Azure DevOps
service connection, of de GitHub-extensie), zodat er geen secret hoeft te worden opgeslagen of geroteerd. Beide integraties worden beschreven in
Spoke-integraties.
3. Valideren en een pull request openen¶
Loop het bestand nog een keer na, commit het naar de branch en open een pull request. Een andere persoon reviewt het (Spoke pull request review). Volg Veilig een wijziging doorvoeren, stap 4–5.
4. Draai de spoke-pipeline¶
Draai spoke met spokeGlob alleen op het nieuwe bestand, bijvoorbeeld team-a/canvas_app1_dev.json.
- Azure DevOps: Pipelines →
spoke→ Run pipeline →spokeGlob=team-a/canvas_app1_dev.json. - GitHub Actions: Actions →
spoke→ Run workflow →spokeGlob=team-a/canvas_app1_dev.json.
Draai niet met de standaard
**/*.jsontenzij je elke spoke wilt plannen. Elk spoke-bestand dat door de glob wordt gevonden moet de configuratietests doorstaan, en de omgeving ervan moet in de lijstenvironmentsvan de pipeline staan (standaard dev → tst → acc → prd). Eensharedspoke laat de run falen, tenzij jesharedaanenvironmentstoevoegt.Zorg dat de entry-pipeline niet op
whatIf: truestaat als je de spoke wilt toepassen (zie Pipelines en workflows).
Wat er wordt aangemaakt¶
Uit src/Xebia.Mcp/Files/terraform/spoke-canvas/deploy/spoke/main.tf:
| Resource | Naam / detail |
|---|---|
| Subscription tags | De JSON-tags plus spoke_canvas_version |
| Plaatsing in management group | Verplaatst de subscription naar managementGroupId, als hij daar nog niet staat |
| Subscription hernoemen | Naar azureSubscriptionName. Als die leeg is, naar SpokeCommon.tenantinfo.SubsciptionNamingTemplate |
| Resource group (per regio) | rg-canvas-<wl>-<env>-<region>-001, tenzij resourceGroup.name is gezet |
| Virtual network, subnets, NSG's, regels, route tables | Uit network[]. Elk subnet krijgt een NSG: die uit linkednetworksecuritygroupname, of een standaard-NSG |
| DNS-servers op het virtual network | dnsServerOverwrite, of de hub DNS-server van de regio (virtual_network_dns_servers in de hub connectivity tfvars) |
Virtual hub connection (bij peerHub, standaard true) |
VNet-naam met vnet- → con-, in de connectivity-subscription, internet_security_enabled = InternetSecurityEnabled (standaard true) |
| Log Analytics workspace (standaard aan) | log-<wl>-<env>-<region>-001 |
| Key Vault (standaard aan) | kv<wl><env><region>001, RBAC-modus, standaard private endpoint |
| Storage account (standaard aan) | st<wl><env><region>001, customer-managed key, standaard private endpoint |
| Entra ID-groepen | <GroupnamePrefix><wl>_<env>_Owners, _Contributors, _Readers, _Support in de administrative unit |
| PIM | Elke ProductTeamGroupNames-groep wordt lid van elke spoke-groep: nopim = actief, self-approve = eligible zonder goedkeuring, approval = eligible met goedkeuring |
| Service principal | <SPNNamePrefix><wl>-<env>. Het secret wordt opgeslagen in de Key Vault van de spoke, tenzij federated credentials worden gebruikt |
| Role assignments | Subscription: SPN en Owners-groep → Owner, Contributors → Contributor, Readers → Reader. Plus data-plane-rollen op de Key Vault en het storage account, toegekend via de rolmap op subscriptionscope (RBAC en PIM) |
| Azure DevOps-repo en service connection | Alleen wanneer het blok azdo aanwezig is |
| GitHub-repository en federated credentials | Alleen wanneer extensions.github is ingeschakeld (Spoke-integraties) |
Niet aangemaakt door het spoke canvas: budgets, en firewallregels voor het verkeer van de spoke.
Controleren¶
- De Apply-stap van de pipeline voor de spoke-omgeving is groen.
- In de Azure portal, de subscription:
- staat onder
managementGroupId; - heeft de tags;
- heeft het virtual network met de verwachte address space en subnets.
- Connectivity-subscription → Virtual WAN → Virtual network connections: het spoke-VNet staat vermeld als verbonden.
- Entra ID: de vier
SG_SPOKE_<wl>_<env>_*-groepen bestaan, en de teamgroep is (eligible) lid zoals geconfigureerd. - Vraag het team hun rol te activeren (als PIM van toepassing is) en de toegang te bevestigen.
Terugdraaien¶
Verwijder de spoke met de runbook Spoke verwijderen. Alleen het JSON-bestand verwijderen doet niets: geen enkele pipeline vernietigt spokes waarvan het bestand ontbreekt.
Krijgt de spoke managed VM's, voeg dan de map ervan toe aan de lijst met spokes van de modulepipeline (zie Managed VM-module).
Veelvoorkomende problemen¶
| Symptoom | Oorzaak |
|---|---|
Config test: environment … must be one of |
De environment van de spoke staat niet in de lijst environments van de pipeline. |
Config test: managementGroupId … must exist |
De groep staat niet in foundation.auto.tfvars van de primaire regio. |
| Config test: schemafout | Ontbrekende verplichte key. Elk subnet heeft isprivatelinksubnet, privateEndpointNetworkPoliciesEnabled, serviceEndpoints, delegations en linkedroutetablename nodig. |
| Plan wil een hele nieuwe spoke aanmaken voor een bestaande | workloadShortName of environment is gewijzigd, waardoor de state key verandert. |
Een nieuwe run plant het vernietigen van azurerm_management_group_subscription_association |
Bekend probleem: de count van de association hangt ervan af of de subscription al in de groep zit. Zie Bekende problemen. Pas die destroy niet toe zonder te begrijpen wat er gebeurt. |
| Spoke kan het internet of andere netwerken niet bereiken | Firewallregels ontbreken. Zie Firewallregels. |