summary refs log tree commit diff
path: root/nixos/modules/services/monitoring
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services/monitoring')
-rw-r--r--nixos/modules/services/monitoring/grafana.nix99
-rw-r--r--nixos/modules/services/monitoring/opentelemetry-collector.nix73
2 files changed, 146 insertions, 26 deletions
diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix
index 8fe84e1206e..12f89196808 100644
--- a/nixos/modules/services/monitoring/grafana.nix
+++ b/nixos/modules/services/monitoring/grafana.nix
@@ -10,7 +10,26 @@ let
   useMysql = cfg.settings.database.type == "mysql";
   usePostgresql = cfg.settings.database.type == "postgres";
 
-  settingsFormatIni = pkgs.formats.ini { };
+  # Prefer using the values from the default config file[0] directly. This way,
+  # people reading the NixOS manual can see them without cross-referencing the
+  # official documentation.
+  #
+  # However, if there is no default entry or if the setting is optional, use
+  # `null` as the default value. It will be turned into the empty string.
+  #
+  # If a setting is a list, always allow setting it as a plain string as well.
+  #
+  # [0]: https://github.com/grafana/grafana/blob/main/conf/defaults.ini
+  settingsFormatIni = pkgs.formats.ini {
+    listToValue = concatMapStringsSep " " (generators.mkValueStringDefault { });
+    mkKeyValue = generators.mkKeyValueDefault
+      {
+        mkValueString = v:
+          if v == null then ""
+          else generators.mkValueStringDefault { } v;
+      }
+      "=";
+  };
   configFile = settingsFormatIni.generate "config.ini" cfg.settings;
 
   mkProvisionCfg = name: attr: provisionCfg:
@@ -405,7 +424,6 @@ in
                 This setting is also important if you have a reverse proxy in front of Grafana that exposes it through a subpath.
                 In that case add the subpath to the end of this URL setting.
               '';
-              # https://github.com/grafana/grafana/blob/cb7e18938b8eb6860a64b91aaba13a7eb31bc95b/conf/defaults.ini#L54
               default = "%(protocol)s://%(domain)s:%(http_port)s/";
               type = types.str;
             };
@@ -453,16 +471,16 @@ in
               description = lib.mdDoc ''
                 Path to the certificate file (if `protocol` is set to `https` or `h2`).
               '';
-              default = "";
-              type = types.str;
+              default = null;
+              type = types.nullOr types.str;
             };
 
             cert_key = mkOption {
               description = lib.mdDoc ''
                 Path to the certificate key file (if `protocol` is set to `https` or `h2`).
               '';
-              default = "";
-              type = types.str;
+              default = null;
+              type = types.nullOr types.str;
             };
 
             socket_gid = mkOption {
@@ -505,8 +523,8 @@ in
                 For example, given a cdn url like `https://cdn.myserver.com`
                 grafana will try to load a javascript file from `http://cdn.myserver.com/grafana-oss/7.4.0/public/build/app.<hash>.js`.
               '';
-              default = "";
-              type = types.str;
+              default = null;
+              type = types.nullOr types.str;
             };
 
             read_timeout = mkOption {
@@ -572,7 +590,7 @@ in
 
             max_open_conn = mkOption {
               description = lib.mdDoc "The maximum number of open connections to the database.";
-              default = 0; # https://github.com/grafana/grafana/blob/cb7e18938b8eb6860a64b91aaba13a7eb31bc95b/conf/defaults.ini#L123-L124
+              default = 0;
               type = types.int;
             };
 
@@ -606,7 +624,7 @@ in
                 For Postgres, use either `disable`, `require` or `verify-full`.
                 For MySQL, use either `true`, `false`, or `skip-verify`.
               '';
-              default = "disable"; # https://github.com/grafana/grafana/blob/cb7e18938b8eb6860a64b91aaba13a7eb31bc95b/conf/defaults.ini#L134
+              default = "disable";
               type = types.enum [ "disable" "require" "verify-full" "true" "false" "skip-verify" ];
             };
 
