Skip to content

Passwordless everywhere

The first deep page in the trust arc. Two sides — app → services and app → database — with the same load-bearing rule: fetch a fresh token on each connect; never cache a connection string. The surface intro named the pattern; this page proves the wire.

The one rule

Zero secrets in your app. Every outbound call is authenticated with a token minted just before use by the platform on behalf of the workload identity. If the words "database password" or "long-lived key" appear in your config, you've dropped out of passwordless mode.

The secrets anti-pattern

DATABASE_URL="postgresql://admin:my_password_never_rotates@…"    # ← THIS
API_KEY="sk-a1b2c3d4e5f6…"                                       # ← THIS

Every one of these:

  • must be created, stored, rotated, revoked by someone — usually a person with a spreadsheet;
  • outlives the workload that uses it (still valid after the pod dies, after the operator quits);
  • fans out — every leak surface (build logs, CI vars, .env in a git commit, exception traces) becomes a compromise vector;
  • can't be tied to who is running the code — only to what has the string.

The passwordless model replaces every one of those strings with a short-lived, workload-scoped, platform-minted token. The platform is the credential authority; your code never sees a static key.

The two halves

  • App → services — how the workload asks the platform for an access token for a cloud service (Key Vault, S3, Vertex AI, whatever). IMDS / metadata server / IRSA. Token lifetimes, refresh, the "cache in the SDK, not in your code" rule.
  • App → database — the same workload identity, one hop further: fetch a fresh DB token on every connect, hand it to psycopg as the password, let the connection pool churn it. Azure Entra token for Postgres (audience https://ossrdbms-aad.database.windows.net/.default), Cloud SQL IAM auth via the Python Connector, RDS generate_db_auth_token().

Docs verified 2026-08-08

Token-refresh vs pooling — the load-bearing subtlety

A traditional connection pool keeps a bag of live TCP connections, each authenticated once at open time. If your DB token expires at 15 minutes but a pooled connection stays open for 12 hours, the connection still works — the token was consumed on the initial handshake; the DB doesn't re-check it on subsequent queries. Different clouds have different rules here:

Provider Token used for Re-validation after connect? Practical rule
Azure Entra → Postgres Initial libpq authentication No — connection lives as long as it's open Cap pool_recycle at token lifetime (55 min for a 60-min token) so a pool never carries a session past the token's practical trust horizon.
Cloud SQL Connector Connector refreshes the underlying IAM token in the background before the ephemeral cert expires Managed by the connector Use the connector as documented; do not hand-roll a token loop around it.
RDS IAM generate_db_auth_token() Initial libpq authentication No — 15-min token used once, connection lives on Cap pool_recycle at 14 min (below the 15-min token TTL) so every new physical connection uses a fresh token.

Two failure modes to design against:

  1. Cached connection strings. If your app stores postgresql://user:<token>@host/db anywhere (an env var, a config object, a wrapper class), it dies the first time that token expires. Store the ingredients (workload identity, hostname, user, DB name), regenerate the password on demand.
  2. SQLAlchemy engines with default pool_recycle=-1. Same problem — a physical connection lives forever, but its auth token doesn't. Set pool_recycle explicitly, per the table above.

The examples show the "fetch fresh on each connect" pattern with psycopg using a password callable — a per-connection token acquisition function passed to the connector so every physical connect goes through a fresh mint.

What passwordless does NOT solve

  • Authorization. Passwordless proves what identity is calling — it says nothing about whether that identity is allowed. Grant narrow IAM/DB roles alongside; passwordless is the credential story, not the policy one.
  • Client-supplied secrets (API keys the end user brings). Passwordless is about the workload's outbound calls. What your users pass in over your API is a separate design problem — see Guardrails + Trust — attributed writes.
  • Cross-account trust. Workload identity federation across accounts adds its own layer (Entra guest tenants, GCP Workload Identity Federation from AWS, AWS sts:AssumeRole between accounts). Same pattern, more setup — a deeper page in this arc covers it.

Where the arc goes next

  • App → services — how to get a token for a cloud service, per provider.
  • App → database — the same identity, but landing as a DB password with the right refresh rule.
  • Later in the arc — cross-account/tenant federation, and RBAC/RLS composed on top of these two halves.