NIST SP 800-53 Rev. 5 · Access Control
AC-2 on Microsoft Sentinel
Residual access after termination — a published KQL query you can run against Microsoft Sentinel / Log Analytics, with the evidence it needs, the settings you decide, and what a result does and does not establish.
Why this matters
A departed employee whose access was never switched off
When someone leaves an organization, their accounts are supposed to be disabled. In practice the human resources record and the computer system are often maintained by different people using different tools, and accounts survive departures. Those accounts are a recurring feature of real breach reports.
Why this check earns its place. It requires joining two sources that do not normally talk to each other — the staff record and the directory. That join is the work most small organizations cannot do for themselves.
- What it reads
- The organization's staff-departure records joined to its user directory.
- What it reports
- Accounts still active after the person's recorded departure date.
See related public disclosures on the Signals page →
What this finds
Identity still enabled after the recorded termination date, with no unexpired access extension.
The requirement
The organization must disable or remove information system accounts when an individual is terminated, transferred, or otherwise no longer requires access, within an organization-defined time period.
NIST SP 800-53 Rev. 5 — AC-2 (Account Management).
NIST states the objective. The authoritative lifecycle source, the subject-matching identifier, the permitted grace period, and the exception workflow are all organization-defined — not NIST-prescribed values.
How this maps to the CISA performance goals
The Cross-Sector Cybersecurity Performance Goals are a voluntary baseline published by CISA — the U.S. federal agency for critical-infrastructure cybersecurity — written for organizations too small to employ security staff. This control speaks to:
- 3.D — Revoke credentials for departing staff
The goal is revoking access when someone leaves; the pack finds access that outlived a termination.
See the full coverage map, including the goals no query can answer →
Evidence this query needs
HR termination events hr_termination_events.csv
Establishes when an individual's employment ended so directory state can be compared against it. Without this file, an enabled account is just an enabled account — there is nothing to compare it to.
Minimum fields: user_principal_name, employment_status, effective_date
A UPN, a status, and a date are enough to run the check. Everything else improves the reviewer's ability to dismiss a false positive without going back to HR.
The query
Published as ac-2-residual-access.azure.kql. Reads IdentityInfo (UEBA), HRTerminations_CL (supplied). Requires: Log Analytics Reader.
Before this returns anything,
IdentityInfo (UEBA) has to be reaching Microsoft Sentinel / Log Analytics, and HRTerminations_CL (supplied) has to be landed there. If not, the query reports nothing found — which looks
exactly like nothing wrong. What has to be switched on first →
// AC-2 -- identities still enabled after an HR termination event
// Requires the hr_termination_events contract landed as HRTerminations_CL.
let LookbackDays = 90d;
let Terminations =
HRTerminations_CL
| where TimeGenerated > ago(LookbackDays)
| where EmploymentStatus_s =~ "terminated"
| summarize arg_max(TimeGenerated, *) by UserKey = tolower(UserPrincipalName_s)
| project UserKey,
EffectiveDate = EffectiveDate_t,
RetainAccessUntil = column_ifexists("RetainAccessUntil_t", datetime(null));
IdentityInfo
| where TimeGenerated > ago(1d)
| summarize arg_max(TimeGenerated, *) by AccountUPN
| project UserKey = tolower(AccountUPN), AccountDisplayName,
IsAccountEnabled, SourceSystem = "Microsoft Entra ID"
| join kind=inner Terminations on UserKey
| where IsAccountEnabled == true
| where EffectiveDate < now()
// Approved access extension suppresses the finding until it lapses
| where isnull(RetainAccessUntil) or RetainAccessUntil < now()
| extend DaysSinceTermination = datetime_diff('day', now(), EffectiveDate)
| project UserKey, AccountDisplayName, SourceSystem,
EffectiveDate, RetainAccessUntil, DaysSinceTermination
| order by DaysSinceTermination desc
Open this pack on Microsoft Sentinel to adjust the settings and download it →
The interactive version opens on Microsoft Sentinel — the platform on this page — even if your environment profile does not list it.
Settings you decide
NIST states the objective and leaves these to your organization. The interactive version of this pack applies them to the query for you.
- Disablement grace period (days) (default 0)
- Accounts are only reported once this many days have passed since the effective termination date.
- HR feed lookback (days) (default 90)
- How far back to read termination records. Must exceed your HR export cadence.
- Limit to specific accounts (optional)
- Paste user principal names, one per line, to scope the query to a defined population.
Running it continuously
Sentinel scheduled analytics rule
Rule type: Scheduled query rule
Run frequency: Every 1 hour
Lookup period: Last 24 hours
Trigger: Number of query results > 0
Entity mapping: Account -> UserKey
Severity: High
MITRE tactic: Persistence (T1078 Valid Accounts)
Incident: Create incident, group alerts by Account entity
Suppression: 24 hours per matched account
Each run returning rows creates an incident with the affected account mapped as an entity, so the analyst can pivot straight to that identity's other activity.
What a result does not prove
An enabled account does not by itself establish unauthorized access or a control failure. Identifier quality, export timing, and accounts held in other directories all remain contextual.
Validation status for this platform: Not tenant-validated. Structure, query generation, and preflight are covered by the project's automated test suites. This pack has not been executed against a live tenant, account, or index. Validate it in a non-production scope before relying on any result.
Before you act on a result
- Is the HR feed authoritative and complete for this population?
- Does an approved extension, legal hold, or rehire explain the account remaining enabled?
- Could an alias or renamed account have produced an incorrect match?
- Has downstream application access been revoked, not just the directory account?
Common questions
- How do I check for residual access after termination in Microsoft Sentinel?
- Run the published KQL query on this page against Microsoft Sentinel / Log Analytics. It reads IdentityInfo (UEBA), HRTerminations_CL (supplied) and reports: Identity still enabled after the recorded termination date, with no unexpired access extension.
- What permissions are needed to run this Microsoft Sentinel query?
- Log Analytics Reader.
- What evidence does AC-2 need that Microsoft Sentinel cannot produce?
- HR termination events (hr_termination_events.csv). Establishes when an individual's employment ended so directory state can be compared against it. Without this file, an enabled account is just an enabled account — there is nothing to compare it to. At minimum it must carry: user_principal_name, employment_status, effective_date.
- Does a result from this query mean the control has failed?
- An enabled account does not by itself establish unauthorized access or a control failure. Identifier quality, export timing, and accounts held in other directories all remain contextual.
Terms used on this page
- NIST SP 800-53the U.S. federal catalogue of security requirements
- The catalogue of security and privacy requirements published by the National Institute of Standards and Technology, a U.S. federal agency. U.S. government systems are measured against it, and many private organizations adopt it voluntarily. Each requirement has an identifier such as AC-2. Official source →
- CISACybersecurity and Infrastructure Security Agency
- The U.S. federal agency responsible for national critical-infrastructure cybersecurity. Its publications are works of the U.S. government and are free to use. Official source →
- KQLKusto Query Language
- The language used to ask questions of data held in Microsoft Sentinel. A query written in it is text, like a spreadsheet formula, and can be read before it is run.
- CPGCross-Sector Cybersecurity Performance Goals
- A voluntary baseline of security practices published by the U.S. Cybersecurity and Infrastructure Security Agency, written specifically for organizations too small to employ security staff. It is a short, plainly written starting list rather than a full standard. Official source →
- not tenant-validatednever executed against real data
- The check has passed the project's automated tests for structure and syntax, but has never been run against real data anywhere. Test it in a safe scope before relying on any result.
The same control on other platforms
- AC-2 on AWS — SQL (Athena) + Lambda
- AC-2 on Splunk — SPL
- All platforms for AC-2