sync: auto-sync from HOWARD-HOME at 2026-04-22 17:39:56
Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-04-22 17:39:56
This commit is contained in:
@@ -107,7 +107,7 @@ All UPNs above use the `@cascadestucson.com` suffix (standard).
|
||||
- **Patricia Sandoval-Beck** — **Resolved 2026-04-22 (CSV inline note from Meredith):** hyphen is correct. SamAccountName may still need to be `Patricia.SandovalBeck` if ALIS/MDM reject hyphens — test during Wave 3.
|
||||
- **Ederick Yuzon** — **Still pending:** spelling asked in 2026-04-22 email.
|
||||
- **Maia Baker** — **Resolved 2026-04-22 (CSV inline note):** part-time, still employed.
|
||||
- **Reliable Agency shared logins (x2)** — **Resolved 2026-04-22 (John's reply): usernames `reliable1@` and `reliable2@` confirmed.** Shared-login accounts, not per-person. Create in Wave 1 alongside Alma/Kyla.
|
||||
- **Reliable Agency caregivers** — **Final decision 2026-04-22 (post-HIPAA review): NO shared logins.** Originally planned `reliable1@` / `reliable2@`; dropped because shared log-on IDs for PHI access violate 45 CFR §164.312(a)(2)(i) (Required spec, no compensating-control exception). Per-person accounts only, created when Reliable Agency supplies individual names. Rationale in `docs/security/hipaa-review-2026-04-22.md`.
|
||||
|
||||
## Licensing plan (when ready — NOT now)
|
||||
|
||||
@@ -171,7 +171,8 @@ Group-policy impact: the `CSC - Folder Redirection (LE)` work done for Life Enri
|
||||
- [x] ~~Confirm Christine Nyanzunda is one person, not two~~ (resolved 2026-04-22 — one person, one account)
|
||||
- [x] ~~HR spelling confirmation on Paty Doran, Polett Pinazavala, Patricia Sandoval-Beck, Maia Baker~~ (all resolved 2026-04-22)
|
||||
- [ ] **Ederick Yuzon first-name spelling** — asked in 2026-04-22 email, still outstanding
|
||||
- [x] ~~Reliable Agency shared-login short usernames~~ (resolved 2026-04-22: reliable1/reliable2 confirmed)
|
||||
- [x] ~~Reliable Agency shared-login short usernames~~ (SUPERSEDED 2026-04-22 by HIPAA review — no shared logins, per-person only)
|
||||
- [ ] **Reliable Agency contract review** — confirm staffing contract says caregivers work under Cascades direct clinical control (workforce) vs. agency-supervised (BA). Get individual caregiver names before any PHI access.
|
||||
- [ ] Will caregivers use ALIS on the shared phones (need ALIS accounts + Entra SSO) or only email?
|
||||
- [ ] Does Cascades want to purchase 39 additional Business Premium licenses up-front, or roll out in waves (e.g., MedTechs first, then CCGs, then Caregivers)?
|
||||
- [ ] Confirm pfSense WAN IP(s) are static enough to rely on in a CA Named Location policy
|
||||
|
||||
@@ -32,7 +32,7 @@ I will send a full list for you all to look over.
|
||||
- **#2 Alma R Montt — ANSWERED.** D+P, ALIS=Y, Outside sign-in=Y. Title = "Memory Care Life Enrichment" (LE staff assigned to Memory Care residents — department stays Life Enrichment, title reflects the MC focus).
|
||||
- **#3 Polett Pinazavala — DEPARTED.** No longer an employee. Was not in AD/M365 yet — just remove from the roster. No license to harvest, no account to disable.
|
||||
- **#4 Ederick Yuzon — STILL PENDING.** John didn't address the spelling; assume he'll send a separate reply or we ping him again.
|
||||
- **#5 / #6 Agency — CONFIRMED.** Usernames `reliable1` and `reliable2` as proposed. Shared-login accounts for whichever Reliable Agency caregiver is on shift.
|
||||
- **#5 / #6 Agency — SUPERSEDED 2026-04-22 by HIPAA review.** Although John approved `reliable1` / `reliable2`, post-review the shared-login approach was dropped: HHS has explicitly stated shared log-on IDs for PHI access violate §164.312(a)(2)(i) (Required spec, no compensating-control exception). Replaced with: Reliable Agency must supply individual names; per-person accounts only. No shared credentials. Full rationale in `docs/security/hipaa-review-2026-04-22.md`.
|
||||
|
||||
### John's note about "keeps not saving things"
|
||||
|
||||
|
||||
@@ -172,14 +172,13 @@ All caregivers sign into the shared company-issued Android phones using their ow
|
||||
| Ezekiel Huerta | Caregiver PRN — Tower | ezekiel.huerta@cascadestucson.com | Y | N |
|
||||
| Maia Baker | MedTech PRN — Memory Care | maia.baker@cascadestucson.com | Y | N |
|
||||
|
||||
### Agency — shared-account logins (confirmed 2026-04-22)
|
||||
### Agency caregivers — no shared logins (HIPAA decision 2026-04-22)
|
||||
|
||||
Shared logins used by whoever from Reliable Agency is covering a shift. Not tied to a specific person. John confirmed `reliable1` and `reliable2` as the usernames.
|
||||
Originally planned as shared logins `reliable1@` / `reliable2@`. **Dropped** after HIPAA review — shared log-on IDs for PHI access violate 45 CFR §164.312(a)(2)(i) Unique User Identification (Required spec, no compensating-control exception). See `docs/security/hipaa-review-2026-04-22.md`.
|
||||
|
||||
| Name | Role | Email | Phone | Outside sign-in |
|
||||
|---|---|---|---|---|
|
||||
| Reliable Agency shared login #1 | Agency caregiver | reliable1@cascadestucson.com | Y | N |
|
||||
| Reliable Agency shared login #2 | Agency caregiver | reliable2@cascadestucson.com | Y | N |
|
||||
**Policy going forward:** Reliable Agency must provide individual names before any shift where a caregiver needs PHI access. Per-person accounts only. If the agency won't commit to that, their caregivers don't get ALIS / email access and must work under direct supervision of a Cascades-employed caregiver who does.
|
||||
|
||||
No entries on this list until names arrive.
|
||||
|
||||
---
|
||||
|
||||
@@ -194,8 +193,8 @@ Shared logins used by whoever from Reliable Agency is covering a shift. Not tied
|
||||
| Shared front-desk receptionists | 4 |
|
||||
| Courtesy Patrol | 3 |
|
||||
| Caregivers / shift staff | 37 |
|
||||
| Agency shared logins | 2 |
|
||||
| **Total active identities / mailboxes** | **68** |
|
||||
| Agency caregivers | 0 *(per-person only; no accounts until Reliable provides names — HIPAA decision 2026-04-22)* |
|
||||
| **Total active identities / mailboxes** | **66** |
|
||||
|
||||
### Employees on the roster but no IT account
|
||||
|
||||
@@ -223,7 +222,7 @@ Shared logins used by whoever from Reliable Agency is covering a shift. Not tied
|
||||
- **Britney Thompson — DEPARTED.** Disable existing AD account and harvest Business Standard + Exchange Online Essentials license.
|
||||
- **Polett Pinazavala — DEPARTED.** Not in AD, no action needed other than removal from roster.
|
||||
- **Alma R Montt — ANSWERED.** Title "Memory Care Life Enrichment", D+P, ALIS=Y, Outside=Y.
|
||||
- **Agency usernames — CONFIRMED.** `reliable1` and `reliable2` as proposed.
|
||||
- **Agency usernames — SUPERSEDED by HIPAA review.** John approved `reliable1` / `reliable2`, but shared-login accounts for PHI access are not HIPAA-compliant (§164.312(a)(2)(i)). No accounts created. Reliable Agency must provide individual names for per-person accounts.
|
||||
- **Drivers — NO ACCOUNTS.** Disable existing 3 AD accounts (Richard Adams, Julian Crim, Christopher Holick).
|
||||
|
||||
## Still pending from Meredith/John
|
||||
|
||||
@@ -110,7 +110,8 @@ No answer yet. This decision directly changes the license count and the CA polic
|
||||
| Office staff with Outside=Y (Office-PHI external-OK) | **18** | Includes Alma. Britney removed (departed). |
|
||||
| + Office Outside=N + ALIS=Y (Allison Reibschied, Sharon Edwards) | **20** | Need CA coverage even in building-only posture |
|
||||
| + Matt Brooks (dual-dept, ALIS=Y) | **21** | Per rollout plan §3 |
|
||||
| All licensed seats under building-only-default | 21 office + 3 Courtesy Patrol + 4 Reception + 37 caregivers + 2 agency = **67** | Plus Ramon Castaneda for office non-PHI = **68** total active identities |
|
||||
| All licensed seats under building-only-default | 21 office + 3 Courtesy Patrol + 4 Reception + 37 caregivers = **65** | Plus Ramon Castaneda for office non-PHI = **66** total active identities |
|
||||
| Agency caregivers (per-person, if/when names arrive) | +1 each | No accounts until Reliable Agency provides names — HIPAA §164.312(a)(2)(i) prohibits shared PHI-access logins |
|
||||
|
||||
## Action items
|
||||
|
||||
@@ -118,7 +119,7 @@ No answer yet. This decision directly changes the license count and the CA polic
|
||||
- [ ] Push Meredith for the "restrict everyone or just some" decision — still unanswered as of 2026-04-22
|
||||
- [x] ~~Britney phone+outside flags~~ (resolved 2026-04-22: departed)
|
||||
- [x] ~~Alma R Montt title~~ (resolved 2026-04-22: Memory Care Life Enrichment, D+P/Y/Y)
|
||||
- [x] ~~Agency shared-login username preference~~ (resolved 2026-04-22: reliable1/reliable2 confirmed)
|
||||
- [x] ~~Agency shared-login username preference~~ (SUPERSEDED 2026-04-22 by HIPAA review — no shared logins; per-person only)
|
||||
- [ ] **Ederick Yuzon spelling** — only remaining question from the 2026-04-22 follow-up email
|
||||
- [ ] Decide: standalone P2 add-on for the 19 OR move those users to Business Premium OR move whole tenant to Business Premium (default recommendation: Premium tenant-wide)
|
||||
- [ ] Build CA policy `CSC - Office Staff PHI Access` separate from the caregiver mobile policy
|
||||
|
||||
@@ -340,9 +340,10 @@ const INITIAL = {
|
||||
["Ezekiel Huerta","Caregiver PRN — Tower","Caregivers (shift staff)","D+P",false,true,""],
|
||||
["Maia Baker","MedTech PRN — Memory Care","Caregivers (shift staff)","D+P",false,true,"Part-time (confirmed)"],
|
||||
|
||||
// Caregivers — agency shared-login accounts (usernames confirmed by John 2026-04-22)
|
||||
["Reliable Agency shared login #1","Agency caregiver","Caregivers (shift staff)","D+P",false,true,"Shared login — whoever from Reliable Agency is on shift signs in. Username: reliable1@cascadestucson.com (confirmed by John)."],
|
||||
["Reliable Agency shared login #2","Agency caregiver","Caregivers (shift staff)","D+P",false,true,"Shared login — whoever from Reliable Agency is on shift signs in. Username: reliable2@cascadestucson.com (confirmed by John)."],
|
||||
// Agency caregivers — no shared accounts. HIPAA review 2026-04-22: shared logins for PHI
|
||||
// access violate 45 CFR 164.312(a)(2)(i) Unique User Identification. Reliable Agency must
|
||||
// supply individual names before per-person accounts can be provisioned. No rows here
|
||||
// until names arrive.
|
||||
]
|
||||
};
|
||||
const CAREGIVER_DEPT = "Caregivers (shift staff)";
|
||||
|
||||
Binary file not shown.
@@ -29,11 +29,11 @@ Build every person on the 2026-04-22 CSV into a consistent AD + M365 identity, l
|
||||
| **Courtesy Patrol** | D+P | N | N | 3 | Sebastian Leon, Sheldon Gardfrey, Ray Rai |
|
||||
| **Shared-PC Reception** | D | N | N | 4 | Cathy, Shontiel, Kyla, Michelle |
|
||||
| **Caregiver (shared-phone)** | D+P | N | Y | 37 | See caregiver-m365-p2-rollout.md |
|
||||
| **Agency shared login** | D+P | N | Y | 2 | `reliable1`, `reliable2` |
|
||||
| **Agency caregivers (per-person)** | D+P | N | Y | 0 | None created. HIPAA-mandated per-person IDs — Reliable must supply names. No shared logins. |
|
||||
| **Driver (no IT access)** | — | — | — | 3 | Richard Adams, Julian Crim, Christopher Holick — on roster for tracking, existing AD accounts to be disabled |
|
||||
| **Departed (disable/remove)** | — | — | — | 2 | Britney Thompson (has AD+M365, must be disabled), Polett Pinazavala (no account, just remove from roster) |
|
||||
|
||||
(Identities to create or keep active: **68**. Roster-only-no-account: 3 drivers. Departures: Britney + Polett. Christine Nyanzunda sits in one persona — Office-PHI — with her caregiver-shift sign-in handled via exception group if needed.)
|
||||
(Identities to create or keep active: **66**. Roster-only-no-account: 3 drivers. Departures: Britney + Polett. No agency accounts created — per-person names required. Christine Nyanzunda sits in one persona — Office-PHI — with her caregiver-shift sign-in handled via exception group if needed.)
|
||||
|
||||
## 3. License mapping per persona
|
||||
|
||||
@@ -51,14 +51,15 @@ Build every person on the 2026-04-22 CSV into a consistent AD + M365 identity, l
|
||||
| Courtesy Patrol | Business Standard | Could be F3 if they don't need full desktop Office; confirm with Meredith |
|
||||
| Shared-PC Reception | Business Standard | Frontdesk@ stays as shared mailbox, named accounts read it |
|
||||
| Caregiver | **Business Premium** | Per `caregiver-m365-p2-rollout.md` — P2 is load-bearing for shared-phone CA |
|
||||
| Agency shared login | **Business Premium** | Same CA posture as caregivers (shared-phone, building-only) |
|
||||
| Agency caregivers (per-person) | **Business Premium** each | Only provisioned when Reliable Agency provides individual names. Zero created as of 2026-04-22. |
|
||||
| Driver | **None** | No IT access — accounts disabled. License previously used (if any) harvested. |
|
||||
| Britney Thompson (departing) | **None** (harvest) | Disable account, free Business Standard + Exchange Online Essentials |
|
||||
|
||||
Expected license count at full rollout:
|
||||
- Business Premium: 18 (office PHI ext) + 2 (office PHI int) + 1 (Matt) + 37 caregivers + 2 agency = **60**
|
||||
- Business Premium: 18 (office PHI ext) + 2 (office PHI int) + 1 (Matt) + 37 caregivers = **58**
|
||||
- Business Standard: 1 (Ramon) + 3 courtesy + 4 reception = **8**
|
||||
- F3: 0 (drivers no longer need accounts)
|
||||
- Per-person agency: +1 each if/when Reliable Agency provides names
|
||||
|
||||
**Post-2026-04-22 update:** With the building-only-by-default CA decision confirmed, every licensed user needs Entra P1 coverage (either via Business Premium, or Business Standard + standalone Entra P1). Without P1, CA policies don't apply and the user sidesteps the default-deny. This effectively collapses the mixed-SKU table above into a recommendation for **Business Premium tenant-wide (~68 seats)** — the Business Standard rows stay in the table only as a reference for what we'd buy if budget forces unbundling. Proceed with Premium-tenant-wide unless Meredith pushes back. Britney's harvested Business Standard + Exchange Online Essentials license plus any freed driver licenses go back into the pool to offset the Premium purchase.
|
||||
|
||||
@@ -129,27 +130,64 @@ These must be resolved before creating or converting accounts. See also `cascade
|
||||
| **Ederick Yuzon** — spelling not confirmed | **Still pending Meredith/John.** | Block on creation of his caregiver account only. Everyone else proceeds. Tentative: `Ederick.Yuzon` if needed to unblock Wave 3. |
|
||||
| **Matt Brooks** — AD dept = Maintenance, CSV note "works in both departments" | Confirmed (CSV-inline). | Keep in Maintenance OU; add to secondary MC group for access overlap. |
|
||||
| **37 caregivers** — on CSV, none in AD | Unchanged. | Create all 37 AD accounts (+ M365) in Wave 3. |
|
||||
| **2 agency placeholders** — on CSV, not in AD | **RESOLVED 2026-04-22 (John's reply) — usernames `reliable1` / `reliable2` confirmed. Shared logins, not per-person.** | Create 2 shared AD/M365 accounts: `reliable1@cascadestucson.com` and `reliable2@cascadestucson.com`. Audit attribution caveat: individual accountability in sign-in logs is weaker because multiple people share the account. Acceptable tradeoff. |
|
||||
| **2 agency placeholders** — on CSV, not in AD | **RESOLVED 2026-04-22 (Howard, post-HIPAA-review) — NO shared logins. Per-person accounts only.** | Do NOT create `reliable1`/`reliable2`. Reliable Agency must supply individual names before any caregiver can access PHI. Until then, agency staff work under direct supervision of a Cascades-employed caregiver who is signed in. Rationale documented in `docs/security/hipaa-review-2026-04-22.md`. |
|
||||
| **Generic AD accounts** (`Culinary`, `RECEPTIONIST`, `saleshare`, `directoryshare`) | Unchanged. | Phase 5 cleanup after named-account coverage. |
|
||||
|
||||
**Username convention for new accounts:** TitleCase `First.Last` (e.g., `Alma.Montt`, `Kyla.QuickTiffany`). Existing lowercase exceptions in AD (`britney.thompson`, `karen.rossini`, `lauren.hasselman`) are the known legacy cases — leave as-is, don't rename. All net-new accounts follow TitleCase.
|
||||
|
||||
## 7. Rollout sequence
|
||||
|
||||
### Wave 0 — Pre-flight (blocks waves 1+)
|
||||
- **Ederick Yuzon spelling** — only remaining email blocker. Blocks Wave 3 only (his caregiver account); does NOT block Waves 1/2.
|
||||
- Final license decision (Business Premium tenant-wide vs. mixed) — recommendation is Premium tenant-wide, needs Meredith sign-off
|
||||
- Purchase license count locked in
|
||||
### Wave 0 — HIPAA pre-flight (must complete before any account changes)
|
||||
|
||||
### Wave 1 — Departures + new office accounts (ready to execute)
|
||||
- Disable `britney.thompson` AD account; convert mailbox to shared; harvest Business Standard + Exchange Online Essentials license
|
||||
Per `docs/security/hipaa-review-2026-04-22.md`. These are compliance blockers, not operational blockers — fix before touching accounts.
|
||||
|
||||
- **Sign Microsoft HIPAA BAA** (5 min, free) — M365 Admin Center → Settings → Org Settings → Security & Privacy → HIPAA BAA
|
||||
- **Verify/sign ALIS BAA** (Meredith-ask)
|
||||
- **Create break-glass cloud-only admin** (`breakglass@cascadestucson.com`): excluded from all CA, FIDO2 security key, vaulted password, sign-in alerts to Howard + Meredith
|
||||
- **Enable SMB3 encryption** on `\\CS-SERVER\homes`: `Set-SmbShare -Name homes -EncryptData $true`
|
||||
- **Extend M365 audit retention** to 6+ years (Purview Audit Premium add-on or retention policy)
|
||||
- **Put Britney's mailbox on Litigation Hold** with verified archive license — BEFORE her account is disabled
|
||||
- **Ask Meredith** for the Reliable Agency staffing contract (confirm direct-control language = workforce, not BA)
|
||||
- **Draft Risk Analysis** `docs/security/risk-analysis-2026-04.md` following NIST 800-66 Rev 2 §3
|
||||
- **Create Security Rule Implementation Register** `docs/security/implementation-register.md`
|
||||
|
||||
### Wave 0.5 — Entra Connect / AD-M365 identity tie-in (before any account creation in Wave 1)
|
||||
|
||||
Without Entra Connect, new accounts are cloud-only and create the same AD-vs-M365 drift the tenant already suffers from. Install order:
|
||||
|
||||
1. **AD prereq cleanup** (no user impact — all reversible):
|
||||
- Rename `Tamra.Johnson` → `Tamra.Matthews`
|
||||
- Rename `strozzi` → `Shelby.Trozzi`
|
||||
- Rename `Alyssa.Shestko` → `Alyssa.Brooks` + delete lowercase duplicate `alyssa.brooks`
|
||||
- Fix `Christopher.Holik` → `Christopher.Holick`
|
||||
- Fix `Matt.Brooks` UPN to `matthew.brooks@` OR update M365 side to `matt.brooks@`
|
||||
- Delete confirmed former employees (Anna.Pitzlin, Nela.Durut-Azizi, Jodi.Ramstack, Monica.Ramirez)
|
||||
- Disable + remove legacy accounts (Haris.Durut, Nuria.Diaz, Cathy.Reece, Kelly.Wallace, Isabella.Islas, ann.dery)
|
||||
2. **Add UPN suffix** `cascadestucson.com` in AD Domains and Trusts
|
||||
3. **Update all synced users' UPN** to `firstname.lastname@cascadestucson.com`
|
||||
4. **Convert M365 role-based accounts to shared mailboxes** FIRST (accounting@, frontdesk@, hr@, etc. — listed in `docs/cloud/m365.md`) — frees 11 licenses
|
||||
5. **Delete** `Kristiana Dowse` and `howaed` typo accounts from M365
|
||||
6. **Reconcile** `nick pavloff` (M365-only) — create AD account if still employed, or delete
|
||||
7. **CS-SERVER readiness check** (separate task — OS version, .NET, disk, FSMO, conflict with QuickBooks DB listener)
|
||||
8. **Install Entra Connect in staging mode** on CS-SERVER → Password Hash Sync → Seamless SSO → scope to `OU=Departments`
|
||||
9. **Review planned sync output** for unexpected matches/duplicates
|
||||
10. **Take out of staging**, verify users see their cloud mailboxes working on the same password
|
||||
11. **Communicate to users:** Outlook will prompt once for password; enter your Windows password
|
||||
|
||||
User-visible impact: one Outlook password prompt on day-of-cutover. **No impact on AD domain logon.**
|
||||
|
||||
### Wave 1 — Departures + new office accounts (ready after Waves 0 and 0.5)
|
||||
- Disable `britney.thompson` AD account — AFTER Litigation Hold is confirmed, mailbox converted to shared with designated custodian (likely Meredith or Lois), Business Standard + Exchange Online Essentials license harvested
|
||||
- Disable 3 driver AD accounts (`Richard.Adams`, `Julian.Crim`, `Christopher.Holick`)
|
||||
- Ask Meredith whether to keep or retire `Transportation@` shared mailbox
|
||||
- Create AD + M365 for Alma R Montt (`Alma.Montt` — Memory Care Life Enrichment, D+P, ALIS=Y, Outside=Y)
|
||||
- Create AD + M365 for Kyla QuickTiffany (`Kyla.QuickTiffany` — Shared-PC Reception, D only, building-only)
|
||||
- Create AD + M365 for `reliable1@` and `reliable2@` (shared agency logins, D+P, ALIS=Y, building-only)
|
||||
- Create AD accounts (and let Entra Connect sync to M365) for:
|
||||
- Alma R Montt (`Alma.Montt` — Memory Care Life Enrichment, D+P, ALIS=Y, Outside=Y)
|
||||
- Kyla QuickTiffany (`Kyla.QuickTiffany` — Shared-PC Reception, D only, building-only)
|
||||
- Validate group membership + CA policy assignment on the new accounts before moving to Wave 2
|
||||
- Pilot the `CSC - Building Only (Default)` policy with Kyla
|
||||
- Pilot the `CSC - Building Only (Default)` policy with Kyla (Report-only mode first)
|
||||
|
||||
### Wave 1 — DO NOT DO
|
||||
- Do NOT create `reliable1@` or `reliable2@` shared agency accounts (HIPAA review 2026-04-22). See §6 reconciliation + `docs/security/hipaa-review-2026-04-22.md`.
|
||||
|
||||
### Wave 2 — Existing office accounts, reassignment only
|
||||
- Move existing users into new OU layout (no identity changes, just OU move + group membership)
|
||||
@@ -185,6 +223,28 @@ Applies to Wave 1 + Wave 3 (and any future hire). Precise script will be built l
|
||||
- **Folder redirection GPO rollout** (`CONTEXT.md` §48) — when we move users to new OUs, make sure the FR GPOs are re-linked to the new OU or stay linked to parent `OU=Cascades Users`. Test on one mover before batch.
|
||||
- **Intune phone rollout** (`PROJECT_STATE.md`) — caregiver accounts must exist before Wave 3 of phone deployment (24 remaining Samsung A15s). Identity-first, device-second.
|
||||
- **Business Premium purchase proposal** (`docs/proposals/m365-premium-upgrade.md`) — blocks wave 1 if Meredith hasn't approved license spend.
|
||||
- **File-share migration: Synology → CS-SERVER** (`docs/migration/phase2-server-prep.md` §4c–4d + `docs/migration/phase4-synology.md`) — Synology Drive Client is live-syncing `\\cascadesds\*` → `D:\Shares\Main` on CS-SERVER (confirmed 2026-03-07). Before users are cut over to CS-SERVER-sourced mapped drives, the AD security groups used for NTFS ACLs on CS-SERVER (`SG-Management-RW`, `SG-Sales-RW`, `SG-Culinary-RW`, `SG-Directory-RW`, `SG-IT-RW`, `SG-Receptionist-RW`, `SG-Chat-RW`, `SG-Server-RW`) must:
|
||||
1. Exist in AD (created by `scripts/phase2-ad-setup.ps1`)
|
||||
2. Have membership that matches the current per-user access on Synology — a **permission-inventory** step (see below) must produce this mapping before `scripts/phase2-file-shares.ps1` runs
|
||||
3. Populate from the user rollout waves — the 22 office-PHI users, 4 receptionists, 3 courtesy patrol, 1 Matt Brooks (dual-dept), 1 Ramon Castaneda, plus caregivers as needed all land in the right `SG-*` groups at account creation
|
||||
- Additional HIPAA additions to the phase2 script (per `docs/security/hipaa-review-2026-04-22.md`): enable SMB3 encryption (`Set-SmbShare -EncryptData $true` on every share) and enable Object Access auditing for §164.312(b) Audit Controls
|
||||
- Drivers off the SG-* lists entirely — they lose file-share access along with their AD accounts
|
||||
|
||||
### Permission-inventory prerequisite
|
||||
|
||||
A one-time non-destructive read of the live Synology is needed to produce the mapping from Synology local users/groups → AD security groups. Commands (run via SSH to `admin@192.168.0.120`, creds at `clients/cascades-tucson/synology-cascadesds.sops.yaml`):
|
||||
|
||||
```bash
|
||||
sudo synogroup --list # Synology local groups
|
||||
sudo synouser --list # Synology local users
|
||||
sudo cat /etc/synoinfo.conf | grep -i share # share definitions
|
||||
for share in homes Management SalesDept Server chat Public Culinary IT Receptionist directoryshare; do
|
||||
sudo synoacltool -get /volume1/$share # ACLs per share
|
||||
done
|
||||
sudo synoshare --get homes # per-share config incl. SMB encryption state
|
||||
```
|
||||
|
||||
Output goes to `docs/migration/synology-permission-inventory.md`, which is then the reference for populating AD groups and building `phase2-file-shares.ps1` inputs. Discovery is non-destructive and can run any time the Synology is up — does not require a maintenance window.
|
||||
|
||||
## 10. Open decisions blocking the rollout
|
||||
|
||||
@@ -199,7 +259,7 @@ Applies to Wave 1 + Wave 3 (and any future hire). Precise script will be built l
|
||||
- Alma R Montt → `Alma.Montt`, title "Memory Care Life Enrichment", D+P, ALIS=Y, Outside=Y (answered by John).
|
||||
- Britney Thompson → **departed (John)**. Disable AD + harvest license.
|
||||
- Polett Pinazavala → **departed (John)**. Remove from roster.
|
||||
- Agency shared logins → usernames `reliable1` / `reliable2` (confirmed by John).
|
||||
- Agency shared logins → **NOT CREATED** (HIPAA review supersedes John's confirmation — §164.312(a)(2)(i) prohibits shared PHI-access log-ons). Per-person accounts only when Reliable Agency provides names.
|
||||
- Drivers → no IT access per Howard. Disable 3 AD accounts. Stay on roster for tracking.
|
||||
|
||||
## 11. Related docs
|
||||
|
||||
@@ -109,6 +109,13 @@ Run `scripts/phase2-file-shares.ps1` on CS-SERVER (AFTER sync completes).
|
||||
|
||||
Creates SMB shares for synced folders and sets NTFS permissions matching Synology access. **HIPAA §164.312(b):** After shares are created, enable Advanced Audit Logging on all PHI-containing shares (Management, Server, homes) to track read/write/delete operations.
|
||||
|
||||
**Prerequisite (added 2026-04-22 per `docs/security/hipaa-review-2026-04-22.md` + user-rollout dependency):** Before this script runs, the Synology permission inventory must be captured and translated to AD security group memberships. See `docs/migration/phase4-synology.md` §6.0.1–6.0.2 for the discovery commands and `docs/migration/synology-permission-inventory.md` (to be created) for the mapping output.
|
||||
|
||||
**HIPAA-review additions (must be applied as part of this phase, not deferred):**
|
||||
- `Set-SmbShare -EncryptData $true` on every share in the table — satisfies Addressable specs §164.312(a)(2)(iv) at-rest and §164.312(e)(2)(ii) in-transit encryption
|
||||
- NTFS SACL (audit rule) set to audit Success + Failure for ReadData / WriteData / Delete / ChangePermissions on all PHI shares — satisfies Required spec §164.312(b) Audit Controls
|
||||
- See `phase4-synology.md` §6.0.3 for the exact PowerShell
|
||||
|
||||
| Share | NTFS Access | SMB Share |
|
||||
|---|---|---|
|
||||
| Management | SG-Management-RW = Modify | `\\CS-SERVER\Management` |
|
||||
|
||||
@@ -1,5 +1,86 @@
|
||||
# Step 6: Synology Transition (~2 hours, remote)
|
||||
|
||||
**Pre-requisite before any of the 6.x steps below:** a permission inventory of the live Synology must be captured and translated into AD group memberships, and CS-SERVER's NTFS + SMB permissions on the synced shares must match before users' drives get remapped. That work lives in §6.0.
|
||||
|
||||
---
|
||||
|
||||
## 6.0 — Permission inventory + CS-SERVER ACL application (pre-cutover)
|
||||
|
||||
**Why:** Synology Drive Client has been live-syncing `\\cascadesds\*` → `D:\Shares\Main` on CS-SERVER since 2026-03-07 (per `phase2-server-prep.md` §4c). Sync copies the files but **not** the permissions — CS-SERVER's shares inherit whatever the script in `phase2-file-shares.ps1` applies, which currently assumes AD security group memberships that are correct for the target state. Those group memberships are empty or incomplete today.
|
||||
|
||||
Before users' mapped drives switch from Synology to CS-SERVER, the ACLs on CS-SERVER must replicate current Synology access rights. Do this in three steps.
|
||||
|
||||
### 6.0.1 — Discovery (non-destructive, no maintenance window needed)
|
||||
|
||||
SSH into `admin@192.168.0.120` (credentials at `clients/cascades-tucson/synology-cascadesds.sops.yaml`). Run:
|
||||
|
||||
```bash
|
||||
sudo synogroup --list
|
||||
sudo synouser --list
|
||||
sudo cat /etc/synoinfo.conf | grep -iE 'share|mode'
|
||||
for share in homes Management SalesDept Server chat Public Culinary IT Receptionist directoryshare; do
|
||||
echo "=== $share ==="
|
||||
sudo synoacltool -get /volume1/$share
|
||||
sudo synoshare --get "$share" 2>/dev/null || true
|
||||
done
|
||||
```
|
||||
|
||||
Paste the output into a new file `docs/migration/synology-permission-inventory.md` with one section per share. Capture:
|
||||
|
||||
- Owner, group, mode (bitmask)
|
||||
- Per-user ACL entries (read / write / delete / changeperm)
|
||||
- Per-group ACL entries
|
||||
- SMB-share-level permission overrides
|
||||
- Inheritance flags
|
||||
|
||||
### 6.0.2 — Map Synology accounts to AD
|
||||
|
||||
Produce a translation table in the inventory doc:
|
||||
|
||||
| Synology identity | AD identity | Notes |
|
||||
|---|---|---|
|
||||
| `admin` | Domain Admins | keep |
|
||||
| `meredith.kuhn` (Synology local) | `Meredith.Kuhn` (AD) | same human |
|
||||
| Synology group `Management` | AD `SG-Management-RW` | direct 1:1 |
|
||||
| Synology group `Marketing` | AD `SG-Sales-RW` | renamed |
|
||||
| ... | ... | ... |
|
||||
|
||||
Any Synology account with no AD equivalent either (a) corresponds to a departed employee and gets dropped, or (b) is a new account we need to create in AD first (feeds back into the user rollout waves).
|
||||
|
||||
### 6.0.3 — Apply to CS-SERVER + HIPAA additions
|
||||
|
||||
Update `scripts/phase2-file-shares.ps1` inputs to reflect the mapping, then run on CS-SERVER. After shares + NTFS are applied, add HIPAA-review-required settings per `docs/security/hipaa-review-2026-04-22.md`:
|
||||
|
||||
```powershell
|
||||
# Enable SMB3 encryption on every PHI-containing share (addresses 164.312(a)(2)(iv), (e)(2)(ii))
|
||||
foreach ($share in 'homes','Management','SalesDept','Server','chat','Culinary','IT','Receptionist','directoryshare') {
|
||||
Set-SmbShare -Name $share -EncryptData $true -Force
|
||||
}
|
||||
|
||||
# Enable Object Access auditing on the PHI file-share root (addresses 164.312(b))
|
||||
auditpol /set /subcategory:"File System" /success:enable /failure:enable
|
||||
# NTFS SACL — audit reads+writes on D:\Shares and subtree
|
||||
$acl = Get-Acl D:\Shares
|
||||
$auditRule = New-Object System.Security.AccessControl.FileSystemAuditRule(
|
||||
'Everyone','ReadData,WriteData,Delete,ChangePermissions','ContainerInherit,ObjectInherit','None','Success,Failure')
|
||||
$acl.AddAuditRule($auditRule)
|
||||
Set-Acl D:\Shares $acl
|
||||
```
|
||||
|
||||
Verify with:
|
||||
|
||||
```powershell
|
||||
Get-SmbShare | Select-Object Name, EncryptData
|
||||
Get-Acl D:\Shares -Audit | Format-List
|
||||
auditpol /get /subcategory:"File System"
|
||||
```
|
||||
|
||||
### 6.0.4 — Validation before any user is cut over
|
||||
|
||||
Pick one pilot user (Sharon Edwards on DESKTOP-DLTAGOI — already our folder-redirection pilot). Map her CS-SERVER drives manually, open representative files from each share she currently uses on Synology, verify open/save/delete works. Do not touch the GPO drive maps or run §6.1 below until the pilot validates cleanly.
|
||||
|
||||
**Rollback at this stage:** no user impact — just don't push the GPO change, and the Synology shares remain authoritative.
|
||||
|
||||
---
|
||||
|
||||
## 6.1 — Verify drive mappings
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
# ============================================================================
|
||||
# Entra Connect Pre-flight Remediation - CS-SERVER
|
||||
# ----------------------------------------------------------------------------
|
||||
# Applies the three items from the 2026-04-22 readiness check:
|
||||
# 1. Time sync (w32tm) - immediate, no reboot
|
||||
# 2. TLS 1.2 enforcement (.NET + Schannel) - requires reboot
|
||||
# 3. Install Windows Server Backup feature - no reboot
|
||||
#
|
||||
# Then schedules a reboot at 18:00 local time (Arizona) for Schannel changes
|
||||
# to take effect. Snapshot of all pre-change state is written to
|
||||
# D:\Backups\pre-entra-connect-<timestamp>\ for rollback.
|
||||
#
|
||||
# To cancel the scheduled reboot at any time before 18:00: shutdown /a
|
||||
# ----------------------------------------------------------------------------
|
||||
# Prepared: 2026-04-22
|
||||
# Source: docs/migration/scripts/entra-connect-preflight-remediation.ps1
|
||||
# ============================================================================
|
||||
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$TargetRebootHour = 18 # 6 PM local (Arizona)
|
||||
|
||||
function Section($n) {
|
||||
Write-Output ''
|
||||
Write-Output ('=' * 72)
|
||||
Write-Output "== $n"
|
||||
Write-Output ('=' * 72)
|
||||
}
|
||||
|
||||
function Status($ok, $msg) {
|
||||
$tag = if ($ok) { '[OK] ' } else { '[FAIL]' }
|
||||
Write-Output "$tag $msg"
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Section '0. Pre-flight snapshot (rollback material)'
|
||||
# ----------------------------------------------------------------------------
|
||||
$ts = Get-Date -Format 'yyyy-MM-dd-HHmm'
|
||||
$backupDir = "D:\Backups\pre-entra-connect-$ts"
|
||||
try {
|
||||
New-Item -Path $backupDir -ItemType Directory -Force | Out-Null
|
||||
Status $true "Backup dir: $backupDir"
|
||||
} catch {
|
||||
Status $false "Could not create $backupDir - $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Export registry keys we're about to modify
|
||||
reg export "HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" "$backupDir\dotnet-64.reg" /y 2>&1 | Out-Null
|
||||
reg export "HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319" "$backupDir\dotnet-32.reg" /y 2>&1 | Out-Null
|
||||
reg export "HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols" "$backupDir\schannel-protocols-pre.reg" /y 2>&1 | Out-Null
|
||||
Status $true 'Registry pre-state exported (.NET + Schannel Protocols)'
|
||||
|
||||
# Snapshot w32tm state
|
||||
w32tm /query /configuration 2>&1 | Out-File "$backupDir\w32tm-config-pre.txt"
|
||||
w32tm /query /status 2>&1 | Out-File "$backupDir\w32tm-status-pre.txt"
|
||||
w32tm /query /peers 2>&1 | Out-File "$backupDir\w32tm-peers-pre.txt"
|
||||
Status $true 'w32tm pre-state captured'
|
||||
|
||||
# Snapshot recent events (for post-reboot comparison)
|
||||
try {
|
||||
Get-WinEvent -LogName System -MaxEvents 200 -ErrorAction Stop |
|
||||
Select-Object TimeCreated, Id, LevelDisplayName, ProviderName, Message |
|
||||
Export-Csv "$backupDir\events-system-pre.csv" -NoTypeInformation
|
||||
Status $true "Event log snapshot saved (200 System events)"
|
||||
} catch {
|
||||
Status $false "Event log snapshot: $_"
|
||||
}
|
||||
|
||||
Write-Output ''
|
||||
Write-Output ("To roll back TLS changes after reboot: " +
|
||||
"`nreg import $backupDir\dotnet-64.reg `nreg import $backupDir\dotnet-32.reg " +
|
||||
"`nreg import $backupDir\schannel-protocols-pre.reg `nRestart-Computer")
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Section '1. Time sync fix (w32tm) - no reboot'
|
||||
# ----------------------------------------------------------------------------
|
||||
try {
|
||||
# PDC emulator should be an authoritative time source + sync from external pool
|
||||
$ntpPeers = 'time.windows.com,0x8 pool.ntp.org,0x8 time.nist.gov,0x8'
|
||||
& w32tm /config /manualpeerlist:$ntpPeers /syncfromflags:manual /reliable:yes /update | Out-Null
|
||||
Status $true "Configured w32tm peer list: $ntpPeers"
|
||||
|
||||
Restart-Service w32time -Force
|
||||
Status $true 'Restarted w32time service'
|
||||
|
||||
Start-Sleep 4
|
||||
& w32tm /resync /force 2>&1 | Out-Null
|
||||
Start-Sleep 3
|
||||
|
||||
$statusOut = & w32tm /query /status 2>&1
|
||||
$statusOut | Out-File "$backupDir\w32tm-status-post.txt"
|
||||
$statusOut | Select-Object -First 20 | ForEach-Object { Write-Output " $_" }
|
||||
|
||||
$refIdLine = $statusOut | Where-Object { $_ -match 'ReferenceId' } | Select-Object -First 1
|
||||
if ($refIdLine -match 'LOCL') {
|
||||
Status $false "ReferenceId still LOCL - w32tm has not synced yet. Check firewall for outbound UDP 123."
|
||||
} else {
|
||||
Status $true "ReferenceId: $refIdLine (no longer LOCL)"
|
||||
}
|
||||
} catch {
|
||||
Status $false "Time sync fix: $_"
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Section '2. TLS 1.2 enforcement (.NET + Schannel) - requires reboot'
|
||||
# ----------------------------------------------------------------------------
|
||||
# .NET framework: enable strong crypto + system default TLS versions for both
|
||||
# 64-bit and 32-bit runtimes. These take effect immediately for new processes.
|
||||
foreach ($p in 'HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319',
|
||||
'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319') {
|
||||
try {
|
||||
if (-not (Test-Path $p)) { New-Item -Path $p -Force | Out-Null }
|
||||
New-ItemProperty -Path $p -Name 'SchUseStrongCrypto' -PropertyType DWord -Value 1 -Force | Out-Null
|
||||
New-ItemProperty -Path $p -Name 'SystemDefaultTlsVersions' -PropertyType DWord -Value 1 -Force | Out-Null
|
||||
Status $true ".NET TLS keys set at $p"
|
||||
} catch {
|
||||
Status $false ".NET TLS at $p - $_"
|
||||
}
|
||||
}
|
||||
|
||||
# Schannel: disable TLS 1.0 and 1.1 (both Client and Server). Enable TLS 1.2
|
||||
# explicitly. Takes effect only after reboot.
|
||||
$base = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols'
|
||||
foreach ($proto in 'TLS 1.0','TLS 1.1') {
|
||||
foreach ($role in 'Client','Server') {
|
||||
$k = "$base\$proto\$role"
|
||||
try {
|
||||
if (-not (Test-Path $k)) { New-Item -Path $k -Force | Out-Null }
|
||||
New-ItemProperty -Path $k -Name 'Enabled' -PropertyType DWord -Value 0 -Force | Out-Null
|
||||
New-ItemProperty -Path $k -Name 'DisabledByDefault' -PropertyType DWord -Value 1 -Force | Out-Null
|
||||
Status $true "Disabled $proto $role"
|
||||
} catch {
|
||||
Status $false "Disable $proto $role - $_"
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($role in 'Client','Server') {
|
||||
$k = "$base\TLS 1.2\$role"
|
||||
try {
|
||||
if (-not (Test-Path $k)) { New-Item -Path $k -Force | Out-Null }
|
||||
New-ItemProperty -Path $k -Name 'Enabled' -PropertyType DWord -Value 1 -Force | Out-Null
|
||||
New-ItemProperty -Path $k -Name 'DisabledByDefault' -PropertyType DWord -Value 0 -Force | Out-Null
|
||||
Status $true "Enabled TLS 1.2 $role"
|
||||
} catch {
|
||||
Status $false "Enable TLS 1.2 $role - $_"
|
||||
}
|
||||
}
|
||||
|
||||
# Snapshot post-state for audit
|
||||
reg export "HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols" "$backupDir\schannel-protocols-post.reg" /y 2>&1 | Out-Null
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Section '3. Install Windows Server Backup feature - no reboot'
|
||||
# ----------------------------------------------------------------------------
|
||||
try {
|
||||
$feature = Get-WindowsFeature -Name Windows-Server-Backup
|
||||
if ($feature.InstallState -eq 'Installed') {
|
||||
Status $true 'Windows-Server-Backup already installed'
|
||||
} else {
|
||||
$result = Install-WindowsFeature -Name Windows-Server-Backup -IncludeManagementTools
|
||||
if ($result.Success) {
|
||||
Status $true "Installed Windows-Server-Backup. RestartNeeded: $($result.RestartNeeded)"
|
||||
} else {
|
||||
Status $false "Install-WindowsFeature returned Success=False"
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Status $false "WSB install: $_"
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Section "4. Schedule reboot for $TargetRebootHour`:00 local"
|
||||
# ----------------------------------------------------------------------------
|
||||
$now = Get-Date
|
||||
$target = $now.Date.AddHours($TargetRebootHour)
|
||||
if ($target -lt $now) { $target = $target.AddDays(1) }
|
||||
$seconds = [int]($target - $now).TotalSeconds
|
||||
|
||||
Write-Output "Current time: $now"
|
||||
Write-Output "Target reboot: $target"
|
||||
Write-Output "Delay: $seconds seconds ($([math]::Round($seconds/60,1)) minutes)"
|
||||
|
||||
if ($seconds -lt 60) {
|
||||
Status $false "Target reboot is less than 1 minute away - not scheduling. Run again closer to window."
|
||||
} elseif ($seconds -gt 86400) {
|
||||
Status $false "Target reboot more than 24 hours away - $seconds seconds. Rejecting."
|
||||
} else {
|
||||
# /r restart, /t timeout, /d p:4:2 = Planned / Application: Maintenance
|
||||
# /c comment (<512 chars) shows in user popup + event log
|
||||
# No /f - we want graceful shutdown of services (AD, Hyper-V, QB VSS)
|
||||
$comment = 'Entra Connect preflight: TLS 1.2 + time sync enforcement. Cancel: shutdown /a'
|
||||
shutdown /r /t $seconds /d p:4:2 /c $comment
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Status $true "Reboot scheduled for $target (in $seconds sec). Cancel with: shutdown /a"
|
||||
} else {
|
||||
Status $false "shutdown command returned exit $LASTEXITCODE"
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Section '5. Summary'
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Output "Backup/rollback dir: $backupDir"
|
||||
Write-Output "Reboot scheduled: $target"
|
||||
Write-Output 'Cancel reboot: shutdown /a'
|
||||
Write-Output ''
|
||||
Write-Output 'Post-reboot verification:'
|
||||
Write-Output ' 1. w32tm /query /status - confirm ReferenceId is no longer LOCL'
|
||||
Write-Output ' 2. nltest /dsgetdc:cascades.local - confirm DC is responding'
|
||||
Write-Output ' 3. Re-run entra-connect-readiness.ps1 for full pass/fail sweep'
|
||||
Write-Output ''
|
||||
Write-Output "Completed at $(Get-Date)"
|
||||
@@ -0,0 +1,288 @@
|
||||
# ============================================================================
|
||||
# Entra Connect Readiness Check - CS-SERVER
|
||||
# ----------------------------------------------------------------------------
|
||||
# Read-only diagnostic. No state changes. No service restarts. No registry
|
||||
# writes. Safe to run on a production DC at any time. Takes ~30-60 seconds.
|
||||
#
|
||||
# Output is structured text with section headers. Copy the full output back
|
||||
# to Howard for analysis.
|
||||
#
|
||||
# Prepared: 2026-04-22
|
||||
# Target: CS-SERVER (cascades.local single DC)
|
||||
# Prerequisite check for: Entra Connect install per user-account-rollout-plan
|
||||
# ============================================================================
|
||||
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$sep = '=' * 76
|
||||
|
||||
function Write-Section($title) {
|
||||
Write-Output ''
|
||||
Write-Output $sep
|
||||
Write-Output "== $title"
|
||||
Write-Output $sep
|
||||
}
|
||||
|
||||
function Write-Check($label, $value, $status = '') {
|
||||
$marker = switch ($status) {
|
||||
'PASS' { '[OK] ' }
|
||||
'WARN' { '[WARN] ' }
|
||||
'FAIL' { '[FAIL] ' }
|
||||
default { ' ' }
|
||||
}
|
||||
Write-Output ("{0}{1,-40}: {2}" -f $marker, $label, $value)
|
||||
}
|
||||
|
||||
Write-Output "Entra Connect Readiness Check - $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz')"
|
||||
Write-Output "Host: $env:COMPUTERNAME"
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '1. Operating System'
|
||||
# ----------------------------------------------------------------------------
|
||||
$os = Get-CimInstance Win32_OperatingSystem
|
||||
Write-Check 'OS Caption' $os.Caption
|
||||
Write-Check 'OS Version' $os.Version
|
||||
Write-Check 'OS Build' $os.BuildNumber
|
||||
Write-Check 'Architecture' $os.OSArchitecture
|
||||
Write-Check 'Install Date' ($os.InstallDate)
|
||||
Write-Check 'Last Boot' ($os.LastBootUpTime)
|
||||
Write-Check 'Uptime (days)' ([math]::Round(((Get-Date) - $os.LastBootUpTime).TotalDays, 1))
|
||||
$osMajor = [int]($os.Version -split '\.')[0]
|
||||
$osBuild = [int]$os.BuildNumber
|
||||
$osStatus = if ($osBuild -ge 14393) { 'PASS' } else { 'FAIL' }
|
||||
Write-Check 'Server 2016+ required' "$($os.Caption) -> $osStatus" $osStatus
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '2. .NET Framework version'
|
||||
# ----------------------------------------------------------------------------
|
||||
# Release key lookup: https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed
|
||||
$netKey = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' -ErrorAction SilentlyContinue
|
||||
if ($netKey) {
|
||||
$release = $netKey.Release
|
||||
$netName = switch ($true) {
|
||||
($release -ge 533320) { '4.8.1' }
|
||||
($release -ge 528040) { '4.8' }
|
||||
($release -ge 461808) { '4.7.2' }
|
||||
($release -ge 461308) { '4.7.1' }
|
||||
($release -ge 460798) { '4.7' }
|
||||
($release -ge 394802) { '4.6.2' }
|
||||
default { "Older (release=$release)" }
|
||||
}
|
||||
$netStatus = if ($release -ge 461808) { 'PASS' } else { 'FAIL' }
|
||||
Write-Check '.NET Framework version' $netName
|
||||
Write-Check '.NET release key' $release
|
||||
Write-Check '.NET 4.7.2+ required' "$netName -> $netStatus" $netStatus
|
||||
} else {
|
||||
Write-Check '.NET Framework v4 Full' 'NOT INSTALLED' 'FAIL'
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '3. PowerShell'
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Check 'PSVersion' $PSVersionTable.PSVersion
|
||||
Write-Check 'PSEdition' $PSVersionTable.PSEdition
|
||||
$psStatus = if ($PSVersionTable.PSVersion.Major -ge 5) { 'PASS' } else { 'FAIL' }
|
||||
Write-Check 'PS 5.0+ required' "$($PSVersionTable.PSVersion) -> $psStatus" $psStatus
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '4. TLS 1.2 configuration'
|
||||
# ----------------------------------------------------------------------------
|
||||
# Entra Connect requires TLS 1.2 enforced for outbound sync
|
||||
$net4 = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319' -Name SchUseStrongCrypto,SystemDefaultTlsVersions -ErrorAction SilentlyContinue
|
||||
$net4w = Get-ItemProperty 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319' -Name SchUseStrongCrypto,SystemDefaultTlsVersions -ErrorAction SilentlyContinue
|
||||
Write-Check '.NET SchUseStrongCrypto (64-bit)' $net4.SchUseStrongCrypto
|
||||
Write-Check '.NET SchUseStrongCrypto (32-bit)' $net4w.SchUseStrongCrypto
|
||||
Write-Check '.NET SystemDefaultTlsVersions (64)' $net4.SystemDefaultTlsVersions
|
||||
Write-Check '.NET SystemDefaultTlsVersions (32)' $net4w.SystemDefaultTlsVersions
|
||||
foreach ($role in 'Client','Server') {
|
||||
foreach ($proto in 'TLS 1.0','TLS 1.1','TLS 1.2') {
|
||||
$k = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$proto\$role"
|
||||
$v = Get-ItemProperty $k -ErrorAction SilentlyContinue
|
||||
$enabled = if ($v) { "Enabled=$($v.Enabled) DisabledByDefault=$($v.DisabledByDefault)" } else { 'unset (OS default)' }
|
||||
Write-Check "SCHANNEL $proto $role" $enabled
|
||||
}
|
||||
}
|
||||
Write-Output '(Entra Connect requires TLS 1.2 client enabled; TLS 1.0/1.1 should be disabled per HIPAA best practice.)'
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '5. Disk space'
|
||||
# ----------------------------------------------------------------------------
|
||||
Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" | ForEach-Object {
|
||||
$free = [math]::Round($_.FreeSpace / 1GB, 1)
|
||||
$total = [math]::Round($_.Size / 1GB, 1)
|
||||
$pct = if ($_.Size) { [math]::Round(100 * $_.FreeSpace / $_.Size, 1) } else { 0 }
|
||||
Write-Check "Drive $($_.DeviceID)" "$free GB free of $total GB ($pct% free)"
|
||||
}
|
||||
Write-Output '(Entra Connect needs ~5-20 GB free on install drive, typically C:.)'
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '6. AD Domain + FSMO roles'
|
||||
# ----------------------------------------------------------------------------
|
||||
try {
|
||||
Import-Module ActiveDirectory -ErrorAction Stop
|
||||
$dom = Get-ADDomain
|
||||
$for = Get-ADForest
|
||||
Write-Check 'Domain' $dom.DNSRoot
|
||||
Write-Check 'NetBIOS name' $dom.NetBIOSName
|
||||
Write-Check 'Forest mode' $for.ForestMode
|
||||
Write-Check 'Domain mode' $dom.DomainMode
|
||||
Write-Check 'Schema master' $for.SchemaMaster
|
||||
Write-Check 'Domain naming master' $for.DomainNamingMaster
|
||||
Write-Check 'PDC emulator' $dom.PDCEmulator
|
||||
Write-Check 'RID master' $dom.RIDMaster
|
||||
Write-Check 'Infrastructure master' $dom.InfrastructureMaster
|
||||
$userCount = (Get-ADUser -Filter * -ResultSetSize $null | Measure-Object).Count
|
||||
$groupCount = (Get-ADGroup -Filter * -ResultSetSize $null | Measure-Object).Count
|
||||
$ouCount = (Get-ADOrganizationalUnit -Filter * | Measure-Object).Count
|
||||
Write-Check 'AD user count' $userCount
|
||||
Write-Check 'AD group count' $groupCount
|
||||
Write-Check 'AD OU count' $ouCount
|
||||
} catch {
|
||||
Write-Check 'AD module' "FAIL: $_" 'FAIL'
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '7. AD Schema version'
|
||||
# ----------------------------------------------------------------------------
|
||||
try {
|
||||
$schema = Get-ADObject (Get-ADRootDSE).schemaNamingContext -Property objectVersion
|
||||
Write-Check 'Schema objectVersion' $schema.objectVersion
|
||||
$schemaName = switch ($schema.objectVersion) {
|
||||
88 { 'Windows Server 2019' }
|
||||
87 { 'Windows Server 2016' }
|
||||
69 { 'Windows Server 2012 R2' }
|
||||
56 { 'Windows Server 2012' }
|
||||
47 { 'Windows Server 2008 R2' }
|
||||
default { "Unknown ($($schema.objectVersion))" }
|
||||
}
|
||||
Write-Check 'Schema version (mapped)' $schemaName
|
||||
} catch {
|
||||
Write-Check 'AD Schema' "FAIL: $_" 'FAIL'
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '8. Time sync'
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Output '(Entra Connect requires clock within ~5 min of Microsoft time.)'
|
||||
$w32status = w32tm /query /status 2>&1
|
||||
$w32status | Out-String | Write-Output
|
||||
$w32peers = w32tm /query /peers 2>&1
|
||||
$w32peers | Out-String | Write-Output
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '9. Internet connectivity to Microsoft sync endpoints'
|
||||
# ----------------------------------------------------------------------------
|
||||
$endpoints = @(
|
||||
'login.microsoftonline.com',
|
||||
'login.windows.net',
|
||||
'secure.aadcdn.microsoftonline-p.com',
|
||||
'management.azure.com',
|
||||
'graph.windows.net',
|
||||
'adminwebservice.microsoftonline.com',
|
||||
'provisioningapi.microsoftonline.com'
|
||||
)
|
||||
foreach ($e in $endpoints) {
|
||||
$r = Test-NetConnection -ComputerName $e -Port 443 -InformationLevel Quiet -WarningAction SilentlyContinue
|
||||
$status = if ($r) { 'PASS' } else { 'FAIL' }
|
||||
Write-Check "HTTPS 443 -> $e" $r $status
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '10. WinHTTP proxy'
|
||||
# ----------------------------------------------------------------------------
|
||||
netsh winhttp show proxy | Out-String | Write-Output
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '11. Existing Entra Connect / AAD Sync installations'
|
||||
# ----------------------------------------------------------------------------
|
||||
$svcs = Get-Service -Name 'ADSync','MIISERVER','Microsoft Azure AD Sync' -ErrorAction SilentlyContinue
|
||||
if ($svcs) {
|
||||
$svcs | ForEach-Object { Write-Check "Existing service $($_.Name)" "$($_.Status) - CONFLICT" 'WARN' }
|
||||
} else {
|
||||
Write-Check 'Entra Connect / AAD Sync service' 'Not found (expected)' 'PASS'
|
||||
}
|
||||
$aadApps = Get-CimInstance Win32_Product -Filter "Name LIKE '%Azure AD%' OR Name LIKE '%Entra%' OR Name LIKE '%AADSync%'" -ErrorAction SilentlyContinue |
|
||||
Select-Object Name, Version, InstallDate
|
||||
if ($aadApps) {
|
||||
$aadApps | Format-Table -AutoSize | Out-String | Write-Output
|
||||
} else {
|
||||
Write-Check 'Azure/Entra installed products' 'none' 'PASS'
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '12. SQL services (LocalDB conflict check)'
|
||||
# ----------------------------------------------------------------------------
|
||||
# Entra Connect installs SQL Server 2019 LocalDB by default. Existing SQL
|
||||
# instances are not a conflict (different service name), but worth noting.
|
||||
$sql = Get-Service -Name 'MSSQL*' -ErrorAction SilentlyContinue
|
||||
if ($sql) {
|
||||
$sql | ForEach-Object { Write-Check "$($_.Name)" "$($_.Status) ($($_.DisplayName))" }
|
||||
} else {
|
||||
Write-Check 'Existing SQL services' 'none'
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '13. Key services running (potential conflicts / heavy load)'
|
||||
# ----------------------------------------------------------------------------
|
||||
$watch = 'NTDS','DNS','DHCPServer','W3SVC','vmms','Spooler','SynoDriveClient','QBIDPService','QuickBooksDB34','DattoAV','ScreenConnect','SyncroDeviceAgent','Splashtop Streamer'
|
||||
Get-Service -Name $watch -ErrorAction SilentlyContinue | Sort-Object Name | ForEach-Object {
|
||||
Write-Check "Service $($_.Name)" "$($_.Status) - $($_.DisplayName)"
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '14. Memory + CPU pressure (current)'
|
||||
# ----------------------------------------------------------------------------
|
||||
$mem = Get-CimInstance Win32_OperatingSystem
|
||||
$memTotal = [math]::Round($mem.TotalVisibleMemorySize / 1MB, 1)
|
||||
$memFree = [math]::Round($mem.FreePhysicalMemory / 1MB, 1)
|
||||
$memUsed = [math]::Round($memTotal - $memFree, 1)
|
||||
$memPct = [math]::Round(100 * $memUsed / $memTotal, 0)
|
||||
Write-Check 'RAM total (GB)' $memTotal
|
||||
Write-Check 'RAM in use (GB)' "$memUsed ($memPct%)"
|
||||
Write-Check 'RAM free (GB)' $memFree
|
||||
$cpu = Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average
|
||||
Write-Check 'CPU load (avg %)' ([math]::Round($cpu.Average,1))
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '15. Event log health (last 24h)'
|
||||
# ----------------------------------------------------------------------------
|
||||
$since = (Get-Date).AddHours(-24)
|
||||
foreach ($log in 'System','Application') {
|
||||
$ev = Get-WinEvent -FilterHashtable @{LogName=$log; Level=1,2; StartTime=$since} -ErrorAction SilentlyContinue
|
||||
$crit = ($ev | Where-Object Level -eq 1 | Measure-Object).Count
|
||||
$err = ($ev | Where-Object Level -eq 2 | Measure-Object).Count
|
||||
Write-Check "$log log errors/critical" "$err errors, $crit critical"
|
||||
if ($ev) {
|
||||
$ev | Group-Object ProviderName |
|
||||
Sort-Object Count -Descending |
|
||||
Select-Object -First 5 Count, Name |
|
||||
Format-Table -AutoSize | Out-String | Write-Output
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '16. DC health (dcdiag subset)'
|
||||
# ----------------------------------------------------------------------------
|
||||
# Focused tests only - full dcdiag is ~2 minutes. Skip if too slow.
|
||||
Write-Output '--- dcdiag /test:connectivity,fsmocheck,services,advertising /v (trimmed) ---'
|
||||
$dc = dcdiag /test:connectivity /test:fsmocheck /test:services /test:advertising 2>&1
|
||||
$dc | Where-Object { $_ -match 'Starting test|passed test|failed test|warning|error' } | Out-String | Write-Output
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '17. Windows Features (Server Backup etc.)'
|
||||
# ----------------------------------------------------------------------------
|
||||
$features = Get-WindowsFeature -Name 'Windows-Server-Backup','ADDS-AdminCenter','RSAT-AD-PowerShell','RSAT-AD-Tools' -ErrorAction SilentlyContinue
|
||||
$features | Format-Table Name, InstallState -AutoSize | Out-String | Write-Output
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section '18. Certificate expirations (local cert store, expires < 90d)'
|
||||
# ----------------------------------------------------------------------------
|
||||
Get-ChildItem Cert:\LocalMachine\My, Cert:\LocalMachine\Root -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.NotAfter -lt (Get-Date).AddDays(90) -or $_.NotAfter -lt (Get-Date) } |
|
||||
Sort-Object NotAfter |
|
||||
Select-Object Subject, NotAfter, Thumbprint |
|
||||
Format-Table -AutoSize -Wrap | Out-String | Write-Output
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Section 'Done'
|
||||
# ----------------------------------------------------------------------------
|
||||
Write-Output "Completed at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz')"
|
||||
169
clients/cascades-tucson/docs/security/hipaa-review-2026-04-22.md
Normal file
169
clients/cascades-tucson/docs/security/hipaa-review-2026-04-22.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# HIPAA Compliance Review — 2026-04-22 User Account Rollout
|
||||
|
||||
**Reviewed by:** Howard Enos (Computer Guru)
|
||||
**Scope:** Decisions captured in `docs/cloud/user-account-rollout-plan.md` as of 2026-04-22
|
||||
**Trigger:** Client request for a pre-execution compliance check before creating / disabling accounts
|
||||
**Primary references:** 45 CFR Part 164 Subpart C (HIPAA Security Rule), NIST SP 800-66 Rev 2 (Feb 2024), HHS OCR guidance
|
||||
|
||||
---
|
||||
|
||||
## Findings classified CRITICAL — must fix before rollout
|
||||
|
||||
### C1. Shared agency logins would violate §164.312(a)(2)(i) — Unique User Identification
|
||||
|
||||
Original plan: create `reliable1@cascadestucson.com` and `reliable2@cascadestucson.com` as shared accounts for rotating Reliable Agency caregivers.
|
||||
|
||||
**Rule:** §164.312(a)(2)(i) Unique User Identification is a **Required** implementation spec (not Addressable). HHS has explicitly answered this in public FAQ: covered entities may not assign the same log-on ID to multiple employees. There is no compensating-control carve-out because Required specs don't permit alternatives. NIST SP 800-66 Rev 2 maps this to SP 800-53 IA-2 (Identification and Authentication) and AC-2 (Account Management), which likewise require individual accounts.
|
||||
|
||||
**Decision 2026-04-22:** Drop `reliable1` / `reliable2`. Require Reliable Agency to supply individual caregiver names before any shift where PHI access is needed. Per-person accounts only. If the agency won't commit, agency staff work under direct supervision of a Cascades-employed caregiver who is signed in — no independent PHI access.
|
||||
|
||||
**Docs updated:** `user-account-rollout-plan.md` §6 and Wave 1; `cascades-staff-working-list-2026-04-22.md`; `cascades-staff-editor-2026-04-22.html`; `p2-staff-candidates.md`; `caregiver-m365-p2-rollout.md`; `cascades-staff-followup-2026-04-22.md`.
|
||||
|
||||
---
|
||||
|
||||
### C2. Britney Thompson mailbox must be placed on Litigation Hold before disable + mailbox conversion
|
||||
|
||||
**Rule:** §164.308(a)(3)(ii)(C) Termination Procedures + §164.316(b)(2)(i) 6-year documentation retention.
|
||||
|
||||
**Issue:** Business Standard doesn't include unlimited archive/hold. Converting a licensed mailbox to shared can trim content based on default retention settings, potentially purging PHI subject to state medical-records retention (AZ = 7 years post-last-encounter) or subpoena.
|
||||
|
||||
**Decision:** Before disabling `britney.thompson`:
|
||||
1. Place mailbox on Litigation Hold (verify Business Standard has Exchange Online Plan 2 features; if not, temporarily assign an EOA or E3 before harvest)
|
||||
2. Designate a named custodian (recommended: Meredith Kuhn as Executive Director, or Lois Lane as Health Services Director)
|
||||
3. Then disable sign-in, revoke tokens
|
||||
4. Then convert to shared and harvest user license
|
||||
|
||||
Documentation of the termination action retained ≥6 years per §164.316(b)(2).
|
||||
|
||||
---
|
||||
|
||||
### C3. Microsoft M365 BAA not yet signed
|
||||
|
||||
**Rule:** §164.308(b)(1) Business Associate contracts.
|
||||
|
||||
**Issue:** `docs/cloud/m365.md` line 12 and `docs/security/hipaa.md` gap #13 note that no Microsoft HIPAA BAA has been signed. Every day Cascades uses M365 for PHI without a BAA is a continuing Security Rule violation. Every new account we provision expands that exposure.
|
||||
|
||||
**Decision:** Sign the Microsoft BAA **before Wave 1** — M365 Admin Center → Settings → Org Settings → Security & Privacy → HIPAA BAA. Free, 5 minutes.
|
||||
|
||||
Parallel: verify or secure an ALIS BAA (go-alis.com) before any new caregiver accesses ALIS.
|
||||
|
||||
---
|
||||
|
||||
### C4. No formal Risk Analysis on file (§164.308(a)(1)(ii)(A) — Required)
|
||||
|
||||
**Rule:** A formal risk analysis covering scope, threats, likelihood, impact, and control effectiveness is Required (not Addressable).
|
||||
|
||||
**Issue:** Cross-doc sweep confirmed no standalone risk analysis document exists. The existing `hipaa.md` gap list is a useful inventory but does not meet the Security Rule's definition.
|
||||
|
||||
**Decision:** Produce `docs/security/risk-analysis-2026-04.md` following the NIST 800-66 Rev 2 §3 framework before Wave 2. Reference it in every Addressable-spec decision.
|
||||
|
||||
---
|
||||
|
||||
## Findings classified HIGH — fix in Wave 1 or before
|
||||
|
||||
### H1. M365 audit log retention default (1 year) is insufficient
|
||||
|
||||
**Rule:** §164.312(b) Audit Controls + §164.316(b)(2) 6-year documentation retention. OCR enforcement posture treats audit logs as documentation subject to the 6-year clock.
|
||||
|
||||
**Decision:** Purchase Microsoft Purview Audit (Premium) add-on (10-year retention) OR configure a retention policy for 7 years via E5 Compliance OR monthly export to immutable Azure Blob. Decision documented in Security Rule Implementation Register (see M2 below).
|
||||
|
||||
---
|
||||
|
||||
### H2. No documented break-glass emergency access account (§164.312(a)(2)(ii) — Required)
|
||||
|
||||
**Decision:** Create `breakglass@cascadestucson.com` — cloud-only (not AD-synced), excluded from all CA policies, protected by FIDO2 security key + unique vaulted password in `clients/cascades-tucson/breakglass.sops.yaml`, sign-in alerted to Howard + Meredith, quarterly test sign-in. Must exist before disabling any other admin accounts.
|
||||
|
||||
---
|
||||
|
||||
### H3. `\\CS-SERVER\homes` SMB3 encryption not enabled; folder redirection routes PHI to that share
|
||||
|
||||
**Rule:** §164.312(a)(2)(iv) Encryption/Decryption + §164.312(e)(2)(ii) Transmission Encryption (both Addressable).
|
||||
|
||||
**Issue:** `CONTEXT.md` notes `EncryptData=false` on the homes share. Folder redirection GPO pushes Documents / Desktop / Downloads — including staff-generated PHI — to that share. In-transit encryption is off; at-rest encryption status on CS-SERVER's D: drive is not documented.
|
||||
|
||||
**Decision:** Before Alma / Kyla folder redirection goes live:
|
||||
- `Set-SmbShare -Name homes -EncryptData $true` (immediate, free)
|
||||
- Verify / enable BitLocker on CS-SERVER D: drive
|
||||
- Document both decisions in Implementation Register
|
||||
|
||||
---
|
||||
|
||||
### H4. Drivers need Privacy Rule training + signed sanctions acknowledgment (workforce, not IT)
|
||||
|
||||
**Rule:** §164.530(b)(1) Privacy training for workforce; §164.530(e) sanctions apply to all workforce; §160.103 defines workforce inclusive of workers with no electronic system access.
|
||||
|
||||
**Issue:** Decision that drivers don't need IT access is correct; however, drivers encounter PHI on pickup sheets (rider names, appointment context).
|
||||
|
||||
**Decision (not an IT deliverable):** Flag to Meredith. Drivers need annual short-form Privacy training, signed confidentiality / sanctions acknowledgment, and documented pickup-sheet handling procedures. If dispatch uses personal phones for texts with rider names, those phones now trigger mobile-device safeguards (§164.312(a)(1) + (e)) — consider moving dispatch to a controlled channel.
|
||||
|
||||
---
|
||||
|
||||
## Findings classified MEDIUM — address before Wave 3 (caregiver bulk)
|
||||
|
||||
### M1. Automatic-logoff duration not codified for shared front-desk PCs and MSDM sign-out
|
||||
|
||||
**Rule:** §164.312(a)(2)(iii) Automatic Logoff (Addressable).
|
||||
|
||||
**Decision:**
|
||||
- GPO `CSC - Shared Workstation`: screen lock at 10 min idle, sign-out at 30 min idle, disable Fast User Switching
|
||||
- MSDM global sign-out timer: 15 min idle
|
||||
- Both documented in Implementation Register as the Addressable-spec implementation
|
||||
|
||||
---
|
||||
|
||||
### M2. No Security Rule Implementation Register
|
||||
|
||||
**Rule:** §164.306(d)(3) Addressable spec decisions; §164.316(b)(1)-(2) documentation retention.
|
||||
|
||||
**Decision:** Create `docs/security/implementation-register.md` — one row per Addressable spec (encryption at rest, encryption in transit, automatic logoff, emergency access mode, integrity controls) with: decision, rationale tied to risk analysis, alternative measure if applicable, owner, next review date. This is the artifact OCR asks for in an audit.
|
||||
|
||||
---
|
||||
|
||||
### M3. Reliable Agency — Business Associate status not determined
|
||||
|
||||
**Decision:** Ask Meredith for the Reliable Agency staffing contract. Confirm direct-control language (workforce) vs. agency-directed (Business Associate). If no workforce-control language, either secure an addendum OR sign a BAA with Reliable. No individual agency-caregiver accounts created until this is sorted.
|
||||
|
||||
---
|
||||
|
||||
### M4. Christine Nyanzunda's single-account dual-role access scoping
|
||||
|
||||
**Rule:** §164.308(a)(4)(ii)(B) Access Authorization (Addressable — minimum necessary).
|
||||
|
||||
**Decision:** Single account retained (MC Admin + part-time MedTech). Document in Implementation Register that operational simplicity was weighed against strict minimum-necessary. Mitigation: rely on ALIS's internal role-based access controls to scope her view based on shift / context if supported.
|
||||
|
||||
---
|
||||
|
||||
## Findings classified GOOD — HIPAA-aligned decisions being kept
|
||||
|
||||
- **Building-only CA default + allow-list for outside sign-in** — defensible implementation of §164.312(a)(1) Access Control, stronger than baseline
|
||||
- **Shared front-desk PCs with individual M365 accounts** — fully compliant (identity is per-person; hardware sharing is fine)
|
||||
- **MSDM shared phones with per-user Entra sign-in** — satisfies unique-ID + automatic-logoff on the mobile tier
|
||||
- **Drivers with no electronic PHI access** — correct minimum-necessary scoping on the IT side
|
||||
- **Same-day account disable on termination** — meets termination-procedure timing
|
||||
- **Business Premium tenant-wide recommendation** — provides the P1 + Defender + DLP + Intune baseline the rest of the design relies on
|
||||
- **Decline to reinstate Sandra Fish admin** — correct; 2026-04-14 revocation stands
|
||||
|
||||
---
|
||||
|
||||
## Open questions unresolved at review time
|
||||
|
||||
| # | Question | Owner |
|
||||
|---|---|---|
|
||||
| 1 | Does Business Standard (current SKU for 23 users) include Exchange Online Plan 2 features needed for Litigation Hold? If not, what's the cheapest path to EOA on Britney's mailbox before harvest? | Howard (verify in M365 Admin Center) |
|
||||
| 2 | Reliable Agency staffing contract — direct-control language or not? | Meredith |
|
||||
| 3 | Audit retention path chosen (Purview Premium add-on vs. E5 Compliance vs. export to immutable storage)? | Meredith (budget) + Howard (design) |
|
||||
| 4 | BitLocker state on CS-SERVER D: drive — enabled, encrypted-no-protectors, or off? | Howard (verify onsite or via SSH) |
|
||||
|
||||
---
|
||||
|
||||
## Source material cited
|
||||
|
||||
- [45 CFR §164.312 — Technical safeguards (eCFR)](https://www.ecfr.gov/current/title-45/subtitle-A/subchapter-C/part-164/subpart-C/section-164.312)
|
||||
- [45 CFR §164.316 — Policies, procedures, documentation (eCFR)](https://www.ecfr.gov/current/title-45/subtitle-A/subchapter-C/part-164/subpart-C/section-164.316)
|
||||
- [45 CFR §164.308 — Administrative safeguards (eCFR)](https://www.ecfr.gov/current/title-45/subtitle-A/subchapter-C/part-164/subpart-C/section-164.308)
|
||||
- [HHS FAQ — shared log-on IDs not permitted](https://www.hhs.gov/hipaa/for-professionals/faq/2018/does-the-security-rule-permit-a-covered-entity-to-assign-the-same-log-on-id-to-multiple-employees/index.html)
|
||||
- [HHS FAQ — Addressable vs Required implementation specs](https://www.hhs.gov/hipaa/for-professionals/faq/2020/what-is-the-difference-between-addressable-and-required-implementation-specifications/index.html)
|
||||
- [HHS — Business Associates guidance](https://www.hhs.gov/hipaa/for-professionals/privacy/guidance/business-associates/index.html)
|
||||
- [NIST SP 800-66 Rev 2 — Implementing the HIPAA Security Rule (Feb 2024)](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-66r2.pdf)
|
||||
- [Microsoft Learn — Entra HIPAA access control safeguards](https://learn.microsoft.com/en-us/entra/standards/hipaa-access-controls)
|
||||
- [Microsoft Learn — Shared device mode overview](https://learn.microsoft.com/en-us/entra/identity-platform/msal-shared-devices)
|
||||
Reference in New Issue
Block a user