Appearance
Quarterly Service Principal Permission Review
Status: Runbook Owner: Infrastructure (Kobe executes, Rory approves all scope changes) Schedule: First business day of January, April, July, October (aligned with SP cleanup) Related: quarterly-sp-cleanup.md, lpriv-baseline.md
Purpose
Verify every service principal holds only the minimum permissions needed for its documented purpose. Over-privileged SPs are a HIPAA least-privilege finding and an elevated compromise risk.
Review Criteria
For each SP with Owner, Contributor, or any other broadly-scoped role:
- Does it have documented automation duties?
- Do those duties require the assigned role, or would a scoped role suffice?
- Is there a custom role in
iam.tfthat would be a better fit? - Is the assignment's scope correct (subscription-wide vs RG-scoped vs resource-scoped)?
Any SP holding a broader role than required = reduction candidate. Scope reductions require Rory's explicit approval.
Procedure
1. Enumerate role assignments
az login --tenant <tenant>
az role assignment list --all --query "[?principalType=='ServicePrincipal'].{sp:principalName, role:roleDefinitionName, scope:scope}" -o json > /tmp/sp-roles.jsonPer subscription if the global query is too large:
for sub in $(az account list --query "[].id" -o tsv); do
az role assignment list --subscription $sub --all --query "[?principalType=='ServicePrincipal']" -o json > /tmp/sp-roles-$sub.json
done2. Classify role breadth
Flag assignments with:
Ownerrole (full control including RBAC)Contributorrole (full control excluding RBAC)User Access Administratorrole- Subscription-level scope on any role
- Management-group-level scope on any role
3. OIDC deploy SPs
OIDC SPs used by GitHub Actions CI/CD should hold only the custom github-deploy-main role (defined in azure-infra/main/iam.tf and equivalent per stack). Any broader role = reduction target.
| SP | Intended Role | Expected Scope |
|---|---|---|
| github-deploy-app | github-deploy-main | Per-subscription |
| github-deploy-dde | github-deploy-main | DDE main + billings |
| github-deploy-aws | AWS role github-deploy-main | Per-account |
4. Arctic Wolf SP
Arctic Wolf has its own custom roles in iam_arctic_wolf.tf and iam_arctic_wolf_roles.tf. Verify it is not also holding Contributor or Reader at subscription scope.
5. Kobe SPs
| SP | Expected Role |
|---|---|
| kobe-cloud-pc | Custom scoped role (CloudPCRole) |
| kobe-security-audit | Reader (subscription-scoped, read-only) |
6. Permissions diff report
For each candidate capture:
- Current role + scope
- Proposed role + scope
- Justification (what duties require this level of access)
- Risk of reducing (what would break)
Write report to /tmp/sp-permission-review-<YYYYQN>.md.
7. Approval
Post to SecOps:
POST /api/changesBody: proposed scope changes. Tag Rory. Wait for explicit approval.
8. Apply reductions (only after approval)
Scope reductions happen in Terraform (preferred):
az role assignment delete --assignee <appId> --role "Contributor" --scope "/subscriptions/<sub>"
az role assignment create --assignee <appId> --role "github-deploy-main" --scope "/subscriptions/<sub>/resourceGroups/<rg>"For Terraform-managed assignments: open a PR updating iam.tf.
9. Evidence
aws s3 cp /tmp/sp-permission-review-<YYYYQN>.md s3://cirius-hipaa-evidence/sp-permission-review/<YYYYQN>/
curl -s -X POST -H "X-API-Key: $SECOPS_API_KEY" -H "Content-Type: application/json" \
-d '{"evidence_type":"sp-permission-review","period_start":"<ISO>","period_end":"<ISO>","s3_key":"sp-permission-review/<YYYYQN>/sp-permission-review-<YYYYQN>.md","source_system":"PROD"}' \
https://soc.bedrockcybersecurity.org/api/evidenceSuccess Criteria
- [ ] All SP role assignments enumerated across both tenants
- [ ] Broad-scope assignments classified and justification requested from owner
- [ ] OIDC SPs confirmed holding only
github-deploy-main - [ ] Reduction candidates compiled and sent to Rory
- [ ] Approved reductions applied via Terraform PR
- [ ] Evidence uploaded and registered
Schedule
Aligned with SP cleanup: Q1 January, Q2 April, Q3 July, Q4 October.
Change Log
| Date | Change | Author |
|---|---|---|
| 2026-04-16 | Initial runbook | Kobe |