feat: credentials at rest — per-secret encrypted files #25
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Prerequisite for #24 (vault-gated actions).
Problem
Forge tokens are in plaintext
.env. Future vault secrets (CLAWHUB_TOKEN, GITHUB_TOKEN, deploy keys) need secure storage. The vault gate (#24) needs to launch containers with specific credentials — not all of them, just the ones an action needs.Design: per-secret files, not a megafile
Instead of one
.env.vault.enccontaining everything, store each secret as an individual file:When
disinto vault-runlaunches a container for an action that needsCLAWHUB_TOKEN, it mounts onlysecrets/CLAWHUB_TOKEN.enc, decrypts it, and injects it as an env var. The container never seesGITHUB_TOKEN.This maps cleanly to the vault proposal: the proposal says
"secrets": ["CLAWHUB_TOKEN"]and vault-run knows exactly which files to mount.How SOPS + age works
age generates a key pair:
~/.config/sops/age/keys.txt(on disk,chmod 600, not in repo).sops.yaml(committed — tells SOPS who can decrypt)SOPS encrypts values, not keys. You can see which secret a file contains, just not its value.
The private key must be on disk for unattended decryption (factory restarts without human). Same trade-off as SSH keys. Protected by filesystem permissions.
When to set up
Not required at init.
disinto initworks without SOPS/age — stores forge tokens in plaintext.envwith a warning. The user runsdisinto secrets migratewhen ready. This keeps the barrier to entry low.Sequence:
disinto init→ plaintext.env(works immediately)disinto secrets migrate→ encrypts.env→.env.enc, deletes plaintextdisinto secrets add CLAWHUB_TOKEN→ prompts for value → writessecrets/CLAWHUB_TOKEN.encImpact on stack stop/start
disinto up:env.shdetects.env.enc, runssops -din memory, exports vars. No plaintext on disk.disinto down: nothing changes. Encrypted files stay.env.shwhich decrypts. Age private key mounted read-only.Compose changes
Mount age key into agents container:
Implementation
disinto secrets add <NAME>— prompts for value, encrypts tosecrets/<NAME>.encdisinto secrets migrate— encrypts existing.env→.env.encdisinto vault-run— reads proposal'ssecretslist, mounts only those files, decrypts at container startenv.shto handle.env.enc(already scaffolded)What stays plaintext
.sops.yaml(public key only)docker-compose.yml(var references, no values)projects/*.toml(no secrets)Acceptance criteria
secrets/directorydisinto secrets add/migratecommands workdisinto vault-runmounts only requested secretsfeat: install SOPS + age for credentials at restto feat: credentials at rest — per-secret encrypted files