Spoke Extensions: Configure Shared Services¶
A spoke extension connects a spoke to a shared service, such as a shared API Management instance or container registry, when the spoke is deployed. The spoke deployment gives the right identities access and sets up what the workload team needs, so the team can use the shared service directly after the spoke is delivered. Nobody has to wait for a separate change.
This page is for the platform team: how to configure the shared services, what each extension creates, and how to add a new extension. For the workload team's view, see Shared services.
Origin of this page
Spoke extensions were introduced in spoke canvas 2.9.0 (History). The shared services live in their own spoke, which is deployed with the same spoke canvas and connected to the hub. Traffic to them goes through the hub firewall. Check the Known issues before you enable an extension: the spoke schema does not accept every field that the Terraform reads.
How it works¶
flowchart LR
spoke["Workload spoke<br/>(spoke JSON: extensions.*.enabled)"] -->|"spoke deployment"| ext["Extension code<br/>(pinned to a version tag)"]
ext -->|"role assignments, groups,<br/>managed identities"| shared["Shared services spoke<br/>APIM, ACR, Service Bus, Event Hub"]
team["Workload team"] -->|"uses the service"| shared
Two things steer the behaviour:
- Generic configuration, once per platform: where the shared services are.
- Spoke-specific configuration, per spoke: which extensions are on.
1. Generic configuration¶
In the current platform the shared services are in SpokeCommon.shared_services of mcp.json
(Configuration reference). In the older stand-alone spoke canvas the same block was in
common.tf (Upgrade guides). The block has the
subscription of the shared services and, per region, the resource IDs:
shared_services = {
subscription_id = null # string, subscription of the shared services
weu = { # one block per region
eventhub_resourceid = null # resource ID of the Event Hub namespace
apim_resourceid = null # resource ID of the API Management instance
acr_resourceid = null # resource ID of the container registry
acr_pull_group_object_id = null # object ID of the main AcrPull group (needed for the ACR extension)
acr_push_group_object_id = null # object ID of the main AcrPush group (needed for the ACR extension)
acr_administrative_unit_id = null # optional, administrative unit for the spoke ACR sub-groups
# (default: tenantinfo.AdministrativeUnitId)
servicebus_resourceid = null # resource ID of the Service Bus namespace
acs_resourceid = null # resource ID of the Communication Services resource
}
}
Fill in only the services you run. Use the region key that your platform uses (weu in the example).
2. Spoke-specific configuration¶
In the spoke JSON, each extension is switched on or off:
"extensions": {
"apim": { "enabled": false },
"acr": { "enabled": false },
"servicebus": { "enabled": false },
"eventhub": { "enabled": false }
}
To turn one on, set enabled to true in a pull request (Change spoke) and run
the spoke deployment (Spoke deployment). The extension code runs as part of that
deployment. The field is described in the Spoke JSON reference.
What each extension creates¶
The roles are assigned to the groups of the spoke (Owners, Contributors, Readers) and to the spoke deployment
principal. See the identity model.
| Extension | What it sets up |
|---|---|
| API Management, central model (default) | API Management Service Contributor for the spoke deployment principal, the Owners group and the Contributors group. API Management Service Reader for the Readers group. |
| API Management, decentral model | An API Management Workspace per spoke. API Management Workspace Contributor on the workspace for the spoke deployment principal, Owners and Contributors. API Management Workspace Reader for Readers. |
| Azure Container Registry | No role assignments on the registry per spoke. AcrPull and AcrPush are assigned once, to the main groups of the shared registry. Per spoke the extension creates two Entra ID sub-groups, <main AcrPull group name>-<spoke> and <main AcrPush group name>-<spoke>, nested in the main groups and owned by the service principal of the spoke, and two managed identities, <prefix>-acrpull-mi and <prefix>-acrpush-mi, that are members of the matching sub-group. |
| Event Hub | A new event hub in the shared namespace. User Access Administrator for the spoke deployment principal. Azure Event Hub Data Owner and Owner for Owners, Contributor for Contributors, Reader for Readers, all on that event hub. |
| Service Bus | A group for Data Sender and Receiver access to Service Bus messaging entities with the roles Azure Service Bus Data Sender and Azure Service Bus Data Receiver on the namespace. Members: Owners and Contributors. A group for Reader access to the Service Bus Namespace with Service Bus Namespace Reader. Members: Readers and the sender/receiver group. The spoke deployment principal gets Service Bus Namespace Manager and User Access Administrator, the latter limited to assigning the two data roles to groups. |
| Communication Services | Currently unavailable. |
Notes:
- ACR. The Owners, Contributors and Readers groups of the spoke get no registry access through the extension. Members that someone adds to the sub-groups by hand are kept. Deleting images is deliberately not allowed, so teams cannot delete each other's images, on purpose or by accident.
- Dedicated groups. To give all team groups access to a central resource, such as the Bastion host or a registry that holds the managed templates, use one dedicated group instead of many role assignments. See Dedicated group manager.
Integration Platform
The Integration Platform builds a per-entity Service Bus automation on top of this extension (Service Bus automation). Its source describes the Service Bus roles differently from the table above. Check the extension version you run before relying on either.
Enable an extension: checklist¶
- The shared service exists and its resource ID is in the
shared_servicesblock of the region. - For ACR: the main
AcrPullandAcrPushgroups exist and their object IDs are set. - The spoke JSON sets
enabledtotruefor the extension. Run the config tests (Run the tests locally). - After review, the spoke deployment runs. Read the plan: you expect new role assignments and groups, no deletes.
- Verify the result in Azure (the role assignments and the groups in the table above) and tell the workload team.
Contribute a new extension¶
An extension is code that a spoke deployment pulls in. To add one, make sure that:
- the extension is in a Git repository that the spoke deployment can read;
- the repository uses version tags, so a spoke deployment pins a version;
- the shared service you extend is available;
- the why and how of the extension are documented.
For a new shared service, the architecture, operations and security functions assess the request first (Service types).