Pattern
August 7, 2026
9 min read
Maxime Dalessandro

AI agents are getting identities. Postgres still sees one role.

A $1B week priced AI agent identity, but every identity product stops at the connection string. The Postgres mechanics of per-agent, short-lived credentials.

#AI agents#Postgres#Database security#Ephemeral credentials#Non-human identity#Audit trails#Guardrails

TL;DR. In nine days spanning late July and early August 2026, Cyera agreed to buy Oasis Security at a reported $1 billion, Okta signed for Permiso at roughly $200 million, Rubrik shipped per-tool-call tokens for agents, and Cloudflare tied every AI request to a named identity. The market has decided AI agents need identities. But every one of these products stops at the connection string: the database at the end of the chain still sees one standing role shared by every agent. This post covers the Postgres half: per-agent roles, short-lived credentials via a template-role pattern, the credential-versus-session-lifetime trap, attribution when usernames are ephemeral, and the pooler configurations that silently erase all of it.

The identity industry has just put a price on AI agent identity. Cyera agreed to acquire Oasis Security, a non-human identity governance platform, at a reported $1 billion. Okta signed a definitive agreement for Permiso Security, which tracks threat activity across human, machine, and agent identities, at about $200 million. Then Black Hat opened and Rubrik unveiled Agent Identity, which mints a scoped, short-lived token for every single MCP tool call, while Cloudflare shipped an Identity-Aware AI Gateway that links each AI request to a named employee or agent. Four moves, nine days, one thesis: an agent should act as itself, with its own identity, its own scope, and its own trail.

Here is the uncomfortable part for anyone running agents against Postgres. All of that identity machinery lives above the database. The token that authorizes the tool call is not the credential that opens the connection. At the bottom of the chain, in most deployments we have seen described publicly, sits one standing database role with one long-lived password, shared by every agent in the fleet, checked exactly once per connection, and named app or agent or worse. The industry consolidated around agent identity in a week. The database layer has not noticed yet.

Nine days that priced agent identity

The deals are worth a moment, because they establish that this is no longer a niche concern. Oasis built governance for non-human identities: service accounts, workloads, and now agents, the identities that outnumber humans in most enterprises by an order of magnitude. A reported $1 billion for that platform, days after Cyera raised at a $12 billion valuation, is a statement about where the exposure is. Okta folding Permiso into its core platform means agent identity threat detection is becoming a default expectation of an identity provider, not an add-on.

Rubrik's Agent Identity is the most technically interesting of the four, because it commits to a granularity: not identity per agent, not identity per session, but a short-lived token minted per tool call, checked against policy before each action executes. Cloudflare's gateway makes the complementary move at the network layer, refusing to let any AI request pass without a named owner attached.

Whatever you think of the individual products, the direction is uniform: standing access for agents is on its way out, one layer at a time. Which raises the question of what the equivalent move is at the layer these products do not touch.

An agent identity stops at the connection string

Trace what actually happens when a governed agent touches your database. The agent authenticates to the gateway as agent:invoice-reconciler. The gateway checks policy and mints a scoped token for the tool call. The MCP server receives the call, validates the token, and then opens a connection to Postgres using the credential in its environment: a static username and password, the same one it uses for every agent, every task, every day. From the database's point of view, invoice-reconciler does not exist. Neither does the tool call, the task, or the token. There is one user, and it is everyone.

This is the gap a production database access policy has to close, and it has two costs. The first is blast radius. A standing credential is valid until someone rotates it, and rotation happens on human timescales: quarters, sometimes years. Agents ingest untrusted input, and a read-only grant does not stop exfiltration of everything that grant can see. A leaked ephemeral credential is a fifteen-minute problem scoped to one agent. A leaked standing credential is an open-ended problem scoped to the whole fleet.

The second cost is attribution. When twelve agents share one role, pg_stat_activity, the server log, and every audit tool keyed on the user column can tell you that something ran, but not which agent ran it. Incident forensics stops at the role name. The audit trail you owe your future incident review has a hole exactly where the interesting question is.

Postgres checks the credential once, then never again

The Postgres primitive everyone reaches for first is VALID UNTIL:

CREATE ROLE agent_run_4821 WITH LOGIN
  PASSWORD 'generated-by-your-secrets-engine'
  VALID UNTIL '2026-08-07 14:45:00+00';

