Open-Source Wikis

/

Vault

/

Systems

/

Expiration and leases

hashicorp/vault

Expiration and leases

Every dynamic secret, token, and renewable auth in Vault has a lease, and the expiration manager is what tracks them. Source: vault/expiration.go (3,116 lines), with shared helpers in vault/expiration_util_ce.go and vault/expiration_testing_util_common.go.

Purpose

  • Persist a record for every issued lease so it survives restarts.
  • Schedule per-lease timers that fire at the lease's expiry (or earlier on demand) and trigger revocation.
  • Handle renewals against the issuing backend.
  • Implement bulk operations: revoke-by-prefix, revoke-by-token, force-revoke, leader-only re-claim.

Directory layout

vault/
├── expiration.go                       # Manager + lease entries + revoker pool
├── expiration_testing_util_common.go
├── expiration_util_ce.go               # CE stub
helper/fairshare/                       # The fair-share work queue used by the revoker

Key abstractions

Symbol File Description
ExpirationManager vault/expiration.go Holds the lease state; one per Core.
leaseEntry vault/expiration.go The persisted record: ID, issue time, expiry time, namespace, mount, secret, auth, version.
ExpirationManager.Register vault/expiration.go Called from Core.HandleRequest whenever a backend returns a Secret or Auth.
ExpirationManager.Revoke vault/expiration.go Single-lease revoke. Calls into the issuing backend.
ExpirationManager.RevokePrefix vault/expiration.go Bulk revoke by mount path; used at unmount.
ExpirationManager.RevokeByToken vault/expiration.go Used when a token is revoked: clean up all leases issued through it.
Fair-share scheduler helper/fairshare/ Per-namespace queue so noisy mounts don't starve quiet ones.

How a lease is born

sequenceDiagram
    participant H as Core.HandleRequest
    participant B as Backend
    participant E as ExpirationManager
    participant Phys as Storage barrier
    participant Tim as time.Timer
    H->>B: HandleRequest(read|write|...)
    B-->>H: *logical.Response{Secret: {LeaseID, TTL, Renewable}}
    H->>E: Register(req, resp)
    E->>Phys: persist leaseEntry
    E->>Tim: set timer for expiry
    H-->>Caller: response (LeaseID + TTL exposed)

When the timer fires (or vault lease revoke <id> is called), the manager loads the lease, calls the originating backend's RevokeOperation, deletes the lease entry on success, and removes the parent/child edges.

Renewal

vault lease renew <id> calls into ExpirationManager.Renew, which:

  1. Loads the leaseEntry.
  2. Asks the backend to renew (framework.Backend.HandleExistenceCheck plus the secret's Renew callback).
  3. Extends the timer up to MaxTTL or Period.
  4. Persists the updated leaseEntry.

Tokens have their own renewal path (auth/token/renew) that ultimately funnels into ExpirationManager.RenewToken.

Restart behavior

On Core unseal the manager re-loads every lease entry and rebuilds its timer wheel. Lease entries that have expired during downtime are scheduled for immediate revocation. The "revocation backlog" metric in core_metrics.go reports how many of these are still outstanding.

Fair-share queue

Revocation is CPU- and IO-bound; pursuing thousands at once can knock storage over. helper/fairshare/ provides a multi-queue scheduler where each mount or namespace is a queue. Workers round-robin between queues so a single noisy mount can't starve revocation for everyone else.

Integration points

  • Token store calls RevokeByToken when a token is revoked.
  • Mount / unmount calls RevokePrefix to clean up leases at unmount time.
  • Replication uses RegisterAuth and lease tombstones to keep secondary clusters in sync.
  • Quotas (vault/quotas/) read lease counts to enforce lease-count limits.
  • The activity log subscribes to lease events to count clients.

Entry points for modification

  • Add a new lease attribute: extend leaseEntry in vault/expiration.go and bump the version.
  • Tweak revoker behavior: see revokeWorker and the fair-share configuration.
  • Add a per-mount default TTL: handled at the framework layer (sdk/framework/lease.go) plus the mount tunables in vault/mount.go.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Expiration and leases – Vault wiki | Factory