# 2026-04-29 — Cascades audit retention design + Pro-Tech Services email investigation ## User - **User:** Mike Swanson (mike) - **Machine:** GURU-BEAST-ROG - **Role:** admin - **Session span:** 2026-04-29 ~13:30 PT to ~14:50 PT (~1.5 hours, two work threads) ## Session Summary The session began with the Cascades Tucson HIPAA work, starting with a `/sync` pull that included recent commits from Howard and Mike, along with a local radio-show commit pushed. Howard's note on the Cascades CA fix Path B execution and his `onboard-tenant.sh` patch were surfaced for review. The Conditional Access bypass design was reviewed and approved, with a critical bug identified in policy 3 that would block GDAP admins during the CA cutover. The bug was corrected by explicitly excluding service provider users from the policy. A concern about the "device bootstrap chicken-and-egg" was raised but later resolved upon clarification that bootstrap users are always admins with MFA on Cascades Wi-Fi. The session then transitioned to the Audit Retention Design, where a hybrid architecture of Log Analytics Workspace and Storage Account with lifecycle policy was decided. The billing model was set to ACG-billed within the HIPAA-tier MRR, and the existing ACG Azure subscription `e507e953-2ce9-4887-ba96-9b654f7d3267` (the GuruRMM Trusted Signing sub) was reused with isolated `rg-audit-*` resource groups. A full runbook was written to document the design and implementation steps. Mike's question about how break-glass relates to existing admin@/sysadmin@/GDAP partner access prompted a reshape from one break-glass account to two, with FIDO2 YubiKeys split between Cascades and ACG. Mike clarified that admin@ and sysadmin@ are intentionally Connect-excluded (cloud-only by design); this was documented in `clients/cascades-tucson/CONTEXT.md` as a permanent reference. For RBAC, Mike asked whether Howard could grant himself Contributor on the new audit RGs rather than Mike doing it. Decision: grant Howard Owner on the entire ACG subscription, matching the existing trust model in `CLAUDE.md`, with two guardrails — a `CanNotDelete` lock on `gururmm-signing-rg` and a $50/mo Cost Management alert. This unblocks all future MSP-side Azure self-service and removes Mike as a permanent bottleneck. A separate thread emerged when Mike asked to check DNS for `pro-techhelps.com`. After pulling records, Mike provided email headers from a "test" message from Jenny Holtsclaw at `pro-techservices.co` (a different domain). DNS recon on both showed they are GoDaddy-resold M365 (`NETORG6702699.onmicrosoft.com` tenant) with no custom DKIM and no DMARC. Inky flagged the test message PCL=4 (high phishing suspicion) but did not quarantine. The diagnosis: DKIM signs only with the `.onmicrosoft.com` fallback selector (not aligned with the From: domain), and combined with absent DMARC, strict receivers (Google Workspace, healthcare, finance) silently drop calendar invites while regular email passes — explaining the "some recipients never receive invites" symptom Jenny had reported. Mike confirmed both domains belong to one company that only sends from `.co`, and decided to pitch Michelle Sora (the business contact) on migrating off GoDaddy onto direct M365 with both domains consolidated under one cleanly-managed tenant. Drafted an email for Michelle — first version too technical/peer-tone, revised to non-technical IT-provider framing once Mike clarified Michelle is "stubborn and afraid of change." Final draft written to a temp file and opened in Notepad for Mike's review. ## Key Decisions - **Hybrid audit retention architecture** (LAW 90d interactive + Storage Account 6yr cold archive). Both fed by the same Diagnostic Settings export — single ingest, two retention tiers. Rationale: balance live forensics against compliance archive cost. - **ACG-billed audit retention**, bundled into HIPAA-tier MRR. ~$0.50–1.00/mo per tenant. Avoids Cascades Azure subscription friction; supports "we handle compliance, you don't think about it" MSP positioning. - **Reuse existing ACG Azure subscription** `e507e953-2ce9-4887-ba96-9b654f7d3267` (the GuruRMM Trusted Signing sub) rather than provisioning a new one. RG isolation between signing and audit. Future split to a dedicated compliance subscription deferred until 3+ HIPAA tenants or audit ask demands it. - **Two break-glass accounts at Cascades** (`breakglass1-csc@` and `breakglass2-csc@`) per Microsoft official guidance. FIDO2 YubiKeys split-stored: one at Cascades sealed envelope, one in ACG safe. Cost $50 vs $25 single — trivial. - **Howard granted Owner on the ACG subscription** rather than per-RG Contributor. Matches `CLAUDE.md` trust model; one-time grant unblocks all future self-service. Guardrails: `CanNotDelete` lock on `gururmm-signing-rg` + $50/mo Cost Management alert. - **CA policy 3 user targeting revised** to exclude "Service provider users" (GDAP foreign principals) in addition to `SG-External-Signin-Allowed` and `SG-Break-Glass`. Without this, ACG GDAP partner admins lose remote MSP access at CA cutover. - **admin@ and sysadmin@ at Cascades are intentionally Connect-excluded** (cloud-only by design). Local AD `Administrator` is a separate on-prem identity layer, not part of the M365 admin model. Documented in CONTEXT.md. - **UAL handling deferred**: poll-based Office 365 Management Activity API harvester to write JSON blobs to the per-tenant Storage Account. Build after pilot CA cutover validated and Cascades audit retention runs cleanly for 30 days. Estimated 4-6 hours dev + test. - **Backfill sweep moved to Howard's column.** Mike originally took ownership; reallocated when it became clear Howard can run it locally during his next session and surface results in his own log. - **Email to Michelle framed as IT-provider follow-up, not technical pitch.** No DNS/DKIM/DMARC jargon. GoDaddy positioned as the external constraint that locks everyone (including Mike) out of fixing it properly. Reassurance front-and-center: same email addresses, same Outlook, nothing changes for the team. ## Problems Encountered - **Policy 3 GDAP bug** (Cascades CA design). Howard's policy 3 ("All users" minus `SG-External-Signin-Allowed`) would block ACG GDAP partner admins because Microsoft's "All users" CA target includes service-provider foreign principals. Caught while walking through Mike's question on how break-glass relates to admin@/sysadmin@/GDAP. Resolved: explicit "Service provider users" exclusion added to the design. - **Bootstrap chicken-and-egg false alarm.** Initially raised concern that new shared phones (non-compliant until first user sign-in) would be trapped by policy 2 (require MFA on non-compliant device). Mike pointed out the bootstrap user is always an admin (sysadmin@ or Howard) on Cascades Wi-Fi — admin has MFA, policy 1 doesn't fire on-network, policy 2 prompts MFA which admin satisfies, device flips compliant. No CA exception needed. Concern retracted in favor of operational rule: phones don't get handed to caregivers until SDM bootstrap is done. - **Misread of "schedule with Howard."** When Mike said "schedule with Howard to get that going," I interpreted it as invoking the `/schedule` skill (remote agent on cron). Started the AskUserQuestion flow. Mike clarified he meant coordinate with Howard via session log when convenient for him, not create a remote agent. Backed out. Coordination is now via the existing session log + cross-user note hook. - **First Michelle email draft was too technical.** Initial draft used peer-MSP tone with DKIM/DMARC explanation, ~450 words. Mike clarified he's already her IT provider and Michelle is "stubborn and afraid of change" — needed non-technical, reassurance-forward framing without DNS jargon. Revised to ~280 words with GoDaddy-as-constraint framing, "nothing changes for users" emphasis, and a soft close on scheduling a call. ## Configuration Changes ### Files created - `.claude/skills/remediation-tool/references/audit-retention-runbook.md` — full design + per-tenant runbook (Phase 1 ACG-side resources, Phase 2 customer-tenant Diagnostic Settings, Phase 3 verification, Phase 4 deferred OMA harvester, operational + cost notes) - `clients/cascades-tucson/session-logs/2026-04-29-mike-audit-retention-design-and-handoff.md` — full handoff log for Howard (covers all 6 decisions, runbook reference, order of operations, four-paths failure-domain map) - `session-logs/2026-04-29-session.md` — this file ### Files modified - `clients/cascades-tucson/CONTEXT.md` — added "M365 admin model" section (full admin landscape: on-prem AD Administrator, Connect-excluded admin@/sysadmin@, GDAP partner principals, two break-glass accounts; CA targeting consequences) ### Files NOT touched (orthogonal to this session, deliberately not committed in this log's commit) - `projects/radio-show/audio-processor/server/main.py` — pre-existing modification, separate radio-show Q&A scoring work - `projects/radio-show/audio-processor/classify_qa_quality.py` — pre-existing untracked file from radio-show work - `.claude/scheduled_tasks.lock` — transient runtime file ### Temp files (not part of repo) - `C:/Users/guru/AppData/Local/Temp/michelle-email-draft.txt` — Michelle Sora email draft (Mike opened in Notepad to review/send) - `C:/Users/guru/AppData/Local/Temp/save_narrative_prompt.txt` — Ollama prompt for this log - `C:/Users/guru/AppData/Local/Temp/save_narrative_output.md` — Ollama narrative output ## Commands & Outputs ### /sync at session start - Pulled 3 commits (Howard cascades close-out, Mike earlier auto-sync, Mike PIM gap note) - Pushed 1 local commit (radio-show `import_to_sqlite.py` from earlier work) - Vault: clean both directions - HEAD after sync: `6b63c15` ### DNS reconnaissance — pro-techhelps.com ``` MX: protechhelps-com0i.mail.protection.outlook.com (pri 0) SPF: "v=spf1 include:spf.protection.outlook.com -all" [direct M365] DMARC: NXDOMAIN DKIM: selector1/selector2 NXDOMAIN WHOIS: registered 2016-12-09, GoDaddy registrar, NS69/NS70.DOMAINCONTROL.COM A: 3.33.130.190, 15.197.148.33 (AWS-hosted) ``` ### DNS reconnaissance — pro-techservices.co ``` MX: protechservices-co0i.mail.protection.outlook.com (pri 0) SPF: "v=spf1 include:secureserver.net -all" [GoDaddy-resold path] "NETORG6702699.onmicrosoft.com" [marker] "v=verifydomain MS=9047794" [M365 verification] DMARC: NXDOMAIN DKIM: selector1/selector2 NXDOMAIN A: 76.223.105.230, 13.248.243.5 (AWS-hosted) Tenant: NETORG6702699.onmicrosoft.com (GoDaddy-resold M365) ``` ### Email header analysis (Jenny Holtsclaw test message) - From: `Jenny Holtsclaw ` to `mike@azcomputerguru.com` - Subject: `test`, sent 2026-04-29 22:31:34 UTC - DKIM: `pass header.d=NETORG6702699.onmicrosoft.com` (fallback signer, not aligned with From: domain) - SPF: pass on first hop, fail on Inky relay (normal forwarding artifact) - DMARC: bestguesspass (no policy) - compauth: `pass reason=130` - Inky verdict: `X-IPW-Inky-PCL: 4` (high phish suspicion), `X-IPW-Inky-SCL: 0` (not spam), `X-Inky-Quarantine: False` ## Credentials & Secrets No new credentials created or rotated this session. Existing references confirmed: - **ACG Azure subscription**: `e507e953-2ce9-4887-ba96-9b654f7d3267` - Vault: `services/azure-trusted-signing.sops.yaml` - Existing usage: `gururmm-signing-rg` for GuruRMM Trusted Signing cert profile - New planned usage: `rg-audit-*` resource groups for HIPAA-tier audit retention - **Cascades tenant ID**: `207fa277-e9d8-4eb7-ada1-1064d2221498` - **Cascades Tenant Admin SP appId**: `709e6eed-0711-4875-9c44-2d3518c47063` (objectId in Cascades: `a5fa89a9-b735-4e10-b664-f042e265d137`) - **Cascades Conditional Access Administrator role template ID**: `b1be1c3e-b65d-4f19-8427-f6fa0d97feb9` - **Microsoft Graph appRole `Policy.Read.All`**: `246dd0d5-5bd0-4def-940b-0421030a5b68` - **Pro-Tech Services tenant**: `NETORG6702699.onmicrosoft.com` (GoDaddy-resold; not under ACG management) ## Infrastructure & Servers - ACG Azure subscription `e507e953-2ce9-4887-ba96-9b654f7d3267` — westus2 region, owner: Mike Swanson, currently single resource group `gururmm-signing-rg`. Planned expansion: `rg-audit-cascadestucson` and future `rg-audit-*` per HIPAA-tier client. - Cascades on-prem: CS-SERVER `192.168.2.254` (DC + file server, domain `cascades.local`); pfSense `192.168.0.1`; Synology `192.168.0.120:5000`. Cascades named location id `061c6b06-b980-40de-bff9-6a50a4071f6f` (both WANs trusted: `72.211.21.217/32` + `184.191.143.62/32`). - Pro-Tech Services external: M365 EOP MX endpoints (`protechservices-co0i.mail.protection.outlook.com`, `protechhelps-com0i.mail.protection.outlook.com`); Inky phishfence (`ipw.inkyphishfence.com` 100.24.129.5) in inbound mail path to ACG. ## Pending / Incomplete Tasks ### Mike's outstanding items (Cascades audit retention) - [ ] Order TWO YubiKeys ($50 total — one for Cascades sealed envelope via Howard, one for ACG safe) - [ ] One-time: grant Howard Owner on ACG subscription ```bash az role assignment create \ --assignee howard.enos@azcomputerguru.com \ --role "Owner" \ --scope "/subscriptions/e507e953-2ce9-4887-ba96-9b654f7d3267" ``` - [ ] One-time: resource lock on signing RG ```bash az lock create --name signing-protect --lock-type CanNotDelete \ --resource-group gururmm-signing-rg \ --notes "Protect GuruRMM Trusted Signing infra from accidental deletion" ``` - [ ] One-time: $50/mo cost alert via Cost Management UI ### Mike's outstanding items (Pro-Tech Services) - [ ] Review the Michelle Sora email draft in Notepad (`C:/Users/guru/AppData/Local/Temp/michelle-email-draft.txt`) - [ ] Send the email when ready; possibly draft a parallel Jenny variant if needed - [ ] If Michelle accepts: schedule discovery call covering user count, tenant access verification (admin.microsoft.com test), other domains, third-party integrations - [ ] If migration proceeds: build proposal, T2T migration plan, license cutover sequencing ### Howard's outstanding items (Cascades, in order) 1. Backfill sweep against 6 ACG tenants (~5 min, idempotent): bg-builders, cascades-tucson, cw-concrete, dataforth, heieck-org, mvan 2. Pilot Outlook + LinkRx/Helpany apps + first phone compliance flip (resume from prior session) 3. Pilot user + cloud group `SG-Caregivers-Pilot` 4. Audit retention buildout (RG, Storage Account with lifecycle, LAW, Diagnostic Settings) per the runbook 5. Two break-glass accounts + YubiKey enrollment + `SG-Break-Glass` group + sign-in alert KQL rule on LAW 6. CA policies in Report-only → 24-48h review → flip to On 7. Phase 3 production rollout (after AD prereq cleanup + Entra Connect staging exit) ### Tracked TODOs (not blocking) - [ ] Teach `role_assigned` helper about `roleAssignmentSchedules` (cosmetic noise only on PIM-managed assignments) - [ ] Build OMA Activity API harvester for UAL (4-6 hours dev when ready, after Cascades audit retention runs cleanly for 30d) - [ ] Codify `onboard-tenant.sh --enable-audit-archive` flag (after pilot validated) - [ ] Codify `onboard-tenant.sh --enable-breakglass` flag (after 3-4 HIPAA tenants on pattern) ## Reference Information ### Files / paths - Audit retention runbook: `.claude/skills/remediation-tool/references/audit-retention-runbook.md` - Cascades handoff log: `clients/cascades-tucson/session-logs/2026-04-29-mike-audit-retention-design-and-handoff.md` - Cascades CONTEXT (M365 admin model added): `clients/cascades-tucson/CONTEXT.md` - Howard's prior session log: `clients/cascades-tucson/session-logs/2026-04-29-howard-cascades-bypass-pilot-phase-b-buildout.md` - onboard-tenant.sh (now patched with CA Admin role + Policy.Read.All backfill): `.claude/skills/remediation-tool/scripts/onboard-tenant.sh` - Michelle email draft (temp): `C:/Users/guru/AppData/Local/Temp/michelle-email-draft.txt` ### Vault entries referenced - `services/azure-trusted-signing.sops.yaml` — ACG Azure subscription - `clients/cascades-tucson/m365-admin.sops.yaml` — Cascades M365 admin - `clients/cascades-tucson/m365-sysadmin.sops.yaml` — Cascades M365 sysadmin - `clients/cascades-tucson/wifi-cscnet.sops.yaml`, `mdm-service-account.sops.yaml`, `pfsense-firewall.sops.yaml` ### Future vault entries (not yet created) - `clients/cascades-tucson/breakglass1.sops.yaml` — primary break-glass (when account created) - `clients/cascades-tucson/breakglass2.sops.yaml` — secondary break-glass ### External - Microsoft Diagnostic Settings on Entra: ARM endpoint `https://management.azure.com/providers/microsoft.aadiam/diagnosticSettings/{name}?api-version=2017-04-01-preview` (NOT a Graph endpoint — Howard validates exact call shape during dry-run) - Microsoft directory role template — Conditional Access Administrator: `b1be1c3e-b65d-4f19-8427-f6fa0d97feb9` - Office 365 Management Activity API (UAL harvester future work): `/api/v1.0/{tenantId}/activity/feed/subscriptions/content?contentType=...` ### Cost model (audit retention) - Per HIPAA-tier tenant: ~$0.50–1.00/mo (LAW $0.23 ingest + $0.03 retention + Storage $0.15 lifecycle blended) - ACG cumulative at 5 HIPAA tenants: ~$5–10/mo - Forensics rehydration (archive blob): ~$50–100 per incident retrieval, one-time per event