spec/tasks: pull repo-credential plumbing into Phase 1
Adds P1-32/33/34: encrypted repo creds carried on the enrollment token, agent-side AEAD secrets file, end-to-end smoke. spec.md §4.2 and §7.3 rewritten to describe the full flow (server-issued at token time, pushed via config.update on hello, persisted encrypted on the agent) and to make the encrypted-file-now / OS-keyring-Phase-2 split explicit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -123,7 +123,14 @@ It is built for small-to-medium fleets (initial target: ~12 endpoints) and is in
|
||||
- **Service integration:** systemd unit (Linux). Windows service via
|
||||
`golang.org/x/sys/windows/svc` — Phase 2.
|
||||
- **Footprint goal:** ≤ 15 MB binary, ≤ 50 MB RSS idle
|
||||
- **Persistence:** local config file + small state DB (BoltDB or JSON) for queued reports if server is unreachable
|
||||
- **Persistence:** `agent.yaml` (server URL, host ID, bearer, secrets
|
||||
key) + an AEAD-encrypted secrets blob (`secrets.enc`) holding the
|
||||
restic repo URL + password. Both files are mode 0600 owned by the
|
||||
agent service user. Phase 1 ships the encrypted-file form on
|
||||
Linux; Phase 2 swaps that for OS-keyring storage (DPAPI on Windows,
|
||||
Secret Service / `pass` on Linux where a session bus is
|
||||
available — see §7.3). A small state DB (BoltDB or JSON) for
|
||||
queued reports lands when offline-resilience work does.
|
||||
- **Restic invocation:** spawns `restic` with `--json`, parses streamed output, forwards to server in real time
|
||||
- **Updates:** distributed via OS package manager — apt repo (Linux) and
|
||||
Chocolatey package (Windows), both pointing at gitea releases. No
|
||||
@@ -341,9 +348,30 @@ offline.
|
||||
- **viewer:** read-only
|
||||
|
||||
### 7.3 Secret handling
|
||||
- Restic repo passwords and REST-server credentials encrypted at rest in SQLite using a server-side key (loaded from env or file at startup)
|
||||
- Pushed to agents only over the authenticated WS, only when needed for a job
|
||||
- Agent stores them in OS keyring where available (Windows DPAPI, Linux Secret Service / fallback to encrypted file with restricted perms)
|
||||
- Restic repo passwords and REST-server credentials encrypted at rest
|
||||
in SQLite using a server-side key (loaded from env or file at
|
||||
startup, AEAD via `internal/crypto`).
|
||||
- Operator supplies repo URL + username + password when minting an
|
||||
enrollment token. The token row holds them as a single encrypted
|
||||
blob; on `ConsumeEnrollmentToken` the blob is moved to a
|
||||
`host_credentials` row keyed by `host_id` (same tx).
|
||||
- Pushed to agents over the authenticated WS as a `config.update`
|
||||
message — sent immediately after the agent's `hello` on every
|
||||
connect, and again whenever the operator edits the credential.
|
||||
Agents that connect before credentials exist proceed normally
|
||||
but refuse to start backup jobs until the push arrives.
|
||||
- Agent persistence:
|
||||
- **Phase 1, Linux:** AEAD-encrypted file at
|
||||
`/var/lib/restic-manager/secrets.enc`, key stored in
|
||||
`agent.yaml` alongside the bearer (same 0600 trust boundary).
|
||||
Atomic writes (tmp+fsync+rename).
|
||||
- **Phase 2:** OS keyring where available — Windows DPAPI; Linux
|
||||
Secret Service via `pass` / `gnome-keyring` / `kwallet` when a
|
||||
session bus is present. The encrypted-file path stays as the
|
||||
fallback for headless boxes.
|
||||
- Plaintext repo passwords never appear in `agent.yaml`, server logs,
|
||||
audit-log payloads, or job-log streams. The audit log records
|
||||
*that* a credential was set/changed and by whom, never the value.
|
||||
|
||||
### 7.4 Repo protection
|
||||
- Restic REST server runs with `--append-only` for routine backups
|
||||
|
||||
Reference in New Issue
Block a user