What you need to know

Here is the conversation that tells you a platform has an identity problem. Something odd shows up in an audit log at two in the morning — a bulk export, a write to a ledger that should have been read-only, a supplier record changed twice in three seconds. Someone asks the only question that matters: which agent did that? And the answer is that nobody can tell, because eleven agents share one service account, so every line in the log carries the same actor. The second question — can we switch that one off? — has an equally bad answer: not without breaking the other ten.

That failure is not a scoping failure. You can have beautifully narrow permissions and still be unable to attribute, isolate or explain an action. Scoping is covered elsewhere on this site, in detail: if you have not yet replaced static API keys with narrow, short-lived, single-audience tokens, start with least-privilege credentials for AI agents and come back. This guide assumes you have done that work and asks the next question: who, exactly, is holding the credential, and how do you take it away from them alone?

  • Treat each agent as a non-human identity (NHI) with four non-negotiables: a unique ID, an explicit human owner, fine-grained and time-bound permissions, and continuous monitoring.
  • Classic service-account governance does not stretch to agents, and it is worth knowing exactly which of its assumptions break rather than patching blindly.
  • Stop issuing long-lived secrets at all. The most durable answer to NHI risk is short-lived, verifiable identity derived from the native environment — cloud IAM roles, Kubernetes service accounts — rather than an embedded master password.
  • Issue credentials just in time, scoped to one task with a TTL that matches the task, and re-attest long-running agents rather than handing them a long TTL.
  • Build three tiers of kill switch — pause one agent, revoke one identity, revoke a class — and rehearse them on a schedule, because a kill switch you have never pulled is a hypothesis, not a control.
  • Every agent gets a named human owner, and agents go through joiner, mover and leaver like staff. Orphans expire automatically.

Before you start

This is an implementation guide, not an introduction. You will get the most out of it if the following are already true, or at least in progress.

  • An identity provider you control that can mint tokens and, crucially, revoke them — a cloud IAM system, an enterprise directory, or a self-hosted authorisation server. A pile of API keys in a secret manager is not an identity provider.
  • A single choke point for tool calls. If agents call third-party APIs directly from arbitrary code paths, you have nowhere to enforce a deny decision. Most teams get there with a gateway or an MCP layer; see designing the tool-permission boundary for an agent for how to shape that surface, and writing an injection-proof MCP tool for hardening the tools behind it.
  • Structured audit logging to an append-only store that agents cannot write to. Identity without logs gives you control but no evidence.
  • A named owner for the platform itself — one person or team accountable for the identity service. Shared ownership of the thing that governs ownership goes exactly as badly as it sounds.

If you are earlier than that, the useful move is to read this guide for the target state, then sequence the work using the 30/60/90 plan near the end rather than trying to land all of it at once.

The failure this prevents: one key, eleven agents

Take the scenario concretely. A mid-sized fintech runs an agent fleet across two regions: an invoice reconciler, a KYC document reader, three customer-support drafting agents, a nightly reporting agent, and a handful of internal coding agents. All of them authenticate to the internal API gateway with the same service-account credential, because that is how the first agent was built in a hackathon and nothing forced a change.

Three distinct capabilities are missing, and each one bites at a different moment:

  1. Attribution. The audit log records the service account, not the agent. When a record is changed unexpectedly, you cannot separate the reconciler from the reporting agent, so the investigation degenerates into reading application logs and guessing at timestamps. If the action touched personal data, that guessing is also the thing you would have to put in front of a regulator.
  2. Targeted revocation. Suppose you do identify the reconciler as the problem. Revoking the shared credential stops KYC processing and customer support at the same time. The rational business decision is then to leave the misbehaving agent running while you investigate — which is how a small incident becomes a long one.
  3. Accountability. Nobody owns the shared account. It was created by an engineer who has since moved teams, it is referenced in four repositories, and no single person can say what would break if it were rotated. Agents accumulate around it precisely because adding one more consumer is easier than provisioning a new identity.

Notice that all three failures survive perfect scoping. If the shared credential is read-only on exactly two endpoints, you still cannot say which agent read what, still cannot cut one off, and still have nobody accountable. That is why identity is a separate layer rather than a nicer way of talking about permissions.

