nixos-config/configs/nixos/plover/modules/services/grafana.nix

182 lines
5.8 KiB
Nix
Raw Normal View History

2023-10-07 19:27:47 +00:00
{ config, lib, pkgs, ... }:
let
hostCfg = config.hosts.plover;
cfg = hostCfg.services.grafana;
2023-10-07 19:27:47 +00:00
monitoringDomain = "monitoring.${config.networking.domain}";
grafanaDatabaseUser = config.services.grafana.settings.database.user;
grafanaDatabaseName = config.services.grafana.settings.database.name;
2023-10-07 19:27:47 +00:00
authDomain = "auth.${config.networking.domain}";
authSubpath = path: "${authDomain}/${path}";
vouchDomain = "vouch.${config.networking.domain}";
vouchSettings = config.services.vouch-proxy.instances."${vouchDomain}".settings;
2023-10-07 19:27:47 +00:00
in
{
2023-12-15 05:27:12 +00:00
options.hosts.plover.services.grafana.enable =
lib.mkEnableOption "monitoring dashboard for ${config.networking.hostName}";
config = lib.mkIf cfg.enable (lib.mkMerge [
{
sops.secrets =
let
grafanaFileAttributes = {
owner = config.users.users.grafana.name;
group = config.users.users.grafana.group;
mode = "0400";
};
in
lib.private.getSecrets ../../secrets/secrets.yaml {
"grafana/database/password" = grafanaFileAttributes;
"grafana/users/admin/password" = grafanaFileAttributes;
};
services.grafana = {
enable = true;
settings = {
auth = {
disable_login_form = true;
login_maximum_inactive_lifetime_duration = "3d";
login_maximum_lifetime_duration = "14d";
};
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;
};
log = {
level = "warn";
mode = "syslog";
};
security = {
admin_email = config.security.acme.defaults.email;
admin_password = "$__file{${config.sops.secrets."grafana/users/admin/password".path}}";
cookie_secure = true;
csrf_trusted_origins = [
vouchDomain
"auth.${config.networking.domain}"
];
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";
http_port = 3000;
root_url = "${monitoringDomain}/grafana";
serve_from_sub_path = true;
};
};
2023-10-07 19:27:47 +00:00
};
}
2023-10-07 19:27:47 +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
extraConfig = ''
auth_request /validate;
2023-10-07 19:27:47 +00:00
# If the user is not logged in, redirect them to Vouch's login URL
error_page 401 = @error401;
location @error401 {
return 302 http://${vouchDomain}/login?url=$scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
}
'';
2023-10-07 19:27:47 +00:00
locations = {
"= /validate" = {
proxyPass = "http://${vouchSettings.vouch.listen}:${builtins.toString vouchSettings.vouch.port}";
extraConfig = ''
proxy_pass_request_body off;
# 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
};
services.nginx.upstreams."grafana" = {
2023-10-07 19:27:47 +00:00
extraConfig = ''
zone services;
2023-10-07 19:27:47 +00:00
'';
servers = {
"localhost:${builtins.toString config.services.grafana.settings.server.http_port}" = { };
};
2023-10-07 19:27:47 +00:00
};
})
(lib.mkIf hostCfg.services.database.enable {
# Setting up with secure schema usage pattern.
systemd.services.grafana = {
preStart =
let
psql = lib.getExe' config.services.postgresql.package "psql";
in
lib.mkBefore ''
# Setting up the appropriate schema for PostgreSQL secure schema usage.
${psql} -tAc "CREATE SCHEMA IF NOT EXISTS AUTHORIZATION ${grafanaDatabaseUser};"
'';
};
# Setting up PostgreSQL with secure schema.
services.postgresql = {
ensureDatabases = [ grafanaDatabaseName ];
ensureUsers = [{
name = grafanaDatabaseName;
ensurePermissions = {
"DATABASE ${grafanaDatabaseName}" = "ALL PRIVILEGES";
"SCHEMA ${grafanaDatabaseUser}" = "ALL PRIVILEGES";
};
}];
};
})
(lib.mkIf hostCfg.services.vouch-proxy.enable {
services.grafana.settings."auth.generic_oauth" = {
api_url = authSubpath "oauth2/authorise";
client_id = "grafana";
client_secret = "$__file{${config.sops.secrets."vouch-proxy/client/secret".path}";
enabled = true;
name = "Kanidm";
oauth_url = authSubpath "ui/oauth2";
scopes = lib.concatStringsSep " " [ "openid" "email" "profile" ];
token_url = authSubpath "oauth2/token";
2023-10-09 12:48:01 +00:00
};
})
]);
2023-10-07 19:27:47 +00:00
}