From b301a414cbe0d4b429d7afc773970bb31d1c5c91 Mon Sep 17 00:00:00 2001 From: sneak Date: Sun, 27 Jul 2025 17:38:46 +0200 Subject: [PATCH] README updates --- README.md | 120 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 90 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 02c4ab9..fc50b82 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ -# Secret - Hierarchical Secret Manager +# secret - Local 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. +secret is a command-line local 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. + +It could be used as password manager, but was not designed as such. I +created it to scratch an itch for a secure key/value store for replacing a +bunch of pgp-encrypted files in a directory structure. ## Core Architecture @@ -8,9 +15,12 @@ Secret is a command-line secret manager that implements a hierarchical key archi 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 +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 @@ -22,7 +32,9 @@ Each secret maintains a history of versions, with each version having: ### 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). +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 @@ -61,7 +73,9 @@ make build ### Initialization #### `secret init` -Initializes the secret manager with a default vault. Prompts for a BIP39 mnemonic phrase and creates the initial directory structure. + +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 @@ -70,23 +84,32 @@ Initializes the secret manager with a default vault. Prompts for a BIP39 mnemoni ### 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. + +**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 @@ -95,18 +118,23 @@ Adds a secret to the current vault. Reads the secret value from stdin. - 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. + +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 #### `secret move ` / `secret mv` / `secret rename` + Moves or renames a secret within the current vault. - Fails if the destination already exists - Preserves all versions and metadata @@ -114,22 +142,29 @@ Moves or renames a secret within the current vault. ### 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. + +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. + +**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`) @@ -138,9 +173,11 @@ Generates and stores a random 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:** @@ -152,29 +189,38 @@ Creates a new unlocker of the specified type: - `--keyid `: GPG key ID (optional for PGP type, uses default key if not specified) #### `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. + +**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 +- **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 @@ -215,12 +261,13 @@ Decrypts data using an Age key stored as a secret. ### Key Management and Encryption Flow -#### Long-term Keys +#### 1: 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 +#### 2: Unlockers + Unlockers provide different authentication methods to access the long-term keys: 1. **Passphrase Unlockers**: @@ -247,8 +294,9 @@ Unlockers provide different authentication methods to access the long-term keys: 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 +#### 3: Secret-specific Keys + +- Each secret version has its own encryption key pair - Private key encrypted to the vault's long-term key - Provides forward secrecy and granular access control @@ -262,29 +310,33 @@ Each vault maintains its own set of unlockers and one long-term key. The long-te ## Security Features ### Encryption -- Uses the [Age encryption library](https://age-encryption.org/) with X25519 keys + +- 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) +- Secure Enclave support planned (requires paid Apple Developer Program for + signed entitlements to access the SEP and doxxing myself to Apple) ## Examples ### Basic Workflow + ```bash # Initialize with a new mnemonic secret generate mnemonic # Copy the output @@ -305,6 +357,7 @@ secret remove ssh/servers/web01 ``` ### Multi-vault Setup + ```bash # Create separate vaults for different contexts secret vault create work @@ -344,6 +397,7 @@ secret unlocker remove ``` ### Version Management + ```bash # List all versions of a secret secret version list database/prod/password @@ -356,6 +410,7 @@ 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 @@ -372,33 +427,35 @@ secret decrypt encryption/mykey --input document.txt.age --output document.txt ### 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) +- **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 + +- **Derivation Index**: Each vault uses a unique derivation index from the mnemonic, and thus a unique key pair - **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 @@ -406,6 +463,7 @@ secret decrypt encryption/mykey --input document.txt.age --output document.txt 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 @@ -437,9 +495,11 @@ go test -tags=integration -v ./internal/cli # Integration tests # Author -Made with love and lots of expensive SOTA AI by [sneak](https://sneak.berlin) in Berlin in the summer of 2025. +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. +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)