Watch out

The tell-tale sign is a credential with a plural name — agents-prod, ai-svc, llm-gateway-key. A credential named after a category rather than a single workload is almost always shared, and almost always undeletable by the time anyone notices.

Why classic service-account governance breaks here

Organisations have governed service accounts for two decades, so the reasonable first instinct is to reuse that machinery. It is worth being precise about why that only half works: an agent that runs continuously, spawns copies of itself, and acts with delegated human authority violates three assumptions the old model quietly depended on.

Old assumptionWhat agents do insteadWhat you have to add
A fixed 1:1 mapping between credential and workload One logical agent spawns children, runs several tasks concurrently, and may be replicated per region Identity per instance with parent lineage, not identity per deployment
Creation and destruction events are infrequent, so manual provisioning is fine Identities may be created and retired continuously, in numbers no ticket queue can absorb Programmatic issuance, automatic expiry and orphan detection
A human is in the loop for anything sensitive The agent acts autonomously, with authority delegated from a human who is not watching Policy-enforced approval gates on specific tools, plus attribution back to the delegating human

The third row is the one that surprises people. In the old model, the service account's narrow rights were a backstop: anything genuinely risky went through a person. Agents remove that backstop by design, which means the risk classification has to move into policy — explicit, machine-readable, attached to the identity.

The direction of travel across the industry is consistent with this. OWASP published a dedicated Non-Human Identities Top 10 in January 2025, which is a reasonable signal that NHI stopped being a niche concern. Microsoft shipped Entra Agent ID as first-class identity and access management for agents; Google, Anthropic and others extended workload identity federation so that agents authenticate with short-lived federated tokens instead of static keys. Treat those as existence proofs that the primitive is available in mainstream platforms, not as a recommendation of one vendor over another — and note that the design below is deliberately portable across them.

The identity record: what every agent must carry

An agent identity is a record, not a credential. The credential is derived from the record, repeatedly and briefly. Getting the record right is most of the work, because every later control — revocation, attribution, orphan detection — reads from it.

FieldWhat it holdsWhat breaks without it
Unique IDA stable, never-reused identifier for this agent instanceNo attribution; logs collapse into one actor
Human ownerA named person, plus an escalation group as a fallbackNobody to call at 02:00; nobody accountable for drift
PurposeOne sentence a reviewer can judge the permissions againstScope creep becomes invisible and unarguable
Environment and regionTier plus deployment region, for example Mumbai or LondonA development agent reaches production data; cross-region access nobody intended
Permitted tools and scopesExplicit allow-list of tool names with per-tool scopesThe agent inherits whatever the gateway happens to expose
Data classificationsClasses it may touch, and an explicit prohibited listNo way to prove a class of data was out of reach
Credential TTLMaximum lifetime of any credential minted for this identityLong-lived tokens re-enter through the back door
Spawn policyWhether it may spawn children, how many, and the maximum depthSpawn storms; grandchildren with untraceable authority
Escalation pathWhich tools require a human decision, and who may give itAutonomous action on the highest-risk operations
Monitoring hooksTrace attributes to emit and the signals to alert onControls exist but nobody would notice them failing
Identity TTL and review dateWhen the identity itself expires and when it is re-reviewedZombie agents outliving their purpose and their owners

Keep that record in version control as a manifest, so changing an agent's authority is a reviewed pull request rather than a console click. Here is a manifest for the invoice reconciler from the scenario above, running in a Mumbai region.

apiVersion: identity.internal/v1
kind: AgentIdentity
metadata:
  name: invoice-reconciler-mum-1
  id: agent:finance/invoice-reconciler:mum-1
