internal/secret | ||
pkg | ||
.gitignore | ||
go.mod | ||
go.sum | ||
LICENSE | ||
Makefile | ||
README.md | ||
test_secret_manager.sh | ||
TODO.md |
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:
- Long-term Keys: Derived from BIP39 mnemonic phrases, these provide the foundation for all encryption
- Unlock Keys: Short-term keys that encrypt the long-term keys, supporting multiple authentication methods
- Secret-specific Keys: Per-secret keys that encrypt individual secret values
Vault System
Vaults provide logical separation of secrets, each with its own long-term key and unlock key set. This allows for complete isolation between different contexts (work, personal, projects).
Installation
Build from source:
git clone <repository>
cd secret
make build
Quick Start
-
Initialize the secret manager:
secret init
This creates the default vault and prompts for a BIP39 mnemonic phrase.
-
Generate a mnemonic (if needed):
secret generate mnemonic
-
Add a secret:
echo "my-password" | secret add myservice/password
-
Retrieve a secret:
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 phraseSB_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>
Retrieves and outputs a secret value to stdout.
secret list [filter] [--json]
/ secret ls
Lists all secrets in the current vault. Optional filter for substring matching.
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
Unlock Key Management
secret keys list [--json]
Lists all unlock keys in the current vault with their metadata.
secret keys add <type> [options]
Creates a new unlock key of the specified type:
Types:
passphrase
: Password-protected unlock keykeychain
: macOS Keychain unlock key (Touch ID/Face ID)pgp
: GPG/PGP key unlock key
Options:
--keyid <id>
: GPG key ID (required for PGP type)
secret keys rm <key-id>
Removes an unlock key from the current vault.
secret key select <key-id>
Selects an unlock key 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").
secret enroll
Enrolls a macOS Keychain unlock key for biometric authentication.
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
$BASE/ # ~/.config/berlin.sneak.pkg.secret (Linux) or ~/Library/Application Support/berlin.sneak.pkg.secret (macOS)
├── configuration.json # Global configuration
├── currentvault -> vaults.d/default # Symlink to current vault
└── vaults.d/
├── default/ # Default vault
│ ├── vault-metadata.json # Vault metadata
│ ├── pub.age # Long-term public key
│ ├── current-unlock-key -> unlock.d/passphrase # Current unlock key symlink
│ ├── unlock.d/ # Unlock keys directory
│ │ ├── passphrase/ # Passphrase unlock key
│ │ │ ├── unlock-metadata.json # Unlock key metadata
│ │ │ ├── pub.age # Unlock key public key
│ │ │ ├── priv.age # Unlock key private key (encrypted)
│ │ │ └── longterm.age # Long-term private key (encrypted to this unlock key)
│ │ ├── keychain/ # Keychain unlock key
│ │ │ ├── unlock-metadata.json
│ │ │ ├── pub.age
│ │ │ ├── priv.age
│ │ │ └── longterm.age
│ │ └── pgp/ # PGP unlock key
│ │ ├── unlock-metadata.json
│ │ ├── pub.age
│ │ ├── priv.asc # PGP-encrypted private key
│ │ └── longterm.age
│ └── secrets.d/ # Secrets directory
│ ├── my-service%password/ # Secret directory (slashes encoded as %)
│ │ ├── value.age # Encrypted secret value
│ │ ├── pub.age # Secret-specific public key
│ │ ├── priv.age # Secret-specific private key (encrypted to long-term key)
│ │ └── secret-metadata.json # Secret metadata
│ └── api%keys%production/
│ ├── value.age
│ ├── pub.age
│ ├── priv.age
│ └── secret-metadata.json
└── work/ # Additional vault
└── ... (same structure as default)
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 unlock keys
Unlock Keys
Unlock keys provide different authentication methods to access the long-term keys:
-
Passphrase Unlock Keys:
- Private key encrypted using a user-provided passphrase
- Stored as encrypted Age identity in
priv.age
-
macOS Keychain Keys:
- Private key stored in the macOS Keychain
- Requires biometric authentication (Touch ID/Face ID)
- Provides hardware-backed security
-
PGP Unlock Keys:
- Private key encrypted using an existing GPG key
- Compatible with hardware tokens (YubiKey, etc.)
- Stored as PGP-encrypted data in
priv.asc
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 locationSB_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 unlock keys
Security Features
Encryption
- Uses the Age encryption library 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-secret encryption keys limit exposure if compromised
- Long-term keys protected by multiple unlock key layers
Hardware Integration
- macOS Keychain support for biometric authentication
- Hardware token support via PGP/GPG integration
Examples
Basic Workflow
# 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
# 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 keys add keychain # Add Touch ID 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
# Add multiple unlock methods
secret keys add passphrase # Password-based
secret keys add keychain # Touch ID (macOS only)
secret keys add pgp --keyid ABCD1234 # GPG key
# List unlock keys
secret keys list
# Select a specific unlock key
secret key select <key-id>
Encryption/Decryption with Age Keys
# 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
- Use strong, unique passphrases for unlock keys
- Enable hardware authentication (Keychain, hardware tokens) when available
- Regularly audit unlock keys and remove unused ones
- Keep mnemonic phrases securely backed up offline
- Use separate vaults for different security contexts
Limitations
- Requires access to unlock keys for secret retrieval
- Mnemonic phrases must be securely stored and backed up
- Hardware features limited to supported platforms
Development
Building
make build # Build binary
make test # Run tests
make lint # Run linter
Testing
The project includes comprehensive tests:
./test_secret_manager.sh # Full integration test suite
go test ./... # Unit tests