About to make changes to Grafana LDAP

This commit is contained in:
niten 2022-02-07 14:08:34 -08:00
parent 2048377c3f
commit 5411c53022
6 changed files with 180 additions and 55 deletions

View File

@ -89,6 +89,7 @@ in {
host-secrets.backplane-host-auth.target-file; host-secrets.backplane-host-auth.target-file;
FUDO_SERVICE_PASSWD_FILE = FUDO_SERVICE_PASSWD_FILE =
host-secrets.backplane-service-auth.target-file; host-secrets.backplane-service-auth.target-file;
# GUILE_AUTO_COMPILE = "0";
}; };
sites.${cfg.backplane-hostname} = { sites.${cfg.backplane-hostname} = {
@ -97,31 +98,32 @@ in {
site-config = { site-config = {
auth_method = "external"; auth_method = "external";
extauth_program = extauth_program =
# "${pkgs.guile}/bin/guile -s /run/backplane-auth.scm";
"${pkgs.guile}/bin/guile -s ${pkgs.backplane-auth}/backplane-auth.scm"; "${pkgs.guile}/bin/guile -s ${pkgs.backplane-auth}/backplane-auth.scm";
extauth_pool_size = 3; extauth_pool_size = 3;
auth_use_cache = true; auth_use_cache = false;
modules = { modules = {
mod_adhoc = {}; mod_adhoc = {};
mod_caps = {}; # mod_caps = {};
mod_carboncopy = {}; # mod_carboncopy = {};
mod_client_state = {}; # mod_client_state = {};
mod_configure = {}; mod_configure = {};
mod_disco = {}; # mod_disco = {};
mod_fail2ban = {}; mod_fail2ban = {};
mod_last = {}; # mod_last = {};
mod_offline.access_max_user_messages = 5000; mod_offline.access_max_user_messages = 5000;
mod_ping = {}; mod_ping = {};
mod_pubsub = { # mod_pubsub = {
access_createnode = "pubsub_createnode"; # access_createnode = "pubsub_createnode";
ignore_pep_from_offline = true; # ignore_pep_from_offline = true;
last_item_cache = false; # last_item_cache = false;
plugins = [ # plugins = [
"flat" # "flat"
"pep" # "pep"
]; # ];
}; # };
mod_roster = {}; # mod_roster = {};
mod_stream_mgmt = {}; mod_stream_mgmt = {};
mod_time = {}; mod_time = {};
mod_version = {}; mod_version = {};

View File

@ -9,6 +9,58 @@ let
hostname = config.instance.hostname; hostname = config.instance.hostname;
domain-name = config.fudo.hosts.${hostname}.domain; domain-name = config.fudo.hosts.${hostname}.domain;
host-secrets = config.fudo.secrets.host-secrets.${hostname};
datasourceOpts = { name, ... }: {
options = with types; {
url = mkOption {
type = str;
description = "Datasource URL.";
};
type = mkOption {
type = enum [ "prometheus" "loki" ];
description = "Type of the datasource.";
};
name = mkOption {
type = str;
description = "Name of the datasource.";
default = name;
};
default = mkOption {
type = bool;
description = "Use this datasource as the default while querying.";
default = false;
};
};
};
ldapOpts = {
options = with types; {
hosts = mkOption {
type = listOf str;
description = "LDAP server hostnames.";
};
bind-dn = mkOption {
type = str;
description = "DN as which to bind with the LDAP server.";
};
bind-passwd = mkOption {
type = str;
description = "Password with which to bind to the LDAP server.";
};
base-dn = mkOption {
type = str;
description = "DN under which to search for users.";
};
};
};
in { in {
options.fudo.metrics.grafana = with types; { options.fudo.metrics.grafana = with types; {
@ -43,6 +95,12 @@ in {
description = "Address from which mail will be sent (i.e. 'from' address)."; description = "Address from which mail will be sent (i.e. 'from' address).";
default = "${toplevel.config.fudo.grafana.smtp.username}@${domain-name}"; default = "${toplevel.config.fudo.grafana.smtp.username}@${domain-name}";
}; };
domain = mkOption {
type = str;
description = "Domain of the SMTP server.";
default = toplevel.config.instance.local-domain;
};
}; };
database = { database = {
@ -67,6 +125,12 @@ in {
}; };
}; };
ldap = mkOption {
type = nullOr (submodule ldapOpts);
description = "";
default = null;
};
admin-password-file = mkOption { admin-password-file = mkOption {
type = str; type = str;
description = "Path to a file containing the admin user's password."; description = "Path to a file containing the admin user's password.";
@ -77,10 +141,10 @@ in {
description = "Path to a file containing the server's secret key, used for signatures."; description = "Path to a file containing the server's secret key, used for signatures.";
}; };
prometheus-hosts = mkOption { datasources = mkOption {
type = listOf str; type = attrsOf (submodule datasourceOpts);
description = "A list of URLs to prometheus data sources."; description = "A list of datasources supplied to Grafana.";
default = []; default = {};
}; };
state-directory = mkOption { state-directory = mkOption {
@ -93,11 +157,26 @@ in {
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
systemd.tmpfiles.rules = let systemd = {
grafana-user = config.systemd.services.grafana.serviceConfig.User; tmpfiles.rules = let
in [ grafana-user = config.systemd.services.grafana.serviceConfig.User;
"d ${cfg.state-directory} 0700 ${grafana-user} - - -" in [
]; "d ${cfg.state-directory} 0700 ${grafana-user} - - -"
];
services.grafana.serviceConfig = {
EnvironmentFile = host-secrets.grafana-environment-file.target-file;
};
};
fudo.secrets.host-secrets.${hostname}.grafana-environment-file = {
source-file = pkgs.writeText "grafana.env" ''
${optionalString (cfg.ldap != null)
''GRAFANA_LDAP_BIND_PASSWD="${cfg.ldap.bind-passwd}"''}
'';
target-file = "/run/metrics/grafana/auth-bind.passwd";
user = config.systemd.services.grafana.serviceConfig.User;
};
services = { services = {
nginx = { nginx = {
@ -133,12 +212,30 @@ in {
smtp = { smtp = {
enable = true; enable = true;
fromAddress = "metrics@fudo.org"; # TODO: create system user as necessary
fromAddress = "${cfg.smtp.username}@${cfg.smtp.domain}";
host = "${cfg.smtp.hostname}:25"; host = "${cfg.smtp.hostname}:25";
user = cfg.smtp.username; user = cfg.smtp.username;
passwordFile = cfg.smtp.password-file; passwordFile = cfg.smtp.password-file;
}; };
extraOptions = mkIf (cfg.ldap != null) (let
config-file = pkgs.writeText "grafana-ldap.toml" ''
[[servers]]
host = "${concatStringsSep " " cfg.ldap.hosts}"
port = 389
start_tls = true
bind_dn = "${cfg.ldap.bind-dn}"
bind_password = "''${GRAFANA_LDAP_BIND_PASSWD}"
search_filter = "(uid=%s)"
search_base_dns = [ "${cfg.ldap.base-dn}" ]
'';
in {
AUTH_LDAP_ENABLED = "true";
AUTH_LDAP_ALLOW_SIGN_UP = "false";
AUTH_LDAP_CONFIG_FILE = config-file;
});
database = { database = {
host = cfg.database.hostname; host = cfg.database.hostname;
name = cfg.database.name; name = cfg.database.name;
@ -147,15 +244,16 @@ in {
type = "postgres"; type = "postgres";
}; };
provision.datasources = imap0 (i: host: { provision = {
editable = false; enable = true;
isDefault = (i == 0); datasources = let
name = builtins.trace "PROMETHEUS-HOST: ${host}" host; make-datasource = datasource: {
type = "prometheus"; editable = false;
url = let isDefault = datasource.default;
scheme = if private-network then "http" else "https"; inherit (datasource) name type url;
in "${scheme}://${host}/"; };
}) cfg.prometheus-hosts; in map make-datasource (attrValues cfg.datasources);
};
}; };
}; };
}; };

View File

@ -96,7 +96,8 @@ let
}; };
config-file = builtins.toJSON jabber-config; config-file = builtins.toJSON jabber-config;
in pkgs.writeText "ejabberd.config.yml.template" config-file; in pkgs.lib.text.format-json-file
(pkgs.writeText "ejabberd.config.yml.template" config-file);
enter-secrets = template: secrets: target: let enter-secrets = template: secrets: target: let
secret-swappers = map secret-swappers = map
@ -170,13 +171,13 @@ in {
}; };
log-level = mkOption { log-level = mkOption {
type = int; type = str;
description = '' description = ''
Log level at which to run the server. Log level at which to run the server.
See: https://docs.ejabberd.im/admin/guide/troubleshooting/ See: https://docs.ejabberd.im/admin/guide/troubleshooting/
''; '';
default = 3; default = "info";
}; };
state-directory = mkOption { state-directory = mkOption {
@ -212,8 +213,6 @@ in {
in { in {
acme.host-domains.${hostname} = mapAttrs' (site: siteOpts: acme.host-domains.${hostname} = mapAttrs' (site: siteOpts:
nameValuePair siteOpts.hostname { nameValuePair siteOpts.hostname {
extra-domains =
(optional (siteOpts.hostname != host-fqdn) host-fqdn);
local-copies.ejabberd = { local-copies.ejabberd = {
user = cfg.user; user = cfg.user;
group = cfg.group; group = cfg.group;

View File

@ -127,7 +127,7 @@ let
userDatabaseAccessSql = user: database: dbOpts: '' userDatabaseAccessSql = user: database: dbOpts: ''
\c ${database} \c ${database}
${join-lines ${join-lines
(mapAttrsToList (userTableAccessSql user) dbOpts.entity-access)} (mapAttrsToList (userTableAccessSql user) dbOpts.entity-access)}
''; '';
userAccessSql = user: userOpts: userAccessSql = user: userOpts:
join-lines (mapAttrsToList (userDatabaseAccessSql user) userOpts.databases); join-lines (mapAttrsToList (userDatabaseAccessSql user) userOpts.databases);
@ -375,20 +375,24 @@ in {
requires = [ "postgresql.target" ]; requires = [ "postgresql.target" ];
after = [ "postgresql.target" "postgresql-password-setter.target" ]; after = [ "postgresql.target" "postgresql-password-setter.target" ];
partOf = [ cfg.systemd-target ]; partOf = [ cfg.systemd-target ];
script = let wantedBy = [ "postgresql.target" ];
allow-user-login = user: "ALTER ROLE ${user} WITH LOGIN;"; serviceConfig = {
User = config.services.postgresql.superUser;
ExecStart = let
allow-user-login = user: "ALTER ROLE ${user} WITH LOGIN;";
extra-settings-sql = pkgs.writeText "settings.sql" '' extra-settings-sql = pkgs.writeText "settings.sql" ''
${concatStringsSep "\n" ${concatStringsSep "\n"
(map allow-user-login (mapAttrsToList (key: val: key) cfg.users))} (map allow-user-login (mapAttrsToList (key: val: key) cfg.users))}
${usersAccessSql cfg.users} ${usersAccessSql cfg.users}
'';
in pkgs.writeShellScript "postgresql-finalizer.sh" ''
${pkgs.postgresql}/bin/psql --port ${
toString config.services.postgresql.port
} -d postgres -f ${extra-settings-sql}
chgrp ${cfg.socket-group} ${cfg.socket-directory}/.s.PGSQL*
''; '';
in '' };
${pkgs.postgresql}/bin/psql --port ${
toString config.services.postgresql.port
} -d postgres -f ${extra-settings-sql}
${pkgs.coreutils}/bin/chgrp ${cfg.socket-group} ${cfg.socket-directory}/.s.PGSQL*
'';
}; };
}; };
}; };

View File

@ -21,6 +21,13 @@ let
gpgsql-password=__PASSWORD__ gpgsql-password=__PASSWORD__
gpgsql-dnssec=${if cfg.enable-dnssec then "yes" else "no"} gpgsql-dnssec=${if cfg.enable-dnssec then "yes" else "no"}
gpgsql-extra-connection-parameters=sslmode=require gpgsql-extra-connection-parameters=sslmode=require
${optionalString cfg.debug ''
log-dns-details
log-dns-queries
log-timestamp
loglevel=6
query-logging
''}
''; '';
pdns-config-dir = pkgs.writeTextDir "pdns.conf" '' pdns-config-dir = pkgs.writeTextDir "pdns.conf" ''
@ -61,6 +68,7 @@ let
networks-string = concatStringsSep " " (v4-nets ++ v6-nets); networks-string = concatStringsSep " " (v4-nets ++ v6-nets);
in ''"v=spf1 mx ${networks-string} -all"'')) in ''"v=spf1 mx ${networks-string} -all"''))
(mkRecord "ns1.${domain-name}" "A" host-ip) (mkRecord "ns1.${domain-name}" "A" host-ip)
(mkRecord domain-name "A" host-ip)
] ++ ] ++
(optional (domain.gssapi-realm != null) (optional (domain.gssapi-realm != null)
(mkRecord "_kerberos.${domain-name}" "TXT" ''"domain.gssapi-realm"'')) ++ (mkRecord "_kerberos.${domain-name}" "TXT" ''"domain.gssapi-realm"'')) ++
@ -158,6 +166,12 @@ in {
default = true; default = true;
}; };
debug = mkOption {
type = bool;
description = "Enable verbose debugging.";
default = false;
};
database = { database = {
host = mkOption { host = mkOption {
type = str; type = str;
@ -190,7 +204,10 @@ in {
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [ cfg.port ]; networking.firewall = {
allowedTCPPorts = [ cfg.port ];
allowedUDPPorts = [ cfg.port ];
};
users = { users = {
users.${cfg.user} = { users.${cfg.user} = {
@ -308,7 +325,6 @@ in {
"--chroot=${runtime-dir}" "--chroot=${runtime-dir}"
"--daemon=no" "--daemon=no"
"--guardian=no" "--guardian=no"
"--disable-syslog"
"--write-pid=no" "--write-pid=no"
"--config-dir=${pdns-config-dir}" "--config-dir=${pdns-config-dir}"
]); ]);

View File

@ -37,6 +37,12 @@ in {
description = "Site name of the current local host."; description = "Site name of the current local host.";
}; };
local-zone = mkOption {
type = nullOr str;
description = "Zone name of the current local host.";
default = null;
};
local-admins = mkOption { local-admins = mkOption {
type = listOf str; type = listOf str;
description = "List of users who should have admin access to the local host."; description = "List of users who should have admin access to the local host.";