diff options
Diffstat (limited to 'secrets/README.md')
| -rw-r--r-- | secrets/README.md | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/secrets/README.md b/secrets/README.md new file mode 100644 index 0000000..293b747 --- /dev/null +++ b/secrets/README.md @@ -0,0 +1,163 @@ +# szecret + +Secret management using [age](https://github.com/FiloSottile/age) encryption. + +## Quick Start + +```bash +# Store a secret +echo "my-api-key" | szecret put api-key + +# Retrieve a secret +szecret get api-key + +# List all secrets +szecret list +``` + +## Commands + +| Command | Description | +|---------|-------------| +| `get <name>` | Retrieve and decrypt a secret | +| `put <name>` | Store a secret (reads from stdin) | +| `list` | List all secrets in the store | +| `ready` | Check if private key is configured | +| `ensure` | Ensure private key is configured (interactive) | +| `rotate` | Generate a new key and re-encrypt the global store | +| `create-local <name> <dir>` | Create a localized secret store | +| `put-local <file>` | Encrypt to a local store | +| `get-local <file>` | Decrypt from a local store | + +## Local Stores + +Local stores allow you to keep encrypted secrets outside the global store, useful for project-specific secrets that live alongside the code. + +### Creating a Local Store + +```bash +# Initialize a local store in a directory +szecret create-local myproject /path/to/project/secrets/ + +# This creates: +# - A key in the global store (local-key-myproject) +# - A metadata file at /path/to/project/secrets/.szecret containing: +# store=myproject +# pubkey=age1... +``` + +The metadata includes the public key for verification, preventing accidental use of the wrong store. + +### Using a Local Store + +```bash +# Encrypt a secret +echo "db-password" | szecret put-local /path/to/project/secrets/db.age + +# Decrypt a secret +szecret get-local /path/to/project/secrets/db.age +``` + +The commands automatically read the store name from the `.szecret` metadata file in the directory. + +## Setup + +### Where the store lives + +These scripts carry no secrets. The global store is a directory of `.age` +files plus `id.pub`, the public key they are encrypted to, kept in a checkout +of its own. szecret looks for it in this order: + +1. `$SZECRET_STORE` and `$SZECRET_PUBLIC_KEY`, if set. +2. `~/.local/share/szecret/store` and `~/.local/share/szecret/id.pub`, beside + the private keys. Normally symlinks into the checkout that holds the store. + +With neither, every command stops with setup instructions, and `ready` +fails silently. + +### Initial Setup + +```bash +# Generate a new keypair (file must be named after its public key) +age-keygen -o private +pubkey="$(age-keygen -y private)" +mkdir -p ~/.local/share/szecret/store +echo "${pubkey}" > ~/.local/share/szecret/id.pub +mv private "${HOME}/.local/share/szecret/${pubkey}" +``` + +### On a New Machine + +```bash +# The ensure command will prompt for your private key +szecret ensure +``` + +### Rotating the Global Key + +```bash +# Re-encrypt all secrets with a new age key +szecret rotate +``` + +This updates `id.pub` and every file in the store. When complete, commit +those changes in the checkout that holds the store, and update the private key +backup in 1Password. + +## Migration Guide + +### Migrating Local Stores (pre-2026) + +If you created local stores before the metadata system was introduced, run +`create-local` again with the directory - it will detect the existing key +and just add the metadata: + +```bash +szecret create-local myapp /path/to/secrets/ +# Output: Added metadata for existing store 'myapp' +``` + +**Before (old syntax):** +```bash +szecret create-local myapp +echo "secret" | szecret put-local myapp /path/to/secrets/password.age +szecret get-local myapp /path/to/secrets/password.age +``` + +**After (new syntax):** +```bash +# One-time migration +szecret create-local myapp /path/to/secrets/ + +# Now use simplified commands +echo "secret" | szecret put-local /path/to/secrets/password.age +szecret get-local /path/to/secrets/password.age +``` + +**For automated scripts:** The old `get-local <store-name> <file>` syntax still works but emits a deprecation warning suggesting the migration command. + +## Environment Variables + +For testing or custom setups, these environment variables override default paths: + +| Variable | Description | Default | +|----------|-------------|---------| +| `SZECRET_STORE` | Global store directory | `~/.local/share/szecret/store` | +| `SZECRET_PUBLIC_KEY` | Public key path | `~/.local/share/szecret/id.pub` | +| `SZECRET_PRIVATE_KEY` | Single private key file (full override) | (none) | +| `SZECRET_PRIVATE_KEY_DIR` | Directory containing private keys (named by their public key) | `~/.local/share/szecret` | + +* Private keys are stored in `~/.local/share/szecret/` (or `$SZECRET_PRIVATE_KEY_DIR`), with each file named after its public key (e.g. `age1...`). +* `id.pub` indicates which public key is current. + +## Testing + +```bash +# Run all tests +./test/run.sh + +# Run specific tests +./test/run.sh local create-local +``` + +See [test/README.md](test/README.md) for more details. |
