Ga naar inhoud

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 **/*.json heeft een / nodig, dus bestanden die direct in spokes/ staan worden niet gevonden.
  • Gebruik een unieke bestandsnaam over alle submappen heen. De bestandsnaam zonder .json wordt 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>.json maakt spokeGlob makkelijk te gebruiken.
  • De aparte spoke canvas-pipeline verwacht meer: de naam begint met canvas_, eindigt op .json en bevat _prod_ of _nonprod_ (bijvoorbeeld canvas_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": true nodig (modules/virtual_network/locals.tf pakt de eerste);
  • wanneer de Key Vault of het storage account wordt uitgerold (de default), heeft elke regio in targetRegions een VNet met zo'n subnet nodig. De private endpoints komen daar te staan. Alle velden, inclusief de optionele blokken keyvault, storageaccount, loganalytics, azdo en extensions, 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 **/*.json tenzij 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 lijst environments van de pipeline staan (standaard dev → tst → acc → prd). Een shared spoke laat de run falen, tenzij je shared aan environments toevoegt.

Zorg dat de entry-pipeline niet op whatIf: true staat 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

  1. De Apply-stap van de pipeline voor de spoke-omgeving is groen.
  2. In de Azure portal, de subscription:
  3. staat onder managementGroupId;
  4. heeft de tags;
  5. heeft het virtual network met de verwachte address space en subnets.
  6. Connectivity-subscription → Virtual WAN → Virtual network connections: het spoke-VNet staat vermeld als verbonden.
  7. Entra ID: de vier SG_SPOKE_<wl>_<env>_*-groepen bestaan, en de teamgroep is (eligible) lid zoals geconfigureerd.
  8. 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.