Skip to main content

Command Palette

Search for a command to run...

How Vault Enterprise Actually Counts Clients

An empirical look at entities, tokens, and billing behavior

Updated
9 min read
M

HashiCorp Vault SME Certified | Passionate about secure secrets management and cloud infrastructure. Sharing insights, tutorials, and best practices on HashiNode to help engineers build resilient, scalable systems. Advocate for DevSecOps and cutting-edge security solutions.

Summary for decision-makers

  • Vault Enterprise bills by client identity, not by token count
  • Entity-backed authentication (LDAP, OIDC, userpass, AppRole with aliases) produces stable, predictable billing
  • Non-entity tokens (direct token creation, orphan tokens, token auth) are billed by unique policy set and can grow unexpectedly
  • Migrating to entity-backed auth is the only reliable way to control client counts

Current best practices to control client counts

  1. Prefer entity-aware auth methods whenever possible
  2. Use entity-aware auth for CI/CD and bootstrap (AppRole, Kubernetes auth, cloud IAM, JWT/OIDC)
  3. For lifecycle independence, re-authenticate via entity-aware method instead of using orphan tokens
  4. Use batch tokens (non-orphan) for short-lived credentials
  5. Audit regularly with sys/internal/counters/activity and audit logs
  6. Monitor for policy name changes and refactors (they create new client identities)

If you run Vault Enterprise in production, you will eventually encounter a moment where the client count doesn't match your expectations.

Nothing changed in your workloads. Nothing new was deployed. And yet the number moved—sometimes sharply.

This post exists to explain why.

Not based on assumptions. Not based on sales slides. But based on controlled, repeatable testing against Vault Enterprise.

The short version is this:

Vault Enterprise does not count tokens. It counts clients. And client identity is derived in two fundamentally different ways, depending on how a token was created.

Understanding that distinction explains most billing surprises—and helps you avoid creating them.


Scope and methodology

All findings below are based on:

  • Vault Enterprise 1.21.1
  • Raft storage
  • Tokens were actually exercised against Vault (unused tokens do not count as clients)
  • Client counts observed via sys/internal/counters/activity

Where Vault behavior is documented, I say so. Where behavior is empirical, I am explicit about that.


The two client identity models

Vault Enterprise uses two distinct client identity models.

1. Entity-backed clients (stable, predictable)

When authentication happens via an entity-aware auth method, Vault assigns an entity_id.

Examples:

  • userpass
  • LDAP
  • OIDC / JWT
  • AppRole

In this model:

  • All tokens associated with the same entity_id count as one client
  • Token policies do not affect client count
  • Child tokens inherit the entity automatically

This behavior is documented and stable.

Note: This deduplication can be dramatic. A single entity-backed user with sudo capability on auth/token/create can mint tokens with any policy—not just subsets of their own. This bypasses the normal "child policies must be subset of parent" rule (see token create documentation). The result: one user creating hundreds of unique policy set combinations, all collapsing to one client. This is efficient for billing, but means client count no longer reflects actual token or policy diversity.

Effectively, client identity behaves as:

client ~ namespace + entity_id

2. Non-entity clients (policy-based, unstable)

When a token is created without entity context, Vault assigns no entity_id.

In this case, client identity is derived from the policy name combination attached to the token.

Empirically, client identity behaves as if derived from:

client ~ namespace + sorted(unique_policy_names)

This behavior is not fully documented, but it is consistent, repeatable, and observable across versions. And it is the source of most billing surprises.

Important: Since Vault 1.9, non-entity tokens with identical namespace + policy sets are deduplicated into a single client (via a constructed entity). Pre-1.9 behavior was much worse—often counting one client per token. The combinatorial explosion described below still applies, but only unique policy sets count.


The policy-set explosion

For non-entity tokens, each unique set of attached policy names creates a separate billed client. Order is irrelevant—[p1, p2] and [p2, p1] are the same client.

Example:

[p1]        -> client A
[p2]        -> client B
[p1, p2]    -> client C
[p1, p3]    -> client D

Four unique policy sets. Four billable clients.

With N policies, the worst case is:

2^N - 1 clients

This is combinatorial growth, not theoretical—and it appears quickly in real systems.

In a real environment with 10 policies, modest variation in policy sets can already produce hundreds of clients where entity-backed authentication would produce one.


How non-entity tokens are created

Non-entity tokens are not edge cases. They are easy to create—often accidentally.

Confirmed creation paths

Direct token creation

vault token create

Common during bootstrap, automation, or CI/CD.

Token chains from a non-entity parent

If the parent token has no entity, children inherit none. The entire chain remains non-entity forever.

Token auth method

auth/token/create

Tokens created via the token auth method have no entity by design.

Orphan tokens

vault token create -orphan

Even when created by an entity-backed user, orphan tokens explicitly drop entity context.

Once a token is non-entity, policy-set-based identity rules apply and client counting becomes unstable.

These paths aren't rare edge cases—they're everyday automation patterns that sneak in during bootstrap, scaling, or CI/CD integration.


Why orphan tokens exist

Orphan tokens solve a real operational problem: lifecycle independence.

They are commonly used for:

  • Long-running batch jobs
  • CI/CD pipelines
  • Service bootstrap tokens
  • Cross-team delegation
  • Break-glass scenarios

In all cases, the requirement is the same:

"This token must survive the revocation or expiration of the token that created it."

That is exactly what orphan tokens do. But there is a cost.


