From 89f2c328fc1b113a9e9b862841e0c7d0391b3d09 Mon Sep 17 00:00:00 2001 From: Tim Keller Date: Thu, 27 Aug 2026 23:07:02 -0500 Subject: generate Grafana's secret key by default Grafana's upstream default for security.secret_key is a constant compiled into every release, which is why nixpkgs 26.05 stopped passing it through and started asserting. Requiring secretKeyFile made that assertion the first thing anyone hit, and forced a secret manager plus a container bindMount on a deployment whose Grafana database holds no credentials at all -- both datasources are provisioned without any. generateSecretKey defaults to true (and to false as soon as secretKeyFile is set), writing 32 random bytes to Grafana's data directory on first start. The unit runs as the grafana user into a directory users.users.grafana.createHome already owns, so there is no chown and nothing fights Grafana for the directory. UMask=0077 makes the file 0600 on creation and an unconditional chmod repairs one left readable by a previous version or a manual copy. The tradeoff is stated in the option description rather than hidden: the key lives beside the database it encrypts, so it defends against a stolen grafana.db, not against filesystem access. secretKeyFile remains for when the database holds a datasource password or a contact-point token. Verified both paths build: with no secret wiring the generator unit is present and LoadCredential points into the data directory; with secretKeyFile set the generator is absent and LoadCredential points at the supplied path. Both emit secret_key=$__file{...} into config.ini. The script is idempotent, leaves an existing key untouched, and restores 0600 on a file chmodded to 0644. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01JKczN1f66kmLxNBLX37voQ --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 9014e1b..5c8e1dc 100644 --- a/README.md +++ b/README.md @@ -76,14 +76,15 @@ nixosConfigurations.poweredge = nixpkgs.lib.nixosSystem { collectors.enable = true; server = { enable = true; - grafana.secretKeyFile = "/run/secrets/grafana-secret-key"; proxy.enable = true; # Grafana on :80 }; }; } ``` -Grafana at `http://localhost`. `collectorHosts` defaults to `[ "localhost" ]`. +Grafana at `http://localhost`. `collectorHosts` defaults to `[ "localhost" ]`, and +Grafana's secret key is generated on first start into `/var/lib/grafana/secret-key` +(mode 0600, owned by `grafana`) — see below if you would rather supply it yourself. ## Example: web services in a container @@ -91,7 +92,7 @@ The host runs the collectors; the container runs everything else. This is the in shape. ```nix -{ config, inputs, ... }: +{ inputs, ... }: { imports = [ inputs.telemetry.nixosModules.collectors ]; @@ -100,23 +101,12 @@ shape. logs.lokiUrl = "http://metrics:3100"; # the container, by name }; - sops.secrets.grafana-secret-key = { - sopsFile = ./secrets/grafana.yaml; - key = "secret_key"; - }; - containers.metrics = { autoStart = true; privateNetwork = true; hostBridge = "br-lan0"; localMacAddress = "02:00:00:00:00:06"; - # The module reads whatever path you point secretKeyFile at. - bindMounts."/run/grafana-secret-key" = { - hostPath = config.sops.secrets.grafana-secret-key.path; - isReadOnly = true; - }; - config = { ... }: { imports = [ inputs.telemetry.nixosModules.server ]; @@ -126,7 +116,6 @@ shape. services.telemetry.server = { enable = true; collectorHosts = [ "poweredge" ]; # the host above - grafana.secretKeyFile = "/run/grafana-secret-key"; proxy.enable = true; }; @@ -262,8 +251,19 @@ inventing placeholder values. render "No data". Don't configure the Grafana datasource by hand. - **The datasource UIDs `prometheus` and `loki` are fixed, not options.** The generated dashboards reference them literally. -- **Grafana's secret key is mandatory** as of nixpkgs 26.05. `openssl rand -base64 32`, - store it somewhere, point `grafana.secretKeyFile` at it. +- **Grafana's secret key is mandatory** as of nixpkgs 26.05, because Grafana's upstream + default is a constant compiled into every release. By default this module generates one + on first start into `/var/lib/grafana/secret-key` (0600, owned by `grafana`), so there + is nothing to wire up. Two things to know: it must stay *stable*, or credentials + encrypted in Grafana's database stop decrypting — so keep the Grafana data directory on + persistent storage; and it sits beside the database it protects, so it defends against + a stolen `grafana.db` but not against filesystem access. Set + `grafana.secretKeyFile` to a path you manage instead once the database holds anything + worth protecting, such as a datasource password: + ```nix + services.telemetry.server.grafana.secretKeyFile = + config.sops.secrets.grafana-secret-key.path; # turns generation off + ``` - **Changing `collectorHosts` changes the label set.** Panels look empty for a minute after first deploy while the recording rules re-evaluate; data from before the change stays under the old labels. -- cgit v1.3.1