# 2026-04-29 — Cascades CA unblock + Phase B Intune buildout + bypass pilot prep

## User
- **User:** Howard Enos (howard)
- **Machine:** HOWARD-HOME
- **Role:** tech
- **Session span:** 2026-04-28 evening into 2026-04-29 early morning (continuous, ~7 hours)

## Resume point (READ THIS FIRST when picking back up)

We are on the **Cascades caregiver shared-phone bypass pilot**, Path B (cloud-only test user). Phase B Intune is fully built. Cascades named location has both WANs trusted.

> **UPDATE 2026-04-29 (after Howard btw — supersedes the original CA design below):**
>
> Rollout is **phased per-group, NOT tenant-wide**. The original §5 / item-5 design (delete legacy all-users-MFA, create 4 tenant-wide policies) would have blocked any office user signing in off-site who wasn't in `SG-External-Signin-Allowed`. Corrected design:
> - **PATCH** existing `Require multifactor authentication for all users` → add `SG-Caregivers-Pilot` to `excludeGroups` (legacy policy stays in place; office staff posture unchanged).
> - **CREATE** `CSC - Block caregivers off Cascades network` — includeGroups: pilot; location not Cascades → **Block**.
> - **CREATE** `CSC - Block caregivers on non-compliant device` — includeGroups: pilot; `device.isCompliant -eq False` → **Block**.
> - **CREATE** `CSC - Caregiver sign-in frequency 8h` — session control on pilot group.
> - Both `admin@` and `sysadmin@` go in `excludeUsers` on all three new policies.
> - Use **Block** directly (not "Require MFA") on non-compliant/off-network for caregivers — they have no MFA device, block is the cleaner UX.
> - **Do not delete the legacy all-users-MFA policy until every population is covered by a phased policy.**
> - Memory: `.claude/memory/project_cascades_ca_phased_rollout.md` (treat any "let's push tenant-wide" suggestion as a regression of this decision).
>
> **Break-glass posture (Option 1):** No dedicated `breakglass@` for now. `admin@` and `sysadmin@` both excluded from all 8 existing CA policies + all 3 new ones. Both stay cloud-only Global Admins. FIDO2 enrollment deferred. A real break-glass account can be added later. Memory: `.claude/memory/project_cascades_admin_accounts.md`.
>
> **Step A executed 2026-04-29:** admin@ added to `excludeUsers` on all 8 existing CA policies (matches sysadmin@'s posture). See "Step A — admin@ exclusion backfill" section below.

**Where we paused:** awaiting Howard's next decision after Phase B is fully populated and one phone successfully completes a real user sign-in flow to flip compliant. Outlook has been added in the portal — pending sync, then assignment + MHS update.

### What's still to do, in order (revised 2026-04-29)

1. **Outlook** — already added in portal by Howard. Once it shows up via Graph beta, assign to `Cascades - Shared Phones` and PATCH `kioskModeApps` to add Outlook alongside ALIS + Teams.
2. Howard adds LinkRx + Helpany web apps in Intune portal when Cascades sends URLs.
3. **Pilot user + cloud group (Path B — confirmed):**
   - Create cloud-only test user `pilot.test@cascadestucson.com` (Howard's `howard.enos` cloud account doesn't exist yet — Entra Connect is in staging).
   - Create cloud-only Entra group `SG-Caregivers-Pilot`.
   - License `pilot.test@` with Business Premium (one of 34 spare seats).
   - Add user to `SG-Caregivers-Pilot`.
   - **Cleanup commitment:** `pilot.test@` and `SG-Caregivers-Pilot` are removed at end of pilot. Memory: `.claude/memory/project_cascades_pilot_cleanup.md`.
4. **Break-glass:** deferred. `admin@` + `sysadmin@` exclusion (Step A) is the interim posture.
5. **New CA policies** — see UPDATE block above for the correct design. Stage in **Report-only** initially, assigned only to `SG-Caregivers-Pilot`, both admins excluded.
6. After 24-48h Report-only and pilot phone test sign-in, flip to On.
7. Phone enrollment dry-run with pilot user → expect no MFA on Cascades Wi-Fi + compliant device, expect block off-network.

### Decisions still pending

- Audit retention: deferred — Azure pay-as-you-go subscription still needs Howard or Mike billing call.
- Whether to backfill `onboard-tenant.sh` against other already-onboarded tenants for the new CA Admin + Policy.Read.All (script now handles this idempotently when re-run; just needs a re-run per tenant).
- FIDO2 enrollment timing for `admin@`, `sysadmin@`, and any future dedicated break-glass.

---

## Session Summary

Picked up from the 2026-04-28 morning save where the Tenant Admin SP had no directory role in Cascades and every `/identity/conditionalAccess/*` call returned 403. Howard granted the Conditional Access Administrator role via PIM (Active assignment, permanent, Path B from yesterday's options). After that landed, CA endpoints **still** returned 403 with the same scope-missing error. Investigation showed Microsoft tightened `LIST /identity/conditionalAccess/namedLocations` to require `Policy.Read.All` as the application permission — `Policy.ReadWrite.ConditionalAccess` (which the SP carried) is no longer accepted for reads on this endpoint. Patched the Tenant Admin app manifest in ACG home to add `Policy.Read.All`, granted the appRoleAssignment in ACG home, Howard re-consented in Cascades. CA reads then worked.

Reading the CA state revealed the existing `Require multifactor authentication for all users` policy is in `enabled` state (not Report-only), which makes the original Track A "Gate A7 — flip from Report-only to On" obsolete. Howard re-stated the pilot goal in plain language: caregivers signing into shared phones on Cascades Wi-Fi with a compliant Intune-managed device should bypass MFA entirely; off-site they should be blocked (no personal device for MFA fallback exists). Eventually this rolls out to all users at Cascades. The existing `user-account-rollout-plan.md §5` design said "Block sign-in unless from Cascades + MFA" — meaning even on-site users get MFA prompted — which doesn't match the goal. Reshaped the CA design to three policies that together produce on-site-compliant = password only, anything else = MFA or block.

In parallel, discovered the `ComputerGuru - Intune Manager` app was still single-tenant, so it couldn't be consented in Cascades. PATCHed `signInAudience` to `AzureADMultipleOrgs` in ACG home, Howard re-consented in Cascades, then queried Intune state. **Phase B is far more built than the 4/20 session log indicated** — at some point between 4/20 and 4/21 someone (likely Howard) finished it. The compliance policy (`CSC - Android Compliance`, type `androidDeviceOwnerCompliancePolicy`), Wi-Fi config (`CSC - CSCNet Wi-Fi`), device restrictions (`CSC - Android Shared Phones Restrictions`), and both Shared Device Mode app config policies (Authenticator + Teams, both with `shared_device_mode_enabled=true`) all exist and are assigned to the `Cascades - Shared Phones` dynamic group. 7 of 8 apps are deployed and assigned (Microsoft Launcher is the only unassigned one).

PATCHed the Cascades named location to add `184.191.143.62/32` (primary WAN). Both WANs now `isTrusted=true`. PATCHed device restrictions to block camera, Bluetooth, and data roaming (per Howard's spec). Enabled Managed Home Screen multi-app kiosk mode with ALIS + Microsoft Teams as visible apps, 10-min idle auto-signout with 1-min warning, no MHS-level PIN (relies on the device PIN already required by compliance). Howard added Microsoft Outlook from Managed Play in the Intune portal. Walked through Wave 0 HIPAA pre-flight: HIPAA BAA is automatic via Microsoft Online Services Terms (no separate signature needed); SMB encryption on `\\CS-SERVER\homes` was False, Howard ran `Set-SmbShare -Name homes -EncryptData $true -Force` to flip it; Diagnostic Settings deferred (will set up Azure pay-as-you-go later for Log Analytics workspace). After the session, ran `/sync` which surfaced Mike's note from earlier in the day approving Path A for the CA fix — superseded by Path B, which Howard already executed. Patched `onboard-tenant.sh` to programmatically assign Conditional Access Administrator role to the Tenant Admin SP and backfill `Policy.Read.All` on existing tenants where the manifest update post-dates their consent.

## Key Decisions

- **Path B (manual portal PIM assignment) for the CA Admin role** instead of the Graph-API Path A Mike approved. Both achieve the same end state. Path B was faster on the day; Path A is now the backfilled default in `onboard-tenant.sh`.
- **Patch `Policy.Read.All` into Tenant Admin manifest**. Microsoft tightened `LIST /identity/conditionalAccess/*` endpoints to require `Policy.Read.All` as the application permission. `Policy.ReadWrite.ConditionalAccess` (legacy) is no longer accepted for reads. New tenants get this from the manifest at consent time; existing tenants get it programmatically via the patched onboard script.
- **Reshape the CA bypass design**. Replace the existing all-users-MFA policy with three policies that together produce: on-site + compliant = password only, off-site or non-compliant = MFA or block. The original Track A §5 design conflated "block off-site" with "require MFA on-site," which doesn't match the actual goal of bypassing MFA when network + device assurance are present.
- **Path B for the pilot** (cloud-only test user) instead of Path A (exit Entra Connect staging first). Faster path to a meaningful test; the production rollout will use the synced `SG-Caregivers` group once staging exits, but that's a separate operation gated on the AD prereq cleanup (Wave 0.5 G1 from `user-account-rollout-plan.md`).
- **Sign-in frequency: 8 hours** for caregivers (revised from initial "every hour" — caregivers re-auth at start of shift and work through without re-prompts; HIPAA-defensible as one strong factor among three).
- **Off-network behavior: block for caregivers, MFA for office allow-list**. Caregivers have no personal device for MFA, so off-network access is denied entirely. Office staff in `SG-External-Signin-Allowed` get MFA off-network without compliant-device requirement (Howard's call — simpler, less brittle).
- **Path X (Managed Home Screen multi-app kiosk)** instead of standard Android launcher. Provides keyboard lockdown, restricted app access, and HIPAA-defensible least-privilege UI for caregivers.
- **MHS auto-signout: 10 min idle, 1 min warning**. Standard healthcare convention for shared-device session lifetime, separate from the device's 1-min screen lock and the 8-hour CA sign-in frequency.
- **Microsoft Launcher: leave unassigned**. With MHS as the kiosk launcher, the Microsoft Launcher app is redundant.
- **Intune Manager app: convert to multi-tenant**. Single-tenant gave AADSTS700016 when consenting in Cascades. PATCH on `signInAudience` to `AzureADMultipleOrgs` was the cleaner fix vs. adding DeviceManagement scopes to Tenant Admin.
- **Audit retention: defer to later**. Microsoft default 30-day Entra retention plus Purview 180-day retention covers near-term forensics. Long-term 6-year HIPAA retention will be added via Azure Storage Account or Log Analytics workspace once an Azure pay-as-you-go subscription is set up. Cost estimate: Storage Account ~$0.20/mo at year-6 max; LAW with live monitoring ~$0.50-1/mo.
- **HIPAA BAA: confirmed automatic via Microsoft Online Services Terms**. The old Admin Center checkbox is gone. Business Premium covers HIPAA-eligible services by default.

## Problems Encountered

- **CA endpoints 403 after CA Admin role assigned** — root cause not directory role missing (already fixed) but Microsoft tightening the OAuth scope. Fixed by patching `Policy.Read.All` into Tenant Admin manifest and re-consenting in Cascades.
- **Intune Manager app single-tenant** — couldn't be consented in Cascades; got AADSTS700016. Fixed by PATCH on `signInAudience` to `AzureADMultipleOrgs` in ACG home.
- **Direct Graph add of Managed Play apps not supported** — POST to `/v1.0/deviceAppManagement/mobileApps` with `androidManagedStoreApp` returns 400 because Managed Play apps must be approved through Google's Play console iframe. Howard added apps via UI; assignments + config policies done via Graph after.
- **Graph v1.0 mobileApps endpoint hides Managed Play apps** — initially saw only ALIS in the inventory. Beta endpoint returned all 8 apps. Switched all subsequent app queries to beta.
- **Kiosk app schema discovery iteration** — `kioskModeApps` requires items typed as `microsoft.graph.appListItem` with required `name` field. Two failed attempts (`androidDeviceOwnerKioskModeManagedAppItem`, `androidDeviceOwnerKioskModeAppPositionItem`) before landing on the correct shape.
- **Phones still noncompliant after all policy work** — expected. Compliance requires a real user sign-in flow to set the 6-digit PIN and trigger Authenticator SDM registration. Will resolve when the pilot user signs into one of the test phones.
- **Existing all-users-MFA policy is enforced, not Report-only** — invalidates Gate A7 from Track A. Reshaped CA design described above.
- **Diagnostic Settings page requires Azure subscription** — no Azure subscription on Cascades yet. Audit retention plan deferred until subscription decision (Cascades direct billing vs ACG bundles it into MSP invoice).
- **Sync notification surfaced Mike's note (now superseded)** — Mike approved Path A while we were already doing Path B. Net result is the same; need a follow-up note to Mike to close the loop.

---

## Configuration Changes

### ComputerGuru ACG home tenant (`ce61461e-81a0-4c84-bb4a-7b354a9a356d`)

- **`ComputerGuru - Tenant Admin` app manifest:** added `Policy.Read.All` (`246dd0d5-5bd0-4def-940b-0421030a5b68`) to `requiredResourceAccess`. Granted appRoleAssignment in home tenant.
- **`ComputerGuru - Intune Manager` app manifest:** flipped `signInAudience` from `AzureADMyOrg` to `AzureADMultipleOrgs`.

### Cascades tenant (`207fa277-e9d8-4eb7-ada1-1064d2221498`)

- **Tenant Admin SP** (`a5fa89a9-b735-4e10-b664-f042e265d137`) now holds **Conditional Access Administrator** directory role (PIM-managed, Active assignment, permanent, no expiration). Status `Provisioned` since 2026-04-28T18:45:50Z.
- **Tenant Admin SP** now also has `Policy.Read.All` appRoleAssignment (added via re-consent).
- **Intune Manager SP** consented + provisioned in Cascades after multi-tenant flip.
- **Cascades named location** (id `061c6b06-b980-40de-bff9-6a50a4071f6f`):
  - Was: `72.211.21.217/32` only (secondary WAN)
  - Now: `72.211.21.217/32` + `184.191.143.62/32` (both WANs)
  - `isTrusted: true`
- **`CSC - Android Shared Phones Restrictions`** (id `070a76c2-a8c3-4f7f-9ba7-1f4ac5084184`) — version bumped 2 → 4:
  - `cameraBlocked: true`
  - `bluetoothBlockConfiguration: true`
  - `dataRoamingBlocked: true`
  - `kioskModeUseManagedHomeScreenApp: "multiAppMode"`
  - `kioskModeApps: [ALIS, Microsoft Teams]`
  - `kioskModeManagedHomeScreenAutoSignout: true`
  - `kioskModeManagedHomeScreenInactiveSignOutDelayInSeconds: 600` (10 min)
  - `kioskModeManagedHomeScreenInactiveSignOutNoticeInSeconds: 60` (1 min warning)
  - `kioskModeManagedHomeScreenPinRequired: false`
- **Microsoft Outlook** added to mobile apps via Intune portal (Managed Play). Pending sync, then assignment + add to MHS app list.

### CS-SERVER (Cascades on-prem DC, `192.168.2.254`)

- `\\CS-SERVER\homes` SMB share: `EncryptData` was `False`, Howard ran `Set-SmbShare -Name homes -EncryptData $true -Force` to flip it.

### Repo

- **`.claude/skills/remediation-tool/scripts/onboard-tenant.sh`** patched:
  - Added `ROLE_CA_ADMIN` constant (`b1be1c3e-b65d-4f19-8427-f6fa0d97feb9`)
  - Added Tenant Admin SP → Conditional Access Administrator assignment block (with role activation, idempotent)
  - Added `Policy.Read.All` backfill block before the consent_app loop (idempotent — only grants if missing)
  - Added Tenant Admin row to the final status table

---

## Commands & Outputs

### Cascades named location PATCH

```bash
TOKEN=$(bash .claude/skills/remediation-tool/scripts/get-token.sh \
  207fa277-e9d8-4eb7-ada1-1064d2221498 tenant-admin)
NL_ID="061c6b06-b980-40de-bff9-6a50a4071f6f"
curl -X PATCH \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  "https://graph.microsoft.com/v1.0/identity/conditionalAccess/namedLocations/$NL_ID" \
  -d '{
    "@odata.type": "#microsoft.graph.ipNamedLocation",
    "isTrusted": true,
    "ipRanges": [
      {"@odata.type": "#microsoft.graph.iPv4CidrRange", "cidrAddress": "72.211.21.217/32"},
      {"@odata.type": "#microsoft.graph.iPv4CidrRange", "cidrAddress": "184.191.143.62/32"}
    ]
  }'
# HTTP 204
```

### Tenant Admin manifest patch (Policy.Read.All)

Inline bash (mirrored Mike's `patch-tenant-admin-manifest.sh` pattern):

```bash
POLICY_READ_ALL_ID="246dd0d5-5bd0-4def-940b-0421030a5b68"
# Patch requiredResourceAccess to include Policy.Read.All
# Then grant appRoleAssignment in ACG home
# Howard re-consented in Cascades via:
#   https://login.microsoftonline.com/207fa277-e9d8-4eb7-ada1-1064d2221498/adminconsent?client_id=709e6eed-0711-4875-9c44-2d3518c47063&redirect_uri=https://azcomputerguru.com&prompt=consent
```

### Intune Manager multi-tenant flip

```bash
INTUNE_APP_OBJ_ID="31017446-c01a-4775-864f-aef96ce43797"
curl -X PATCH \
  -H "Authorization: Bearer $MGMT_TOKEN" -H "Content-Type: application/json" \
  "https://graph.microsoft.com/v1.0/applications/$INTUNE_APP_OBJ_ID" \
  -d '{"signInAudience": "AzureADMultipleOrgs"}'
# HTTP 204 (initial verify lagged; re-verified after 8s — confirmed)
```

### Device restrictions PATCHes

```bash
TOKEN=$(bash .claude/skills/remediation-tool/scripts/get-token.sh \
  207fa277-e9d8-4eb7-ada1-1064d2221498 intune-manager)
RESTRICT_ID="070a76c2-a8c3-4f7f-9ba7-1f4ac5084184"

# Block camera + bluetooth + roaming
curl -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  "https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations/$RESTRICT_ID" \
  -d '{
    "@odata.type": "#microsoft.graph.androidDeviceOwnerGeneralDeviceConfiguration",
    "cameraBlocked": true,
    "bluetoothBlockConfiguration": true,
    "dataRoamingBlocked": true
  }'

# Enable MHS multi-app kiosk
curl -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  "https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations/$RESTRICT_ID" \
  -d '{
    "@odata.type": "#microsoft.graph.androidDeviceOwnerGeneralDeviceConfiguration",
    "kioskModeUseManagedHomeScreenApp": "multiAppMode",
    "kioskModeApps": [
      {"@odata.type": "#microsoft.graph.appListItem", "name": "ALIS",            "appId": "fcbf803d-ceb7-4f4e-93ed-2be1b91a05f3"},
      {"@odata.type": "#microsoft.graph.appListItem", "name": "Microsoft Teams", "appId": "0eb81676-299b-4eb2-bfd9-8be914a82f91"}
    ],
    "kioskModeManagedHomeScreenAutoSignout": true,
    "kioskModeManagedHomeScreenInactiveSignOutDelayInSeconds": 600,
    "kioskModeManagedHomeScreenInactiveSignOutNoticeInSeconds": 60,
    "kioskModeManagedHomeScreenPinRequired": false
  }'
```

### CS-SERVER SMB encryption

```powershell
Set-SmbShare -Name homes -EncryptData $true -Force
Get-SmbShare -Name homes | Select Name,EncryptData
# Name  EncryptData
# ----  -----------
# homes        True
```

---

## CA design correction (revised from `user-account-rollout-plan.md` §5)

> **[SUPERSEDED — see UPDATE block at top of file. The table below was a tenant-wide design that would have blocked off-site office users. Phased per-group rollout is the corrected approach. Memory: `project_cascades_ca_phased_rollout.md`. Kept here for historical record only.]**

Existing all-users MFA policy is `enabled` not Report-only. Original §5 design said "block off-site, require MFA on-site" — that conflicts with Howard's actual goal of bypass on-site + compliant. Corrected design (deferred for build until break-glass exists):

| # | Name | Users | Conditions | Grant |
|---|---|---|---|---|
| — | (DELETE) `Require multifactor authentication for all users` | — | — | — |
| 1 | `CSC - Require MFA off Cascades network` | All users (admins still hit by separate admin policy) | Locations: include All, exclude Cascades named location | Require MFA |
| 2 | `CSC - Require MFA on non-compliant device` | All users | Filter for devices: include `device.isCompliant -eq False` | Require MFA |
| 3 | `CSC - Block off-network unless allow-listed` | All users **except** `SG-External-Signin-Allowed` and break-glass | Locations: include All, exclude Cascades named location | Block |
| 4 | `CSC - Sign-in frequency 8h` (session control) | `SG-Caregivers-Pilot` (then `SG-Caregivers`) | (none — applies to all sessions for the group) | Session control: re-auth every 8 hours |

**Logic verification:** caregiver on Cascades + compliant phone → no policy applies → password only. Caregiver off-network → policy 3 blocks. Caregiver on Cascades + non-compliant → policy 2 → MFA (which they can't do → effectively blocked, by design). External-allowed user off-site + compliant device → policy 1 → MFA only. Office user not allow-listed off-site → policies 1 + 3 → block wins.

Keep existing risk-based + admin-targeted policies as defense in depth (they'll continue to add MFA on top in suspect scenarios, even when the bypass would otherwise apply — which is correct for HIPAA).

---

## Pending / Incomplete Tasks

### Immediate (resume here)
- [ ] Howard finishes Outlook Managed Play sync, tells me, I assign + add to MHS app list
- [ ] Howard adds LinkRx + Helpany web apps when URLs available
- [ ] Pick a phone and run real user sign-in flow → verify compliance flips to compliant

### Path B pilot
- [ ] Decide: create new `pilot.test@cascadestucson.com` cloud user, or use an existing cloud user
- [ ] Create cloud-only Entra group `SG-Caregivers-Pilot`, add pilot user
- [ ] Assign Business Premium license to pilot user

### Wave 0 HIPAA pre-flight (before any CA change goes live)
- [ ] Break-glass admin: design + create. Cloud-only Global Admin, FIDO2 (1 YubiKey on hand), excluded from all CA, vaulted password, sign-in alerts to Howard + Mike
- [ ] Audit retention 6yr: decide Cascades-billed vs ACG-billed, then create Azure pay-as-you-go subscription, Log Analytics workspace, Diagnostic Settings export
- [ ] ALIS BAA: ask Meredith (Howard sends email)
- [ ] Risk Analysis doc: draft via Ollama, Mike reviews

### CA bypass build
- [ ] Stage 4 new policies in **Report-only**, assigned to `SG-Caregivers-Pilot` initially
- [ ] Run pilot validation tests (the 8 from the earlier write-up)
- [ ] After 24-48h Report-only and break-glass verified working, flip to On

### Production rollout (later)
- [ ] AD prereq cleanup (G1 from §7) — renames, UPN suffix add, former-employee deletes, etc.
- [ ] Exit Entra Connect staging mode (G3-G5)
- [ ] Replace `SG-Caregivers-Pilot` with synced `SG-Caregivers` in CA policy targets
- [ ] Roll Phase 3 (all users at Cascades on Cascades net + compliant device → bypass)
- [ ] Run patched `onboard-tenant.sh` against all other already-onboarded ACG customer tenants to backfill CA Admin role + Policy.Read.All

### Side-track from 4/25 (still in limbo)
- [ ] 7-mailbox shared conversion + Jodi Ramstack license removal (blocked on Exchange RBAC propagation lag)

---

## Reference Information

### Cascades tenant
- Tenant ID: `207fa277-e9d8-4eb7-ada1-1064d2221498`
- Tenant Admin SP appId: `709e6eed-0711-4875-9c44-2d3518c47063`
- Tenant Admin SP objectId in Cascades: `a5fa89a9-b735-4e10-b664-f042e265d137`
- Intune Manager SP appId: `46986910-aa47-4e5e-b596-f65c6b485abb`
- Cascades named location id: `061c6b06-b980-40de-bff9-6a50a4071f6f`
- Trusted IPs (both WANs): `72.211.21.217/32` (secondary), `184.191.143.62/32` (primary)
- Vault: `clients/cascades-tucson/wifi-cscnet.sops.yaml`, `clients/cascades-tucson/mdm-service-account.sops.yaml`

### Cascades Intune resources
- Compliance policy: `CSC - Android Compliance` id `27eeaeda-8390-462e-a514-7d2a558f412c`
- Wi-Fi config: `CSC - CSCNet Wi-Fi (WPA2-Personal)` id `b572ba54-1a04-4c40-9ac5-dd5aec444611`
- Device restrictions: `CSC - Android Shared Phones Restrictions` id `070a76c2-a8c3-4f7f-9ba7-1f4ac5084184`
- SDM Authenticator config: id `a1bfbda0-a36c-45e5-8844-8470f80ecc8d`
- SDM Teams config: id `3c6a354c-1616-434b-ac81-4dad7795e67b`
- Enrollment profile: `CSC - Android Shared Phones`, token `MVDVVDMPSHYJAGDAJOCN` (expires 2026-06-22)
- Target group: `Cascades - Shared Phones` (cloud, dynamic, security) id `ea96f4b7-3000-45da-ab1f-ddb28f509526`, rule: `device.enrollmentProfileName -eq "CSC - Android Shared Phones"`

### Microsoft directory role template IDs
- Conditional Access Administrator: `b1be1c3e-b65d-4f19-8427-f6fa0d97feb9`
- Security Administrator: `194ae4cb-b126-40b2-bd5b-6091b380977d`
- Global Reader: `f2ef992c-3afb-46b9-b7cf-a126ee74c451`

### Microsoft Graph appRole IDs
- `Policy.Read.All`: `246dd0d5-5bd0-4def-940b-0421030a5b68`
- `Policy.ReadWrite.ConditionalAccess`: `01c0a623-fc9b-48e9-b794-0756f8e8f067`
- `RoleManagement.ReadWrite.Directory`: `9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8`

### Currently-enrolled test phones (both noncompliant pending real sign-in flow)
- Device 1: SM-A146U, enrolled 2026-04-20, last sync 2026-04-23, isEncrypted=true, jailBroken=Unknown
- Device 2: SM-A146U, enrolled 2026-04-23, last sync 2026-04-27, isEncrypted=true, jailBroken=Unknown

---

## Note for Mike

Closing the loop on your 2026-04-28 note re: Cascades CA fix.

**Path A vs Path B:** I executed Path B (PIM portal click as `sysadmin@cascadestucson.com`, Active assignment, permanent) before seeing your note approving Path A. Both produce the same end state — the directory role is in place on the Tenant Admin SP since 2026-04-28T18:45:50Z. No follow-up needed on the Cascades-specific assignment; it's done.

**The actual blocker turned out to be different:** even with the directory role, CA endpoints kept returning 403 with "required scopes are missing in the token." Microsoft tightened `LIST /identity/conditionalAccess/namedLocations` and `/policies` to require `Policy.Read.All` as the application permission — `Policy.ReadWrite.ConditionalAccess` (which the SP carried) is no longer accepted for reads. Patched the Tenant Admin app manifest to add `Policy.Read.All`, granted in ACG home, Howard re-consented in Cascades. CA reads then worked.

**`onboard-tenant.sh` patch — done.** Per the new tool-vs-project approval workflow, Howard approved this and I patched. Two changes:
1. Tenant Admin SP now gets `Conditional Access Administrator` directory role assigned at onboard time (idempotent — handles already-assigned via the existing Conflict-fallback in `assign_role`).
2. New backfill block: detects whether Tenant Admin SP has `Policy.Read.All` and grants it programmatically if missing. Required for tenants where Tenant Admin was consented before the manifest update on 2026-04-29.

Validated with `bash onboard-tenant.sh 207fa277-e9d8-4eb7-ada1-1064d2221498 --dry-run` — clean.

**Recommended backfill against other onboarded tenants:** re-run `bash onboard-tenant.sh <tenant-id>` against every customer where Tenant Admin was consented before 2026-04-29 today's manifest update. Idempotent — safe to re-run. If a tenant has a pre-existing PIM-managed CA Admin assignment (like Cascades does after Howard's PIM click), the role_assigned helper might mistakenly report MISSING because PIM-managed assignments may not appear in the legacy `roleAssignments` query. The actual `assign_role` call will hit `Conflict` and the helper treats that as success — so the script is still correct, just slightly noisy in its reporting. Worth a follow-up to teach `role_assigned` about `roleAssignmentSchedules` too, but not blocking.

**Phase B Intune state at Cascades:** done in full (compliance, Wi-Fi, restrictions w/ MHS multi-app kiosk, both SDM app configs, all 8 apps assigned except Microsoft Launcher). Pilot phone enrollment will validate the full flow once Outlook landed (Howard added it tonight).

**Wave 0 HIPAA pre-flight status:** BAA confirmed automatic via MOST. Break-glass admin not yet created — that's the next pre-flight before we touch CA policies. Audit retention deferred until Cascades-billed vs ACG-billed decision (your call when you're back). The CA bypass design needed reshaping — original §5 plan didn't actually achieve the bypass goal; corrected design is in this log under "CA design correction."

If anything in the corrected CA design or the onboard-tenant patch isn't to your liking, ping back and I'll adjust.

---

**Session duration:** ~7 hours continuous (2026-04-28 ~16:00 → 2026-04-29 ~07:30 PT, with breaks for portal tasks)
**Commits during session:** 1 sync auto-commit (`ff4577c`) before this log; this log + onboard-tenant patch will land in a fresh commit after `/save`
**Files changed in this log's commit:** 2 (`.claude/skills/remediation-tool/scripts/onboard-tenant.sh`, this session log)

---

## Update: 07:42 PT — close-out

Session log + `onboard-tenant.sh` patch landed in commit `a2f38c1` and pushed to Gitea (`a1209b2..a2f38c1`).

`/sync` was clean (no incoming, only this commit pushed). Working tree clean. No outstanding local changes.

Picking back up next session: see "Resume point" at the top of this file.
