libvault – RustyVault Library
libvault is the embedded Rust library that provides the core functionality of
RustyVault, a lightweight, HashiCorp‑Vault‑compatible secrets manager written in
Rust. It is used by RK8s as the certificate authority and general
key‑value store for the control plane (RKS) and data nodes (RKL).
Table of Contents
- Why libvault?
- Key Concepts
- Architecture Overview
- Public API (Rust)
- Typical Workflows
- Modules
- Storage Back‑ends
- Security Model
- Building & Testing
- License
Why libvault?
- Embedded – No external process is required; you can embed the vault directly into any Rust binary (e.g., the RKS control plane).
- Full Vault semantics – Supports KV, PKI, auth methods, policies, and token‑based access control.
- Zero‑knowledge storage – All secret material is encrypted with a Security Barrier before being persisted.
- Modern Rust – Async‑ready,
ArcSwap‑based lock‑free state,zeroizefor secret memory wiping, andthiserrorfor typed errors.
Key Concepts
| Concept | Description |
|---|---|
| Seal / Unseal | The vault starts in a sealed state. A seal configuration defines how many unseal key shares are required (secret_shares) and the threshold (secret_threshold). Unsealing reconstructs the master KEK using Shamir's Secret Sharing. |
| Root Token | After a successful init, a root token is generated. It grants full privileges and can be used for the first login. |
| Mounts | Logical back‑ends (e.g., kv/, pki/) are mounted under a path. Mounts are stored in the encrypted barrier and can be added/removed at runtime. |
| Modules | Extensible components (auth, kv, pki, credential, policy, crypto, system) that implement the Module trait and are managed by ModuleManager. |
| Handlers | Low‑level request/response hooks (pre_route, route, post_route, log) that can be added to customise processing. |
| Physical Backend | The actual storage implementation (file‑based, Xline KV, etc.) that the barrier reads/writes to. |
Architecture Overview
+-------------------+ +-------------------+ +-------------------+
| RustyVault | | SecurityBarrier | | PhysicalBackend |
| (Core) |<---->| (AES‑GCM) |<---->| (File / Xline) |
+-------------------+ +-------------------+ +-------------------+
^ ^ ^ ^
| | | |
| | +-------+-------+ +--------+--------+
| +---------------->| MountsRouter| | ModuleManager |
| +---------------+ +-----------------+
| |
| +----------+----------+
| | Logical Back‑ends |
| +---------------------+
| (KV, PKI, Credential …)
+--------------------+-------------------+
- Core – Holds the runtime state (
CoreState), the barrier, router, and module manager. - SecurityBarrier – Encrypts/decrypts all data using a KEK derived from unseal keys.
- PhysicalBackend – Pluggable storage. The default is a mock backend for tests; production uses a file backend (during bootstrap) or Xline KV after migration.
- MountsRouter – Resolves a request path (
sys/mounts/...) to the appropriate logical backend. - Modules – Provide higher‑level functionality (e.g., PKI creates certificates, KV stores secrets).
Public API (Rust)
libvault exposes a single entry point: RustyVault.
use ;
use HashMap;
// 1️⃣ Choose a physical backend (file‑based for bootstrap)
let mut conf = new;
conf.insert;
let backend = new_backend?;
// 2️⃣ Optional configuration (mount HMAC level, monitor interval, …)
let config = Some;
// 3️⃣ Create the vault instance
let vault = new?;
// 4️⃣ Initialise the vault (first time only)
let seal_cfg = SealConfig ;
let init_res = vault.init.await?;
println!;
// 5️⃣ Unseal with enough key shares
let unseal_keys = vec!;
for key in unseal_keys
// Note: `unseal_once` rotates keys automatically upon successful unseal
// 6️⃣ Set the root token for subsequent calls
vault.set_token;
// 7️⃣ Example: mount a KV engine and store a secret
vault.mount.await?;
let data = json!.as_object.cloned;
vault.write.await?;
let resp = vault.read.await?;
println!;
Core Methods
| Method | Purpose |
|---|---|
new(backend, config) |
Create a new RustyVault instance. |
init(seal_cfg) |
Initialise the vault, generate root token and (optionally) initial unseal keys. |
unseal(key) / unseal_once(key) |
Provide unseal key(s); unseal_once also rotates keys. |
seal() |
Seal the vault, wiping KEK from memory. |
mount(token, path, type) |
Create a new logical mount (e.g., kv, pki). |
unmount(token, path) |
Remove a mount. |
read/write/delete/list(token, path, data) |
Low‑level CRUD operations on logical back‑ends. |
login(path, data) |
Perform an auth login; stores returned client token for later calls. |
set_token(token) |
Manually set the client token to be used for subsequent calls. |
All async methods return Result<_, libvault::errors::RvError>.
Typical Workflows
Bootstrapping a New Cluster
- Generate a temporary PKI –
rks gen pems --config config.yamlstarts an embedded Vault with a file backend and creates a root CA, RKS certificate, and an Xline KV certificate. - Persist PEM files – The generated PEMs are saved to disk for later use.
- Start RKS –
rks start --config config.yamllaunches the control plane, unseals the embedded Vault and migrates data from the file backend to Xline. - Migration – Vault reads all encrypted entries from the file backend and writes them to Xline, after which Xline becomes the primary storage.
The above steps are captured in the original Mermaid diagrams; the Rust implementation follows the same sequence via the
RustyVaultAPI.
Storing & Retrieving Secrets
// Mount a KV engine at `secret/`
vault.mount.await?;
// Write a secret
let data = json!.as_object.cloned;
vault.write.await?;
// Read it back
let resp = vault.read.await?;
println!;
PKI / Certificate Issuance
// Enable the PKI engine
vault.mount.await?;
// Configure a role that allows issuing leaf certificates
let role_data = json!;
vault.write.await?;
// Issue a leaf certificate (CSR is sent in the request body)
let csr = read_to_string?;
let issue_data = json!;
let cert_resp = vault.write.await?;
println!;
Modules
| Module | Responsibility |
|---|---|
| auth | Token issuance, login, token revocation, token lookup. |
| kv | Simple key‑value store (versioned, metadata, TTL). |
| pki | Certificate Authority, role‑based issuance, CRL generation. |
| credential / cert | Higher‑level certificate handling used by RK8s for node bootstrapping. |
| policy | ACL policies that control token capabilities. |
| crypto | Cryptographic helpers (e.g., HMAC, RSA/ECDSA adapters). |
| system | Internal system paths (sys/) such as seal config, health checks, and mounts. |
Modules are loaded automatically by RustyVault::new; additional custom modules can be added via
Core::add_handler or Core::add_auth_handler.
Storage Back‑ends
- FileBackend – Plain files under a directory (used for the initial bootstrap).
Data is encrypted with the barrier before being written. - XlineBackend – Distributed KV store (used in production).
The migration pathCore::migratecopies all entries from the file backend to Xline. - MockBackend – In‑memory backend used by unit tests.
Backends implement the storage::Backend trait and can be swapped at runtime.
Security Model
- Seal / Unseal – Vault starts sealed. Unseal requires a threshold of key shares
generated via Shamir’s Secret Sharing. Keys are held in a
Zeroizing<Vec<u8>>wrapper to guarantee memory wiping. - Zero‑knowledge – All secret material (keys, certificates, KV entries) is stored behind the AES‑GCM barrier. The barrier key (KEK) is never persisted.
- Token‑based auth – Every request must include a client token; tokens carry policies that restrict capabilities.
- In‑memory only for private keys – When RKL nodes receive a client certificate, the private key is never written to disk; it lives only in process memory.
- Audit logging – Structured audit events for each request phase are emitted via
Handler::logon top of thetracingcrate, while some components still emit traditional logs via thelogcrate. Configure observability to handle both.
Building & Testing
# Build the library
# Run unit tests (including async tests)
# Benchmark hot paths (e.g., seal/unseal, KV read/write)
The crate follows the repository‑wide policies:
rustfmtwith defaults.clippywarnings are treated as errors for new code.- Avoid
unwrap()/expect()in new library code and public APIs; propagate errors asRvErrorinstead.
License
libvault is dual‑licensed under the Apache‑2.0 and MIT licenses, as
declared in the LICENSE-APACHE and LICENSE-MIT files at the repository root.
For further details, see the source code under src/ and the
copilot-instructions.md file for repository‑wide conventions.