Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Store repository secrets encrypted, with a CLI and a settings form

0c40a1d3b48eb0ade37334f62ee526c371ecb61c · Keenan Nemetz · 7d ago · parent 122cbe4f

Store repository secrets encrypted, with a CLI and a settings form

A repository has values that cannot live in its code: a deploy key, a
registry token, a staging password. They are now stored in data/secrets.db,
sealed with AES-256-GCM under data/secrets.key, and read through one store
that records every read and every change. The key is a separate file, and
secrets_key can move it, so a backup of the data directory can be a backup of
ciphertext rather than of plaintext.

`vole secret list|set|get|rm` asks the instance over the key the caller
already pushes with, since the store is server-side. set reads the value from
stdin or a file and never from the argument list; get writes the value and
nothing else. The maintainer role is the capability: the accounts that approve
work and allow CI own the credentials those jobs will use.

The repository's Settings tab gains the same list — names, versions, who
changed one, when a value was last read — with set, replace and delete. It
never renders a value, and a maintainer who is not an admin now reaches that
page for this section alone.

Values are limited to what one environment variable can carry: 128 KiB for
NAME=value, valid UTF-8 and no NUL. A longer value could never reach a step,
and the refusal says so.

Slice 1 of #154.

docs/operations.md +18−5

@@ -54,6 +54,8 @@ vole admin account backup backup/users.db # accounts, keys, sessions, rule
54 54 sqlite3 data/runs.db ".backup 'backup/runs.db'" # CI history, queue, and approvals
55 55 cp -a data/logs backup/ # CI attempt logs
56 56 cp data/ssh_host_ed25519_key backup/ # the SSH host key
57 sqlite3 data/secrets.db ".backup 'backup/secrets.db'" # sealed repository secrets
58 cp data/secrets.key backup/ # the key those secrets need
57 59 cp -a data/acme backup/ 2>/dev/null # TLS account key and certificates, if ACME is on
58 60 cp data/audit.log backup/ 2>/dev/null # history of admin actions
59 61 ```
@@ -63,6 +65,12 @@ cp data/audit.log backup/ 2>/dev/null # history of admin actions
63 65 database file yet. Do the same for `runs.db` with SQLite's backup command; copying it
64 66 by hand while the server is writing can miss WAL pages.
65 67
68 Keep `data/secrets.key` apart from the copies of `data/`. A backup that holds both
69 the database and its key is a backup of plaintext: the encryption protects a copy
70 that loses the key, not one that keeps it. Restoring `data/secrets.db` beside a
71 newly generated key reads nothing, and Vole says so rather than handing a job an
72 empty value.
73
66 74 If you lose the account database, you need to recreate accounts and re-enroll
67 75 their passkeys. You do not lose repositories. The backup contains account metadata,
68 76 public keys, and hashes of session and enrollment tokens; it does not contain a
@@ -76,8 +84,9 @@ must be backed up with it.
76 84 ## Restore an instance
77 85
78 86 1. Restore `data/users.db`, `data/runs.db`, `data/logs/`,
79 `data/ssh_host_ed25519_key`, `data/audit.log`, and `data/acme/` if the instance
80 obtains its own TLS certificates.
87 `data/ssh_host_ed25519_key`, `data/audit.log`, `data/secrets.db` with the
88 `data/secrets.key` that sealed it, and `data/acme/` if the instance obtains its
89 own TLS certificates.
81 90 2. Restore the repositories under `data/repos/` and the object store under
82 91 `data/lfs/` if you keep CI artifacts.
83 92 3. Run `vole admin index rebuild`.
@@ -149,9 +158,13 @@ it cannot restore CI history.
149 158
150 159 ## Security notes
151 160
152 - The SSH host key is the only long-term secret Vole stores. Keep it readable
153 only by the Vole user (`0600`). Browser session and enrollment tokens are
154 stored as hashes.
161 - Two long-term secrets are stored: the SSH host key, and the key that seals
162 repository secrets. Keep both readable only by the Vole user (`0600`). Browser
163 session and enrollment tokens are stored as hashes.
164 - Repository secrets are encrypted at rest, which protects a copy of `data/` that
165 leaves the host. It does not protect a host somebody already owns: file modes
166 are the boundary, and the default key location is beside the database. Anything
167 that can read the data directory can read the values.
155 168 - Vole creates its own secrets at `0600` and its data directory at `0700`: the
156 169 roster (`users.db`), the audit log, the SSH host key and the ACME account
157 170 directory. It also tightens an existing instance on startup, and logs the paths