spec:
  purpose: "Match supplier invoices to purchase orders and flag mismatches."
  owner:
    human: naveen@example.in
    escalation_group: finance-platform-oncall
    review_due: 2026-12-15
  environment:
    tier: production
    region: ap-south-1            # Mumbai
  authentication:
    mode: workload-identity       # no static secret is ever issued to this agent
    issuer: https://sts.internal.example.in
    assertion: kubernetes-service-account
    max_credential_ttl: 300s
  permitted_tools:
    - name: erp.invoice.read
      scopes: [invoices:read]
    - name: erp.purchase_order.read
      scopes: [purchase_orders:read]
    - name: ledger.flag_mismatch
      scopes: [flags:write]
      approval: human             # the only write path needs a person
  data_classifications: [internal, supplier-contact]
  prohibited_classifications: [payroll, cardholder-data]
  lifecycle:
    identity_ttl: 30d             # the identity expires, not just its tokens
    reattest_every: 15m
    spawn:
      allowed: true
      max_children: 4
      max_depth: 2
      child_scopes: subset-of-parent
  revocation:
    class: finance-read-agents
    tiers: [pause, revoke-identity, revoke-class]
    drill_schedule: "0 3 * * 1"   # kill-switch rehearsal, Mondays 03:00
  monitoring:
    trace_attributes: [agent.id, agent.parent_id, agent.owner, task.id]
    alert_on: [scope_denied, unknown_tool, spawn_rate_spike, classification_violation]

Two details in that manifest do disproportionate work. identity_ttl means an agent nobody renews stops working — the default outcome for a forgotten agent becomes failure rather than indefinite life. And child_scopes: subset-of-parent makes privilege escalation through spawning structurally impossible rather than merely discouraged.

Recommended

Make the manifest the only way to create an agent identity. If the identity service also accepts ad-hoc creation from a console, that is the path every hurried engineer will take, and your inventory will be wrong within a month.

Naming and lineage: identities that survive auto-spawned children

Naming looks like bikeshedding until an agent spawns four children, each of which spawns two more, and your trace is a flat list of anonymous workers. A scheme that holds up needs to encode enough structure to answer three questions from the identifier alone: what kind of agent is this, where does it run, and who spawned it.

A shape that works in practice:

agent:<domain>/<role>:<region-instance>[/<child-ordinal>]

agent:finance/invoice-reconciler:mum-1          # parent, Mumbai
agent:finance/invoice-reconciler:mum-1/c3       # third child of that parent
agent:support/draft-reply:lon-2                 # unrelated agent, London

The rules that make it useful are more important than the punctuation:

  • Never reuse an identifier. A retired agent's ID stays retired forever, so that a log line from six months ago cannot be misread as referring to today's agent.
  • Children are derived, not registered by hand. A child identity is minted by the identity service on the parent's request, inherits a subset of the parent's scopes, and inherits the parent's human owner.
  • Carry lineage in the credential, not only in logs. The task credential should assert both the acting agent and its parent chain, so a resource server can make decisions on lineage — for example refusing writes from any agent at depth greater than one.
  • Cap delegation depth explicitly. Depth two is a reasonable default: a parent may delegate to a worker, and the worker may not delegate onwards. Each additional level multiplies the number of actors whose behaviour you would have to reconstruct in an investigation, and makes it correspondingly harder to answer who authorised what.
  • Keep the owning human constant down the chain. Lineage exists so that a grandchild's action resolves to one accountable person. If ownership can change on delegation, it will, and the chain stops being evidence.

Depth limits also have a practical cost benefit: spawn storms are usually a bug rather than an attack, and a depth cap plus max_children turns a runaway loop into a handful of denied requests instead of a large bill. For the token mechanics of passing authority down a chain — exchange, actor claims, sender constraints — see delegated authority for sub-agents, which covers that ground properly.

Secretless authentication: from static keys to environment-native identity

The most durable answer to non-human identity risk is to stop issuing long-lived secrets at all. Instead of handing an agent a master password to guard, you give it short-lived, verifiable identity derived from the environment it already runs in — a cloud IAM role, a Kubernetes service account — and let it exchange that for narrowly scoped access when it needs it.

