@homeflare/hfs
v0.28.0
Published
Encrypted secret vault CLI for Cloudflare Workers
Readme
hfs - Encrypted Secret Vault CLI
CLI for managing your encrypted secret vault on Cloudflare Workers.
Install
# Homebrew (macOS/Linux)
brew tap homeflare/tap && brew install homeflare
# npm
npm install -g @homeflare/hfsInstalls both homeflare secrets (umbrella CLI) and hfs (shortcut alias).
Requires cloudflared for interactive login.
Getting started
hfs config set --url https://secrets.yourcompany.com # point to your vault
hfs login # authenticate (opens browser)
hfs keygen --register # generate e2e encryption keyAn admin gives you the vault URL. If auto-provisioning is enabled, your account is created on first login.
Auth
Two modes, no fallback. They never mix.
Human - Set the vault URL with hfs config set --url, then hfs login opens a browser via cloudflared. Tap your YubiKey or use your IdP. Short-lived JWT stored locally.
Machine - Set HFS_URL, HFS_CLIENT_ID, HFS_CLIENT_SECRET env vars. Must correspond to a registered service token. Tokens registered with --secret authenticate via hashed client secret and work on all endpoints, not just Access-protected paths.
Commands
Secrets
hfs get <key> Get a decrypted secret
hfs get <key> -q Print only the value (pipe-friendly)
hfs get <key> -j Output as JSON
hfs set <key> <value> Store a secret
hfs set <key> --from-file Read value from a file
hfs set <key> -t <tags> Set with comma-separated tags
hfs set <key> --expires <date> Set with expiry (ISO 8601 date or duration)
hfs set <key> --ttl <dur> Set with relative expiry (e.g. 90d, 12h, 2w)
hfs get <key> --resolve Resolve ${SECRET} references in the value
hfs env --resolve <keys> Resolve references in exported values
hfs expiring List secrets expiring within 7 days (shows EXPIRES column)
hfs expiring --within 30d Custom time window
hfs rm <key> Delete a secret (confirms first)
hfs ls List all secret keys
hfs versions <key> List version history
hfs restore <key> <id> Restore a previous version
hfs env <key> [key...] Output as KEY=value (dashes → underscores)
hfs env -e <key> [key...] Same with export prefix
hfs export Export all as JSON (includes tags)
hfs import <file> Import from JSON
hfs cp <src> <dest> Copy a secret to a new key
hfs cp <src> <dest> -m Move (copy + delete source, confirms first)
hfs diff <key> <id> Compare current value with a version
hfs template <file> Render {{SECRET_KEY}} placeholders from vault
hfs template <file> -o out Write rendered output to file
hfs template <file> --resolve Also resolve ${SECRET} references in rendered outputEnd-to-end encryption
hfs keygen Generate age identity + bind ZT device (one-time setup)
hfs pubkey Show your age public key (share with teammates)
hfs set <key> <value> --e2e Encrypt for all eligible team members (RBAC)
hfs set <key> <value> --private Encrypt for only yourself (not shared)
hfs set <key> <value> --recipients <file> Encrypt for explicit recipient list
hfs rewrap <key> Re-encrypt for current eligible recipients
hfs rewrap --all Re-encrypt all e2e secrets (after user changes)
hfs get <key> Auto-decrypts e2e secrets with your identity
hfs get <key> --raw Show age ciphertext (what the server stores)
hfs config set --e2e-identity <path> Use a custom identity fileThe server never sees plaintext for --e2e secrets. Uses age encryption.
Auth & config
hfs login Authenticate via cloudflared
hfs logout Clear stored session
hfs whoami Show auth method, role, and scopes
hfs whoami -j Output as JSON
hfs health Check vault connectivity (no auth)
hfs config set --url <url> Set vault URL
hfs config show Show config + auth status
hfs config clear Clear all configUsers (admin only)
hfs user ls List all users
hfs user add <email> -r <role> [-n <name>] Add or update a user
hfs user rm <email> Remove a user
hfs user disable <email> Disable without deleting
hfs user enable <email> Re-enable a disabled user
hfs user role <email> <role> Change a user's roleRoles (admin only)
hfs role ls List all roles with scopes and allowed_tags
hfs role set <name> <scopes> [-d <desc>] [--allowed-tags <tags>] Create or update a role
hfs role rm <name> Delete a role (must have no users)
hfs role policy ls <role> List policies for a role
hfs role policy add <role> <scopes> [-t tags] Add a policy rule
hfs role policy rm <role> <id> Remove a policy rule by IDService tokens (interactive only)
hfs token register <id> -n <name> [-s <scopes>] [-r <role>] [--secret <s>] [--age-key <k>] [-d <desc>]
hfs token revoke <id> Revoke a token
hfs token ls List tokens with last-used timesFeature flags
hfs flag ls List all flags
hfs flag get <key> Get a flag value (-q for value only, -j for JSON)
hfs flag set <key> <value> Set a flag (auto-detects type)
hfs flag rm <key> Delete a flagAuto-type detection: "true"/"false" become boolean, numeric strings become number, valid JSON objects become json, everything else is string. Flags are plaintext KV, not encrypted like secrets.
Profiles
hfs profile ls List available profiles (tags) with secret counts
hfs profile show <tag> List secrets in a profile
hfs profile env <tag> Export profile secrets as shell variables (KEY=value)
hfs profile env <tag> -e Same with export prefix
hfs profile env <tag> --resolve Resolve ${SECRET} references in exported values
hfs profile diff <a> <b> Compare two profiles side by sideProfiles are virtual groupings based on tags. Any tag you apply to secrets becomes a profile automatically.
Admin
hfs audit [-n 100] [-j] View audit log
hfs audit --action get Filter by action
hfs audit --identity <email> Filter by identity
hfs audit --key <key> Filter by secret key
hfs audit --from/--to <date> Filter by date range
hfs audit consumers <key> Show who accessed a secret (identity, agent, count)
hfs audit-verify [-n 1000] Verify audit log hash chain integrity
hfs re-encrypt Migrate legacy secrets to envelope encryption
hfs rotate-key --stdin Re-wrap all DEKs with a new master key (reads from stdin)
hfs rotate-key <new-key> Same, but key on command line (leaks to shell history)
hfs deploy Deploy the Worker to Cloudflare
hfs completion bash|zsh Generate shell completionsScopes
read, write, delete, or * (default). Combine: read,write
Examples
# Load secrets into shell
eval $(hfs env -e API_KEY DB_PASSWORD)
# Pipe into tools
hfs get github-token -q | gh auth login --with-token
# Store a cert from file
hfs set tls-cert --from-file ./cert.pem -d "Prod TLS"
# Backup and restore
hfs export > backup.json
hfs import backup.json --overwrite
# Register a read-only CI token
hfs token register abc.access -n ci-pipeline -s read --secret "your-client-secret"
# Audit
hfs audit -n 50Shell integration
Load secrets into your shell on startup. Add to ~/.bashrc or ~/.zshrc:
# Load secrets from vault (requires hfs login session)
if command -v hfs &>/dev/null && hfs health &>/dev/null 2>&1; then
eval $(hfs env -e CLOUDFLARE_API_KEY GITHUB_TOKEN 2>/dev/null)
fiThis silently skips if hfs isn't installed, the vault is unreachable, or the session is expired. Secrets are fetched fresh on each shell startup.
For CI/CD, use service token env vars instead:
export HFS_URL=https://vault.example.com
export HFS_CLIENT_ID=abc123.access
export HFS_CLIENT_SECRET=your-secret
eval $(hfs env -e DEPLOY_KEY DB_PASSWORD)Backup and restore
# Export all secrets (decrypted JSON)
hfs export > vault-backup.json
# Restore to same or different vault
hfs import vault-backup.json --overwriteThe export file contains decrypted values. Store it securely and delete after use. If you change the ENCRYPTION_KEY, existing secrets become unreadable. Export first, rotate the key, then re-import.
Security
RBAC with custom roles, no credentials stored on disk (URL + short-lived JWT only), hard errors on expired auth, and every operation audit-logged.
See Encryption Architecture for detailed diagrams and Threat Model for the hardening guide.
