Hermit is a minimalist secret manager designed to let infrastructure admins version their secrets securely. Secrets are generated and stored encrypted alongside their configuration, forming a single versioned source of truth.
When managing a homelab with many services (Authelia, Immich, LLDAP, Vikunja, Outline, etc.), you face a classic dilemma:
- Option 1: Store secrets in plaintext → security risk
- Option 2: Generate secrets manually and store them separately → config/secrets drift
- Option 3: Use a complex secret manager like Vault → overkill for a homelab
Hermit offers a simple but effective approach:
- Declare secrets in
secrets.yamlalongside your config - Generate secrets automatically (RSA keys, random values, etc.)
- Encrypt secrets with version them in Git
- Modify secrets securely by decrypting them locally
- Re-encrypt before committing
Key advantage: Your configuration and its secrets live together, versioned, encrypted, without depending on external infrastructure.
Consider a typical homelab:
services:
- Authelia (centralized auth)
- LLDAP (user directory)
- Forgejo (self-hosted git)
Each service needs secrets:
- JWT keys for authentication
- Database passwords
- Encryption keys
- OAuth OIDC secrets
With Hermit, you organize everything in secrets.yaml:
secrets:
- name: authelia/jwt_secret
type: random_hex
- name: authelia/oidc
type: rsa
- name: authelia/oidc_clients/vikunja
type: random_hex
- name: lldap/jwt_secret
type: random_hexThen generate, encrypt, and version everything:
hermit generate # Creates secrets encrypted
git commit -m "chore: generate secrets"Later, to modify a secret:
hermit unwrap # Decrypts to .secrets/ (Git-ignored)
vim .secrets/authelia/jwt_secret
hermit wrap # Re-encrypts modifications- Simple: Single YAML file to declare and configure secrets
- Portable: Encryption with age (modern standard)
- Flexible: Support for multiple secret types
random_hex: Random hexadecimal valuesrsa: RSA key pairs (private + public)manual: Interactive user input- Extensible with custom generators
- Secure: Secrets encrypted at rest, safe modification workflows
- Organized: Directory hierarchy supported (
authelia/jwt_secret,oidc_clients/vikunja, etc.) - Versionable: Encrypted secrets ready for Git, just backup your age key securely
- No external state: No Vault server, no network dependencies
- Go 1.21+
git clone https://github.com/ruets/hermit
cd hermit
go build -o hermit .
./hermit --helpCreate a secrets.yaml file in your config directory or use hermit init to generate a default one:
key_path: ~/.config/hermit/hermit.key # Optional, path to age key
secrets:
- name: authelia/jwt_secret
type: random_hex
- name: authelia/oidc
type: rsa
- name: authelia/oidc_clients/vikunja
type: random_hex
- name: lldap/jwt_secret
type: random_hexYou can configure hermit via:
YAML config file (secrets.yaml):
key_path: Path to age encryption key (optional, overrides CLI flag if set)
CLI flags:
hermit [command] \
--config path/to/secrets.yaml \
--key-path ~/.config/hermit/hermit.key--config: Path tosecrets.yaml(default:./secrets.yaml)--key-path: Path to age key (default:~/.config/hermit/hermit.key)
Priority: If key_path is set in secrets.yaml, it takes priority over the --key-path flag.
Secrets are always stored alongside the config file:
{config_dir}/secrets/: Encrypted secrets{config_dir}/.secrets/: Temporary plaintext (Git-ignored)
| Command | Description |
|---|---|
hermit init |
Initialize Hermit config files |
hermit generate |
Generate missing secrets |
hermit status |
Show secret status |
hermit unwrap |
Decrypt secrets (plaintext) |
hermit wrap |
Re-encrypt modifications |
hermit clean |
Remove orphaned secrets |
hermit initInitializes Hermit by creating a default secrets.yaml and adding secrets and key to gitignore.
hermit generateCreates missing secrets in {config_dir}/secrets/ (encrypted by default)
hermit statusShows list of secrets and their status
hermit unwrapDecrypts secrets to {config_dir}/.secrets/ (plaintext files)
For RSA keys, the public key is automatically generated from the private key
hermit wrapRe-encrypts secrets, save modified secrets and removes plaintext versions
To change whether a secret is encrypted (encrypted: true/false in secrets.yaml):
- Run
hermit unwrap(ensure secrets are decrypted to.secrets/) - Update
secrets.yamlwith the new encryption setting - Run
hermit wrap(detects the format change and re-encrypts) - Run
hermit clean(removes backup files left by wrap)
Example:
# Before: encrypted: false → After: encrypted: true
hermit unwrap # Decrypt secrets first
# Edit secrets.yaml to change encryption setting
hermit wrap # Re-encodes secret to encrypted format
hermit clean # Removes plaintext backup fileshermit cleanRemoves secrets no longer in secrets.yaml
Generates a random hexadecimal string.
- name: shared/api_token
type: random_hexGenerates: a3f7e2c9d1b4e8f6c2a9e7d4b1f8c5a3
Generates a 2048-bit RSA key pair (private + public).
- name: authelia/oidc
type: rsaGenerates two files:
secrets/authelia/oidc.age: Encrypted private key.secrets/authelia/oidc+.pub: Plaintext during decryption
The public key is generated on-the-fly from the private key, never stored.
Prompts user for interactive input.
- name: shared/admin_password
type: manual- Algorithm: Age (filippo.io/age)
- Key derivation: X25519
- Format:
.agefiles containing encrypted secrets
- Secrets encrypted at rest (
secrets/) - Decryption happens locally only (
.secrets/) - Plaintext editing on your machine
- Re-encryption before commit
.secrets/ignored by Git
# First time, hermit generates your age key
✓ generated age key at ~/.config/hermit/hermit.key
⚠ back up this file — losing it means losing access to all secretsImportant: Backup your age key (~/.config/hermit/hermit.key). Losing it means losing access to all encrypted secrets.
For detailed information about the architecture and development, see CLAUDE.md.
This project was primarily developed by hand, with AI assistance on specific parts. The AI contributed to:
- Initial code structure and some implementation details
- Documentation writing
- Testing and validation
The code has been reviewed and tested. Feel free to audit it for your use case, as with any open-source project.
Contributions welcome! Open an issue or pull request.
Hermit: Manage your secrets simply, keeping them close to your config, encrypted and versioned.