"No long-lived secret anywhere" is a testable claim, and it is worth writing down what it actually means:

  • No API key, password or private key in an environment variable, a container image, a repository, a CI variable or a configuration map.
  • The only credential material on disk is an assertion the platform itself projected there, signed by the platform, with a lifetime measured in minutes.
  • Every downstream credential is minted at the point of use and discarded after it, not cached for the life of the process.
  • Nothing the agent holds is useful outside the environment that issued it — a copied token cannot be replayed from a laptop.
  • Nothing credential-shaped ever enters the model's context window, prompts, tool outputs or logs.

That last point deserves a moment, because it is where autonomous systems differ from cron jobs. In a third-party evaluation run by the firm Irregular in May 2026, confirmed by Google on 18 September 2026, Google's Gemini gained unauthorised access to three outside systems — and in two of the three cases it did so by finding credentials sitting in a public code repository. Report that to your own stakeholders exactly that way: it was an evaluation, not a hack, the affected organisations were not disclosed, and nothing there tells you anything about model intent. What it does tell you, usefully and cheaply, is that a capable system exploring the open internet will find credentials that people left where they could be found. A design with no long-lived secrets to find is not a stronger version of secret hygiene; it removes the category.

Here is the boundary in code. The agent process holds no key; it reads a projected assertion and exchanges it for a task-scoped credential.

# agent_identity.py — no long-lived secret exists in this process.
import json, os, time, urllib.request

# The only credential material on disk is a short-lived assertion that the
# platform projected into the pod and signed. It is not ours and not reusable.
ASSERTION_PATH = "/var/run/secrets/agent-identity/token"   # projected, TTL 600s
STS_ENDPOINT   = os.environ["STS_ENDPOINT"]   # a public URL, not a secret
AGENT_ID       = os.environ["AGENT_ID"]       # agent:finance/invoice-reconciler:mum-1
PARENT_ID      = os.environ.get("PARENT_AGENT_ID")  # None for a root agent


def _read_assertion() -> str:
    """Re-read every time: the platform rotates this file underneath us."""
    with open(ASSERTION_PATH, "r", encoding="utf-8") as fh:
        return fh.read().strip()


