- Fixed MSI build on Pluto (missing WixToolset.Util.wixext in install.rs) - Created docs/DESIGN.md in gururmm repo (per-component design guide) - Saved BirthBiologic GuruRMM site credentials to vault - Added birth-biologic and mvan-inc client session logs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8.1 KiB
Gotchas — Permissions, Roles, Consent
Onboarding a new tenant
Run onboard-tenant.sh after admin consents each app. This assigns required directory roles automatically.
Quick steps:
- Send consent URLs (Tenant Admin FIRST, then others)
- After admin accepts:
bash scripts/onboard-tenant.sh <domain> - Verify output shows all roles [OK]
- Update tenant table below
If Tenant Admin is not yet consented, onboard-tenant.sh will output all needed consent URLs.
App Suite (tiered architecture)
Five multi-tenant apps replace the old single over-permissioned app. Use minimum necessary tier.
| Tier | Display name in customer tenant | App ID | Vault file |
|---|---|---|---|
investigator / investigator-exo |
ComputerGuru Security Investigator | bfbc12a4-f0dd-4e12-b06d-997e7271e10c |
computerguru-security-investigator.sops.yaml |
exchange-op |
ComputerGuru Exchange Operator | b43e7342-5b4b-492f-890f-bb5a4f7f40e9 |
computerguru-exchange-operator.sops.yaml |
user-manager |
ComputerGuru User Manager | 64fac46b-8b44-41ad-93ee-7da03927576c |
computerguru-user-manager.sops.yaml |
tenant-admin |
ComputerGuru Tenant Admin | 709e6eed-0711-4875-9c44-2d3518c47063 |
computerguru-tenant-admin.sops.yaml |
defender |
ComputerGuru Defender Add-on | dbf8ad1a-54f4-4bb8-8a9e-ea5b9634635b |
computerguru-defender-addon.sops.yaml |
Deprecated (do not use): ComputerGuru - AI Remediation (fabb3421) — old single-app with 159 permissions including Defender ATP. Broke consent on tenants without MDE license. Retire/delete from portal when confirmed no active tenants depend on it.
When searching customer admin portals for a service principal (role assignments, app role assignments, CA exclusions), search by the display name for that tier (e.g., "ComputerGuru Security Investigator").
Per-tenant prerequisites
Graph API permissions alone are not enough. Most privileged operations require directory roles on the specific service principal in that tenant:
| Operation | App tier | Required directory role on that SP |
|---|---|---|
| Exchange REST read (Get-InboxRule, Get-Mailbox) | investigator-exo |
Exchange Administrator |
| Exchange REST write (Set-Mailbox, Remove-InboxRule) | exchange-op |
Exchange Administrator |
| Password reset, user property updates | user-manager |
User Administrator |
| MFA method reset | user-manager |
Authentication Administrator |
| Conditional Access reads/writes | tenant-admin |
Conditional Access Administrator OR Security Administrator |
| Teams policies | tenant-admin |
Teams Administrator |
How to assign a role to an SP in a customer tenant
- Sign into the customer's Entra admin center as Global Admin:
https://entra.microsoft.com/#@{customer-domain} - Identity -> Roles & admins -> All roles -> select the role (e.g., Exchange Administrator)
- Add assignments -> search by the app display name (e.g., "ComputerGuru Security Investigator") -> Assign (Active, permanent — service principals cannot activate eligible assignments)
Admin consent URLs
Each app must be individually consented in each customer tenant. Format:
https://login.microsoftonline.com/{tenant-id}/adminconsent?client_id={app-id}&redirect_uri=https://azcomputerguru.com&prompt=consent
Security Investigator (consent this first — needed for all breach checks):
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=bfbc12a4-f0dd-4e12-b06d-997e7271e10c&redirect_uri=https://azcomputerguru.com&prompt=consent
Exchange Operator (consent when remediation scope is needed):
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=b43e7342-5b4b-492f-890f-bb5a4f7f40e9&redirect_uri=https://azcomputerguru.com&prompt=consent
User Manager:
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=64fac46b-8b44-41ad-93ee-7da03927576c&redirect_uri=https://azcomputerguru.com&prompt=consent
Tenant Admin:
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=709e6eed-0711-4875-9c44-2d3518c47063&redirect_uri=https://azcomputerguru.com&prompt=consent
Defender Add-on (MDE-licensed tenants only — AADSTS650052 if no MDE license):
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=dbf8ad1a-54f4-4bb8-8a9e-ea5b9634635b&redirect_uri=https://azcomputerguru.com&prompt=consent
The customer admin signs in as Global Admin, clicks Accept. Redirect lands on azcomputerguru.com — expected. Verify via /servicePrincipals/{sp-id}/appRoleAssignments (grants timestamped today confirm success).
Diagnosing "required scopes are missing"
Token returned 403 with "required scopes are missing in the token":
- Decode the JWT payload (2nd segment, base64url) and check the
rolesclaim. - If the expected scope is missing from
roles:- Confirm the scope is in the app manifest in the home tenant (saved, not just selected).
- Grant admin consent in the home tenant.
- Re-run the customer admin consent URL above for that specific app.
- If the scope IS in
rolesbut you still get 403: check for a missing directory role (see table above).
Diagnosing Exchange REST 403
- Wrong token scope: must request
https://outlook.office365.com/.default(useinvestigator-exoorexchange-optier, NOTinvestigator). - Missing Exchange Administrator role on the specific SP in that tenant.
- Propagation delay: newly assigned role can take up to 15 minutes to reach Exchange Online. If just assigned, wait and retry.
AADSTS650052 — service not licensed
If token request or API call returns AADSTS650052 referencing WindowsDefenderATP (fc780465): the tenant does not have an MDE license. Do not use the defender tier for this tenant. Security investigation proceeds with investigator + investigator-exo only.
Common, benign "failures" in sign-in logs
error 50140"Keep me signed in interrupt" — KMSI prompt, not a real failure.error 65001"has not consented to use the application" — fires during onboarding and before consent granted. IfappDisplayNamematches any ComputerGuru app, those are our own consent attempts, not attacker activity.error 50126from the sysadmin account during onboarding is typo/retry noise — checkipAddressagainst Mike's known IPs before flagging.
Tenants where apps are consented (as of 2026-04-20)
| Tenant | Tenant ID | Sec Inv | Exch Op | User Mgr | Tenant Admin | Defender | Exch Admin (Sec Inv) | User Admin (User Mgr) | Auth Admin (User Mgr) | Notes |
|---|---|---|---|---|---|---|---|---|---|---|
| Valleywide Plastering | 5c53ae9f... | old app only | — | — | — | — | — | old app only | — | Needs migration to new app suite |
| Dataforth | 7dfa3ce8... | old app only | — | — | — | — | old app only | old app only | — | Needs migration |
| Cascades Tucson | 207fa277-e9d8-4eb7-ada1-1064d2221498 | old app only | — | — | — | — | old app only | old app only | — | IdentityRiskyUser scope still not consented as of 2026-04-16 |
| Grabblaw | 032b383e-96e4-491b-880d-3fd3295672c3 | YES (2026-04-20) | — | YES (2026-04-20) | YES (2026-04-20) | — | ASSIGNED (2026-04-20) | ASSIGNED (2026-04-20) | ASSIGNED (2026-04-20) | Fully onboarded |
| martylryan.com | (resolve via script) | YES (2026-04-20) | — | YES (old app) | YES (2026-04-20) | — | ASSIGNED (2026-04-20) | ASSIGNED (2026-04-20) | ASSIGNED (2026-04-20) | Fully onboarded |
| mvaninc.com | 5affaf1e-de89-416b-a655-1b2cf615d5b1 | YES (2026-04-21) | — | YES (2026-04-21) | YES (2026-04-21) | — | — | — | — | Fully onboarded. Incident 2026-04-21: sysadmin GA account unauthorized sign-in from OKC via device PRT (MITCH-LAPTOP/JUNE). Remediated: pw reset, sessions revoked. CA policy (MFA all users) still pending — Mike to create. |
Migration note: Valleywide, Dataforth, and Cascades still use the old deprecated app. Next visit: consent Security Investigator + assign Exchange Administrator role to new SP, then retire old app consent.
Keep this table updated when rolling out to new tenants or migrating existing ones. Run onboard-tenant.sh after each consent and update the role columns from the script's final status output.