summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorMaximilian Bosch <maximilian@mbosch.me>2022-11-08 19:37:45 +0100
committerMaximilian Bosch <maximilian@mbosch.me>2022-11-20 18:21:40 +0100
commit4ec456b7252a8afabff87fc40eab613c138f43d6 (patch)
tree6086162df5b2632bf264a88e194884981f42e92f /nixos
parentb300ec349cf7ae63b3e2335cab673658b67c335e (diff)
downloadnixpkgs-4ec456b7252a8afabff87fc40eab613c138f43d6.tar
nixpkgs-4ec456b7252a8afabff87fc40eab613c138f43d6.tar.gz
nixpkgs-4ec456b7252a8afabff87fc40eab613c138f43d6.tar.bz2
nixpkgs-4ec456b7252a8afabff87fc40eab613c138f43d6.tar.lz
nixpkgs-4ec456b7252a8afabff87fc40eab613c138f43d6.tar.xz
nixpkgs-4ec456b7252a8afabff87fc40eab613c138f43d6.tar.zst
nixpkgs-4ec456b7252a8afabff87fc40eab613c138f43d6.zip
nixos/grafana: fix secret-related warnings
Closes #198646

* The options `password`/`basicAuthPassword` were removed for
  datasources in Grafana 9. The only option to declare them now is to use
  `secureJsonData`.
* Fix description for contactPoints provisioning: when using file/env
  providers, nothing will be leaked into the store.
* Fix regex in file-provider usage check: it's also possible to either
  use `$__env{FOO}` or `$FOO` to fetch secrets from the environment.
* Fix warning for datasources: `password`/`basicAuthPassword` was
  removed, also check for each setting in `secureJsonData` if
  env/file-provider was used (then no warning is needed!).
Diffstat (limited to 'nixos')
-rw-r--r--nixos/modules/services/monitoring/grafana.nix87
1 files changed, 45 insertions, 42 deletions
diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix
index 6019fad3ae5..69a25731f24 100644
--- a/nixos/modules/services/monitoring/grafana.nix
+++ b/nixos/modules/services/monitoring/grafana.nix
@@ -72,6 +72,17 @@ let
   grafanaTypes.datasourceConfig = types.submodule {
     freeformType = provisioningSettingsFormat.type;
 
+    imports = [
+      (mkRemovedOptionModule [ "password" ] ''
+        `services.grafana.provision.datasources.settings.datasources.<name>.password` has been removed
+        in Grafana 9. Use `secureJsonData` instead.
+      '')
+      (mkRemovedOptionModule [ "basicAuthPassword" ] ''
+        `services.grafana.provision.datasources.settings.datasources.<name>.basicAuthPassword` has been removed
+        in Grafana 9. Use `secureJsonData` instead.
+      '')
+    ];
+
     options = {
       name = mkOption {
         type = types.str;
@@ -101,28 +112,6 @@ let
         default = false;
         description = lib.mdDoc "Allow users to edit datasources from the UI.";
       };
-      password = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = lib.mdDoc ''
-          Database password, if used. Please note that the contents of this option
-          will end up in a world-readable Nix store. Use the file provider
-          pointing at a reasonably secured file in the local filesystem
-          to work around that. Look at the documentation for details:
-          <https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#file-provider>
-        '';
-      };
-      basicAuthPassword = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = lib.mdDoc ''
-          Basic auth password. Please note that the contents of this option
-          will end up in a world-readable Nix store. Use the file provider
-          pointing at a reasonably secured file in the local filesystem
-          to work around that. Look at the documentation for details:
-          <https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#file-provider>
-        '';
-      };
       secureJsonData = mkOption {
         type = types.nullOr types.attrs;
         default = null;
@@ -600,6 +589,7 @@ in {
                   description = lib.mdDoc "List of datasources to insert/update.";
                   default = [];
                   type = types.listOf grafanaTypes.datasourceConfig;
+                  apply = map (flip builtins.removeAttrs [ "password" "basicAuthPassword" ]);
                 };
 
                 deleteDatasources = mkOption {
@@ -858,7 +848,7 @@ in {
                 };
 
                 contactPoints = mkOption {
-                  description = lib.mdDoc "List of contact points to import or update. Please note that sensitive data will end up in world-readable Nix store.";
+                  description = lib.mdDoc "List of contact points to import or update.";
                   default = [];
                   type = types.listOf (types.submodule {
                     freeformType = provisioningSettingsFormat.type;
@@ -1165,31 +1155,44 @@ in {
 
   config = mkIf cfg.enable {
     warnings = let
-      usesFileProvider = opt: defaultValue: builtins.match "^${defaultValue}$|^\\$__file\\{.*}$" opt != null;
+      doesntUseFileProvider = opt: defaultValue:
+        let
+          regex = "${optionalString (defaultValue != null) "^${defaultValue}$|"}^\\$__(file|env)\\{.*}$|^\\$[^_\\$][^ ]+$";
+        in builtins.match regex opt == null;
     in
+      # Ensure that no custom credentials are leaked into the Nix store. Unless the default value
+      # is specified, this can be achieved by using the file/env provider:
+      # https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#variable-expansion
       (optional (
-        ! usesFileProvider cfg.settings.database.password "" ||
-        ! usesFileProvider cfg.settings.security.admin_password "admin"
-      ) "Grafana passwords will be stored as plaintext in the Nix store! Use file provider instead.")
+        doesntUseFileProvider cfg.settings.database.password "" ||
+        doesntUseFileProvider cfg.settings.security.admin_password "admin"
+      ) ''
+        Grafana passwords will be stored as plaintext in the Nix store!
+        Use file/env provider or an env-var instead.
+      '')
+      # Warn about deprecated notifiers.
+      ++ (optional (cfg.provision.notifiers != []) ''
+        Notifiers are deprecated upstream and will be removed in Grafana 10.
+        Use `services.grafana.provision.alerting.contactPoints` instead.
+      '')
+      # Ensure that `secureJsonData` of datasources provisioned via `datasources.settings`
+      # only uses file/env providers.
       ++ (optional (
         let
-          checkOpts = opt: any (x: x.password != null || x.basicAuthPassword != null || x.secureJsonData != null) opt;
-          datasourcesUsed = optionals (cfg.provision.datasources.settings != null) cfg.provision.datasources.settings.datasources;
-        in checkOpts datasourcesUsed
-        ) ''
-          Datasource passwords will be stored as plaintext in the Nix store!
-          It is not possible to use file provider in provisioning; please provision
-          datasources via `services.grafana.provision.datasources.path` instead.
-        '')
+          datasourcesToCheck = optionals
+            (cfg.provision.datasources.settings != null)
+            cfg.provision.datasources.settings.datasources;
+          declarationUnsafe = { secureJsonData, ... }:
+            secureJsonData != null
+            && any (flip doesntUseFileProvider null) (attrValues secureJsonData);
+        in any declarationUnsafe datasourcesToCheck
+      ) ''
+        Declarations in the `secureJsonData`-block of a datasource will be leaked to the
+        Nix store unless a file/env-provider or an env-var is used!
+      '')
       ++ (optional (
         any (x: x.secure_settings != null) cfg.provision.notifiers
-      ) "Notifier secure settings will be stored as plaintext in the Nix store! Use file provider instead.")
-      ++ (optional (
-        cfg.provision.notifiers != []
-        ) ''
-            Notifiers are deprecated upstream and will be removed in Grafana 10.
-            Use `services.grafana.provision.alerting.contactPoints` instead.
-        '');
+      ) "Notifier secure settings will be stored as plaintext in the Nix store! Use file provider instead.");
 
     environment.systemPackages = [ cfg.package ];