summaryrefslogtreecommitdiff
path: root/secrets/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'secrets/README.md')
-rw-r--r--secrets/README.md163
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.