It looks like a TTL on access. It is a TTL on authentication. The expiry is evaluated during the password handshake and at no other moment. A session opened one second before the deadline survives it indefinitely; the role keeps existing, and the live session keeps its privileges. The managed-cloud equivalents share the trap: an RDS or Cloud SQL IAM authentication token expires fifteen minutes after issuance, but a connection opened with it lives as long as the client holds it. Identity vendors sell "short-lived credentials", and the phrase quietly means short-lived handshakes.

So bounding the credential is half the job. The session needs its own bounds, and Postgres has them, settable per role so they travel with the identity:

ALTER ROLE agent_template SET statement_timeout = '30s';
ALTER ROLE agent_template SET idle_in_transaction_session_timeout = '30s';
ALTER ROLE agent_template SET idle_session_timeout = '5min';  -- Postgres 14+

For revocation that cannot wait for a timeout, there is pg_terminate_backend() against the sessions in pg_stat_activity whose usename matches the role being retired. Any automation that drops expired agent roles needs this step first: DROP ROLE fails while sessions exist, which is exactly the failure mode of naive cleanup jobs.

Per-agent identity in plain Postgres

None of this requires buying anything. The pattern that secrets engines automate is two roles deep. A standing template role holds the grants and cannot log in. An ephemeral login role, created per agent or per task, inherits the grants and carries the expiry:

-- Standing: the scope, no login.
CREATE ROLE agent_readonly NOLOGIN;
GRANT USAGE ON SCHEMA app TO agent_readonly;
GRANT SELECT ON app.orders, app.customers_masked TO agent_readonly;

-- Ephemeral: the identity, minted per task, dropped after.
CREATE ROLE agent_recon_x7f3 WITH LOGIN
  PASSWORD '...'
  VALID UNTIL '2026-08-07 14:45:00+00'
  IN ROLE agent_readonly;

HashiCorp Vault's database secrets engine runs precisely this shape: its creation statements template a CREATE ROLE ... VALID UNTIL ... IN ROLE, it hands the generated username and password to the caller as a lease, and its revocation statements drop the role when the lease expires. The standing thing in your infrastructure stops being a credential and becomes a grant set. What logs in is disposable.

Standing shared credential

Lifetime
months to years, rotated by humans
Leak impact
whole fleet's scope, open-ended
Attribution
one username for every agent
Revocation
rotate and redeploy everything
Postgres objects
one LOGIN role

Ephemeral per-agent credential

Lifetime
minutes to hours, expires alone
Leak impact
one agent's scope, minutes
Attribution
username = agent + task
Revocation
let the lease lapse, terminate backends
Postgres objects
NOLOGIN template + disposable LOGIN roles

Rubrik's per-tool-call granularity has a Postgres analogue too, without a new connection per call. Hold the connection under a low-privilege login role and scope each unit of work inside a transaction:

BEGIN;
SET LOCAL ROLE agent_readonly;
-- the tool call's statements run here, under the scoped role
COMMIT;  -- SET LOCAL evaporates with the transaction

SET LOCAL ROLE resets at commit or rollback, which makes it the one form of role switching that stays correct under transaction pooling. The gateway or MCP server issues it per call, and the privilege boundary moves per action while the connection stays warm.

Ephemeral usernames break your audit trail unless you plan for it

There is a real cost to disposable identities, and teams hit it in their first incident review: the log is full of usernames like v-token-agent-recon-x7f3 that stopped existing twenty minutes after they were created. The grep-for-the-username workflow dies. Three habits restore it, and end up making the trail stronger than the shared-role baseline.

First, keep the join key. The secrets engine knows which lease produced which username for which caller at which time; export that mapping to wherever your logs live, at issuance time, not on demand. Second, log the username on every line: log_line_prefix = '%m [%p] user=%u app=%a ' puts %u and application_name in front of every statement the server records. Third, make the agent runtime set application_name to the task or run identifier when it connects. Now every logged statement carries agent, task, and time, and the ephemeral username is a feature: it maps to exactly one agent doing exactly one task in exactly one window, which is more than a standing shared role could ever tell you.

The pooler is where per-agent identity goes to die

One infrastructure component can quietly erase everything above: the connection pooler. PgBouncer in transaction mode multiplexes many clients onto few server connections, and those server connections authenticate as whatever the pool is configured with. Route twelve per-agent credentials into a pool that connects onward as one role, and you have rebuilt the shared credential with extra steps; the database sees the pool's user, and attribution ends at the pooler's doorstep.

