A first-principles approach to reducing access risk, cleaning identity sprawl, and improving audit readiness.
Aging analysis is the practice of classifying user accounts by time-based signals (e.g., last sign-in, last password change, time since creation, and time since last entitlement change) to identify accounts that are inactive, stale, orphaned, or over-privileged. It turns a messy identity estate into an actionable queue: review → remediate → prevent recurrence.
Why it matters (risk model)
From first principles, access risk is driven by a simple product: Risk ≈ (likelihood of misuse) × (impact of misuse) × (time exposed). Account aging analysis targets the time exposed factor directly and reduces likelihood by shrinking the set of “forgotten” identities.
- Stale accounts increase attack surface: credentials may be leaked, reused, or guessed, and nobody notices because the account is “quiet.”
- Orphaned accounts (no valid owner) break accountability and fail audits.
- Over-privileged dormant accounts are the most dangerous class: high impact with low detection probability.
- Identity sprawl increases operational cost: more tickets, more policy exceptions, more uncertainty.
Aging analysis is not just “disable old accounts.” Done correctly, it is a lifecycle control: it finds the backlog and then prevents the backlog from reappearing.
Core signals and what they actually tell you
Aging analysis works when your signals map to real-world states. The most useful signals are below; each has failure modes and must be interpreted in context.
| Signal | What it indicates | Common caveats |
|---|---|---|
| Last sign-in | Account activity / presence | Non-interactive sign-ins (tokens, service principals), cached logons, and system processes can make “activity” look human. |
| Account creation date | How long an identity has existed | Old account ≠ risky by itself. It becomes risky when combined with inactivity, missing owner, or privilege. |
| Password last changed | Credential hygiene / rotation | Passwordless and SSO reduce relevance; service accounts may have non-expiring passwords (which should be replaced with managed identities/secrets). |
| Last group/role change | Entitlement freshness | Harder to collect consistently across systems. Still valuable for privilege aging and certification cycles. |
| MFA status & method | Resilience against credential compromise | MFA present ≠ safe if weak methods or poor enforcement. Track enforcement and exceptions. |
| Owner/manager | Accountability | HR drift: managers change, contractors roll off, shared mailboxes replace people. Missing owner is a strong remediation trigger. |
Practical rule: never take a single signal as the verdict. Use combinations (e.g., “no sign-in for 90 days” + “privileged role” + “no owner”).
Account taxonomy (humans, service, external)
Aging rules must differ by account type. A single “inactive for 60 days” policy applied to everything will either break systems or miss risk.
1) Human accounts (employees, contractors)
- Primary signal: interactive sign-in inactivity
- Secondary signals: HR status (active/terminated), manager, device compliance, MFA enforcement
2) Service accounts / non-human identities
- Primary signal: authentication events and workload activity (API calls, scheduled tasks, app logs)
- Secondary signals: secret/cert rotation, owner/team, change window, dependency mapping
- Key objective: replace static credentials with managed identities or workload identity federation where possible
3) External/guest accounts
- Primary signal: last sign-in + last resource access
- Secondary signals: sponsorship (internal owner), expiration policy, invited vs redeemed status
- Key objective: time-bound access by default
Every non-human identity must have an explicit owning team and a rotation/attestation cadence. If ownership is unknown, treat it as a defect to fix.
Methodology: define, measure, bucket, act
A reliable aging analysis pipeline has four steps:
- Define your signals, sources, and account types (taxonomy).
- Measure with consistent data extraction and normalization (timestamps, time zones, event types).
- Bucket accounts into clear aging bands and risk tiers.
- Act via an action matrix with approvals, exceptions, and automation.
Data sources (typical)
- Directory: AD / Entra ID / LDAP
- SSO / IdP logs: interactive vs non-interactive sign-ins
- HR system: employment status, start/end dates, manager
- Privileged access: admin role assignments, PAM/PIM activation logs
- Asset/endpoint: device compliance, last check-in
- Application logs: for service identities and APIs
Normalization choices that prevent bad decisions
- Choose one canonical time zone for reporting (store raw timestamps, report normalized).
- Separate interactive and non-interactive sign-ins.
- Ensure “last sign-in” is the max of relevant signals (directory attribute alone is often incomplete).
- Track “unknown” explicitly; don’t silently coerce nulls to old dates.
Recommended aging buckets
Buckets should be stable, understandable, and aligned to real operational rhythms (monthly access reviews, quarterly audits). Below is a practical starting point for human accounts; tune to your environment.
| Bucket | Inactivity (interactive sign-in) | Interpretation |
|---|---|---|
| Active | 0–30 days | Normal usage. |
| Cooling | 31–60 days | Potential leave/rotation. Start soft checks. |
| Stale | 61–90 days | High probability of unnecessary access. Begin remediation workflow. |
| Dormant | 91–180 days | Strong candidate for disablement unless justified. |
| Abandoned | 181+ days | Almost certainly not required. Disable and investigate ownership/status. |
For service accounts, use different buckets (e.g., based on workload activity or token usage), and never disable without dependency validation.
Action matrix (what to do per bucket)
Aging analysis is only valuable when each bucket produces a consistent action. The goal is a deterministic playbook with exceptions handled through policy.
| Bucket | Default action | Approvals / checks | Notes |
|---|---|---|---|
| Cooling | Notify owner/manager; verify HR status | None (informational) | Catch vacations/role changes early. |
| Stale | Remove high-risk entitlements (admin groups) or require re-attestation | Manager + app owner attestation | Least privilege first: reduce impact before disablement. |
| Dormant | Disable account; revoke sessions/tokens; reset credentials if policy requires | HR status check; ticket record | Provide a defined re-enable path with identity proofing. |
| Abandoned | Disable + move to quarantine OU/group; remove access; investigate ownership | Security sign-off for privileged accounts | Keep evidence: last sign-in, roles, mailbox access, device associations. |
Apply stricter thresholds. Example: “no interactive use for 14–30 days” triggers entitlement removal or requires explicit re-approval. The correct default is: privilege is temporary unless actively needed.
Implementation blueprint
Step 1: Establish the identity inventory
- Export all identities with immutable IDs, account type, owner, and status.
- Classify into human/service/guest, then sub-classify (admin, break-glass, shared mailbox, etc.).
- Define “source of truth” for employment status (usually HR).
Step 2: Build the aging dataset
- Collect last interactive sign-in, last non-interactive sign-in, last password change, creation date, last role/group change (if available).
- Enrich with privilege level: admin roles, tier-0 groups, sensitive app assignments.
- Enrich with accountability: manager/owner and owning team distribution list.
Step 3: Score risk (optional but useful)
Buckets are easy to operationalize; a risk score helps prioritize within buckets. A simple additive model is often enough:
- +3 if privileged
- +2 if no owner/manager
- +2 if MFA not enforced
- +2 if external/guest with no sponsor
- +1 if password age > policy
- +1 if device unknown/non-compliant (for human accounts)
Keep scoring interpretable. The value is prioritization, not “math theater.”
Step 4: Automate the workflow
- Generate a weekly report (or dashboard) and create tickets for “Stale/Dormant/Abandoned” according to the action matrix.
- For “Dormant/Abandoned,” automate disablement after required approvals and waiting periods.
- For guests, enforce expirations by policy (e.g., 30/60/90 days) and require sponsor renewal.
Step 5: Prevent recurrence
- Joiner/Mover/Leaver (JML) process integrated with HR triggers.
- Default expirations for contractors and guests.
- Privilege elevation through time-bound access (PAM/PIM) instead of permanent admin membership.
- Mandatory owner field for service identities; prohibit “unknown owner.”
Example output schema (for your report)
identity_id
username
account_type # human | service | guest
employment_status # active | leave | terminated | unknown
owner_team
manager
created_at
last_interactive_signin
last_noninteractive_signin
password_last_changed
privilege_tier # none | elevated | admin | tier0
mfa_enforced # true | false | unknown
aging_bucket # active | cooling | stale | dormant | abandoned
recommended_action
ticket_id / workflow_state
Common pitfalls and how to avoid them
-
Using directory-only “last logon” attributes as truth.
Mitigation: rely on centralized sign-in logs where possible; reconcile across sources. -
Disabling service accounts based on “no interactive sign-in.”
Mitigation: separate non-human identities and use workload activity + dependency mapping. -
Ignoring ownership gaps.
Mitigation: treat “no owner” as a defect; implement policy gates that require owners for creation. -
Over-relying on password age in modern SSO environments.
Mitigation: focus on MFA enforcement, session revocation, token hygiene, and conditional access posture. -
No re-enable process.
Mitigation: define identity proofing steps, approvals, and a safe reactivation workflow.
KPIs and reporting
Track both the backlog (current exposure) and the flow (process health). Useful KPIs:
- Stale/Dormant/Abandoned count by account type and business unit
- Privileged stale accounts (count and % of privileged population)
- Mean time to remediate (MTTR) for each bucket
- % accounts with valid owner (especially service identities)
- Guest account average age and % expired/renewed on time
- Exceptions volume and top exception reasons (used to improve policy)
Show two numbers for every bucket: count and privileged count. This aligns stakeholders quickly on what matters.
Quick checklist
- ☐ Separate human, service, and guest identities before applying aging rules
- ☐ Use sign-in logs (interactive vs non-interactive) as primary activity evidence
- ☐ Define buckets and actions that map to operations (tickets, approvals, automation)
- ☐ Remove privilege earlier than you disable accounts
- ☐ Enforce owners for service identities and sponsors for guests
- ☐ Automate disablement with a safe quarantine + re-enable path
- ☐ Integrate with JML so stale accounts don’t re-accumulate
- ☐ Track backlog + flow KPIs and publish them regularly
