pkg | ||
.gitignore | ||
go.mod | ||
go.sum | ||
LICENSE | ||
Makefile | ||
README.md | ||
test_secret_manager.sh |
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 profilesecret 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 ashsm
). 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 forsecret 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>" } }