Core Abstraction: The Vault
TheVault struct crates/palyra-vault/src/api.rs#12-12 acts as the primary interface for secret management. It coordinates between the BlobBackend for raw data storage and the metadata layer for indexing and integrity.
Data Flow: Putting a Secret
When a secret is stored viaput_secret crates/palyra-vault/src/tests.rs#138-138, the following sequence occurs:
- Key Validation: The key is checked for length and character constraints crates/palyra-vault/src/crypto.rs#93-113.
- Object ID Generation: A unique storage ID is derived using SHA-256 of the scope and key crates/palyra-vault/src/crypto.rs#115-122.
- Encryption (Sealing): The payload is encrypted using ChaCha20-Poly1305. The Key Encryption Key (KEK) is derived from the device identity crates/palyra-vault/src/crypto.rs#20-33.
- Blob Storage: The encrypted blob is passed to the active
BlobBackendcrates/palyra-vault/src/backend.rs#90-90. - Metadata Update: An entry is added to
objects.store.jsoncontaining the key, timestamps, and size crates/palyra-vault/src/backend.rs#26-26.
Secret Storage Architecture
The diagram below illustrates how theVault bridges the high-level API to platform-specific storage entities.
Vault System Entities
Sources: crates/palyra-vault/src/api.rs#12-12, crates/palyra-vault/src/backend.rs#88-93, crates/palyra-vault/src/crypto.rs#89-91
Blob Backends
TheBlobBackend trait crates/palyra-vault/src/backend.rs#88-93 abstracts the physical storage of encrypted blobs. The system automatically selects the most secure backend available for the current platform unless overridden in the configuration.
| Backend Kind | Platform | Implementation Details |
|---|---|---|
MacosKeychain | macOS | Uses security CLI to interface with the macOS Keychain crates/palyra-vault/src/backend.rs#28-29. |
LinuxSecretService | Linux | Uses secret-tool to interface with the Freedesktop Secret Service API crates/palyra-vault/src/backend.rs#30-35. |
WindowsDpapi | Windows | Uses DPAPI (CryptProtectData) to bind secrets to the current user’s credentials crates/palyra-vault/src/backend.rs#36-37. |
EncryptedFile | All | Stores blobs in an objects/ directory with filesystem-level owner-only permissions crates/palyra-vault/src/backend.rs#194-205. |
Backend Selection Logic
Theselect_backend function crates/palyra-vault/src/backend.rs#95-133 determines the storage mechanism. If a backend.kind marker file exists in the vault root, it enforces that backend. Otherwise, it follows the BackendPreference (Auto or EncryptedFile) crates/palyra-vault/src/backend.rs#83-86.
Sources: crates/palyra-vault/src/backend.rs#39-49, crates/palyra-vault/src/backend.rs#135-158
Encryption and Key Derivation
Palyra uses an Envelope Encryption model. Secrets are sealed using a device-specific Key Encryption Key (KEK).KEK Derivation Process
The KEK is never stored directly. It is derived at runtime from the device’s private identity material:- Seed Extraction: The
private_key_pemis extracted from the identity store crates/palyra-vault/src/crypto.rs#50-78. - HKDF Expansion: The seed is processed through HMAC-based Key Derivation Function (HKDF) using the salt
palyra.vault.kek.v1crates/palyra-vault/src/crypto.rs#13-14. - Output: A 32-byte KEK is generated for use in ChaCha20-Poly1305 crates/palyra-vault/src/crypto.rs#80-87.
Integrity with AAD
Each secret is bound to its scope and key via Additional Authenticated Data (AAD). The AAD stringpalyra.vault.v1|<scope>|<key> is passed to the AEAD cipher crates/palyra-vault/src/crypto.rs#89-91. This prevents “cipher-text substitution” attacks where an attacker might try to move an encrypted blob from one key to another.
Sources: crates/palyra-vault/src/crypto.rs#13-33, crates/palyra-vault/src/crypto.rs#156-174
Vault Configuration and References
In thepalyra.toml configuration, sensitive fields are not stored as plaintext. Instead, they use a VaultRef.
VaultRef Structure
AVaultRef is a string in the format scope/key (e.g., global/openai_api_key) crates/palyra-vault/src/api.rs#12-12.
Configuration Injection
When the daemon loads the configuration, it identifies paths marked inSECRET_CONFIG_PATHS. If a value at one of these paths matches a VaultRef pattern, the daemon:
- Opens the
Vault. - Resolves the
VaultRefto its decrypted bytes. - Injects the secret into the runtime configuration while keeping the file on disk clean.
Security Guarantees
Atomic Writes and Persistence
TheEncryptedFileBackend ensures data integrity during writes using a temporary file and atomic rename strategy crates/palyra-vault/src/backend.rs#120-130. This prevents partial writes from corrupting the vault if the process is interrupted.
Memory Safety
TheSensitiveBytes wrapper crates/palyra-vault/src/crypto.rs#156-174 is used for decrypted secrets. It implements the Drop trait to zero-fill the underlying memory buffer when the secret is no longer in use, minimizing the window for memory forensics.
Filesystem Hardening
The Vault enforces strict filesystem permissions. Both the vault root and individual object files are checked to ensure they are accessible only by the owner (0700 for directories, 0600 for files) crates/palyra-vault/src/filesystem.rs#15-15.
Sources: crates/palyra-vault/src/backend.rs#120-132, crates/palyra-vault/src/crypto.rs#170-174, crates/palyra-vault/src/backend.rs#199-205