Files

111 lines
4.9 KiB
Markdown
Raw Permalink Normal View History

2026-08-19 09:52:07 -07:00
# M6.5 — Postgres credentials for the Mac client
| Field | Value |
|---|---|
| Phase | M6 — agent-manager migration |
| Size | S — <1 day |
| Status | ⬜ Not started |
| Flags | homelab |
| Spec | inlined below |
| Blocks | M6.1 |
## Goal
The `agent-manager` process running on the Mac gets a Postgres connection
string/credentials, managed the same ksops way the rest of this homelab
handles secrets — not a password pasted into a local config file or env
var by hand.
## Facts (inlined — no spec read needed)
**Existing pattern to follow: ksops-managed secret**, same as
`model-invoke-apikey` elsewhere in this homelab. CNPG itself already
generates an in-cluster Secret for the `app` user
(`agent-manager-db-app` by its usual naming convention) — the work here is
getting that credential (or a dedicated read-write user, if reusing the
CNPG-generated superuser-adjacent `app` credential isn't desired) to a
process running outside the cluster, on the Mac.
**Two credentials touch two different trust boundaries:**
- Cluster-internal: CNPG's own generated Secret, already ksops-free
(CNPG manages it, not this repo).
- Mac client: needs that same username/password (or a separate,
narrower-scoped user) delivered to `~/workplace/agent-manager`'s
runtime config, via a ksops-encrypted file in git rather than a
manually-copied value.
## Steps
1. Decide: reuse CNPG's auto-generated `app` user, or create a dedicated
`agent_manager_client` role scoped to only the `sessions`/`groups`/
`settings`/`review_*` tables (narrower blast radius if the credential
ever leaks from a Mac laptop, which is a meaningfully different threat
model than a credential that only ever lives inside the cluster).
2. If a dedicated role: add it via CNPG's declarative `Database` /
`postInitSQL` (or a one-time migration in M6.2's schema setup) rather
than a manual `psql` grant.
3. Encrypt the resulting connection string (or user/password pair) with
ksops, following the exact file layout `model-invoke-apikey` uses.
4. Commit the encrypted secret to git (safe — that's the point of ksops),
push to both remotes.
5. Wire agent-manager's config loading (check `cmd/` / existing config
file handling on the `add-headless-spawn` branch) to read the
decrypted value at runtime — decide whether decryption happens via a
`sops exec-env`-style wrapper the Mac invokes, or a decrypted file
materialized once locally and gitignored, matching whatever
`model-invoke-apikey`'s consumers already do.
6. Verify agent-manager connects using only the ksops-sourced credential
— no plaintext password anywhere in the repo or in shell history.
## Acceptance
- No Postgres password appears in plaintext in git, in
`~/workplace/agent-manager`'s tracked config, or was typed directly
into a `kubectl`/`psql` command during setup.
- The credential is encrypted with ksops in the same repo location/
pattern as `model-invoke-apikey`.
- agent-manager on the Mac successfully authenticates through M6.4's
ingress route using this credential.
## Verify
**Harness:** manual — this is a secret-handling task, not one to automate
a fake credential through.
**Checklist** (no `verify/*.sh`, since scripting a real credential check
means committing something that either leaks a real secret or asserts
nothing):
1. `git grep -i "password"` in both the homelab repo and
`~/workplace/agent-manager` shows only ksops-encrypted blobs or
references to environment/config loading, never a literal value.
2. The ksops secret file's structure matches `model-invoke-apikey`'s
(same encryption provider, same key layout) — a side-by-side diff of
the YAML structure (not values) confirms this.
3. `psql` from the Mac using the decrypted credential (via M6.4's route)
succeeds.
4. Revoking/rotating the credential (delete the CNPG Secret or drop the
dedicated role, if one was created) and re-running step 3 fails
cleanly — confirms the client isn't caching or falling back to
something else.
**False pass:**
- Confirming connectivity once with a credential typed in manually during
setup, then wiring the ksops path afterward without re-testing that the
*ksops-sourced* value is what actually authenticates. Checklist item 4
(rotate and confirm the old path is really gone) is the guard against
"it worked, but only because of leftover state."
## Traps
- Granting the dedicated role (if created) superuser or
database-owner-equivalent privileges "to avoid permission errors during
setup" and never narrowing it afterward — defeats the reason to create
a dedicated role at all.
- Storing the decrypted credential in a file the Mac client reads that
isn't gitignored, recreating the plaintext-secret problem one directory
away from the ksops-encrypted source of truth.
---
Background: [M6.1](M6.1-agent-manager-db-manifest.md) · `model-invoke-apikey` (ksops pattern reference, this homelab)