111 lines
4.9 KiB
Markdown
111 lines
4.9 KiB
Markdown
# 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)
|