@@ -621,20 +639,20 @@ in
 
             ca_cert_path = mkOption {
               description = lib.mdDoc "The path to the CA certificate to use.";
-              default = "";
-              type = types.str;
+              default = null;
+              type = types.nullOr types.str;
             };
 
             client_key_path = mkOption {
               description = lib.mdDoc "The path to the client key. Only if server requires client authentication.";
-              default = "";
-              type = types.str;
+              default = null;
+              type = types.nullOr types.str;
             };
 
             client_cert_path = mkOption {
               description = lib.mdDoc "The path to the client cert. Only if server requires client authentication.";
-              default = "";
-              type = types.str;
+              default = null;
+              type = types.nullOr types.str;
             };
 
             server_cert_name = mkOption {
@@ -642,8 +660,8 @@ in
                 The common name field of the certificate used by the `mysql` or `postgres` server.
                 Not necessary if `ssl_mode` is set to `skip-verify`.
               '';
-              default = "";
-              type = types.str;
+              default = null;
+              type = types.nullOr types.str;
             };
 
             path = mkOption {
@@ -751,8 +769,8 @@ in
                 Format: `ip_or_domain:port` separated by spaces.
                 PostgreSQL, MySQL, and MSSQL data sources do not use the proxy and are therefore unaffected by this setting.
               '';
-              default = "";
-              type = types.str;
+              default = [ ];
+              type = types.oneOf [ types.str (types.listOf types.str) ];
             };
 
             disable_brute_force_login_protection = mkOption {
@@ -870,6 +888,27 @@ in
             # how exactly the quoting of the default value works. See also
             # https://github.com/grafana/grafana/blob/cb7e18938b8eb6860a64b91aaba13a7eb31bc95b/conf/defaults.ini#L364
             # https://github.com/grafana/grafana/blob/cb7e18938b8eb6860a64b91aaba13a7eb31bc95b/conf/defaults.ini#L373
+
+            # These two options are lists joined with spaces:
+            # https://github.com/grafana/grafana/blob/916d9793aa81c2990640b55a15dee0db6b525e41/pkg/middleware/csrf/csrf.go#L37-L38
+
+            csrf_trusted_origins = mkOption {
+              description = lib.mdDoc ''
+                List of additional allowed URLs to pass by the CSRF check.
+                Suggested when authentication comes from an IdP.
+              '';
+              default = [ ];
+              type = types.oneOf [ types.str (types.listOf types.str) ];
+            };
+
+            csrf_additional_headers = mkOption {
+              description = lib.mdDoc ''
+                List of allowed headers to be set by the user.
+                Suggested to use for if authentication lives behind reverse proxies.
+              '';
+              default = [ ];
+              type = types.oneOf [ types.str (types.listOf types.str) ];
+            };
           };
 
           smtp = {
@@ -887,8 +926,8 @@ in
 
             user = mkOption {
               description = lib.mdDoc "User used for authentication.";
-              default = "";
-              type = types.str;
+              default = null;
+              type = types.nullOr types.str;
             };
 
             password = mkOption {
@@ -905,14 +944,14 @@ in
 
             cert_file = mkOption {
               description = lib.mdDoc "File path to a cert file.";
-              default = "";
-              type = types.str;
+              default = null;
+              type = types.nullOr types.str;
             };
 
             key_file = mkOption {
               description = lib.mdDoc "File path to a key file.";
-              default = "";
-              type = types.str;
+              default = null;
+              type = types.nullOr types.str;
             };
 
             skip_verify = mkOption {
@@ -933,6 +972,12 @@ in
               type = types.str;
             };
 
+            ehlo_identity = mkOption {
+              description = lib.mdDoc "Name to be used as client identity for EHLO in SMTP dialog.";
+              default = null;
+              type = types.nullOr types.str;
+            };
+
             startTLS_policy = mkOption {
               description = lib.mdDoc "StartTLS policy when connecting to server.";
               default = null;
@@ -1050,6 +1095,8 @@ in
               type = types.str;
             };
 
+            # Lists are joined via space, so this option can't be a list.
+            # Users have to manually join their values.
             hidden_users = mkOption {
               description = lib.mdDoc ''
                 This is a comma-separated list of usernames.
diff --git a/nixos/modules/services/monitoring/opentelemetry-collector.nix b/nixos/modules/services/monitoring/opentelemetry-collector.nix
new file mode 100644
index 00000000000..1d211b68977
--- /dev/null
+++ b/nixos/modules/services/monitoring/opentelemetry-collector.nix
@@ -0,0 +1,73 @@
+{ config, lib, pkgs, ... }:
+
+let
+  inherit (lib) mkEnableOption mkIf mkOption types getExe;
+
+  cfg = config.services.opentelemetry-collector;
+  opentelemetry-collector = cfg.package;
+
+  settingsFormat = pkgs.formats.yaml {};
+in {
+  options.services.opentelemetry-collector = {
+    enable = mkEnableOption (lib.mdDoc "Opentelemetry Collector");
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.opentelemetry-collector;
+      defaultText = lib.literalExpression "pkgs.opentelemetry-collector";
+      description = lib.mdDoc "The opentelemetry-collector package to use.";
+    };
+
+    settings = mkOption {
+      type = settingsFormat.type;
+      default = {};
+      description = lib.mdDoc ''
+        Specify the configuration for Opentelemetry Collector in Nix.
+
+        See https://opentelemetry.io/docs/collector/configuration/ for available options.
+      '';
+    };
+
+    configFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = lib.mdDoc ''
+        Specify a path to a configuration file that Opentelemetry Collector should use.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    assertions = [{
+      assertion = (
+        (cfg.settings == {}) != (cfg.configFile == null)
+      );
+      message  = ''
+        Please specify a configuration for Opentelemetry Collector with either
+        'services.opentelemetry-collector.settings' or
+        'services.opentelemetry-collector.configFile'.
+      '';
+    }];
+
+    systemd.services.opentelemetry-collector = {
+      description = "Opentelemetry Collector Service Daemon";
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig = let
+        conf = if cfg.configFile == null
+               then settingsFormat.generate "config.yaml" cfg.settings
+               else cfg.configFile;
+      in
+      {
+        ExecStart = "${getExe opentelemetry-collector} --config=file:${conf}";
+        DynamicUser = true;
+        Restart = "always";
+        ProtectSystem = "full";
+        DevicePolicy = "closed";
+        NoNewPrivileges = true;
+        WorkingDirectory = "/var/lib/opentelemetry-collector";
+        StateDirectory = "opentelemetry-collector";
+      };
+    };
+  };
+}