366 lines
12 KiB
Markdown
366 lines
12 KiB
Markdown
# Secret - Hierarchical Secret Manager
|
|
|
|
Secret is a modern, secure 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 sophisticated 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
|
|
- Encrypted metadata 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 <repository>
|
|
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]`
|
|
Lists all available vaults.
|
|
|
|
#### `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 Management
|
|
|
|
#### `secret add <secret-name> [--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 <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.
|
|
|
|
### Version Management
|
|
|
|
#### `secret version list <secret-name>`
|
|
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.
|
|
|
|
### 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`)
|
|
- `--force, -f`: Overwrite existing secret
|
|
|
|
### Unlocker Management
|
|
|
|
#### `secret unlockers list [--json]`
|
|
Lists all unlockers in the current vault with their metadata.
|
|
|
|
#### `secret unlockers add <type> [options]`
|
|
Creates a new unlocker of the specified type:
|
|
|
|
**Types:**
|
|
- `passphrase`: Traditional passphrase-protected unlocker
|
|
- `pgp`: Uses an existing GPG key for encryption/decryption
|
|
|
|
**Options:**
|
|
- `--keyid <id>`: GPG key ID (required for PGP type)
|
|
|
|
#### `secret unlockers rm <unlocker-id>`
|
|
Removes an unlocker.
|
|
|
|
#### `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
|
|
|
|
### 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.age # Encrypted metadata
|
|
│ │ │ │ │ └── 20231216.001/ # Another version
|
|
│ │ │ │ └── current -> versions/20231216.001
|
|
│ │ │ └── database%password/ # Secret: database/password
|
|
│ │ │ ├── versions/
|
|
│ │ │ └── current -> versions/20231215.001
|
|
│ │ └── current-unlocker -> ../unlockers.d/passphrase
|
|
│ └── work/
|
|
│ ├── unlockers.d/
|
|
│ ├── secrets.d/
|
|
│ └── current-unlocker
|
|
├── currentvault -> vaults.d/default
|
|
└── configuration.json
|
|
```
|
|
|
|
### 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
|
|
|
|
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
|
|
|
|
## 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
|
|
```
|
|
|
|
### 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 unlockers 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
|
|
```
|
|
|
|
### Advanced Authentication
|
|
```bash
|
|
# Add multiple unlock methods
|
|
secret unlockers add passphrase # Password-based
|
|
secret unlockers add pgp --keyid ABCD1234 # GPG key
|
|
|
|
# List unlockers
|
|
secret unlockers list
|
|
|
|
# Select a specific unlocker
|
|
secret unlocker select <unlocker-id>
|
|
```
|
|
|
|
### 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
|
|
|
|
### File Formats
|
|
- **Age Files**: Standard Age encryption format (.age extension)
|
|
- **Metadata**: JSON format with timestamps and type information
|
|
- **Configuration**: JSON configuration files
|
|
|
|
### Cross-Platform Support
|
|
- **macOS**: Full support including Keychain integration
|
|
- **Linux**: Full support (excluding Keychain 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
|
|
./test_secret_manager.sh # Full integration test suite
|
|
go test ./... # Unit tests
|
|
```
|
|
|
|
## Features
|
|
|
|
- **Multiple Authentication Methods**: Supports passphrase-based and PGP-based 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
|
|
|