The escapes are known, they just have to be chosen deliberately. Per-role pools preserve identity at the cost of connection-count multiplication. Auth passthrough setups let the pooler authenticate each client with its own credential. And the SET LOCAL ROLE pattern above keeps identity per transaction even through a shared pool, provided nothing uses plain SET ROLE, which leaks session state across transaction boundaries to whichever client borrows the connection next.

Two honest caveats close the loop. Ephemeral credentials bound leaks and restore attribution; they do not judge intent. An agent holding a perfectly scoped, fifteen-minute credential can still run a catastrophic query inside its scope in milliseconds, which is why identity is one layer of a safe production access setup, alongside a policy gate in the data path. And per-task role churn has operational weight: role creation is cheap in Postgres, but catalogs, grants on new tables, and cleanup jobs all need owners. This is a pattern to adopt deliberately, not a checkbox.

The direction, though, is not in doubt. A market that just paid a billion dollars for non-human identity governance has decided that standing credentials for agents are the anomaly. The primitives to fix it have been sitting in Postgres all along.

Datapace is building the context layer between your databases and your AI: resolved meaning validated by the people who own the data, the workload evidence beside it (cost, performance, usage and freshness, lineage), and a policy gate over what an agent may do and access, served over MCP. If you are working out what governed agent access to production data should look like for your team, book a call and we can walk through it.

Sources

  1. Cyera agrees to acquire Oasis Security for ~$1B, TechCrunch, July 28, 2026
  2. Okta buys AI security startup Permiso for about $200M, TechCrunch, July 30, 2026
  3. Rubrik unveils Agent Identity to govern AI agents one tool call at a time, SiliconANGLE, August 4, 2026
  4. Cloudflare launches Identity-Aware AI Gateway, SiliconANGLE, August 5, 2026
  5. PostgreSQL documentation: CREATE ROLE (VALID UNTIL, IN ROLE)
  6. PostgreSQL documentation: client connection defaults, idle_session_timeout
  7. HashiCorp Vault: database secrets engine, PostgreSQL
  8. AWS RDS: IAM database authentication token lifetime
  9. PgBouncer documentation: pooling modes and session state

Frequently asked questions

How do I give an AI agent its own database identity in Postgres?
Create a dedicated role per agent instead of sharing an application credential, and make the login credential short-lived. The standard pattern is a standing template role that holds the grants but cannot log in, plus a dynamically created login role per agent or per task that inherits from it via IN ROLE and expires via VALID UNTIL. Secrets engines like HashiCorp Vault automate the create-and-drop lifecycle. The username in pg_stat_activity and the logs then tells you which agent ran which statement.
Does VALID UNTIL in Postgres terminate a session when the password expires?
No. VALID UNTIL is checked only during password authentication, when the connection is established. A session opened one second before expiry stays open indefinitely after it. The same applies to IAM authentication tokens on RDS and Cloud SQL: the token has a lifetime of minutes, the session it opens does not. To bound the session itself, set idle_session_timeout, idle_in_transaction_session_timeout, and statement_timeout on the role, or terminate sessions explicitly with pg_terminate_backend.
Do ephemeral database credentials break audit logs?
They break the naive workflow of grepping the log for a known username, because a dynamically created role has a generated name that exists for minutes. The fix is to keep the join key: record the mapping from secrets-engine lease to agent and task at issuance time, log usernames with %u in log_line_prefix, and have the agent runtime set application_name to the run or task identifier so every log line carries it. The audit trail then gets stronger than with a shared role, because each username maps to exactly one agent and task.
Does connection pooling defeat per-agent database identity?
It can. A pooler multiplexing many clients over a few server connections under a single role erases the per-agent identity before it reaches Postgres. Options that preserve identity: separate pools per agent role, authenticating the pooler per client credential rather than a shared one, or scoping identity per transaction with SET LOCAL ROLE, which is safe under transaction pooling because it resets at commit. What is not safe under transaction pooling is plain SET ROLE, which leaks across transaction boundaries to other clients.
Why not just give all AI agents one shared read-only credential?
Two reasons. Attribution: with a shared credential, the database cannot tell which of your agents ran a statement, so incident forensics stops at the role name. Blast radius: a leaked standing credential is valid until someone notices and rotates it, and agents handle untrusted input that can exfiltrate whatever they can read. A per-agent, short-lived credential bounds the leak to one agent's scope for a few minutes and makes every statement attributable.

Keep reading

Ready to let agents touch production, safely?

Bring a use case. We will show you what agents can do on your live data, inside your guardrails.