4.8 KiB
When the user says "365 remediation tool" or "remediation tool", they mean ACG's direct Graph/Exchange tooling against customer tenants via the /remediation-tool skill (.claude/skills/remediation-tool/). This is NOT CIPP.
App suite (current — tiered): Security Investigator bfbc12a4 (Graph read + EXO read), Exchange Operator b43e7342 (EXO write), User Manager 64fac46b (user/license/MFA/pw write), Tenant Admin 709e6eed (high-priv directory), Defender Add-on dbf8ad1a (MDE-licensed tenants ONLY). Secrets in msp-tools/computerguru-*.sops.yaml. Client-credentials auth; tenant ID via OpenID discovery (or the *.onmicrosoft.com domain when the primary domain isn't verified). Use the lowest tier needed. Each app is consented per-tenant (URLs in references/gotchas.md); privileged ops also need directory roles assigned to the SP in that tenant (onboard-tenant.sh).
DEPRECATED — do NOT consent to customer tenants: fabb3421 ("AI Remediation" / "Claude-MSP-Access", secret msp-tools/claude-msp-access-graph-api.sops.yaml). ~159 perms incl. Defender ATP, so admin consent breaks with AADSTS650052 on any tenant lacking an MDE license. It still works where already consented (e.g. ACG's own tenant — the /mailbox skill reads our own mailboxes with it), but new onboarding MUST use the tiered suite. (Corrected 2026-05-27 during Quantum onboarding — nearly consented the deprecated app to a no-MDE tenant.)
Why (original): user clarified "remediation tool" != CIPP after a wrong CIPP navigation. How to apply: prefer the /remediation-tool skill — it wraps tenant resolution, token caching, breach check, sweep, gated remediation, and consent/onboarding URLs (references/gotchas.md, graph-endpoints.md, checklist.md).
Directory Role Requirements (discovered 2026-04-01)
Graph API permissions alone are NOT sufficient for privileged operations. The service principal also needs Entra directory roles assigned per-tenant:
| Operation | Required Directory Role |
|---|---|
| Password reset | User Administrator |
| Exchange transport rules, mailbox permissions | Exchange Administrator |
Roles assigned so far:
- Valleywide Plastering (5c53ae9f...): User Administrator
- Dataforth (7dfa3ce8...): User Administrator, Exchange Administrator
- azcomputerguru.com (ce61461e...): full set assigned 2026-06-05 — Sec-Inv + Exch-Op = Exchange Administrator; Tenant Admin = Conditional Access Administrator; User Manager = User Administrator + Authentication Administrator.
For new tenants: onboard-tenant.sh <domain> assigns the directory roles programmatically (Tenant Admin tier) — no manual portal step needed. The app cannot self-assign; the Tenant Admin SP does it.
GOTCHA — pre-2026-04-20 tenants have NO directory roles. The directory-role assignment block was added to onboard-tenant.sh in commit cd50117a on 2026-04-20. Before that, "onboarding" only did app consent + Graph/EXO API permissions. So any tenant onboarded before that date has full app permissions but zero directory role assignments — Graph reads work, but Exchange REST (quarantine, Get-Mailbox, message trace) and other privileged ops 401 until you re-run onboard-tenant.sh. This is NOT a removal/breach — the roles were simply never assigned, and with no Entra ID P2 there's no PIM to auto-expire anything. ACG's own tenant hit exactly this on 2026-06-05 (EOP quarantine check 401'd). Re-run onboard-tenant.sh on any tenant onboarded before 2026-04-20 — Valleywide, Dataforth, Cascades are prime candidates to verify proactively. Confirm actual state with roleManagement/directory/roleAssignments?$filter=principalId%20eq%20'<sp-oid>'&$expand=roleDefinition (tenant-admin token; classic endpoint, no P2 needed — the PIM roleAssignmentSchedules endpoints return AadPremiumLicenseRequired without P2).
BUG (fixed 2026-06-05): onboard-tenant.sh role_assigned() had an unencoded space in its $filter (principalId eq '...'), so the query always failed → function always returned false → script always printed "MISSING -> ASSIGNING" and leaned on the conflict-tolerant POST for idempotency (assignment still worked, but PRESENT/MISSING reporting was meaningless). Fixed to %20. The old TODO blaming PIM was a misdiagnosis.
Exchange Online REST API
For Exchange cmdlets (Get-TransportRule, Add-MailboxPermission, etc.), use scope https://outlook.office365.com/.default and POST to https://outlook.office365.com/adminapi/beta/$TENANT_ID/InvokeCommand with {"CmdletInput":{"CmdletName":"...", "Parameters":{...}}}.