The critical orphan token rule

Orphan tokens never inherit entity_id. Not sometimes. Not conditionally. Never.

This was tested via:

  • Orphan creation from root
  • Orphan creation from entity-backed users with sudo
  • Orphan token child chains

In all cases:

  • entity_id = n/a
  • Token is treated as non-entity
  • Policy-based client identity applies

Child vs orphan tokens

PropertyChild tokenOrphan token
Inherits entity_idYes (if parent has one)No
LifecycleRevoked with parentIndependent
Client identityEntity-basedPolicy-set-based
Client explosion riskOnly if parent is non-entityAlways

There is no native Vault mechanism that provides both:

  • lifecycle independence and
  • entity-anchored client identity

If you need both, you must re-authenticate via an entity-aware auth method.


Children of orphan tokens

Orphan tokens do not inherit entity context. Neither do their children.

Entity user (entity_id: abc-123)
    |
    +-- [creates orphan] --> orphan token (entity_id: n/a)
                                  |
                                  +-- child A (entity_id: n/a)
                                  |       |
                                  |       +-- grandchild (entity_id: n/a)
                                  |
                                  +-- child B (entity_id: n/a)

Once a token becomes non-entity, the entire chain remains non-entity forever. There is no mechanism to recover entity context downstream—the only option is to discard the chain and re-authenticate.


Batch tokens: the safe alternative

Batch tokens behave differently—and this matters.

Batch tokens inherit entity_id like service tokens, but can't be renewed or create children—making them safer for short-lived automation where you don't want token sprawl.

vault token create -type=batch -policy=p1

Result:

  • entity_id inherited
  • No new client created

However:

vault token create -type=batch -orphan -policy=p1

Result:

  • entity_id lost
  • New non-entity client (based on policy set)

Batch vs service tokens

Token Typeentity_idNew Client?RenewableChildren
Service (child)InheritedNoYesYes
Service (orphan)LostYesYesYes
Batch (normal)InheritedNoNoNo
Batch (orphan)LostYesNoNo

Batch tokens are appropriate when you need:

  • Short-lived credentials
  • No renewal
  • No child tokens
  • Entity-anchored billing

From a billing perspective, batch tokens behave like entity-anchored child tokens—unless created with the -orphan flag.


Remediation options

If you're currently using non-entity tokens and want to reduce client count:

Current StateRecommended MigrationClient Impact
Root token -> child tokensEntity-aware auth methodReduces to 1 client per identity
Orphan tokens for CI/CDEntity-aware auth with short TTLEntity-anchored, no explosion
Orphan tokens for long jobsRe-auth via entity-aware methodFresh entity-backed token
Token auth methodMigrate to entity-aware authStable identity
Non-entity token chainsRe-auth at chain rootEntire chain becomes entity-backed
Short-lived automationBatch tokens (non-orphan)Inherits parent entity

The common theme: re-authenticate via an entity-aware method rather than creating tokens from tokens.


What does not affect client identity

Explicitly tested and not used in client counting:

  • Token accessor
  • Token creation time
  • Parent token
  • Periodic vs non-periodic
  • Policy content

Policy name matters. Renaming a policy creates a new client. Changing what it allows does not.


Namespaces matter

Client identity is namespace-scoped, which means the same policy set used in different namespaces counts as different clients. This is expected behavior, but it's easy to overlook in multi-namespace deployments where teams might unknowingly duplicate policy structures across namespaces.


Auditing your current exposure

vault read sys/internal/counters/activity/monthly

Warning signs

Look for these patterns in your activity data:

  • Non-entity clients significantly outnumber entity clients
  • Client count grows after policy refactors or renames
  • Many clients with similar or overlapping policy sets
  • Client spikes without corresponding workload changes

If you see these patterns, you likely have policy-set-based client identity at work—and it may be worth investigating migration options.


Documentation and stability

HashiCorp explicitly warns that token behavior may change across versions (see the token documentation). That alone is reason to be cautious about relying on undocumented heuristics for billing-sensitive behavior. The patterns described in this post have been stable since Vault 1.9, but always verify after major upgrades.


Why this matters

This behavior enables both:

Over-counting Policy set sprawl leads to combinatorial client growth, which leads to billing surprises.

Under-counting Many workloads anchored under a single entity can collapse into fewer clients than expected—which might seem like a win until you realize your billing doesn't reflect actual usage patterns.

Real-world example: dozens of microservices as 1 client

A client with a lot of microservices each using distinct policy sets but Vault bills them as a single client.

How it works:

  1. Entity-backed auth (userpass or AppRole) → gets entity_id
  2. sudo on auth/token/create → bypasses "child must be subset of parent" rule
  3. Creates tokens with any arbitrary policy combination
  4. All tokens inherit same entity_id1 client

This is not a bug. It's how entity deduplication works when combined with sudo capability on token creation (see token create documentation).

Trade-off: Billing is efficient, but client count no longer reflects workload diversity. To maintain visibility, consider using audit logs with client ID correlation, or split into multiple entities where usage diversity matters for reporting.


This behavior isn't misuse or misconfiguration. It's simply how Vault works today. The mechanics are consistent and predictable once you understand them, but most teams learn the hard way—staring at an unexpected invoice wondering what changed.

This post exists so you don't have to go through that.


Tested on Vault Enterprise 1.21.1 (Jan 2026). Behavior stable since 1.9, but always verify after upgrades as token mechanics may evolve.