Manage Management Groups¶
The engineer's guide to the management group hierarchy. Use this runbook to:
- Add a management group.
- Move or rename one.
- Get a change applied (any engineer can write it; a senior lets it go live).
For what each group is for, see Management Group Hierarchy. For why it's applied this way, see Tier 0 Just-in-Time CI Apply.
This is Tier 0
Moving a subscription or a group changes which policies and roles it
inherits from mg-intermediate-root. Read the plan for every destroy
and every parent change before you merge.
Where it lives¶
Project: t0-azure-management-groups
One file per management group, mg-<name>.tf, each calling
solution-manage-management-groups:
module "mg_online" {
source = "git::https://gitlab.com/grinntec-cloud/terraform-modules/terraform-solutions/solution-manage-management-groups.git?ref=v1.0.0"
name = "mg-online"
display_name = "Online"
parent_management_group_id = module.mg_landingzones.id
}
Platform subscriptions are placed in mg-platform.tf. Workload
subscriptions are placed by subscription vending, not here.
Who does what¶
| Step | Who | Needs |
|---|---|---|
| Write the change and open the MR | Any engineer | Developer on the project |
| Review and merge | A senior engineer | Maintainer |
| Check the saved plan, grant CI access | A senior engineer | (tier 0) Management Groups (pag-t0-management-groups), PIM-activated |
Click apply |
Anyone who can run main pipelines |
Allowed to merge to main (protected-branch jobs) |
Make a change¶
Add a management group¶
- Copy an existing
mg-*.tffile tomg-<name>.tf. - Set
name(mg-<name>, lowercase),display_nameandparent_management_group_id. - Rename the module and the output to match.
- Keep
role_assignmentsempty. Nothing in this project can grant roles at these groups, and that's on purpose.
Rename or move one¶
display_name: safe, changes in place.- Parent: change
parent_management_group_id. Moves in place, with its subscriptions and children. name: can't be changed. Azure destroys the group and its role assignments, and moves its children to the tenant root. Create a new group, move things across, then delete the old one in a later MR.
Open the MR¶
Push a branch and open an MR. CI runs secret scan, fmt, tflint, validate,
checkov and plan, and posts the plan as a comment. Get it reviewed and
merged.
Apply it¶
After the merge, the main pipeline plans again, saves the plan, and stops
at a manual apply job.
Senior:
- Open the
mainpipeline and read theplanjob's output. It's what will be applied. - In PIM → My roles → Groups, activate (tier 0) Management Groups with a justification.
-
From your checkout of the project:
It checks your group is active, then gives CI's write identity
Management Group Contributorat the tenant root for 30 minutes. You should see "Gave … for 30 minutes". -
Tell the engineer to click apply. You're done: you don't revoke anything.
Engineer:
- On the same
mainpipeline, click the apply job's play button. It waits for the access (up to 5 minutes), applies, and removes anyOwnerAzure gave it. Look for "Apply complete!".
The access ends 30 minutes after step 3, by itself.
Check it worked¶
- The
applyjob ends with "Apply complete!" and "No creator-Owner to remove" (or "Removed Owner …" if it created a group). - The portal shows the hierarchy you expect (Management groups).
-
After the 30 minutes, the write identity holds nothing:
It ends with "… holds no Azure roles".
When it fails¶
| You see | Meaning | Do this |
|---|---|---|
apply: "Not authorised yet (try N of 5)" |
The grant isn't there yet, or the 30 minutes ran out | Senior runs ./authorize-apply.ps1 again. The job picks it up on its next try, or retry the job |
apply: "No access after 5 tries. Nothing was applied." |
No grant within 5 minutes | Grant, then Retry the job |
authorize-apply.ps1: "… isn't active for you" |
PIM group not active, or you signed in before activating | Activate, then az account clear; az login |
authorize-apply.ps1: "already has … at the tenant root" |
An earlier grant is still running | Nothing to do; it's usable until it ends |
| "Saved plan is stale" | State changed after CI planned. Nothing was applied | Re-run the main pipeline, then grant and apply again |
| A 403 during the apply | The change needs more than Management Group Contributor (for example a role assignment) |
That change doesn't belong in this project. Don't widen the grant |
-Revoke: "still holds the roles above" |
Someone gave the write identity a role by another route | Treat it as a finding: find out who, then remove it |
Fallback: human apply¶
If CI can't run, a senior can still apply main's saved plan locally with
./apply.ps1 and the same PIM group. See
Lane A Apply. If that apply creates a management group,
you become its Owner. Remove that afterwards (see the project README).