README updates
This commit is contained in:
parent
92c41bdb0c
commit
b301a414cb
120
README.md
120
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 <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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user