# Secret - Hierarchical Secret Manager Secret is a command-line secret manager that implements a hierarchical key architecture for storing and managing sensitive data. It supports multiple vaults, various unlock mechanisms, and provides secure storage using the Age encryption library. ## Core Architecture ### Three-Layer Key Hierarchy Secret implements a three-layer key architecture: 1. **Long-term Keys**: Derived from BIP39 mnemonic phrases, these provide the foundation for all encryption 2. **Unlockers**: Short-term keys that encrypt the long-term keys, supporting multiple authentication methods 3. **Version-specific Keys**: Per-version keys that encrypt individual secret values ### Version Management Each secret maintains a history of versions, with each version having: - Its own encryption key pair - Metadata (unencrypted) including creation time and validity period - Immutable value storage - Atomic version switching via symlink updates ### Vault System Vaults provide logical separation of secrets, each with its own long-term key and unlocker set. This allows for complete isolation between different contexts (work, personal, projects). ## Installation Build from source: ```bash git clone cd secret make build ``` ## Quick Start 1. **Initialize the secret manager**: ```bash secret init ``` This creates the default vault and prompts for a BIP39 mnemonic phrase. 2. **Generate a mnemonic** (if needed): ```bash secret generate mnemonic ``` 3. **Add a secret**: ```bash echo "my-password" | secret add myservice/password ``` 4. **Retrieve a secret**: ```bash secret get myservice/password ``` ## Commands Reference ### Initialization #### `secret init` Initializes the secret manager with a default vault. Prompts for a BIP39 mnemonic phrase and creates the initial directory structure. **Environment Variables:** - `SB_SECRET_MNEMONIC`: Pre-set mnemonic phrase - `SB_UNLOCK_PASSPHRASE`: Pre-set unlock passphrase ### Vault Management #### `secret vault list [--json]` / `secret vault ls` Lists all available vaults. The current vault is marked. #### `secret vault create ` Creates a new vault with the specified name. #### `secret vault select ` Switches to the specified vault for subsequent operations. #### `secret vault remove [--force]` / `secret vault rm` ⚠️ 🛑 **DANGER**: Permanently removes a vault and all its secrets. Like Unix `rm`, this command does not ask for confirmation. Requires --force if the vault contains secrets. With --force, will automatically switch to another vault if removing the current one. - `--force, -f`: Force removal even if vault contains secrets - **NO RECOVERY**: All secrets in the vault will be permanently deleted ### Secret Management #### `secret add [--force]` Adds a secret to the current vault. Reads the secret value from stdin. - `--force, -f`: Overwrite existing secret **Secret Name Format:** `[a-z0-9\.\-\_\/]+` - Forward slashes (`/`) are converted to percent signs (`%`) for storage - Examples: `database/password`, `api.key`, `ssh_private_key` #### `secret get [--version ]` Retrieves and outputs a secret value to stdout. - `--version, -v`: Get a specific version (default: current) #### `secret list [filter] [--json]` / `secret ls` Lists all secrets in the current vault. Optional filter for substring matching. #### `secret remove ` / `secret rm` ⚠️ 🛑 **DANGER**: Permanently removes a secret and ALL its versions. Like Unix `rm`, this command does not ask for confirmation. - **NO RECOVERY**: Once removed, the secret cannot be recovered - **ALL VERSIONS DELETED**: Every version of the secret will be permanently deleted ### Version Management #### `secret version list ` / `secret version ls` Lists all versions of a secret showing creation time, status, and validity period. #### `secret version promote ` Promotes a specific version to current by updating the symlink. Does not modify any timestamps, allowing for rollback scenarios. #### `secret version remove ` / `secret version rm` ⚠️ 🛑 **DANGER**: Permanently removes a specific version of a secret. Like Unix `rm`, this command does not ask for confirmation. - **NO RECOVERY**: Once removed, this version cannot be recovered - Cannot remove the current version (must promote another version first) ### Key Generation #### `secret generate mnemonic` Generates a cryptographically secure BIP39 mnemonic phrase. #### `secret generate secret [--length=16] [--type=base58] [--force]` Generates and stores a random secret. - `--length, -l`: Length of generated secret (default: 16) - `--type, -t`: Type of secret (`base58`, `alnum`) - `--force, -f`: Overwrite existing secret ### Unlocker Management #### `secret unlocker list [--json]` / `secret unlocker ls` Lists all unlockers in the current vault with their metadata. #### `secret unlocker add [options]` Creates a new unlocker of the specified type: **Types:** - `passphrase`: Traditional passphrase-protected unlocker - `pgp`: Uses an existing GPG key for encryption/decryption - `keychain`: macOS Keychain integration (macOS only) **Options:** - `--keyid `: GPG key ID (required for PGP type) #### `secret unlocker remove [--force]` / `secret unlocker rm` ⚠️ 🛑 **DANGER**: Permanently removes an unlocker. Like Unix `rm`, this command does not ask for confirmation. Cannot remove the last unlocker if the vault has secrets unless --force is used. - `--force, -f`: Force removal of last unlocker even if vault has secrets - **CRITICAL WARNING**: Without unlockers and without your mnemonic phrase, vault data will be PERMANENTLY INACCESSIBLE - **NO RECOVERY**: Removing all unlockers without having your mnemonic means losing access to all secrets forever #### `secret unlocker select ` Selects an unlocker as the current default for operations. ### Import Operations #### `secret import --source ` Imports a secret from a file and stores it in the current vault under the given name. #### `secret vault import [vault-name]` Imports a mnemonic phrase into the specified vault (defaults to "default"). ### Encryption Operations #### `secret encrypt [--input=file] [--output=file]` Encrypts data using an Age key stored as a secret. If the secret doesn't exist, generates a new Age key. #### `secret decrypt [--input=file] [--output=file]` Decrypts data using an Age key stored as a secret. ## Storage Architecture ### Directory Structure ``` ~/.local/share/secret/ ├── vaults.d/ │ ├── default/ │ │ ├── unlockers.d/ │ │ │ ├── passphrase/ # Passphrase unlocker │ │ │ └── pgp/ # PGP unlocker │ │ ├── secrets.d/ │ │ │ ├── api%key/ # Secret: api/key │ │ │ │ ├── versions/ │ │ │ │ │ ├── 20231215.001/ # Version directory │ │ │ │ │ │ ├── pub.age # Version public key │ │ │ │ │ │ ├── priv.age # Version private key (encrypted) │ │ │ │ │ │ ├── value.age # Encrypted value │ │ │ │ │ │ └── metadata.json # Unencrypted metadata │ │ │ │ │ └── 20231216.001/ # Another version │ │ │ │ └── current -> versions/20231216.001 │ │ │ └── database%password/ # Secret: database/password │ │ │ ├── versions/ │ │ │ └── current -> versions/20231215.001 │ │ ├── vault-metadata.json # Vault metadata │ │ ├── pub.age # Long-term public key │ │ └── current-unlocker -> ../unlockers.d/passphrase │ └── work/ │ ├── unlockers.d/ │ ├── secrets.d/ │ ├── vault-metadata.json │ ├── pub.age │ └── current-unlocker └── currentvault -> vaults.d/default ``` ### Key Management and Encryption Flow #### Long-term Keys - **Source**: Derived from BIP39 mnemonic phrases using hierarchical deterministic (HD) key derivation - **Purpose**: Master keys for each vault, used to encrypt secret-specific keys - **Storage**: Public key stored as `pub.age`, private key encrypted by unlockers #### Unlockers Unlockers provide different authentication methods to access the long-term keys: 1. **Passphrase Unlockers**: - Encrypted with user-provided passphrase - Stored as encrypted Age keys - Cross-platform compatible 2. **PGP Unlockers**: - Uses existing GPG key infrastructure - Leverages existing key management workflows - Strong authentication through GPG 3. **Keychain Unlockers** (macOS only): - Stores unlock keys in macOS Keychain - Protected by system authentication (Touch ID, password) - Automatic unlocking when Keychain is unlocked - Cross-application integration 4. **Secure Enclave Unlockers** (macOS - planned): - Hardware-backed key storage using Apple Secure Enclave - Currently partially implemented but non-functional - Requires Apple Developer Program membership and code signing entitlements - Full implementation blocked by entitlement requirements Each vault maintains its own set of unlockers and one long-term key. The long-term key is encrypted to each unlocker, allowing any authorized unlocker to access vault secrets. #### Secret-specific Keys - Each secret has its own encryption key pair - Private key encrypted to the vault's long-term key - Provides forward secrecy and granular access control ### Environment Variables - `SB_SECRET_STATE_DIR`: Custom state directory location - `SB_SECRET_MNEMONIC`: Pre-set mnemonic phrase (avoids interactive prompt) - `SB_UNLOCK_PASSPHRASE`: Pre-set unlock passphrase (avoids interactive prompt) - `SB_GPG_KEY_ID`: GPG key ID for PGP unlockers ## Security Features ### Encryption - Uses the [Age encryption library](https://age-encryption.org/) with X25519 keys - All private keys are encrypted at rest - No plaintext secrets stored on disk ### Access Control - Multiple authentication methods supported - Hierarchical key architecture provides defense in depth - Vault isolation prevents cross-contamination ### Forward Secrecy - Per-version encryption keys limit exposure if compromised - Each version is independently encrypted - Long-term keys protected by multiple unlocker layers - Historical versions remain encrypted with their original keys ### Hardware Integration - Hardware token support via PGP/GPG integration - macOS Keychain integration for system-level security - Secure Enclave support planned (requires Apple Developer Program) ## Examples ### Basic Workflow ```bash # Initialize with a new mnemonic secret generate mnemonic # Copy the output secret init # Paste the mnemonic when prompted # Add some secrets echo "supersecret123" | secret add database/prod/password echo "api-key-xyz" | secret add services/api/key echo "ssh-private-key-content" | secret add ssh/servers/web01 # List and retrieve secrets secret list secret get database/prod/password secret get services/api/key # Remove a secret ⚠️ 🛑 (NO CONFIRMATION - PERMANENT!) secret remove ssh/servers/web01 ``` ### Multi-vault Setup ```bash # Create separate vaults for different contexts secret vault create work secret vault create personal # Work with work vault secret vault select work echo "work-db-pass" | secret add database/password secret unlocker add passphrase # Add passphrase authentication # Switch to personal vault secret vault select personal echo "personal-email-pass" | secret add email/password # List all vaults secret vault list # Remove a vault ⚠️ 🛑 (NO CONFIRMATION - PERMANENT!) secret vault remove personal --force ``` ### Advanced Authentication ```bash # Add multiple unlock methods secret unlocker add passphrase # Password-based secret unlocker add pgp --keyid ABCD1234 # GPG key secret unlocker add keychain # macOS Keychain (macOS only) # List unlockers secret unlocker list # Select a specific unlocker secret unlocker select # Remove an unlocker ⚠️ 🛑 (NO CONFIRMATION!) secret unlocker remove ``` ### Version Management ```bash # List all versions of a secret secret version list database/prod/password # Promote an older version to current secret version promote database/prod/password 20231215.001 # Remove an old version ⚠️ 🛑 (NO CONFIRMATION - PERMANENT!) secret version remove database/prod/password 20231214.001 ``` ### Encryption/Decryption with Age Keys ```bash # Generate an Age key and store it as a secret secret generate secret encryption/mykey # Encrypt a file using the stored key secret encrypt encryption/mykey --input document.txt --output document.txt.age # Decrypt the file secret decrypt encryption/mykey --input document.txt.age --output document.txt ``` ## Technical Details ### Cryptographic Primitives - **Key Derivation**: BIP32/BIP39 hierarchical deterministic key derivation - **Encryption**: Age (X25519 + ChaCha20-Poly1305) - **Key Exchange**: X25519 elliptic curve Diffie-Hellman - **Authentication**: Poly1305 MAC - **Hashing**: Double SHA-256 for public key identification ### File Formats - **Age Files**: Standard Age encryption format (.age extension) - **Metadata**: Unencrypted JSON format with timestamps and type information - **Vault Metadata**: JSON containing vault name, creation time, derivation index, and public key hash ### Vault Management - **Derivation Index**: Each vault uses a unique derivation index from the mnemonic - **Public Key Hash**: Double SHA-256 hash of the index-0 public key identifies vaults from the same mnemonic - **Automatic Key Derivation**: When creating vaults with a mnemonic, keys are automatically derived ### Cross-Platform Support - **macOS**: Full support including Keychain and planned Secure Enclave integration - **Linux**: Full support (excluding macOS-specific features) - **Windows**: Basic support (filesystem operations only) ## Security Considerations ### Threat Model - Protects against unauthorized access to secret values - Provides defense against compromise of individual components - Supports hardware-backed authentication where available ### Best Practices 1. Use strong, unique passphrases for unlockers 2. Enable hardware authentication (Keychain, hardware tokens) when available 3. Regularly audit unlockers and remove unused ones 4. Keep mnemonic phrases securely backed up offline 5. Use separate vaults for different security contexts ### Limitations - Requires access to unlockers for secret retrieval - Mnemonic phrases must be securely stored and backed up - Hardware features limited to supported platforms ## Development ### Building ```bash make build # Build binary make test # Run tests make lint # Run linter ``` ### Testing The project includes comprehensive tests: ```bash make test # Run all tests go test ./... # Unit tests go test -tags=integration -v ./internal/cli # Integration tests ``` ## Features - **Multiple Authentication Methods**: Supports passphrase, PGP, and macOS Keychain unlockers - **Vault Isolation**: Complete separation between different vaults - **Per-Secret Encryption**: Each secret has its own encryption key - **BIP39 Mnemonic Support**: Keyless operation using mnemonic phrases - **Cross-Platform**: Works on macOS, Linux, and other Unix-like systems # Author Made with love and lots of expensive SOTA AI by [sneak](https://sneak.berlin) in Berlin in the summer of 2025. Released as a free software gift to the world, no strings attached, under the [WTFPL](https://www.wtfpl.net/) license. Contact: [sneak@sneak.berlin](mailto:sneak@sneak.berlin) [https://keys.openpgp.org/vks/v1/by-fingerprint/5539AD00DE4C42F3AFE11575052443F4DF2A55C2](https://keys.openpgp.org/vks/v1/by-fingerprint/5539AD00DE4C42F3AFE11575052443F4DF2A55C2)