Cyber Home Lab: Identity Controls in a Live Tenant, Audited Against Themselves

In progress

Entra ID and SharePoint governance built in a real Microsoft 365 tenant — then reviewed against itself, which is how I found that the audit log had never been turned on.

Verified Confirmed against the repo 2026-10-25. Two of its labs are still in progress, and Conditional Access is report-only, not enforcing.

m365 iam grc security

At a glance

Problem
Every other GRC project I've built is a simulation for a company that doesn't exist. Paper controls can be written to pass their own review. A real tenant pushes back.
What I built
Identity and information-governance controls in a live Microsoft 365 tenant — privileged access moved from standing to just-in-time, an access review run to completion, SharePoint permissions broken out of inheritance, external sharing tightened per-site, and unified audit logging enabled and proven.
Evidence
45 screenshots, PowerShell scripts with their session transcripts, exported Conditional Access policy JSON, a sign-in log export, and a POA&M — all committed to the repo.
Status
In progress, and genuinely so.

Verified Confirmed against the repo on 2026-10-25. Lab 02 (cloud identity) is marked Complete; Lab 06 (SharePoint) is In progress with Days 1-4 done and Days 5-6 outstanding; Lab 04 (Active Directory) is In progress; Lab 05 (STIG) is empty scaffolding and nothing here claims it. The audit-log timeline quoted below is the real transcript output committed at 05-sharepoint-admin/transcripts/02-search-unified-audit-log.txt. Conditional Access policies are configured in report-only and are not enforcing; Security Defaults is what enforces MFA in this tenant today.

The problem

My GRC Security Program case study builds a complete program for a fictional coffee shop. It's honest about being a simulation, but a simulation has a structural weakness: I wrote the controls and the evidence and the review. Nothing in it could tell me I was wrong.

So I wanted the opposite — a real tenant with real licensing limits and real consequences for misconfiguration — and then to review my own work in it the way an auditor would. The interesting result wasn't the controls I configured. It was what the review found about them.

What I built

Configure, evidence, review, finding, POA&M Controls are configured in a live tenant, which produces evidence, which is reviewed. The review produces findings that feed a POA&M, and the POA&M loops back into configuration. Four findings came out of reviewing my own work. Configure Evidence Review Findings POA&M remediate 4 findings, all against my own work
The same loop as the GRC Security Program diagram, run against a real tenant instead of a fictional company. The difference is that this one produced findings I didn't want.

Two halves, in one tenant.

Identity (Entra ID). Users, a security group, and a scoped role assignment — alice.admin as Security Reader, deliberately not Global Administrator. Conditional Access policies for MFA and sign-in risk, plus one requiring phishing-resistant authentication strength rather than the generic "require MFA" grant, which any registered method satisfies including SMS.

The piece worth dwelling on is privileged access. Alice's Security Reader role started as a standing Active assignment with no expiration — access she holds whether or not she's using it. Using PIM, that became an eligible assignment she has to activate, the standing one was removed, and role settings now require approver sign-off rather than self-service justification.

Entra ID Privileged Identity Management, Security Reader assignments, Eligible assignments tab: Alice Admin listed as a Direct, Permanent eligible assignment at Self scope, with the tenant domain redacted.
After conversion — the Eligible tab. The Active tab for this role is empty, which is the actual claim: no standing privileged access.

That assignment was then recertified through a one-time access review, with "require reason on approval" turned on so the decision carries a recorded justification.

Entra ID access review results: Alice Admin, Outcome Approved, Recommended action Deny, reviewed by Michael Nault on 7/4/2026, with tenant domains redacted.
The system recommended Deny — Alice has never signed in, so there's no usage justifying the role. I approved anyway, since the account exists to demonstrate the assignment. That disagreement is the point of a review: a recorded human decision, not a rubber stamp.

Information governance (SharePoint Online). A document library broken out of permission inheritance, an eDiscovery case with legal hold and content search, and one decision worth spelling out: the tenant-wide external sharing default was "Anyone", the most permissive tier. Rather than tighten the whole tenant, I overrode sharing at site level for the site holding restricted evidence and left the looser default alone.

Decisions and trade-offs

What went wrong, and what I changed

I went to pull an audit report on sharing activity and found that unified audit logging had never been turned on in this tenant at all. Not misconfigured — never enabled. Every action from the first day of the lab had happened without being recorded.

Enabling it is not retroactive. That history is simply gone and cannot be reconstructed.

Then the fix went wrong in a more interesting way. I'd concluded the blocker was that the tenant had never run Enable-OrganizationCustomization, a one-time Exchange Online bootstrap that tenant-wide admin cmdlets depend on. I wrote a remediation script to run both steps. Its own before-check reported IsDehydrated: False — the organization was already customized, probably triggered silently by an earlier admin-center action. My diagnosis was wrong. The actual fix was one line: Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true.

So I verified it end to end rather than trusting the toggle. I performed a deliberate test action — granting a user read access to the restricted library — and searched the log for it. Twenty-seven records came back, and the timeline matched what I'd actually done, including the part I'd done wrong:

5:52:50 PM   PermissionLevelAdded x6
5:54:19 PM   SharingInheritanceBroken, SharingSet
6:11:13 PM   SharingSet x4

The 5:52 cluster is a mistake. I first granted access through the Teams Add members panel, which adds someone as an M365 Group Member — a group role, not a SharePoint permission level — handing them Edit through the group's existing entry on the library. Restricting the file itself to view-only then did nothing, because SharePoint permissions are additive, not overriding: a narrower item-level grant can't revoke access already held through a broader group one. The 5:54 pair is me undoing it; 6:11 is the correct approach, an explicit Read entry on the library's own unique permissions.

The audit log I'd just finished fixing captured my own error, with a timestamp and an actor. That is precisely what an audit log is for, and I'd rather demonstrate it that way than with a clean timeline that proves nothing.

SharePoint Restricted-Evidence library permissions: Alice Admin with Edit, Bob Reader with Read, and three SharePoint groups — Compliance-Evidence Members with Edit, Owners with Full Control, Visitors with Read.
The access review this produces: five entries, each one accounted for. The two named users were granted explicitly and appear in the audit log with an actor and timestamp; the three groups were copied onto the library when inheritance was broken. Nothing here is an unreviewed default.

What's verified, and what isn't

What I'd do next

Links

Keep reading

Next: Home EDR: From Watching My Own PC to a Governance Pipeline