README updates

This commit is contained in:
Jeffrey Paul 2025-07-27 17:38:46 +02:00
parent 92c41bdb0c
commit b301a414cb

120
README.md
View File

@ -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 ## 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: Secret implements a three-layer key architecture:
1. **Long-term Keys**: Derived from BIP39 mnemonic phrases, these provide the foundation for all encryption 1. **Long-term Keys**: Derived from BIP39 mnemonic phrases, these provide
2. **Unlockers**: Short-term keys that encrypt the long-term keys, supporting multiple authentication methods the foundation for all encryption
3. **Version-specific Keys**: Per-version keys that encrypt individual secret values 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 ### Version Management
@ -22,7 +32,9 @@ Each secret maintains a history of versions, with each version having:
### Vault System ### 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 ## Installation
@ -61,7 +73,9 @@ make build
### Initialization ### Initialization
#### `secret init` #### `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:** **Environment Variables:**
- `SB_SECRET_MNEMONIC`: Pre-set mnemonic phrase - `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 ### Vault Management
#### `secret vault list [--json]` / `secret vault ls` #### `secret vault list [--json]` / `secret vault ls`
Lists all available vaults. The current vault is marked. Lists all available vaults. The current vault is marked.
#### `secret vault create <name>` #### `secret vault create <name>`
Creates a new vault with the specified name. Creates a new vault with the specified name.
#### `secret vault select <name>` #### `secret vault select <name>`
Switches to the specified vault for subsequent operations. Switches to the specified vault for subsequent operations.
#### `secret vault remove <name> [--force]` / `secret vault rm` ⚠️ 🛑 #### `secret vault remove <name> [--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 - `--force, -f`: Force removal even if vault contains secrets
- **NO RECOVERY**: All secrets in the vault will be permanently deleted - **NO RECOVERY**: All secrets in the vault will be permanently deleted
### Secret Management ### Secret Management
#### `secret add <secret-name> [--force]` #### `secret add <secret-name> [--force]`
Adds a secret to the current vault. Reads the secret value from stdin. Adds a secret to the current vault. Reads the secret value from stdin.
- `--force, -f`: Overwrite existing secret - `--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` - Examples: `database/password`, `api.key`, `ssh_private_key`
#### `secret get <secret-name> [--version <version>]` #### `secret get <secret-name> [--version <version>]`
Retrieves and outputs a secret value to stdout. Retrieves and outputs a secret value to stdout.
- `--version, -v`: Get a specific version (default: current) - `--version, -v`: Get a specific version (default: current)
#### `secret list [filter] [--json]` / `secret ls` #### `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-name>` / `secret rm` ⚠️ 🛑 #### `secret remove <secret-name>` / `secret rm` ⚠️ 🛑
**DANGER**: Permanently removes a secret and ALL its versions. Like Unix `rm`, this command does not ask for confirmation. **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 - **NO RECOVERY**: Once removed, the secret cannot be recovered
- **ALL VERSIONS DELETED**: Every version of the secret will be permanently deleted - **ALL VERSIONS DELETED**: Every version of the secret will be permanently deleted
#### `secret move <source> <destination>` / `secret mv` / `secret rename` #### `secret move <source> <destination>` / `secret mv` / `secret rename`
Moves or renames a secret within the current vault. Moves or renames a secret within the current vault.
- Fails if the destination already exists - Fails if the destination already exists
- Preserves all versions and metadata - Preserves all versions and metadata
@ -114,22 +142,29 @@ Moves or renames a secret within the current vault.
### Version Management ### Version Management
#### `secret version list <secret-name>` / `secret version ls` #### `secret version list <secret-name>` / `secret version ls`
Lists all versions of a secret showing creation time, status, and validity period. Lists all versions of a secret showing creation time, status, and validity period.
#### `secret version promote <secret-name> <version>` #### `secret version promote <secret-name> <version>`
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-name> <version>` / `secret version rm` ⚠️ 🛑 #### `secret version remove <secret-name> <version>` / `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 - **NO RECOVERY**: Once removed, this version cannot be recovered
- Cannot remove the current version (must promote another version first) - Cannot remove the current version (must promote another version first)
### Key Generation ### Key Generation
#### `secret generate mnemonic` #### `secret generate mnemonic`
Generates a cryptographically secure BIP39 mnemonic phrase. Generates a cryptographically secure BIP39 mnemonic phrase.
#### `secret generate secret <name> [--length=16] [--type=base58] [--force]` #### `secret generate secret <name> [--length=16] [--type=base58] [--force]`
Generates and stores a random secret. Generates and stores a random secret.
- `--length, -l`: Length of generated secret (default: 16) - `--length, -l`: Length of generated secret (default: 16)
- `--type, -t`: Type of secret (`base58`, `alnum`) - `--type, -t`: Type of secret (`base58`, `alnum`)
@ -138,9 +173,11 @@ Generates and stores a random secret.
### Unlocker Management ### Unlocker Management
#### `secret unlocker list [--json]` / `secret unlocker ls` #### `secret unlocker list [--json]` / `secret unlocker ls`
Lists all unlockers in the current vault with their metadata. Lists all unlockers in the current vault with their metadata.
#### `secret unlocker add <type> [options]` #### `secret unlocker add <type> [options]`
Creates a new unlocker of the specified type: Creates a new unlocker of the specified type:
**Types:** **Types:**
@ -152,29 +189,38 @@ Creates a new unlocker of the specified type:
- `--keyid <id>`: GPG key ID (optional for PGP type, uses default key if not specified) - `--keyid <id>`: GPG key ID (optional for PGP type, uses default key if not specified)
#### `secret unlocker remove <unlocker-id> [--force]` / `secret unlocker rm` ⚠️ 🛑 #### `secret unlocker remove <unlocker-id> [--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 - `--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 - **CRITICAL WARNING**: Without unlockers and without your mnemonic phrase,
- **NO RECOVERY**: Removing all unlockers without having your mnemonic means losing access to all secrets forever 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 <unlocker-id>` #### `secret unlocker select <unlocker-id>`
Selects an unlocker as the current default for operations. Selects an unlocker as the current default for operations.
### Import Operations ### Import Operations
#### `secret import <secret-name> --source <filename>` #### `secret import <secret-name> --source <filename>`
Imports a secret from a file and stores it in the current vault under the given name. Imports a secret from a file and stores it in the current vault under the given name.
#### `secret vault import [vault-name]` #### `secret vault import [vault-name]`
Imports a mnemonic phrase into the specified vault (defaults to "default"). Imports a mnemonic phrase into the specified vault (defaults to "default").
### Encryption Operations ### Encryption Operations
#### `secret encrypt <secret-name> [--input=file] [--output=file]` #### `secret encrypt <secret-name> [--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. Encrypts data using an Age key stored as a secret. If the secret doesn't exist, generates a new Age key.
#### `secret decrypt <secret-name> [--input=file] [--output=file]` #### `secret decrypt <secret-name> [--input=file] [--output=file]`
Decrypts data using an Age key stored as a secret. Decrypts data using an Age key stored as a secret.
## Storage Architecture ## Storage Architecture
@ -215,12 +261,13 @@ Decrypts data using an Age key stored as a secret.
### Key Management and Encryption Flow ### Key Management and Encryption Flow
#### Long-term Keys #### 1: Long-term Keys
- **Source**: Derived from BIP39 mnemonic phrases using hierarchical deterministic (HD) key derivation - **Source**: Derived from BIP39 mnemonic phrases using hierarchical deterministic (HD) key derivation
- **Purpose**: Master keys for each vault, used to encrypt secret-specific keys - **Purpose**: Master keys for each vault, used to encrypt secret-specific keys
- **Storage**: Public key stored as `pub.age`, private key encrypted by unlockers - **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: Unlockers provide different authentication methods to access the long-term keys:
1. **Passphrase Unlockers**: 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. 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 #### 3: Secret-specific Keys
- Each secret has its own encryption key pair
- Each secret version has its own encryption key pair
- Private key encrypted to the vault's long-term key - Private key encrypted to the vault's long-term key
- Provides forward secrecy and granular access control - 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 ## Security Features
### Encryption ### 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 - All private keys are encrypted at rest
- No plaintext secrets stored on disk - No plaintext secrets stored on disk
### Access Control ### Access Control
- Multiple authentication methods supported - Multiple authentication methods supported
- Hierarchical key architecture provides defense in depth
- Vault isolation prevents cross-contamination - Vault isolation prevents cross-contamination
### Forward Secrecy ### Forward Secrecy
- Per-version encryption keys limit exposure if compromised - Per-version encryption keys limit exposure if compromised
- Each version is independently encrypted - Each version is independently encrypted
- Long-term keys protected by multiple unlocker layers
- Historical versions remain encrypted with their original keys - Historical versions remain encrypted with their original keys
### Hardware Integration ### Hardware Integration
- Hardware token support via PGP/GPG integration - Hardware token support via PGP/GPG integration
- macOS Keychain integration for system-level security - 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 ## Examples
### Basic Workflow ### Basic Workflow
```bash ```bash
# Initialize with a new mnemonic # Initialize with a new mnemonic
secret generate mnemonic # Copy the output secret generate mnemonic # Copy the output
@ -305,6 +357,7 @@ secret remove ssh/servers/web01
``` ```
### Multi-vault Setup ### Multi-vault Setup
```bash ```bash
# Create separate vaults for different contexts # Create separate vaults for different contexts
secret vault create work secret vault create work
@ -344,6 +397,7 @@ secret unlocker remove <unlocker-id>
``` ```
### Version Management ### Version Management
```bash ```bash
# List all versions of a secret # List all versions of a secret
secret version list database/prod/password secret version list database/prod/password
@ -356,6 +410,7 @@ secret version remove database/prod/password 20231214.001
``` ```
### Encryption/Decryption with Age Keys ### Encryption/Decryption with Age Keys
```bash ```bash
# Generate an Age key and store it as a secret # Generate an Age key and store it as a secret
secret generate secret encryption/mykey secret generate secret encryption/mykey
@ -372,33 +427,35 @@ secret decrypt encryption/mykey --input document.txt.age --output document.txt
### Cryptographic Primitives ### Cryptographic Primitives
- **Key Derivation**: BIP32/BIP39 hierarchical deterministic key derivation - **Key Derivation**: BIP32/BIP39 hierarchical deterministic key derivation
- **Encryption**: Age (X25519 + ChaCha20-Poly1305) - **Encryption**: Age (X25519 + ChaCha20-Poly1305)
- **Key Exchange**: X25519 elliptic curve Diffie-Hellman
- **Authentication**: Poly1305 MAC - **Authentication**: Poly1305 MAC
- **Hashing**: Double SHA-256 for public key identification - **Hashing**: Double SHA-256 for public key identification
### File Formats ### 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 - **Metadata**: Unencrypted JSON format with timestamps and type information
- **Vault Metadata**: JSON containing vault name, creation time, derivation index, and public key hash - **Vault Metadata**: JSON containing vault name, creation time, derivation index, and public key hash
### Vault Management ### 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 - **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 - **Automatic Key Derivation**: When creating vaults with a mnemonic, keys are automatically derived
### Cross-Platform Support ### Cross-Platform Support
- **macOS**: Full support including Keychain and planned Secure Enclave integration - **macOS**: Full support including Keychain and planned Secure Enclave integration
- **Linux**: Full support (excluding macOS-specific features) - **Linux**: Full support (excluding macOS-specific features)
- **Windows**: Basic support (filesystem operations only)
## Security Considerations ## Security Considerations
### Threat Model ### Threat Model
- Protects against unauthorized access to secret values - Protects against unauthorized access to secret values
- Provides defense against compromise of individual components - Provides defense against compromise of individual components
- Supports hardware-backed authentication where available - Supports hardware-backed authentication where available
### Best Practices ### Best Practices
1. Use strong, unique passphrases for unlockers 1. Use strong, unique passphrases for unlockers
2. Enable hardware authentication (Keychain, hardware tokens) when available 2. Enable hardware authentication (Keychain, hardware tokens) when available
3. Regularly audit unlockers and remove unused ones 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 5. Use separate vaults for different security contexts
### Limitations ### Limitations
- Requires access to unlockers for secret retrieval - Requires access to unlockers for secret retrieval
- Mnemonic phrases must be securely stored and backed up - Mnemonic phrases must be securely stored and backed up
- Hardware features limited to supported platforms - Hardware features limited to supported platforms
@ -437,9 +495,11 @@ go test -tags=integration -v ./internal/cli # Integration tests
# Author # 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) Contact: [sneak@sneak.berlin](mailto:sneak@sneak.berlin)