Skip to content
Hameed's dev blog

Blog

IAM Chapter 7, Part 3: Nobody to Ask

·10 min read·---
Hermit crab.jpg
On this page

Part of the IAM study series.

There are machines in the building: the cleaning robot, the HVAC controller, the conveyor. They all have keys, but nobody issued them a badge. An engineer cut a key and taped it to the machine.

1. Non-Human Identities

KindWhat it isCredential
Service accountA directory account used by a job, like BOM-SyncA password, usually non-expiring
App registrationThe OAuth client (Chapter 5)Client ID and secret
Managed / workload identityThe platform vouches for the workloadNone stored
Bot / RPAAutomation driving a UI as if it were a personOften a real human-shaped account
Device identityA machine account in the domainRotated automatically
API key / tokenA credential that behaves like an identityThe key itself

These outnumber humans ten to fifty times, so the population you govern least is the largest you have. And as Part 1 showed, nothing surfaces the problem: a service account keeps succeeding, which looks exactly like one nobody needs.

They need JML rebuilt into four things:

  1. Registration, recording purpose, owner, expected lifetime, and crucially what breaks if this is disabled. That last field is what makes decommissioning possible years later.
  2. Ownership by a team, not a person. If someone merely uses an account, disable it when they leave. If they own it, raise a transfer 14 days out, escalate to the manager at 30, and only then disable, with notice.
  3. Credential management: rotation, nothing embedded, nothing shared.
  4. Decommissioning: a review date, set at birth.

To find the ones nobody recorded, look for no manager and no HR line, passwords set to never expire or last changed in 2019, no interactive logons, naming patterns like svc- or -batch, and privileges far above any human in the same OU. None is conclusive alone. Together they give a candidate list, and the real work is finding a human who will admit to owning each one.

The decommissioning deadlock. Nobody will delete what they can't prove is unused, and you can't prove a negative about a job that runs quarterly. So instrument usage, wait a full quarter, disable with an announcement, keep a rollback window where a named person can re-enable in minutes, and delete at 60 days. Most people will agree to switch off something that can be switched back on in five minutes.

2. The Better Answer: Have No Credential at All

A key taped to a machine can be photographed, works forever, and still opens the door after the machine is scrapped. With managed identity there's no key. The conveyor says "I'm in bay 3", the building can see that it is, and it gets a one-hour pass. Identity comes from where you run, not what you know.

PlatformCalled
AzureManaged Identity, system-assigned or user-assigned
AWSIAM roles: instance profile, IRSA for EKS, Lambda execution role
GCPAttached service accounts, Workload Identity on GKE
KubernetesProjected service account tokens; the cluster is an OIDC issuer
On-prem ADgMSA: Windows generates a 240-char password and rotates it every 30 days

Workload identity federation extends this: a GitHub Actions job presents a token GitHub signed, and your cloud trusts that issuer for a specific repo and branch. No secret exists anywhere. The best-managed secret is the one that doesn't exist: nothing to embed, rotate, steal, or leave behind.

3. A Worked Case: An OpenShift App That Needs AD

People ask: Kerberos, or a secrets manager? That's the wrong shape. They're different layers, and you normally use both. Kerberos answers how the app authenticates on the wire, and the vault answers where the bootstrapping credential lives at rest.

  1. AD_PASSWORD=... in config ends up in the image, in git, and copied between environments, and is never rotated.
  2. "Use Kerberos" gives you /etc/krb5.keytab. Same shape, different format.
  3. Add a vault, and there's nothing in the pod but its projected service account token. The keytab lives in one place that rotates it, is fetched into memory, and every fetch is logged.

The catch nobody mentions: a Linux workload can't type a password, so it gets a TGT using a keytab, a file holding the principal's long-term key. That keytab is the credential. Copy it and you can mint TGTs as that principal indefinitely. In practice it's handled worse than a password, because people treat it as a file, and it's almost never rotated. Switching to Kerberos is a real improvement on the wire and none at rest.

The decision that actually matters is what the target is:

  1. A web API behind ADFS or Entra that accepts OIDC? Stop, and use workload identity federation. It's the only path that removes the secret rather than relocating it.
  2. An AD-native service, like SQL Server or a file share? Kerberos is the only thing that works. Keep the keytab in the vault.
  3. Just LDAP queries against AD? You have two genuine options:
Simple bind over LDAPSSASL / GSSAPI
In the podA password, from the vaultA keytab, from the vault
On the wirePassword, inside TLSNothing; the key never travels
Moving partsTLS trustkrb5.conf, DNS, SPNs, clock sync, ticket cache
RotationChange it in one placeRegenerate and redistribute the keytab

