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
@ -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 <name>`
Creates a new vault with the specified name.
#### `secret vault select <name>`
Switches to the specified vault for subsequent operations.
#### `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
- **NO RECOVERY**: All secrets in the vault will be permanently deleted
### Secret Management
#### `secret add <secret-name> [--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 <secret-name> [--version <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-name>` / `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 <source> <destination>` / `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-name>` / `secret version ls`
Lists all versions of a secret showing creation time, status, and validity period.
#### `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` ⚠️ 🛑
**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 <name> [--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 <type> [options]`
Creates a new unlocker of the specified type:
**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)
#### `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
- **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 <unlocker-id>`
Selects an unlocker as the current default for operations.
### Import Operations
#### `secret import <secret-name> --source <filename>`
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 <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.
#### `secret decrypt <secret-name> [--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 <unlocker-id>
```
### 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)