Prepare Identity and Access¶
This page covers the Entra ID and Azure objects that must exist before the first deployment: the platform team's groups, the administrative unit, the PIM flow, the RBAC roles, the management group, and the deployment identities with their service connections. The model behind them is in Identity and access model.
In many implementations the customer creates the first part (groups, administrative unit, management group, PIM) from a written request, and the platform team verifies it with the prerequisite checks. In a self-managed implementation your own identity team usually does it. The steps are the same either way.
What you create¶
| Object | Purpose | Created by |
|---|---|---|
| Platform engineers group | All people who work on the platform. Not role-assignable. | Customer identity team |
| Platform maintainers group | The group that holds the permanent role assignments. It has no active members: access comes from PIM. Role-assignable. | Customer identity team |
| Administrative unit | Scopes the Entra ID groups that the spoke pipeline creates | Customer identity team |
| Platform management group | Root of the platform hierarchy | Customer, or the platform team |
| PIM configuration | Makes the engineers group an eligible member of the maintainers group, with approval | Customer identity team |
| RBAC and directory roles | Give the maintainers group the rights to deploy | Customer identity team |
| Deployment service principals | The identities the pipelines use, per platform environment | Platform team |
| Service connections or federated credentials | Let Azure DevOps or GitHub sign in as those service principals | Platform team |
Example names
The names below follow the convention of one implementation (prefix ASG_ for Azure security groups, an
administrative unit named after the platform). They are examples. Use the naming standard of the customer.
1. Groups¶
Create two security groups in Microsoft Entra ID (Groups, New group):
| Group | Example name | Membership type | Microsoft Entra roles can be assigned to the group | Members |
|---|---|---|---|---|
| Platform engineers | ASG_Platform_Engineers |
Assigned | No | The people of the platform team |
| Platform maintainers | ASG_CloudPlatform_Maintainers |
Assigned | Yes (confirm the pop-up) | None. Membership comes from PIM. |
The setting Microsoft Entra roles can be assigned to the group can only be chosen when the group is created.
2. Management group¶
If the customer has not created it, create the platform management group (Management groups, Create):
| Field | Value |
|---|---|
| Management group ID | A short ID without spaces, for example <customer>-platform. Cannot be changed later. |
| Display name | A readable name |
This ID becomes management_group_organization_id (mapping). Place the platform
subscriptions under it (Prerequisites).
3. Administrative unit¶
Create an administrative unit (Microsoft Entra ID, Administrative units, Add):
| Field | Value |
|---|---|
| Name | For example AU_CloudPlatform |
| Description | What it is used for |
| Restricted management administrative unit | No |
Copy its object ID. It becomes SpokeCommon.tenantinfo.AdministrativeUnitId in mcp.json. The spoke pipeline creates
the spoke groups in this unit (New spoke).
4. RBAC and directory roles for the maintainers group¶
Assign these to the maintainers group, so nobody holds them permanently.
On the platform management group¶
- Open Management groups, the platform management group, Access control (IAM).
- Add, Add role assignment. Choose the role Owner (under Privileged administrator roles).
- As member, choose the maintainers group.
- On the Conditions tab, choose Allow user to assign all roles (highly privileged). The deployment creates role assignments, so Owner without this condition is not enough.
- Review + assign.
On the administrative unit¶
Open the administrative unit, Roles and administrators. Assign each of these roles to the maintainers group:
- Groups Administrator
- User Administrator
For each: assignment type Active, permanent, and a justification that says the group has no active members and that membership is given through PIM flows for just-in-time and just-enough access.
In the directory¶
Open Microsoft Entra ID, Roles and administrators, Application Developer, and assign it to the maintainers group in the same way (active, permanent, same justification). It allows the team to create the deployment service principals.
5. PIM flow¶
The engineers group becomes an eligible member of the maintainers group. Engineers activate the membership when they need to work.
- Open Microsoft Entra Privileged Identity Management, Groups, Discover groups.
- Search for the maintainers group, select it, and choose Manage groups. Confirm the pop-up and wait for it to finish.
- Open the maintainers group, Assignments, Add assignments. Role: Member. Member: the engineers group. Keep the default settings, which make the assignment eligible for a year. Renew it before it expires.
- Open Settings, the Member role, Edit. Select Require approval to activate and choose the approvers.
Choose approvers that fit the operating model:
- In the managed model, the approvers are usually members of the platform team itself (a second engineer approves) or a customer group, as agreed in the contract.
- In the self-managed model, use a group of the customer's security or cloud platform owners, or a second engineer of the team.
Engineers then activate the group assignment in PIM (My roles, Groups, Activate) before they work. This is also the first check in the prerequisite checks.
6. Deployment service principals¶
Create one service principal per platform environment (canary and prod). The pipelines use it to sign in to Azure.
mcp.json refers to it as Azure.TerraformState.Hub.ServicePrincipalId (and .Spoke. for spokes). You may use one
service principal for hub and spokes or separate ones. Separate ones let you give the spoke identity its directory
permissions without giving them to the hub identity.
Activate PIM first
Creating service principals and role assignments needs the rights from the maintainers group. Activate your PIM assignment before you start.
Sign in to the customer's tenant, then create the service principals and give them Owner on the platform management group:
az login --tenant <tenant-id>
$customerShortName = "<short-name>" # at most 6 characters
$managementGroupId = "<management-group-id>"
foreach ($env in "CANARY", "PROD") {
$name = "SPN_${customerShortName}_LZ_${env}"
$sp = az ad sp create-for-rbac --name $name | ConvertFrom-Json
az role assignment create --assignee $sp.appId --role "Owner" `
--scope "/providers/Microsoft.Management/managementGroups/$managementGroupId"
"$name client id: $($sp.appId) tenant: $($sp.tenant)"
# $sp.password holds the client secret. Store it in your vault now. It is shown only once.
}
The name pattern SPN_<short-name>_LZ_<ENV> is an example from earlier runbooks; use your own standard.
Store the secret safely
az ad sp create-for-rbac creates a client secret and prints it once. Put it in the secret store that your team uses
(as a secret value, never in plain text, chat or the repository). Better: use federated credentials and skip the
secret (GitHub variant, and workload identity federation for Azure DevOps
service connections). The update-spn pipeline in the code repository stores and rotates a deployment secret in the
hub Key Vault (Responsibilities).
Permissions of the spoke identity¶
The identity that deploys spokes needs more than Azure RBAC, because the spoke canvas creates Entra ID groups, service principals and PIM settings. In the runbooks for the GitHub variant these were:
| Where | Permission |
|---|---|
| Microsoft Graph, application permissions | AdministrativeUnit.ReadWrite.All, Application.ReadWrite.All, DelegatedPermissionGrant.ReadWrite.All, Group.Read.All, GroupMember.Read.All, PrivilegedAccess.ReadWrite.AzureADGroup, PrivilegedEligibilitySchedule.ReadWrite.AzureADGroup, RoleManagement.ReadWrite.Directory, RoleManagementPolicy.ReadWrite.AzureADGroup, RoleManagementPolicy.ReadWrite.Directory, User.Read.All |
| Administrative unit | Groups Administrator |
| State storage account | Storage Blob Data Contributor |
| Platform management group | Enough to move subscriptions and create role assignments. The deployment identity's Owner assignment covers this. |
If you deploy spokes with two spoke identities (canary and production), give each the Owner role on the landing zone management group of its own environment, and the Groups Administrator role on the administrative unit. More in Prepare the spoke pipeline.
Granting the Graph permissions needs admin consent from someone with the right directory role. Ask the customer's administrator, or use your PIM-activated role if you hold it. The authoritative list for your version is in the documentation of the spoke canvas in the code repository you pin (How to use spoke deployment, section Prerequisites, Pipeline, Service principal). Check the list against it before you request consent.
7. Service connections (Azure DevOps)¶
For each deployment service principal create an Azure Resource Manager service connection in the Azure DevOps project (Project settings, Service connections, New service connection):
| Field | Value |
|---|---|
| Identity type | App registration or managed identity (manual) |
| Credential | Secret, or workload identity federation if you set up federated credentials |
| Scope level | Subscription: the management subscription of that platform environment |
| Subscription ID and name | The management subscription of canary, or of prod |
| Application (client) ID | The client ID of the service principal |
| Directory (tenant) ID | The customer's tenant ID |
| Client secret | The secret, when you use one |
| Service connection name | The name that pipelines/variables.yaml expects, for example <env>.serviceConnectionNameHub (Pipelines) |
Choose Verify, then Save. Use separate service connections for canary and prod. This is part of the security baseline.
Service connections at management group scope, as used by the separate spoke canvas pipeline, are described in Prepare the spoke pipeline.
If the code repository lives on a different host than the customer's Azure DevOps (for example in the managed model,
where it is synced from a GitHub Enterprise instance), you also need a service connection of that host for the
mcp-code repository resource. See Repositories.
For the agent pool, the service connection of the infrastructure pipeline needs Contributor or Owner on the
subscription that holds the job runners, and the pool service needs rights in Azure DevOps. See
Pipelines and agents.
Checklist¶
- [ ] Two groups exist; the maintainers group is role-assignable and has no members
- [ ] Platform management group exists; subscriptions are placed under it
- [ ] Administrative unit exists; its object ID is noted
- [ ] Maintainers group: Owner (with all-roles condition) on the management group; Groups Administrator and User Administrator on the administrative unit; Application Developer in the directory
- [ ] PIM: engineers group is eligible for the maintainers group, with approval
- [ ] Deployment service principals exist per platform environment, with secrets stored or federated credentials set
- [ ] Spoke identity: Graph permissions with admin consent, administrative unit role, state storage role
- [ ] Service connections exist, verified, separate for canary and prod
- [ ] If spokes create Azure DevOps or GitHub resources: Prepare spoke integrations is done