Skip to content

Manage Subscription Access

The engineer's guide to who can do what in a vended subscription. Use this runbook to:

  • Give a team Contributor, RBAC Administrator or Reader on a subscription.
  • Take that access away.
  • Activate the access when you need it.
  • Renew eligibility that has expired.

This covers access inside one subscription. Platform-wide admin roles (Owner at a management group, Entra directory roles) are personas: see Manage Access Packages.

Groups, never people

Vending never adds a person to a subscription. You nominate a team's own Entra group, and vending makes it a member of the subscription's access group. Who is in the team is managed on the team's group, in one place, not in every subscription the team uses.

How access is built

Every vended subscription gets three Entra groups, and each holds one role on the subscription:

Group Role on the subscription Assignment
grp-<name>-contributor Contributor PIM-eligible: members activate it when they need it
grp-<name>-role-based-access-administrator Role Based Access Control Administrator PIM-eligible
grp-<name>-reader Reader Standing: always on
grp-payments-devs  ──member of──▶  grp-payments-prod-westeu-00-contributor
   (team's group)                         │ eligible
                                          ▼
                                  Contributor on payments-prod-westeu-00

Nobody holds Owner on a vended subscription. The subscription's own pipeline identity, sp-sub-tf-<name>-rw, holds Contributor and a locks-only custom role, so the team's normal changes go through their GitLab pipeline, not through activated access.

The projects

Project Lane Holds
subscription-vending-workload B The rbac block in each workload subscription's <name>.tf. CI applies on merge.
subscription-vending-platform A The rbac block in each platform subscription's <name>.tf. You apply with ./apply.ps1 under pag-t0-platform-subscriptions.

Grant a team access

📁 subscription-vending-*: 📃 <name>.tf

Add the team's group display name to the tier it needs:

  rbac = {
    contributor                     = { group_names = ["grp-payments-devs"] }
    role-based-access-administrator = { group_names = ["grp-payments-leads"] }
    reader                          = { group_names = ["grp-payments-devs", "grp-finops-readers"] }
  }

Pick the smallest tier that does the job:

  • Reader to look around, read logs and check costs. Always on.
  • Contributor to fix something by hand that the pipeline can't, e.g. during an incident. Needs activating.
  • RBAC Administrator only for whoever has to grant access inside the subscription, e.g. a managed identity a role on a Key Vault. Needs activating.

The same group can be in more than one tier. A Contributor team usually also wants Reader, so it can see the subscription without activating.

Open an MR. The plan should show only azuread_group_member adds, one per group per tier. Merge (and for a platform subscription, run ./apply.ps1).

The nominated group must already exist

Vending looks each group up by display name. If it can't find it, the plan fails with a data.azuread_group.members error. Create the team's group first. Display names must be unique in the tenant, or the lookup is ambiguous.


Remove access

Remove the group name from the tier's list. The plan should show only azuread_group_member destroys. Merge and apply.

Access ends as soon as the membership is gone. An activation already in progress lasts until it expires (up to its maximum duration).

To remove one person, take them out of the team's own group. Nothing changes in vending.


Use the access

Contributor and RBAC Administrator are eligible, not active. Before you use them:

  1. Go to Entra ID → Privileged Identity Management → My roles → Azure resources.
  2. Find the role on the subscription and select Activate.
  3. Give a justification and a duration. MFA is required.
  4. Sign in again so the new token carries the role:

    az account clear
    az login
    az account set --subscription <name>
    

Deactivate it when you're done rather than waiting for it to expire.


Grant one principal eligibility directly

Sometimes a principal needs a role that isn't one of the three tiers, or needs to be eligible without joining a team group (for example a break-glass group as Owner). Use pim_eligible_role_assignments:

  pim_eligible_role_assignments = {
    break-glass-owner = {
      principal_id         = "00000000-0000-0000-0000-000000000000" # object ID, not display name
      role_definition_name = "Owner"
    }
  }

Keep this rare and comment every entry with why. Never make assignments by hand in the portal: they're invisible to code review and show up as drift in the AzGovViz reports.


Renew expired eligibility

Every eligible assignment vending creates expires after 180 days. The tenant's PIM policy doesn't allow permanent eligibility. The next apply after it lapses creates it again, but nothing renews it in between.

If a subscription's file hasn't been applied for 180 days, its groups' members find nothing to activate in PIM. To renew:

  • Workload: re-run the latest main pipeline of subscription-vending-workload.
  • Platform: re-run the main pipeline, then ./apply.ps1.

The plan shows the expired azurerm_pim_eligible_role_assignment resources being created again. Nothing else should change.


Check it worked

# Who is in the access group
az ad group member list --group grp-payments-prod-westeu-00-contributor \
  --query "[].displayName" -o tsv

# Eligible assignments on the subscription (needs Reader)
az rest --method get \
  --url "https://management.azure.com/subscriptions/<sub-id>/providers/Microsoft.Authorization/roleEligibilityScheduleInstances?api-version=2020-10-01&\$filter=atScope()" \
  --query "value[].{principal:properties.expandedProperties.principal.displayName, role:properties.expandedProperties.roleDefinition.displayName, ends:properties.endDateTime}" -o table

When it fails

Symptom Cause Fix
Plan fails on data.azuread_group.members["<group>"] The group doesn't exist, or its name is misspelled, or two groups share the name Create the group, fix the spelling, or rename the duplicate.
A member can't see the role in PIM Eligibility expired after 180 days, or the member was added to the team group minutes ago Renew it. Group membership can take a few minutes to show in PIM.
RoleAssignmentRequestPolicyValidationFailed: ExpirationRule The tenant's maximum eligible duration for the role is now shorter than 180 days Lower pim_eligible_duration_days in the bootstrap module to match the PIM role settings, release, and bump the solution ref.
Activated Contributor but az still returns 403 The CLI token was issued before activation az account clear and az login again.
Workload pipeline: Insufficient privileges adding a group member The vending pipeline can only change groups it owns. The grp-<name>-* group was created by someone else, or its owner was changed. Make sp-pla-tf-subscription-vending-rw an owner of the group again (needs Groups Administrator).