Worst Part Of The Job Today
Worst Part Of The Job Today
Introduction
The terminal blinked back at me with cold indifference as I typed the commands - userdel jsmith, passwd -l jsmith, az ad user delete --id jsmith@contoso.com. Each keystroke felt like driving nails into a coffin. My colleague’s Slack avatar grayed out instantly, their GitHub contributions graph froze mid-curve, and their SSH keys evaporated from production systems. This is the worst part of our profession - the digital euthanasia required when team members leave organizations, whether through tragedy, termination, or transition.
In the world of DevOps and system administration, we architect robust infrastructures, automate deployment pipelines, and harden security postures. But no certification prepares you for the moment when infrastructure management intersects with human mortality. The Reddit sysadmin who shared their experience of disabling a deceased coworker’s account articulated what many of us have felt but seldom discuss - the emotional weight of our technical responsibilities.
This guide addresses the unspoken reality of privileged access management in extreme scenarios. We’ll examine:
- The technical and ethical dimensions of account deprovisioning
- Automated systems for access revocation
- Audit trails and compliance requirements
- Psychological considerations for technical teams
Whether managing enterprise Active Directory forests or self-hosted homelab environments, these principles remain critical. A single stale credential can become an attack vector, yet reckless deletion can destroy institutional knowledge. We’ll navigate this minefield with technical precision and human sensitivity.
Understanding Account Deprovisioning
What Is Access Revocation?
Account deprovisioning is the systematic removal of digital privileges and credentials from users who no longer require access. In DevOps contexts, this spans multiple layers:
| Access Layer | Examples | Risks of Inadequate Deprovisioning |
|---|---|---|
| Infrastructure | SSH keys, VPN credentials | Privilege escalation, data exfiltration |
| Cloud Platforms | IAM roles, service principals | Resource hijacking, cryptojacking |
| Development Tools | Git repositories, CI/CD pipelines | Code sabotage, secret leakage |
| Business Systems | CRM, ERP, HRIS access | Data privacy violations, fraud |
The Evolution of Identity Management
The history of access control reveals why deprovisioning remains challenging:
- Mainframe Era (1960s): Physical access logs and shared operator accounts
- Client-Server (1980s): Domain controllers with manual user management
- Directory Services (1990s): LDAP/Active Directory with group policies
- Cloud Era (2010s): Federated identities across SaaS/PaaS/IaaS
- Zero Trust (2020s): Continuous authentication with JIT access
Each paradigm added complexity. Modern organizations average 75 SaaS applications per employee (BetterCloud, 2022), creating a sprawling attack surface that demands automated deprovisioning.
Technical and Ethical Challenges
Technical Complexities:
- Orphaned resources (S3 buckets, VM instances)
- Service account dependencies
- Multi-cloud IAM inconsistencies
- Replication latency in distributed systems
Human Factors:
- Emotional impact on technical staff
- Legal requirements (SOX, HIPAA, GDPR)
- Knowledge preservation vs. security
- Cultural norms around digital legacy
Prerequisites for Responsible Deprovisioning
Technical Foundation
Before implementing deprovisioning workflows, ensure:
- Centralized Identity Provider:
- Active Directory (on-prem)
- Azure AD/Entra ID (cloud)
- OpenLDAP (open-source)
- Okta/Ping Identity (SaaS)
- Automation Capabilities:
- SCIM 2.0 provisioning
- Webhook integrations
- Infrastructure-as-Code (Terraform, CloudFormation)
- Audit Systems:
- SIEM (Splunk, ELK Stack)
- CloudTrail/Azure Activity Logs
- Open-source alternatives like Wazuh
Policy Requirements
- Legal Compliance:
- GDPR Article 17 (Right to Erasure)
- CCPA Section 1798.105
- HIPAA Security Rule §164.308(a)(3)(ii)(C)
- HR Integration:
- Termination workflow triggers
- Manager approval chains
- Legal hold exceptions
- Technical Safeguards:
- 48-hour delay for permanent deletion
- Backup restoration process
- Break-glass accounts
Pre-Implementation Checklist
- Document all identity stores and dependencies
- Establish HRIS integration points
- Create encrypted backup process
- Define roles with privileged access management
- Implement mandatory access logging
Automated Deprovisioning Implementation
Active Directory Example
For on-premise environments, automate user disablement via PowerShell:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Disable AD account with termination reason
Disable-ADAccount -Identity $Username -Confirm:$false
# Remove group memberships except baseline
Get-ADUser $Username -Properties MemberOf |
ForEach-Object {$_.MemberOf} |
Remove-ADGroupMember -Members $Username -Confirm:$false
# Move to Disabled Users OU
Get-ADUser $Username | Move-ADObject -TargetPath "OU=Disabled,DC=contoso,DC=com"
# Export attributes for legal preservation
Get-ADUser $Username -Properties * |
Export-Clixml -Path "\\archive\users\$Username.xml"
Cloud Identity (Azure AD) Automation
Azure Automation Runbook for cloud identities:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Connect-AzureAD
# Revoke active sessions
Revoke-AzureADUserAllRefreshToken -ObjectId $User.ObjectId
# Disable account
Set-AzureADUser -ObjectId $User.ObjectId -AccountEnabled $false
# Remove licenses to prevent billing
$Licenses = Get-AzureADUserLicenseDetail -ObjectId $User.ObjectId
Set-AzureADUserLicense -ObjectId $User.ObjectId -RemoveLicenses $Licenses.SkuId
# Remove group memberships
Get-AzureADUserMembership -ObjectId $User.ObjectId |
ForEach-Object {
Remove-AzureADGroupMember -ObjectId $_.ObjectId -MemberId $User.ObjectId
}
Infrastructure-as-Code (Terraform)
Manage cloud resources through version-controlled definitions:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# terraform/modules/iam/main.tf
data "aws_iam_user" "employee" {
for_each = toset(var.active_users)
user_name = each.key
}
resource "aws_iam_user_policy_attachment" "revoke" {
for_each = { for u in var.terminated_users : u => u if contains(var.active_users, u) == false }
user = each.value
policy_arn = aws_iam_policy.deny_all.arn
}
resource "aws_iam_policy" "deny_all" {
name = "deny-all-access"
description = "Policy to deny all actions"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = ["*"]
Effect = "Deny"
Resource = "*"
}
]
})
}
Verification Workflow
After deprovisioning, validate effectiveness:
1
2
3
4
5
6
7
8
9
10
11
# Check AWS IAM access
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/jsmith \
--action-names "s3:*" "ec2:*"
# Test Azure AD sign-in (requires admin consent)
Invoke-MgBetaSignIn -UserId $User.Id -IsInteractive:$false
# Verify Linux account status
getent passwd $USERNAME
sudo -U $USERNAME -l
Configuration Best Practices
Security Hardening
- Temporal Access: ```yaml
Okta policy example
policies:
- type: OAUTH_AUTHORIZATION_POLICY conditions: people: users: exclude: [DEACTIVATED] grant: lifetime: value: 1 unit: HOURS ```
- JIT Privileges:
1 2 3 4 5 6 7 8
# Boundary configuration resource "boundary_role" "db_admin" { scope_id = boundary_scope.project.id grant_scope_id = boundary_scope.project.id grant_strings = ["id=*;type=*;actions=*"] principal_ids = [boundary_user.jsmith.id] duration = "3600" # 1 hour }
Performance Optimization
Batch processing for large-scale operations:
1
2
3
4
5
6
7
8
9
10
11
12
13
# Python pseudocode for batch deprovisioning
def disable_users(users):
with ThreadPoolExecutor(max_workers=8) as executor:
futures = []
for user in users:
futures.append(executor.submit(
disable_single_user,
user,
preserve_home=True
))
for future in as_completed(futures):
log_operation(future.result())
Dependency Mapping
Visualize account relationships before deletion:
graph LR
A[User Account] --> B[SSH Keys]
A --> C[OAuth Tokens]
A --> D[CI/CD Pipelines]
A --> E[Cloud Resources]
E --> F[S3 Buckets]
E --> G[EC2 Instances]
E --> H[Lambda Functions]
Operational Considerations
Monitoring and Alerting
Detect stale credentials with Splunk SPL:
index=aws (eventName=ListBuckets OR eventName=DescribeInstances)
| eval user_type=case(
match(userIdentity.arn,".*:assumed-role.*"), "Role",
match(userIdentity.arn,".*:user.*"), "User",
1=1, "Other")
| stats count by userIdentity.arn, user_type
| where user_type="User"
| lookup terminated_users.csv userIdentity.arn OUTPUTNEW termination_date
| where termination_date < relative_time(now(), "-24h")
Backup Strategy
Preserve critical data without retaining credentials:
1
2
3
4
5
# Archive home directory without SSH keys
tar --exclude='.ssh' --exclude='.aws' -czvf /backups/$USERNAME.tar.gz /home/$USERNAME
# Encrypt backup with age
age -R ~/.ssh/backup_key.pub /backups/$USERNAME.tar.gz > $USERNAME.tar.gz.age
Knowledge Transfer Protocol
Before deprovisioning technical staff:
- Rotate shared secrets (API keys, database passwords)
- Transfer repository ownership
- Document tribal knowledge
- Archive credential-free configurations
Knowledge capture template
Critical Systems Owned
- Load Balancer Configs (HAProxy)
- Certificate Renewal Process
- Database Backup Scripts
Pending Tasks
- Certificate renewal due 2024-03-15
- Storage volume expansion ticket #4512
Unique Configurations
- Custom kernel parameters in /etc/sysctl.d/99-tuning.conf
- AWS S3 lifecycle policy exceptions ```
Troubleshooting Deprovisioning Issues
Common Problems and Solutions
| Symptom | Diagnosis | Resolution |
|---|---|---|
| Access persists after revocation | Replication delay | Check directory sync status; force replication |
| Service disruptions | Orphaned service dependencies | Audit systemd units/cron jobs before removal |
| Compliance failures | Incomplete logging | Enable auditd rules for user modifications |
| License overages | Failed license deallocation | Verify API responses from SaaS providers |
Debugging Commands
Active Directory replication status:
1
repadmin /showrepl dc=contoso,dc=com
AWS effective permissions check:
1
2
3
aws iam simulate-custom-policy \
--policy-input-list file://policy.json \
--action-names s3:ListBuckets ec2:StartInstances
Linux account verification:
1
2
3
4
5
6
7
8
# Check locked status
passwd -S $USERNAME
# Verify PAM restrictions
grep $USERNAME /etc/security/access.conf
# Audit recent activity
ausearch -ua $USERNAME -ts today
Conclusion
Account deprovisioning represents the intersection of technical rigor and human empathy in system administration. Through automated workflows, comprehensive auditing, and thoughtful process design, we can fulfill our security obligations while respecting the human dimension of these operations.
Key takeaways:
- Automate Compassion: Build systems that handle revocation consistently, removing ad-hoc emotional burden
- Audit Relentlessly: Implement immutable logs of all access changes
- Preserve Context: Archive non-sensitive user data before deletion
- Psychological Safety: Create team protocols for handling difficult deprovisioning scenarios
As infrastructure grows increasingly ephemeral, our approach to digital identity must balance security with humanity. The commands we execute in these moments - whether userdel, Remove-AdUser, or gcloud iam service-accounts delete - carry weight beyond their technical function. They represent the final interface between a colleague’s digital presence and organizational memory.
For further learning:
- NIST Digital Identity Guidelines (SP 800-63B)
- AWS IAM Best Practices
- Microsoft Entra ID Lifecycle Management
In the end, we manage machines to serve people - even when our duties require us to erase their digital footprints. That balance defines professional infrastructure management at its most challenging and most necessary.