{ lib, pkgs, config, ...}: let ldap = pkgs.writeTextFile { name = "ldap.toml"; text = '' [[servers]] host = "ldap.cloonar.com" port = 636 use_ssl = true bind_dn = "cn=grafana,ou=system,ou=users,dc=cloonar,dc=com" bind_password = "$__file{/run/secrets/grafana-ldap-password}" search_filter = "(&(objectClass=cloonarUser)(mail=%s))" search_base_dns = ["ou=users,dc=cloonar,dc=com"] [servers.attributes] name = "givenName" surname = "sn" username = "mail" email = "mail" member_of = "memberOf" [[servers.group_mappings]] group_dn = "cn=Administrators,ou=groups,dc=cloonar,dc=com" org_role = "Admin" grafana_admin = true # Available in Grafana v5.3 and above ''; }; in { imports = [ # Individual alert files removed, now handled by alerting/system/default.nix ./alerting/system/default.nix # Added: Imports the consolidated system alerts module ./alerting/service/default.nix # Added: Imports the new service alerts module ./alerting/websites/default.nix # Added: Imports the new websites alerts module # ... other rule files can be added here ... ./datasources/victoriametrics.nix ./datasources/loki.nix # Add Loki datasource ]; systemd.services.grafana.script = lib.mkBefore '' export GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET=$(cat /run/secrets/grafana-oauth-secret) export PUSHOVER_API_TOKEN=$(cat /run/secrets/pushover-api-token) export PUSHOVER_USER_KEY=$(cat /run/secrets/pushover-user-key) ''; services.grafana = { enable = true; settings = { analytics.reporting_enabled = false; "auth.ldap".enabled = true; "auth.ldap".config_file = toString ldap; "auth.generic_oauth" = { enabled = true; name = "Authelia"; icon = "signin"; client_id = "grafana"; scopes = "openid profile email groups"; empty_scopes = false; auth_url = "https://auth.cloonar.com/api/oidc/authorization"; token_url = "https://auth.cloonar.com/api/oidc/token"; api_url = "https://auth.cloonar.com/api/oidc/userinfo"; login_attribute_path = "preferred_username"; groups_attribute_path = "groups"; role_attribute_path = "contains(groups, 'Administrators') && 'Admin' || contains(groups, 'editor') && 'Editor' || 'Viewer'"; allow_assign_grafana_admin = true; name_attribute_path = "name"; use_pkce = true; }; "auth.anonymous".enabled = true; "auth.anonymous".org_name = "Cloonar e.U."; "auth.anonymous".org_role = "Viewer"; server = { root_url = "https://grafana.cloonar.com"; domain = "grafana.cloonar.com"; enforce_domain = true; enable_gzip = true; http_addr = "0.0.0.0"; http_port = 3001; }; smtp = { enabled = true; host = "mail.cloonar.com:587"; user = "grafana@cloonar.com"; password = "$__file{${config.sops.secrets.grafana-ldap-password.path}}"; fromAddress = "grafana@cloonar.com"; }; database = { type = "postgres"; name = "grafana"; host = "/run/postgresql"; user = "grafana"; }; security.admin_password = "$__file{${config.sops.secrets.grafana-admin-password.path}}"; }; provision = { alerting = { rules.settings.groups = lib.mkMerge []; # Allows rule groups to be merged (including the one from system/default.nix) contactPoints = { settings = { apiVersion = 1; # As per Grafana provisioning API contactPoints = [{ orgId = 1; name = "cp_dominik"; receivers = [{ uid = "dominik_pushover_cp_receiver"; # Made UID even more specific type = "pushover"; settings = { apiToken = "\${PUSHOVER_API_TOKEN}"; userKey = "\${PUSHOVER_USER_KEY}"; device = "iphone"; priority = 2; retry = "30s"; expire = "2m"; sound = "siren"; okSound = "magic"; message = '' {{ template "default.message" . }} ''; }; }]; }]; }; }; policies = { # Corrected from notificationPolicies to policies settings = { apiVersion = 1; # As per Grafana provisioning API # Grafana's new unified alerting expects a single policy tree per org. # For OrgID 1 (default), this defines the root of that tree. # The NixOS module should translate this into the correct YAML structure. # The `policies` attribute within `settings` usually takes a list of policy trees. # For a single default organization, we define one policy tree. # Grafana's own YAML examples show a top-level 'route' for the default policy, # or a list under 'policies' if you're managing multiple policy sets (less common for basic setup). # Given the NixOS option `services.grafana.provision.alerting.policies.settings.policies`, # it's likely expecting a list here. policies = [{ # This outer list corresponds to the `policies` option # orgId = 1; # Usually implicit for the default policy file, but can be specified receiver = "cp_dominik"; # This sets the default receiver for the root route # The actual routing tree starts here. # For a simple setup where all alerts go to one receiver, # just setting the top-level 'receiver' is often enough. # If more complex routing is needed, 'routes' would be defined here. # Example: # route = { # receiver = "cp_dominik"; # group_by = [ "alertname", "job" ]; # # ... other root route settings # routes = [ # { # matcher_re = { severity = "critical" }; # receiver = "critical_alerts_receiver"; # Another contact point # continue = false; # }, # # ... other specific routes # ]; # }; # For the simplest case, just defining the receiver at this level should work # as the root policy for the default organization. }]; # resetPolicies = false; # Default, set to true to remove existing policies not in this config. }; }; }; datasources.settings.datasources = lib.mkMerge []; # Allows datasources to be merged }; }; services.nginx.virtualHosts."grafana.cloonar.com" = { forceSSL = true; enableACME = true; acmeRoot = null; locations."/".extraConfig = "proxy_pass http://localhost:3001;"; }; services.postgresql.ensureUsers = [ { name = "grafana"; ensureDBOwnership = true; } ]; services.postgresql.ensureDatabases = [ "grafana" ]; services.postgresqlBackup.databases = [ "grafana" ]; sops.secrets = { grafana-admin-password.owner = "grafana"; grafana-ldap-password.owner = "grafana"; grafana-oauth-secret.owner = "grafana"; pushover-api-token.owner = "grafana"; pushover-user-key.owner = "grafana"; }; }