2024-02-11 07:16:25 +00:00
|
|
|
{ config, lib, pkgs, foodogsquaredLib, ... }:
|
2023-10-07 19:27:47 +00:00
|
|
|
|
|
|
|
let
|
2023-12-11 08:30:00 +00:00
|
|
|
hostCfg = config.hosts.plover;
|
|
|
|
cfg = hostCfg.services.grafana;
|
|
|
|
|
2023-10-07 19:27:47 +00:00
|
|
|
monitoringDomain = "monitoring.${config.networking.domain}";
|
2023-10-14 03:01:57 +00:00
|
|
|
|
2023-10-07 19:27:47 +00:00
|
|
|
authDomain = "auth.${config.networking.domain}";
|
|
|
|
authSubpath = path: "${authDomain}/${path}";
|
|
|
|
|
|
|
|
vouchDomain = "vouch.${config.networking.domain}";
|
2024-10-02 13:17:22 +00:00
|
|
|
vouchSettings =
|
|
|
|
config.services.vouch-proxy.instances."${vouchDomain}".settings;
|
|
|
|
in {
|
2023-12-15 05:27:12 +00:00
|
|
|
options.hosts.plover.services.grafana.enable =
|
|
|
|
lib.mkEnableOption "monitoring dashboard for ${config.networking.hostName}";
|
2023-12-11 08:30:00 +00:00
|
|
|
|
|
|
|
config = lib.mkIf cfg.enable (lib.mkMerge [
|
|
|
|
{
|
2024-10-02 13:17:22 +00:00
|
|
|
state.ports.grafana.value = 3000;
|
|
|
|
|
|
|
|
sops.secrets = let
|
|
|
|
grafanaFileAttributes = {
|
|
|
|
owner = config.users.users.grafana.name;
|
|
|
|
group = config.users.users.grafana.group;
|
|
|
|
mode = "0400";
|
2023-12-11 08:30:00 +00:00
|
|
|
};
|
2024-10-02 13:17:22 +00:00
|
|
|
in foodogsquaredLib.sops-nix.getSecrets ../../secrets/secrets.yaml {
|
|
|
|
"grafana/database/password" = grafanaFileAttributes;
|
|
|
|
"grafana/users/admin/password" = grafanaFileAttributes;
|
|
|
|
};
|
2023-12-11 08:30:00 +00:00
|
|
|
|
|
|
|
services.grafana = {
|
|
|
|
enable = true;
|
|
|
|
|
|
|
|
settings = {
|
|
|
|
auth = {
|
|
|
|
disable_login_form = true;
|
|
|
|
login_maximum_inactive_lifetime_duration = "3d";
|
|
|
|
login_maximum_lifetime_duration = "14d";
|
|
|
|
};
|
|
|
|
|
|
|
|
log = {
|
|
|
|
level = "warn";
|
|
|
|
mode = "syslog";
|
|
|
|
};
|
|
|
|
|
|
|
|
security = {
|
|
|
|
admin_email = config.security.acme.defaults.email;
|
2024-10-02 13:17:22 +00:00
|
|
|
admin_password = "$__file{${
|
|
|
|
config.sops.secrets."grafana/users/admin/password".path
|
|
|
|
}}";
|
2023-12-11 08:30:00 +00:00
|
|
|
cookie_secure = true;
|
2024-10-02 13:17:22 +00:00
|
|
|
csrf_trusted_origins =
|
|
|
|
[ vouchDomain "auth.${config.networking.domain}" ];
|
2023-12-11 08:30:00 +00:00
|
|
|
strict_transport_security = true;
|
|
|
|
strict_transport_security_subdomains = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
users = {
|
|
|
|
default_theme = "system";
|
|
|
|
default_language = "detect";
|
|
|
|
};
|
|
|
|
|
|
|
|
server = {
|
|
|
|
enable_gzip = true;
|
|
|
|
enforce_domain = true;
|
|
|
|
http_addr = "127.0.0.1";
|
2024-10-02 13:17:22 +00:00
|
|
|
http_port = config.state.ports.grafana.value;
|
2023-12-11 08:30:00 +00:00
|
|
|
root_url = "${monitoringDomain}/grafana";
|
|
|
|
serve_from_sub_path = true;
|
|
|
|
};
|
|
|
|
};
|
2023-10-07 19:27:47 +00:00
|
|
|
};
|
2023-12-11 08:30:00 +00:00
|
|
|
}
|
2023-10-07 19:27:47 +00:00
|
|
|
|
2023-12-11 08:30:00 +00:00
|
|
|
(lib.mkIf hostCfg.services.reverse-proxy.enable {
|
|
|
|
services.nginx.virtualHosts."${monitoringDomain}" = {
|
|
|
|
forceSSL = true;
|
|
|
|
enableACME = true;
|
|
|
|
acmeRoot = null;
|
2023-10-07 19:27:47 +00:00
|
|
|
|
2023-12-11 08:30:00 +00:00
|
|
|
extraConfig = ''
|
|
|
|
auth_request /validate;
|
2023-10-07 19:27:47 +00:00
|
|
|
|
2023-12-11 08:30:00 +00:00
|
|
|
# If the user is not logged in, redirect them to Vouch's login URL
|
|
|
|
error_page 401 = @error401;
|
|
|
|
location @error401 {
|
2024-10-20 10:21:54 +00:00
|
|
|
return 302 http://vouch-proxy/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
|
2023-12-11 08:30:00 +00:00
|
|
|
}
|
|
|
|
'';
|
2023-10-07 19:27:47 +00:00
|
|
|
|
2023-12-11 08:30:00 +00:00
|
|
|
locations = {
|
|
|
|
"= /validate" = {
|
2024-10-20 10:21:54 +00:00
|
|
|
proxyPass = "http://vouch-proxy";
|
2023-12-11 08:30:00 +00:00
|
|
|
extraConfig = ''
|
|
|
|
proxy_pass_request_body off;
|
2024-10-20 10:21:54 +00:00
|
|
|
proxy_set_header Content-Length "";
|
2023-12-11 08:30:00 +00:00
|
|
|
|
|
|
|
# These will be passed to @error_401 call.
|
|
|
|
auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;
|
|
|
|
auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
|
|
|
|
auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
|
|
|
|
auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
# Make Grafana as the default to be redirected.
|
|
|
|
"= /".return = "301 /grafana";
|
|
|
|
|
|
|
|
# Serving Grafana with a subpath.
|
|
|
|
"/grafana" = {
|
|
|
|
proxyPass = "http://grafana";
|
|
|
|
extraConfig = ''
|
|
|
|
proxy_set_header X-Vouch-User $auth_resp_x_vouch_user;
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
2023-10-07 19:27:47 +00:00
|
|
|
};
|
|
|
|
|
2023-12-11 08:30:00 +00:00
|
|
|
services.nginx.upstreams."grafana" = {
|
2023-10-07 19:27:47 +00:00
|
|
|
extraConfig = ''
|
2023-12-11 08:30:00 +00:00
|
|
|
zone services;
|
2023-10-07 19:27:47 +00:00
|
|
|
'';
|
2023-12-11 08:30:00 +00:00
|
|
|
servers = {
|
2024-10-02 13:17:22 +00:00
|
|
|
"localhost:${
|
|
|
|
builtins.toString config.services.grafana.settings.server.http_port
|
|
|
|
}" = { };
|
2023-12-11 08:30:00 +00:00
|
|
|
};
|
2023-10-07 19:27:47 +00:00
|
|
|
};
|
|
|
|
|
2023-12-11 08:30:00 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
(lib.mkIf hostCfg.services.database.enable {
|
2024-10-02 13:17:22 +00:00
|
|
|
services.postgresql = let
|
|
|
|
grafanaDatabaseName = config.services.grafana.settings.database.name;
|
|
|
|
in {
|
2023-12-11 08:30:00 +00:00
|
|
|
ensureDatabases = [ grafanaDatabaseName ];
|
2024-09-22 14:07:59 +00:00
|
|
|
ensureUsers = lib.singleton {
|
2023-12-11 08:30:00 +00:00
|
|
|
name = grafanaDatabaseName;
|
2024-09-22 14:07:59 +00:00
|
|
|
ensureDBOwnership = true;
|
|
|
|
};
|
2023-10-14 03:01:57 +00:00
|
|
|
};
|
2024-10-20 10:21:54 +00:00
|
|
|
|
|
|
|
services.grafana.settings = {
|
|
|
|
database = rec {
|
|
|
|
host =
|
|
|
|
"127.0.0.1:${builtins.toString config.services.postgresql.port}";
|
|
|
|
password =
|
|
|
|
"$__file{${config.sops.secrets."grafana/database/password".path}}";
|
|
|
|
type = "postgres";
|
|
|
|
name = "grafana";
|
|
|
|
user = name;
|
|
|
|
};
|
|
|
|
};
|
2023-12-11 08:30:00 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
(lib.mkIf hostCfg.services.vouch-proxy.enable {
|
2024-10-04 06:25:18 +00:00
|
|
|
sops.secrets = let
|
|
|
|
grafanaFileAttributes = {
|
|
|
|
owner = config.users.users.grafana.name;
|
|
|
|
group = config.users.users.grafana.group;
|
|
|
|
mode = "0400";
|
|
|
|
};
|
|
|
|
in foodogsquaredLib.sops-nix.getSecrets ../../secrets/secrets.yaml {
|
|
|
|
"grafana/oauth_client_secret" = grafanaFileAttributes;
|
|
|
|
};
|
2024-10-02 13:17:22 +00:00
|
|
|
|
2023-12-11 08:30:00 +00:00
|
|
|
services.grafana.settings."auth.generic_oauth" = {
|
|
|
|
enabled = true;
|
|
|
|
name = "Kanidm";
|
2024-10-20 10:21:54 +00:00
|
|
|
client_id = "grafana";
|
|
|
|
client_secret =
|
|
|
|
"$__file{${config.sops.secrets."grafana/oauth_client_secret".path}}";
|
|
|
|
allow_sign_up = true;
|
|
|
|
use_pkce = true;
|
|
|
|
use_refresh_token = true;
|
2023-12-11 08:30:00 +00:00
|
|
|
oauth_url = authSubpath "ui/oauth2";
|
|
|
|
token_url = authSubpath "oauth2/token";
|
2024-10-20 10:21:54 +00:00
|
|
|
api_url = authSubpath "oauth2/openid/grafana/userinfo";
|
|
|
|
login_attribute_path = "preferred_username";
|
|
|
|
groups_attribute_path = "groups";
|
|
|
|
role_attribute_path = ''
|
|
|
|
contains(grafana_role[*], 'GrafanaAdmin') && 'GrafanaAdmin' || contains(grafana_role[*], 'Admin') && 'Admin' || contains(grafana_role[*], 'Editor') && 'Editor' || 'Viewer'
|
|
|
|
'';
|
|
|
|
allow_assign_grafana_admin = true;
|
|
|
|
scopes =
|
|
|
|
lib.concatStringsSep " " [ "openid" "email" "profile" "groups" ];
|
2023-10-09 12:48:01 +00:00
|
|
|
};
|
2023-12-11 08:30:00 +00:00
|
|
|
})
|
|
|
|
]);
|
2023-10-07 19:27:47 +00:00
|
|
|
}
|