hashicorp/vault
Activity / client counting
Vault counts unique clients per month for licensing and billing. The activity log subsystem is a piece of operational telemetry hidden in the vault package: vault/activity_log.go is 117k bytes in a single file, with helpers in vault/activity_log_util*.go, vault/activity/, and sdk/helper/clientcountutil/.
Purpose
- Identify each unique client (entity, non-entity token, ACME identity) that interacted with Vault in a given billing period.
- Roll those identities into monthly summaries on disk.
- Surface the counts via
sys/internal/counters/activityand via Enterprise utilization reports.
Data flow
graph LR
Req[Authenticated request] -->|hashed entity / token id| AL[ActivityLog.HandleTokenUsage]
AL --> Buckets[Per-month bitmap buckets in memory]
Tick[Periodic ticker] --> Persist[Persist segment files under sys/counters/]
Tick --> Roll[Roll up monthly summaries]
Op[sys/internal/counters/activity] --> AL
AL --> Op
Enterprise[Utilization reporter] --> RollEach request that's authenticated becomes a single update to a per-month bitmap. The bitmap is keyed by an HMAC of the entity ID (or, for non-entity tokens, the token's namespace + accessor). When a roll-up runs, the bitmap is walked to count distinct keys and persisted as a summary segment.
Why it's so much code
The single-file size comes from:
- Three different "client types" (entity, non-entity token, ACME identity) plus mount-level breakdown.
- Multiple rollup intervals (per minute, hour, day, month, billing cycle).
- Replication-aware merging (a perf-secondary pre-aggregates and ships partial bitmaps to the primary).
- Backfill: re-counting a window when configuration changes.
- Privacy options: operators can disable the activity log entirely.
Configuration
vault write sys/internal/counters/config \
enabled=enable \
retention_months=24 \
default_report_months=12 \
minimum_retention_months=12The config decides whether to count, how long to keep data, and the default reporting window. With enabled=disable the in-memory bitmaps are never written to storage.
API endpoints
sys/internal/counters/activity— read per-month and per-mount counts.sys/internal/counters/activity/export— JSONL export of clients (Enterprise + redacted in OSS).sys/internal/counters/config— read/write config.sys/internal/counters/tokens— count of in-memory tokens.
Billing / Enterprise integration
vault/billing/, vault/consumption_billing*.go, and vault/logical_system_use_case_billing.go (~38k LoC together) build on the activity log to drive Enterprise's utilization-reporting workflow. The data flows monthly into vault operator utilization-friendly bundles.
Privacy
Counting is pseudonymous: the activity log stores HMAC'd IDs, not the underlying entity names or token IDs. Even an exposed activity log doesn't directly leak who used Vault, just how many distinct identities did. Operators that consider even pseudonymous counting too sensitive can disable it with enabled=disable.
Integration points
- Hooked into
Core.HandleRequestto record every authenticated call. - Stored under the system mount's storage view (
sys/counters/...). - Surfaced via the activity API endpoints.
- Cert-counting (
vault/cert_count/) integrates with PKI issuance to count unique cert subjects as a separate client class.
Entry points for modification
- Add a new client class: extend
clienttype_enumer.goand theHandleTokenUsageswitch. - Change rollup intervals: see the constants in
vault/activity_log.go. - New export format:
vault/logical_system_activity*.goandvault/activity/.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.