secret/README.md
2025-05-28 14:06:29 -07:00

137 lines
6.4 KiB
Markdown

# architecture
* `secret vault` allows you to change 'vaults'. vaults are just a universe
of secrets (and a single associated long-term key). you can have multiple
vaults, each with its own long-term key and secrets. this is useful for
separating work and personal secrets, or for separating different projects
with different long-term keys.
* `secret vault list`
* `secret vault create <name>` creates a new profile
* `secret vault select <name>` selects (switches to) a profile
the first and initial vault is titled `default`.
* `secret init` initializes a new vault and imports a user-provided BIP39
mnemonic phrase. The user must provide their own mnemonic phrase. The
long-term keypair is derived from this mnemonic. The long-term keypair is
used to encrypt and decrypt secrets. The long-term keypair is stored in the
vault. The private key for the vault is encrypted to a short-term keypair.
The short-term keypair private key is encrypted to a passphrase.
Use `secret generate mnemonic` to create a new BIP39 mnemonic phrase if you
need one.
if there is already a vault, `secret init` exits with an error.
* `secret import [vaultname]` will derive a long-term key pair from a bip32 seed
phrase and import it into the named vault. if no vault name is specified,
`default` is used. if the named vault already exists, it exits with
an error.
first:
* the long term key pair will be derived in memory
* a random short term (unlock) key pair will be derived in memory
then:
* the long term key pair public key will be written to disk
* the short term key pair public key will be written to disk
* the long term key pair private key will be encrypted to the short term
public key and written to disk
* the short term key pair private key will be encrypted to a passphrase
and written to disk
* `secret enroll sep` creates a short-term keypair inside the secure enclave
of a macOS device. it will then use one of your existing short-term
keypairs to decrypt the long-term keypair, re-encrypt it to the secure
enclave short-term keypair, and write it to disk. it requires an existing
vault, and errors otherwise.
* short-term keypairs are called 'unlock keys'.
* `secret add <secret>` adds a secret to the vault. this will generate a
keypair (secret-specific key) and encrypt the private portion of the
secret-specific key (called an 'unlock key') to the long-term keypair and
write it to disk. if the secret already exists it will not overwrite, but
will exit with an error, unless `--force`/`-f` is used. the secret
identifier is [a-z0-9\.\-\_\/]+ and is used as a storage directory name.
slashes are converted to % signs.
in a future version, overwriting a secret will cause the current secret to
get moved to a timestamped history archive.
* `secret get <secret>` retrieves a secret from the vault. this will use an
unlock keypair to decrypt the long-term keypair in memory, then use the
long-term keypair to decrypt the secret-specific keypair, which is then
used to decrypt the secret. the secret is then returned in plaintext on
stdout.
* `secret keys list` lists the short-term keypairs in the current vault.
this will show the public keys of the short-term keypairs and their
creation dates, as well as any flags (such as `hsm`). their identifiers
are a metahash of the public key data using the sha256 algorithm.
* `secret keys rm <keyid>` removes a short-term keypair from the vault. this will
remove the short-term keypair from the vault, and remove the long-term
keypair from the short-term keypair.
* `secret keys add pgp <pgp keyid>` adds a new short-term keypair to the vault.
this will generate a new short-term keypair and encrypt it to a given gpg
key, to allow unlocking a vault with an existing gpg key, for people who
use yubikeys or other gpg keys with an agent. the new short-term keypair
is randomly generated, the public key stored, and the private key encrypted
to the gpg key and stored.
* `secret key select <keyid>` selects a short-term keypair to use for
`secret get` operations.
# file layout
$BASE = ~/.config/berlin.sneak.pkg.secret (on linux per XDG)
$BASE = ~/Library/Application Support/berlin.sneak.pkg.secret (on macOS)
$BASE/configuration.json
$BASE/currentvault -> $BASE/vaults.d/default (symlink)
$BASE/vaults.d/default/
$BASE/vaults.d/default/vault-metadata.json
$BASE/vaults.d/default/pub.age
$BASE/vaults.d/default/current-unlock-key -> $BASE/vaults.d/default/unlock.d/passphrase (symlink)
$BASE/vaults.d/default/unlock.d/passphrase/unlock-metadata.json
$BASE/vaults.d/default/unlock.d/passphrase/pub.age
$BASE/vaults.d/default/unlock.d/passphrase/priv.age
$BASE/vaults.d/default/unlock.d/passphrase/longterm.age # long-term keypair, encrypted to this short-term keypair
$BASE/vaults.d/default/unlock.d/sep/unlock-metadata.json
$BASE/vaults.d/default/unlock.d/sep/pub.age
$BASE/vaults.d/default/unlock.d/sep/priv.age
$BASE/vaults.d/default/unlock.d/sep/longterm.age # long-term keypair, encrypted to this short-term keypair
$BASE/vaults.d/default/unlock.d/pgp/unlock-metadata.json
$BASE/vaults.d/default/unlock.d/pgp/pub.age
$BASE/vaults.d/default/unlock.d/pgp/priv.asc
$BASE/vaults.d/default/unlock.d/pgp/longterm.age # long-term keypair, encrypted to this short-term keypair
$BASE/vaults.d/default/secrets.d/my-tinder-password/value.age
$BASE/vaults.d/default/secrets.d/my-tinder-password/pub.age
$BASE/vaults.d/default/secrets.d/my-tinder-password/priv.age # secret-specific key, encrypted to long-term key
$BASE/vaults.d/default/secrets.d/my-tinder-password/secret-metadata.json
$BASE/vaults.d/default/secrets.d/mail%berlin.sneak.secrets.imaplogin/value.age
$BASE/vaults.d/default/secrets.d/mail%berlin.sneak.secrets.imaplogin/pub.age
$BASE/vaults.d/default/secrets.d/mail%berlin.sneak.secrets.imaplogin/priv.age
$BASE/vaults.d/default/secrets.d/mail%berlin.sneak.secrets.imaplogin/secret-metadata.json
# example configuration.json
`json
{
"$id": "https://berlin.sneak.pkg.secret/configuration.json",
"$schema": "https://berlin.sneak.pkg.secret/configuration.schema.json",
"version": 1,
"configuration": {
"createdAt": "2025-01-01T00:00:00Z",
"requireAuth": false,
"pubKey": "<public key of the long-term keypair>",
"pubKeyFingerprint": "<fingerprint of the long-term keypair>"
}
}
`