Kerberos in containers bites later: clock skew over five minutes fails everything, forward and reverse DNS must resolve, and the ticket cache must live somewhere in an ephemeral pod. For LDAP reads, simple bind over LDAPS with the password in a vault is often the better engineering decision.

4. Vaults: The Key Cabinet

A vault (or secrets manager) holds secrets, controls who may read each one, logs every read, and rotates them. The logbook means that, for the first time, you can answer who is actually using a credential.

The question that makes it work is secret zero: if the app needs a key to reach the cabinet, you've only moved the problem. The answer is platform identity. The app authenticates with something it already has and never stored, such as a pod's service account token, a VM's managed identity, or an instance's IAM role. Platform identity gets you through the cabinet door, and the vault gives you everything the platform can't issue directly.

Static secretsDynamic secrets
The secretExists, stored onceCreated per request
Shared?YesNo
LifetimeUntil next rotationAn hour
Vault needs admin on targetNoYes

Dynamic is clearly better, but only works where the target lets the vault create and drop accounts: usually databases, cloud platforms, and SSH, but usually not AD and most enterprise apps. So most real estates run mostly static.

On products, CyberArk usually arrives from the human privileged-access side and HashiCorp Vault from the machine side. They've converged, and plenty of estates run both. Delinea is similar to CyberArk, and the cloud-native managers (Azure Key Vault, AWS Secrets Manager, GCP Secret Manager) are simpler, platform-bound, and often enough.

5. Access Requests: The Front Door

Birthright and business roles cover the predictable 70–80%. This is the tail, where creep concentrates if it's built badly.

Nobody can choose from 47,000 entitlements. Hand someone a raw list and they'll request everything, or give up and email an admin, which is the ungoverned path you were trying to close. Offer an access package instead: "Engine Drawings – Read", with who it's for, what you get, who approves, and how long it lasts. Approval usually goes to the line manager, who knows the person, then the resource owner, who knows the access.

Record who asked, why, who approved, when, and for how long. The why is always blank or "needed for work", so make it structured: pick a project or reference a ticket. Three checks are far cheaper here than in a reconciliation report:

  • Separation of duties: does this combination create a conflict? Caught here it's a conversation; caught in an audit it's a finding.
  • Risk tier: does this need a second approver or a shorter expiry?
  • Already have it? If a role grants it, don't create a duplicate grant that will outlive the role.

Time-bound by default

This is the highest-leverage decision in the chapter. If every requestable grant carries an expiry, creep becomes self-limiting. Review campaigns need a human to act to remove access, while expiry needs a human to act to keep it. That's the right way round, and it closes the hole from Part 1: the engine archive door no mover event could remove now removes itself.

Approvers will still approve everything, because they have little information, no consequence, too much volume, and a social cost to saying no. Add context to the request (what it grants, who else has it, whether they used it last time), move repeats into roles, and lean on expiry, which works whether or not anyone was paying attention.

Expiry also creates a wave. Switch on 5,000 grants on 1 January, all expiring 1 April, and you get 5,000 renewals in one day. Randomise the first expiry across the window and it's about 55 a day, continuously.

Don't shorten the period to reduce the queue, because shorter means more renewals. Instead, let unused access lapse silently, auto-renew low risk, feed repeat renewals back into the role model, and make renewal lighter than approval. Vary the period by risk: a year for drawings, eight hours for production admin.

What Breaks in Practice

MistakeWhat goes wrongFix
Service account secret in a config fileIn the image, in git, never rotatedPlatform identity, or a vault where not
Swapping a password for a keytabStill a stored secret, rotated even lessKeytab in the vault
A secret to reach the secrets managerSecret zero: the problem movedAuthenticate with the platform token
Service account disabled when its owner leavesA production job breaks overnightTransfer ownership to a team
Deleting a service account to clean upA quarterly job breaks three months laterInstrument, disable, rollback window, delete
Kerberos in containers without prerequisitesIntermittent, hard-to-diagnose failuresCheck them first; consider LDAPS plus a vault
Permanent requestable grantsThe tail only ever growsTime-bound by default
Uniform expiry switched on in one goA permanent quarterly flood of renewalsRandomise the first expiry
Manager-only approvalA rubber stamp on what they can't evaluateManager and resource owner, in sequence
Free-text justification"Needed for work" is useless laterA structured reason: a project, a ticket

🔴 CHECKPOINT: Study Notes

IAM Chapter 7 Part 3: Nobody to Ask, handwritten study notes on non-human identities, vaults and access requests

← Previous: Out and Back · Back to the series start

Notes from a technical product leader on product management, identity & access management, and agentic AI — from 12 years of building enterprise software.