oidc-client: keycloak makes each consumer its client; grafana logs in through it #155
Open
mesh-admin
wants to merge 6 commits from
feat/oidc-client-provision into main
pull from: feat/oidc-client-provision
merge into: :main
:main
:fix/resolver-passes-the-dnssec-bit
:fix/mailu-admin-asks-the-machines-resolver
:fix/postgres-is-not-named-after-the-seat
:fix/110-the-resolver-answers-a-container
:feat/qbittorrent-for-ace
:feat/servarr-api-provision
:feat/home-assistant-for-ace
:feat/tautulli-for-ace
:feat/bookshelf-for-ace
:feat/lidarr-for-ace
:feat/radarr-for-ace
:feat/sonarr-for-ace
:feat/oidc-client-provision
:feat/kometa-for-ace
:feat/plex-for-ace
:fix/manifests-publish-software-ports
:feat/n8n-for-ace
:feat/baserow-for-ace
:feat/supabase-for-ace
:feat/nzbget-for-ace
:feat/matrix-for-ace
:feat/bazarr-for-ace
:fix/sidecars-dial-the-port-they-were-given
:feat/grafana-for-ace
:feat/ombi-for-ace
:chore/remove-the-network-checker-module
:feat/a-network-checker-module
:feat/modules-name-their-endpoints
:fix/a-routed-module-listens-from-the-mesh
:fix/the-resolver-declares-both-protocols
:fix/sshd-declares-the-daemon-it-owns
:fix/fail2ban-bans-through-what-every-machine-has
:fix/fail2ban-declares-the-log-its-own-jail-reads
:fix/fail2ban-restarts-on-its-log-target
:fix/fail2ban-declares-where-it-logs
:feat/the-catalogue-hears-what-it-missed
:feat/the-catalogue-prepares-its-own-schema
:fix/the-catalogue-declares-the-event-it-emits
:feat/a-merge-rebuilds-what-it-changed
:fix/a-merge-older-than-the-watching-is-history
:fix/a-merge-announced-is-said
:fix/the-forge-watches-every-repository
:feat/the-forge-announces-every-merge
:feat/nats-serves-the-meshs-certificate
:fix/nats-declares-its-base
:feat/amqp-leaves-the-catalogue
:restore/broker-claim
:revert/broker-seat-claim
:fix/broker-seat-must-stay-held
:fix/go-126-base
:feat/nats-genesis
:feat/ssh-client-module
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d2f03736fa |
grafana: its InfluxDB data source comes from the influxdb-api provision
ace's grafana reads InfluxDB through a data source somebody typed into its database: a LAN address, a database InfluxDB 2 does not have, and a password for a v1 user of an earlier instance. Nothing in the mesh knew it existed, so migrating influxdb could only break it further. grafana now requires influxdb-api, contributes read access, and the mesh renders a provisioning file grafana reads at start: the address, port, org's default bucket (as the InfluxQL database) and its own login from the binding, the password by $__file from the pair credential the mesh delivers, 0400 for grafana's uid 472. It is a data source of its own name and uid, read-only in the UI and not the default, so the data source a person made is never overwritten; a changed binding or a rotated password restarts grafana, which re-reads the file. Includes #152 (merged into this branch): influxdb provides influxdb-api. |
||
|
|
c5e273e232 |
Merge feat/influxdb-for-ace (#152) into feat/oidc-client-provision
grafana's data source requires influxdb-api, which influxdb provides only on #152's branch; merged so this branch's catalogue has the provider of everything grafana requires. #152 should merge first. |
||
|
|
5a906b757d |
keycloak, grafana: their public names come from the mesh, not the manifest
GF_SERVER_ROOT_URL=https://grafana.zurag.be, KC_HOSTNAME=https://keycloak.novox.be and the served issuer's novox default were domains in definitions — wrong on every other machine (ADR 0112). The names now come from ${bound:route:name} (mesh-controller #149, hq 122): grafana's in oidc.env, keycloak's in a hostname.env its server reads. The issuer includes the realm and stays the assignment's, with no default: unset, a consumer asking for it is refused and the provisioner says so, rather than both quietly using novox's URL. Rendered through mesh-controller #149 from these manifests on a zurag.be node: KC_HOSTNAME=https://keycloak.zurag.be, GF_SERVER_ROOT_URL= https://grafana.zurag.be, OIDC URLs from the issuer setting. Needs #149 merged and rolled out first. |
||
|
|
d8ee88e487 |
grafana: log in through keycloak's oidc-client provision
HAL's grafana logged in through a hand-made Keycloak client whose secret sat in its .env. Requiring oidc-client gives it a client the mesh makes and keeps: the id and URLs come from the binding, the secret arrives as a file grafana reads itself (__FILE), and the callback it contributes is what keycloak registers as its redirect. GF_SERVER_ROOT_URL is still a literal: a module cannot yet learn the public name the mesh composes for its own endpoint (hq issue 122), and without it grafana sends a redirect Keycloak refuses. |
||
|
|
54557b77bf |
keycloak: provide oidc-client, one mesh-made client per consumer
A module that logs people in through Keycloak had to be given a client by
hand, with its secret copied into the consumer's environment. As a provision
the mesh derives the client id (the consumer's identity, mesh_<node>_<module>)
and mints its secret, and delivers both ends: keycloak creates exactly that
confidential client, the consumer names it through ${bound:oidc-client:as}.
The consumer says where its browser comes back to (`callback`) and which
endpoint it is reached on (`label`/`endpoint`), so the redirect is built from
the same names the mesh composes for its route. keycloak serves the issuer and
the endpoint paths under it; the issuer is the one value an assignment sets,
and the realm is read out of it, so consumer and client cannot disagree.
Only what the mesh made is touched: its clients carry mesh.provisioned=true;
a client of the same id without the mark is refused, never adopted, updated
or deleted. The runtime now gets the admin password as a file, which its
tools also needed and never had.
|
||
|
|
a5e21cb438 |
grafana: its directories are placed, its admin password is a file, and it runs the build in use
The module stated /var/lib/grafana-module and /services/grafana/data, a
layout no definition may carry (ADR 0112). State and data are now placed
directories; the admin secret lives beside the broker account under the
mesh's own state.
The admin password reached grafana through an env-file. Grafana honours
GF_SECURITY_ADMIN_PASSWORD__FILE, so it is now a 0400 file owned by the
image's user (472) and mounted, and "secrets-in-environment" is gone
(ADR 0086).
The runtime sidecar was given no credential at all - its config file was
"{}", so GrafanaClient.fromEnv threw and the tools and the alert watcher
did nothing. It now carries user/password from the same secret, and it
calls grafana on the machine port the mesh assigned (${port:3000}) rather
than a literal 3000.
Image pinned to the 13.2.2 build ace's predecessor runs; the old pin was
13.2.1, older than the data it would open.
Verified: catalogue tests with MESH_CATALOGUE pointing here; a throwaway
container of the pinned image with the file-mounted secret answers
/api/health and authenticates admin with the file's value (default
admin/admin refused); restarted over the same data with a different file
value, the original password still holds - so a migrated instance's
password must be accepted, not minted; data owned by another uid fails to
start, so a moved data directory must be chowned to 472.
|