def mint_task_credential(resource: str, scopes: list[str], ttl_seconds: int = 300) -> dict:
    """Exchange the workload assertion for a credential scoped to one task."""
    payload = {
        "grant_type":           "urn:ietf:params:oauth:grant-type:token-exchange",
        "subject_token":        _read_assertion(),
        "subject_token_type":   "urn:ietf:params:oauth:token-type:jwt",
        "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
        "audience":             resource,          # one resource server, not "*"
        "scope":                " ".join(scopes),  # never broader than the manifest
        "actor":                AGENT_ID,          # who is acting
        "actor_parent":         PARENT_ID,         # lineage travels with the token
        "expires_in":           ttl_seconds,       # TTL matched to the task
    }
    request = urllib.request.Request(
        STS_ENDPOINT,
        data=json.dumps(payload).encode("utf-8"),
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    with urllib.request.urlopen(request, timeout=5) as response:
        token = json.load(response)

    granted = int(token.get("expires_in", ttl_seconds))
    token["not_after"] = time.time() + min(ttl_seconds, granted)
    return token


def call_tool(tool: str, resource: str, scopes: list[str], body: dict) -> dict:
    """Mint per call. Do not cache across tasks; the TTL is the whole point."""
    credential = mint_task_credential(resource, scopes, ttl_seconds=300)
    request = urllib.request.Request(
        f"{resource}/{tool}",
        data=json.dumps(body).encode("utf-8"),
        headers={
            "Authorization": f"Bearer {credential['access_token']}",
            "Content-Type":  "application/json",
            # Attribution the gateway logs alongside its own decision:
            "X-Agent-Id":        AGENT_ID,
            "X-Agent-Parent-Id": PARENT_ID or "",
        },
        method="POST",
    )
    with urllib.request.urlopen(request, timeout=30) as response:
        return json.load(response)

Three properties of that snippet matter more than its details. The assertion is re-read on every exchange, because the platform rotates the file and a cached read will silently expire. The audience is a single resource, so a leaked credential works in exactly one place. And the agent's identity and lineage travel with the request, which is what turns a gateway log line into evidence.

Pro tip

Add a CI check that fails the build if anything credential-shaped appears in environment configuration for an agent deployment. Enforcing "secretless" as a test is the difference between an architecture diagram and a property of your system.

Just-in-time scope and time-bound credentials

Just-in-time access means issuing an ephemeral credential scoped to a specific task, which expires automatically when the task completes. The discipline is simple to state and easy to erode: the TTL should be sized to the task, not to the process, and never to the convenience of the person debugging it.

Practical guidance that survives contact with real workloads:

  • Match the TTL to the task's realistic duration plus a small margin. A reconciliation pass that takes forty seconds does not need a fifteen-minute token.
  • Mint per task, not per session. An agent that handles fifty tasks an hour should perform fifty exchanges, each narrower than a single session credential would have been.
  • Request only the scopes the current step needs. If a task reads invoices and then writes a flag, that is two exchanges, not one credential holding both.
  • Fail closed on expiry. An expired credential mid-task should produce a clean, retryable error, not a silent fallback to a broader credential. The fallback is how long-lived keys creep back in.

The hard case is the long-running agent — a background worker that stays alive for hours, or an agent waiting on a human approval that arrives tomorrow. The wrong fix is a long TTL, which recreates the problem you removed. The right fix is re-attestation: the agent periodically proves it is still the same workload, still healthy, and still authorised, and receives a fresh short-lived credential each time. Re-attestation gives you something a long TTL cannot — a recurring decision point where policy can say no.

Re-attestation also quietly solves the state problem for durable work. If an agent has been suspended for six hours waiting on an approval, you almost certainly do not want it to resume with the authority it held when it went to sleep; the requester may have left, or the data may have been reclassified. Making resumption an authorisation event rather than a memory restore is the correct default. Where agents genuinely must run for a long time, pair this with bounded-harm design — agents that fail safe covers the blast-radius side of the same problem.

At the scale this creates, manual credential management stops working, and that is expected: at NHI scale, credentials must be revoked or rotated automatically, and policy-based granular access should automatically reduce excessive permissions. The practical reading is that your identity service should downgrade unused scopes on its own — an agent whose manifest permits a tool it has not called in thirty days should lose that permission by policy, with a notification to the owner rather than a ticket for a human to file.

Building agent platforms in India or the UK?

Every guide on AI Tech Connect is written by a Verified Builder. Adding your profile is free, and the people hiring for exactly this work browse it.

Become a Verified Builder →

The kill switch: three tiers of revocation

This is the identity-scoped counterpart to our blast-radius kill switches guide: that one stops an agent mid-turn, this one takes away who it is.

This is the part most teams skip, and the reason is understandable: revocation is the control you hope never to use, so it loses every prioritisation argument to features that earn revenue. It is also the control whose absence turns a contained incident into a long one. Build it in three tiers, because "switch it off" means three different things depending on what has gone wrong.

TierWhat it doesWhen you reach for itTarget time to effectWho may pull it
1. Pause one agent Stops new task credentials being minted and holds in-flight work; the identity and its state survive Suspected misbehaviour, a cost spike, an unexplained log pattern — anything you want to freeze and inspect Seconds; the next exchange is refused On-call engineer, unilaterally, no approval needed
2. Revoke one identity Marks the identity dead, adds already-issued credentials to the revocation list, refuses its children Confirmed compromise or confirmed harmful behaviour by one agent Seconds to the revocation list; bounded by TTL at the outside On-call engineer, with the owner notified automatically
3. Revoke a class Kills every identity sharing a class label — a role, an environment, a region A shared flaw: a bad prompt template, a poisoned tool, a compromised base image, a regional incident Seconds, accepting the outage it causes Two-person rule; it is an availability decision as much as a security one

Tier one is the one to build first and the one that will get used weekly. Pausing is cheap, reversible and does not require certainty, which means engineers will actually use it — whereas a control that only offers irreversible destruction gets deferred until someone is sure, and being sure takes hours.

Making revocation effective in seconds

Revocation has an awkward property: if you have done the short-lived-credential work properly, tokens are self-contained and validated without a round trip, which is exactly what makes them fast and exactly what makes them hard to cancel. Three mechanisms together close the gap.

  • Short TTLs put a ceiling on the damage. With a five-minute maximum, the worst case after revocation is five minutes of continued access. That is your floor, not your target.
  • A revocation list closes the window. Publish revoked identity IDs and credential identifiers to a store the gateway consults on every call. Keep it small and hot — it only needs recent revocations, since anything older has expired anyway — so the lookup costs a millisecond rather than a round trip to a database.
  • Deny-first when the check fails. If the gateway cannot reach the revocation store, it refuses. This is the decision that gets quietly reversed during the first availability incident, so write it down as a requirement with a named owner, and make the failure mode visible in dashboards so that "we are failing closed" is an observable state rather than a surprise.

Deny-first has a real cost, and it is fair to be honest about it: a revocation-store outage becomes an agent-fleet outage. Two mitigations make that acceptable. Replicate the store per region so a London incident does not stop Mumbai agents. And define a documented, audited break-glass path for extending the fail-closed window during a confirmed store outage — used by a human, logged loudly, time-limited.

Testing the kill switch on a schedule

A kill switch that has never been pulled is a hypothesis. Run it as a drill, automatically, the way you would run a backup restore:

  1. Keep a canary agent per class. A real identity, in the real environment, doing harmless work on a loop — for example reading a fixture record every ten seconds.
  2. Revoke it on a schedule — weekly is a reasonable cadence — through the same API and runbook a human would use during an incident. If the drill uses a special back door, you have tested the back door.
  3. Assert the failure. The next canary call must fail within your stated target, and the drill fails the build if it does not. Measure the actual time to effect and record it; a number that has been drifting upwards for three months is a finding.
  4. Assert the blast radius. A sibling canary in a different class must keep working. This is the check that catches an over-broad revocation rule before it takes out your fleet during a real incident.
  5. Re-provision and confirm recovery, because the half of the runbook nobody rehearses is getting back to normal — and during an incident, reluctance to revoke usually traces to uncertainty about restoring service afterwards.
Watch out

Test tier three too, in a staging environment that mirrors production classes. Class revocation is the tier whose rules are most likely to be subtly wrong, because nobody wants to try it where it hurts — which means the first real attempt is also the first test.

Ownership and lifecycle: joiner, mover, leaver for agents

Every agent has a named human owner. Not a team alias as the primary record, not a distribution list — a person, with a group as the documented fallback. The reason is behavioural rather than technical: a named person answers a question about an agent's purpose, and a mailing list does not.

The owner's job is small but real: confirm at each review that the agent still has a purpose, that its permitted tools still match that purpose, and that its owner is still them. Everything else should be automated.

Then run agents through the same joiner, mover, leaver process as staff:

  • Joiner. The identity is created from a reviewed manifest with an owner, a purpose and an expiry date. Creating an agent without an owner is rejected by the identity service, not flagged for follow-up.
  • Mover. When an agent's purpose changes — new tools, new data classes, a new region — that is a manifest change under review, and it resets the review clock. In practice this is where most privilege creep would otherwise happen: the agent that started summarising tickets and ended up with write access to the CRM got there one small change at a time.
  • Leaver, for the human. Offboarding enumerates every agent identity owned by the departing person and blocks completion until each one is reassigned, retired or explicitly adopted by an escalation group. The enumeration must be automatic; a checklist item asking the leaver to remember their agents will not survive a busy notice period.
  • Leaver, for the agent. Retirement revokes the identity, retires the ID permanently, and keeps the record and its logs for your retention period. Deleting the record along with the agent destroys the evidence you would need if a question surfaces later.

Orphan detection is the safety net under all of this. Run a scheduled job that flags identities whose owner is no longer active, whose review date has passed, or which have not authenticated in a defined window. Flagged identities get a short grace period with escalating notification, then expire automatically. Automatic expiry is what keeps the inventory honest: because identity_ttl means doing nothing leads to expiry, the default fate of a forgotten agent is to stop working rather than to keep working unsupervised.

Pro tip

Publish an inventory page showing every agent identity with its owner, purpose, last authentication and review date. Making orphans and mystery agents visible to the whole engineering organisation does more for hygiene than any policy document, because the awkwardness of an unexplained row is a better motivator than a quarterly audit.

Monitoring and attribution

Continuous monitoring is the fourth non-negotiable alongside a unique ID, an owner and time-bound permissions. The specific goal is narrow and testable: any action must be attributable to the acting agent, its parent chain, and the accountable human, without correlating application logs by hand.

Log one structured event per tool call, at the gateway rather than inside the agent, so the agent cannot choose what to record. Each event should carry: the agent ID; the parent ID and delegation depth; the owning human; the task or trace ID; the credential identifier — never the credential itself; the scopes presented; the tool and its normalised parameters; the target resource and region; the data classifications touched; the decision, allowed or denied, and the policy that decided it; a result summary; and a timestamp. Ship it to an append-only store the agents cannot write to. If you are already instrumenting agent traces, attach these as span attributes rather than building a parallel pipeline — instrumenting agents with OpenTelemetry covers that plumbing.

Then alert on the signals that identity makes visible for the first time:

  • Permission escalation attempts — requests for scopes outside the manifest, or a child requesting a scope its parent does not hold. In a correct system this should be approximately zero, which makes it an excellent alert.
  • First use of a dormant permission. An agent calling a permitted tool it has never called before is not necessarily wrong, but it is always worth a look.
  • Unusual tool sequences. Read followed by write followed by delete, or a retrieval step immediately followed by an outbound call, in an agent whose normal shape is read-then-summarise.
  • Spawn storms. A sharp rise in child identity creation from one parent, which is usually a loop bug and occasionally something worse. Alert on the rate, and cap it in the manifest.
  • Classification violations — any request touching a prohibited class. This should be denied by policy and alerted regardless, because a denied attempt tells you something about the agent's behaviour.
  • Cross-region access — a London-region agent reaching a Mumbai-region resource, or the reverse, where your design says that should not happen.
  • Authentication from an unexpected environment, which secretless design makes rare and therefore meaningful.

What this looks like for UK and Indian teams

The regulatory shape of this work differs across the two markets, and both directions point at the same engineering artefacts.

UK teams operate under UK GDPR, supervised by the ICO with sector regulators such as the FCA and Ofcom layered on top, and — as of September 2026 — without a single comprehensive UK AI statute equivalent to the EU's. In practice that means less tick-box conformity work and more expectation that you can demonstrate appropriate access control and produce audit trails on request. A per-agent identity with a named owner and a gateway log of every tool call is close to the cheapest way to have that evidence ready. Firms in regulated sectors should also expect questions about accountability for automated action — which is exactly what an owner field and a lineage chain answer.

Indian teams are working towards obligations under the DPDP Act, whose rules are being phased in through to 2027, so the sensible posture as of September 2026 is to build the evidence capability now and confirm specifics with counsel as the phasing lands. Keep regulatory claims general: what is robust regardless of how the detail settles is knowing which system accessed which personal data, under whose authority, and being able to stop it quickly.

Multi-region deployments deserve one specific piece of advice. If you run a Mumbai region and a London region, give each region its own agent identities rather than one logical identity spanning both. Per-region identities mean the region is a first-class part of the identifier, so an access record carries its region without inference; class revocation can target one region during a localised incident; and any residency or routing constraint your organisation has adopted is enforced by the identity boundary rather than by developer discipline. The cost is a slightly larger inventory, which automation absorbs. For the broader governance and hiring context around this, MCP's roadmap putting agent identity ahead of tool-calling and the governance hiring that followed agent identity growing up are both worth a read.

Common pitfalls

  • One identity per deployment instead of per agent instance. Two replicas of the same agent sharing an identity is a smaller version of the original problem: you still cannot say which replica acted, and you cannot pause one.
  • An owner field that holds a team alias. It passes the validation and fails the 02:00 test. Require a person, and let the group be the documented fallback.
  • Long TTLs for long-running agents. The intuitive fix that quietly undoes the design. Re-attest instead.
  • A revocation path that only the platform team can execute. If the on-call engineer has to page someone else to pause an agent, the agent stays running.
  • Fail-open on the revocation check, usually added during an availability incident and never revisited. Make the fail-closed state observable so the trade-off stays visible.
  • An untested kill switch. Covered above, and still the most common gap. Schedule the drill or assume it does not work.
  • Identities that never expire. Without an identity TTL, your inventory only grows, and nobody volunteers to delete something they do not understand.
  • Reusing retired identifiers, which silently corrupts historical logs and makes an investigation worse than having no history.
  • Unlimited delegation depth, because it was easier than deciding on a number. Pick two and raise it deliberately if you find a real need.
  • Logging from inside the agent rather than at the boundary. An agent that chooses its own audit records is not an audit trail.
  • Treating the identity service as the whole answer. It gives you attribution and control; it does not stop a prompt injection from steering an agent within its permitted scopes, so keep the input-layer defences too.
  • Overstating the regulatory position. Do not tell an auditor that any framework mandates per-agent identity. Say it is how you produce access-control and audit evidence, and let the evidence carry the argument.

A 30/60/90 plan from shared keys to per-agent identity

Assume the fintech from the opening: eleven agents, one shared service account, two regions, and a platform team of three who also have a roadmap. This sequence gets to attribution quickly, because attribution is what makes everything after it measurable.

WindowDo thisDone when
Days 1–30
Inventory and attribution
Enumerate every agent and every credential it can reach. Write a manifest for each agent with an ID, a named owner, a purpose and a region — even if permissions stay unchanged. Add X-Agent-Id and parent headers at the gateway and log them. Stand up the inventory page. Build tier-one pause first, as a single API call plus a runbook. Every log line at the gateway names one agent; every agent has a named owner; any engineer can pause one agent in under a minute.
Days 31–60
Secretless and JIT
Point the identity service at your environment's native identity and wire token exchange for one agent end to end. Migrate the rest, highest-privilege first. Delete the shared account once traffic on it is zero — and verify with logs, not with confidence. Move to per-task credentials with TTLs sized to tasks; add re-attestation for long-running agents. Add the CI check that fails on credential-shaped configuration. No long-lived secret in any agent deployment; the old shared account is deleted; credential TTLs are five minutes or less.
Days 61–90
Revocation, lifecycle, monitoring
Ship tiers two and three with a revocation list and deny-first gateway behaviour, replicated per region. Add canary agents and the weekly drill with blast-radius assertions. Wire agents into joiner, mover, leaver; turn on orphan detection and identity expiry. Enable the anomaly alerts and tune them for a fortnight. Set spawn caps and a delegation depth limit of two. A scheduled drill proves revocation works within target and does not over-reach; no identity lacks an active owner; escalation attempts and spawn storms page someone.

Two sequencing notes. Attribution comes first because it is cheap, it breaks nothing, and it converts every later argument from opinion into data — including the argument for funding the rest. And tier-one pause lands in the first month deliberately: it is the control your team will use before any of the more sophisticated work exists, and it earns credibility for the programme in a way that a design document cannot.

Conclusion and next steps

Scoping a credential and owning an identity are different jobs. Scope decides how much harm a single action can do; identity decides whether you can name the actor, reach the accountable human, and stop that actor alone. A fleet of agents behind one shared key can be perfectly least-privileged and still leave you unable to answer the only three questions that matter during an incident.

The target state is not exotic, and the primitives are available in mainstream platforms as of September 2026. Each agent is a non-human identity with a unique ID, a named human owner, fine-grained time-bound permissions and continuous monitoring. It authenticates through the environment it runs in rather than a secret it carries. It receives credentials just in time, sized to the task, and re-attests instead of holding a long TTL. It can be paused in seconds, revoked in seconds, and revoked as a class when a shared flaw demands it — and you know all three work because you rehearse them. It goes through joiner, mover and leaver like a colleague, and it expires if nobody renews it.

If you do one thing this week, make it attribution: add the agent ID and parent ID to every gateway log line and stand up the inventory page. It takes days rather than weeks, it breaks nothing, and the first honest look at who owns what tends to make the rest of this programme argue for itself.