ADORSYS-GIS / ADORSYS-GIS/ai-helm
[Ticket]: Read-only Grafana Postgres datasource over the governance database
- Lenguaje dominante
- Go Template
- Estrellas
- 3
- Forks
- 1
- Merge medio
- 19 h 24 min
- PR fusionados (30 d)
- 80
Descripción
### Type
Operational task
### Summary
We need a **read-only Grafana Postgres datasource over the `governance` database**, because the governance dashboards — which are **the product** — read tenant, application, repo and team as *columns* rather than as metric labels.
Expected result:
> A `GrafanaDatasource` pointing at a least-privilege read-only role on the governance database, with the Cilium egress that makes it reachable, so dashboards can be built against it.
### Intent
This is what lets both connectors drop most of their metric-publishing and all of their low-cardinality label constraints. Usernames, repos, teams and applications become columns. The "keep cardinality low, avoid `username` labels" constraint that shapes the source specs simply evaporates for the business dashboards — Mimir keeps only the ~10 operational metrics.
It is not a new idea here: ADR-0063 already runs exactly this pattern for the Keycloak user directory (`uid: keycloak`).
### Source of truth (links)
- Epic: ADORSYS-GIS/lightbridge-governance#4
- Enables the dashboards in ADORSYS-GIS/lightbridge-governance#5
- Roadmap: ADORSYS-GIS/ai-helm#872 §2 ("The Grafana-reads-Postgres pattern")
- **Precedent: ADR-0063** and `docs/patterns/per-user-observability.md`
- Depends on: the `governance` role + database ticket
### Current Behavior
No governance database exists yet, so no datasource. The precedent (`uid: keycloak`) is live and working, including its least-privilege role and its Cilium egress.
### Expected Behavior
- A `GrafanaDatasource` (`uid: governance`) over the governance database, **read-only**.
- A dedicated least-privilege role — **not** the application's own role.
- Cilium egress from Grafana to Postgres.
- Dashboards can query tenant/application/repo/team as columns.
### Acceptance Criteria
- [ ] Given the datasource, when Grafana queries it, then it succeeds and returns governance data.
- [ ] Given the role it connects as, when its grants are inspected, then it has **SELECT only**, on **only** the tables the dashboards need. ⚠️ Least-privilege is not a formality here — ADR-0063's `grafana_ro` was deliberately never granted the Keycloak `credential` or federated-token tables. Apply the same discipline: grant the minimum, enumerate it, and write down why anything excluded is excluded.
- [ ] Given the role, when a write is attempted, then it fails.
- [ ] Given Cilium's default-deny egress, when Grafana connects, then an explicit `CiliumNetworkPolicy` allows it — shipped in the same change.
- [ ] Given the datasource definition, when it is stored, then credentials come from an ExternalSecret, never a literal.
- [ ] ⚠️ **Secret-first**, or the ExternalSecret sits in `SecretSyncedError` and the datasource silently fails to authenticate.
### Out of Scope
- The dashboards themselves — separate ticket under the Copilot epic.
- Any write path from Grafana.
- Changing the existing `keycloak` datasource.
### Technical Context
- Datasource + egress + secret-copy belong in **`ai-helm-values`**; the dashboard sources live in `ai-helm` (`tools/dashboards/`).
- ⚠️ **Values-repo-first.** The file must exist on `ai-helm-values` `main` before the chart change merges, or `ignoreMissingValueFiles` silently falls back to chart defaults.
- ⚠️ The GRANT itself should be idempotent and owned where the cluster is owned — the `grafana_ro` precedent uses an idempotent GRANT Job in the repo that owns the database.
- After editing dashboard sources: `uv run dashboards build` and commit the regenerated JSON, or `dashboards-drift` CI fails.
### Risks
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| **Over-granted role exposes more than the dashboards need** | Medium | **High** | Enumerate grants explicitly; SELECT-only; review the grant list as part of this ticket, not later |
| Cilium blocks the connection, looks like a datasource bug | **High** | Low | Ship the CNP in the same change; this has bitten every Postgres datasource here |
| Secret not synced → silent auth failure | Medium | Medium | Secret-first; verify `SecretSynced=True` |
| Values-repo ordering wrong → chart defaults silently used | Medium | Medium | Values-repo-first, always |
### Test Plan
1. Confirm the remote secret key exists.
2. Apply the read-only role and its grants; verify with `\dp` (or equivalent) that only the intended tables are readable.
3. Attempt a write as that role; confirm it fails.
4. Apply the datasource + CNP; use Grafana's "Test" button.
5. Run a representative query from a panel.
### Verification evidence
*To be completed on delivery.*
Required:
- The enumerated grants for the read-only role.
- Evidence a write attempt fails.
- Grafana datasource test passing.
- `SecretSynced=True`.
- Confirmation the values-repo file landed before the chart change.
### Human accountable owner
@stephane-segning
### AI Usage Declaration
Drafting the ticket
### Human verification completed
- [x] I understood the intent
- [x] I checked the source of truth
- [x] I documented remaining risks
- [x] I am the accountable owner and accept responsibility for this ticket.
Guía de contribución
Evaluación
Este issue todavía no se ha evaluado.