Changes over time
This commit is contained in:
parent
125d2d3d57
commit
2048377c3f
7
lib.nix
7
lib.nix
|
@ -1,10 +1,11 @@
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
ip = import ./lib/lib/ip.nix { inherit pkgs; };
|
|
||||||
dns = import ./lib/lib/dns.nix { inherit pkgs; };
|
dns = import ./lib/lib/dns.nix { inherit pkgs; };
|
||||||
passwd = import ./lib/lib/passwd.nix { inherit pkgs; };
|
fs = import ./lib/lib/filesystem.nix { inherit pkgs; };
|
||||||
|
ip = import ./lib/lib/ip.nix { inherit pkgs; };
|
||||||
lisp = import ./lib/lib/lisp.nix { inherit pkgs; };
|
lisp = import ./lib/lib/lisp.nix { inherit pkgs; };
|
||||||
network = import ./lib/lib/network.nix { inherit pkgs; };
|
network = import ./lib/lib/network.nix { inherit pkgs; };
|
||||||
fs = import ./lib/lib/filesystem.nix { inherit pkgs; };
|
passwd = import ./lib/lib/passwd.nix { inherit pkgs; };
|
||||||
|
text = import ./lib/lib/text.nix { inherit pkgs; };
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,25 +118,48 @@ in {
|
||||||
# Sigh. Leave it the same as nginx default, so it works whether or not
|
# Sigh. Leave it the same as nginx default, so it works whether or not
|
||||||
# nginx feels like helping or not.
|
# nginx feels like helping or not.
|
||||||
default = "/var/lib/acme/acme-challenge";
|
default = "/var/lib/acme/acme-challenge";
|
||||||
|
# default = "/run/acme-challenge";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
security.acme.certs = mapAttrs (domain: domainOpts: {
|
security.acme.certs = mapAttrs (domain: domainOpts: {
|
||||||
email = domainOpts.admin-email;
|
# email = domainOpts.admin-email;
|
||||||
webroot = cfg.challenge-path;
|
# webroot = cfg.challenge-path;
|
||||||
extraDomainNames = domainOpts.extra-domains;
|
# group = "nginx";
|
||||||
|
# extraDomainNames = domainOpts.extra-domains;
|
||||||
}) localDomains;
|
}) localDomains;
|
||||||
|
|
||||||
# Assume that if we're acquiring SSL certs, we have a real IP for the
|
# Assume that if we're acquiring SSL certs, we have a real IP for the
|
||||||
# host. nginx must have an acme dir for security.acme to work.
|
# host. nginx must have an acme dir for security.acme to work.
|
||||||
services.nginx = mkIf hasLocalDomains {
|
services.nginx = mkIf hasLocalDomains {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
recommendedGzipSettings = true;
|
|
||||||
recommendedOptimisation = true;
|
|
||||||
recommendedTlsSettings = true;
|
recommendedTlsSettings = true;
|
||||||
recommendedProxySettings = true;
|
virtualHosts = let
|
||||||
|
server-path = "/.well-known/acme-challenge";
|
||||||
|
in (mapAttrs (domain: domainOpts: {
|
||||||
|
# THIS IS A HACK. Getting redundant paths. So if {domain} is configured
|
||||||
|
# somewhere else, assume ACME is already set.
|
||||||
|
# locations.${server-path} = mkIf (! (hasAttr domain config.services.nginx.virtualHosts)) {
|
||||||
|
# root = cfg.challenge-path;
|
||||||
|
# extraConfig = "auth_basic off;";
|
||||||
|
# };
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
serverAliases = domainOpts.extra-domains;
|
||||||
|
}) localDomains) // {
|
||||||
|
"default" = {
|
||||||
|
serverName = "_";
|
||||||
|
default = true;
|
||||||
|
locations = {
|
||||||
|
${server-path} = {
|
||||||
|
root = cfg.challenge-path;
|
||||||
|
extraConfig = "auth_basic off;";
|
||||||
|
};
|
||||||
|
"/".return = "403 Forbidden";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||||
|
@ -170,7 +193,17 @@ in {
|
||||||
if (copyOpts.group != null) then
|
if (copyOpts.group != null) then
|
||||||
"${copyOpts.user}:${copyOpts.group}"
|
"${copyOpts.user}:${copyOpts.group}"
|
||||||
else copyOpts.user;
|
else copyOpts.user;
|
||||||
|
dirs = unique [
|
||||||
|
(dirOf copyOpts.certificate)
|
||||||
|
(dirOf copyOpts.full-certificate)
|
||||||
|
(dirOf copyOpts.chain)
|
||||||
|
(dirOf copyOpts.private-key)
|
||||||
|
];
|
||||||
install-certs = pkgs.writeShellScript "fudo-install-${domain}-${copy}-certs.sh" ''
|
install-certs = pkgs.writeShellScript "fudo-install-${domain}-${copy}-certs.sh" ''
|
||||||
|
${concatStringsSep "\n" (map (dir: ''
|
||||||
|
mkdir -p ${dir}
|
||||||
|
chown ${owners} ${dir}
|
||||||
|
'') dirs)}
|
||||||
cp ${source}/cert.pem ${copyOpts.certificate}
|
cp ${source}/cert.pem ${copyOpts.certificate}
|
||||||
chmod 0444 ${copyOpts.certificate}
|
chmod 0444 ${copyOpts.certificate}
|
||||||
chown ${owners} ${copyOpts.certificate}
|
chown ${owners} ${copyOpts.certificate}
|
||||||
|
|
|
@ -32,7 +32,6 @@ in {
|
||||||
domain = mkOption {
|
domain = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = "Domain under which this host is registered.";
|
description = "Domain under which this host is registered.";
|
||||||
default = "fudo.link";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
server = mkOption {
|
server = mkOption {
|
||||||
|
|
|
@ -1,48 +1,52 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib; {
|
with lib; {
|
||||||
imports = [
|
imports = [
|
||||||
./acme-certs.nix
|
./backplane-service/dns.nix
|
||||||
./authentication.nix
|
|
||||||
./backplane
|
./acme-certs.nix
|
||||||
./chat.nix
|
./adguard-dns-proxy.nix
|
||||||
./client/dns.nix
|
./authentication.nix
|
||||||
./deploy.nix
|
./backplane.nix
|
||||||
./distributed-builds.nix
|
./chat.nix
|
||||||
./dns.nix
|
./client/dns.nix
|
||||||
./domains.nix
|
./deploy.nix
|
||||||
./garbage-collector.nix
|
./distributed-builds.nix
|
||||||
./git.nix
|
./dns.nix
|
||||||
./global.nix
|
./domains.nix
|
||||||
./grafana.nix
|
./garbage-collector.nix
|
||||||
./hosts.nix
|
./git.nix
|
||||||
./host-filesystems.nix
|
./global.nix
|
||||||
./initrd-network.nix
|
./grafana.nix
|
||||||
./ipfs.nix
|
./hosts.nix
|
||||||
./jabber.nix
|
./host-filesystems.nix
|
||||||
./kdc.nix
|
./initrd-network.nix
|
||||||
./ldap.nix
|
./ipfs.nix
|
||||||
./local-network.nix
|
./jabber.nix
|
||||||
./mail.nix
|
./kdc.nix
|
||||||
./mail-container.nix
|
./ldap.nix
|
||||||
./minecraft-server.nix
|
./local-network.nix
|
||||||
./netinfo-email.nix
|
./mail.nix
|
||||||
./node-exporter.nix
|
./mail-container.nix
|
||||||
./nsd.nix
|
./minecraft-server.nix
|
||||||
./password.nix
|
./netinfo-email.nix
|
||||||
./postgres.nix
|
./node-exporter.nix
|
||||||
./prometheus.nix
|
./nsd.nix
|
||||||
./secrets.nix
|
./password.nix
|
||||||
./secure-dns-proxy.nix
|
./postgres.nix
|
||||||
./sites.nix
|
./powerdns.nix
|
||||||
./slynk.nix
|
./prometheus.nix
|
||||||
./ssh.nix
|
./secrets.nix
|
||||||
./system.nix
|
./secure-dns-proxy.nix
|
||||||
./system-networking.nix
|
./sites.nix
|
||||||
./users.nix
|
./slynk.nix
|
||||||
./vpn.nix
|
./ssh.nix
|
||||||
./webmail.nix
|
./system.nix
|
||||||
./wireless-networks.nix
|
./system-networking.nix
|
||||||
./zones.nix
|
./users.nix
|
||||||
];
|
./vpn.nix
|
||||||
|
./webmail.nix
|
||||||
|
./wireless-networks.nix
|
||||||
|
./zones.nix
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,12 +48,54 @@ let
|
||||||
default = "admin@${domain}";
|
default = "admin@${domain}";
|
||||||
};
|
};
|
||||||
|
|
||||||
gssapi-realm = mkOption {
|
grafana-hosts = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "List of hosts acting as Grafana metric analyzers. Requires prometheus hosts as well.";
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
log-aggregator = mkOption {
|
||||||
type = nullOr str;
|
type = nullOr str;
|
||||||
description = "GSSAPI (i.e. Kerberos) realm of this domain.";
|
description = "Host which will accept incoming log pushes.";
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
postgresql-server = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description = "Hostname acting as the local PostgreSQL server.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane = mkOption {
|
||||||
|
type = nullOr (submodule {
|
||||||
|
options = {
|
||||||
|
nameserver = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description = "Host acting as backplane dynamic DNS server.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
dns-service = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description = "DNS backplane service host.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
domain = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Domain name of the dynamic zone served by this server.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
description = "Backplane configuration.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
gssapi-realm = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "GSSAPI (i.e. Kerberos) realm of this domain.";
|
||||||
|
};
|
||||||
|
|
||||||
kerberos-master = mkOption {
|
kerberos-master = mkOption {
|
||||||
type = nullOr str;
|
type = nullOr str;
|
||||||
description = "Hostname of the Kerberos master server for the domain, if applicable.";
|
description = "Hostname of the Kerberos master server for the domain, if applicable.";
|
||||||
|
@ -72,6 +114,12 @@ let
|
||||||
default = [];
|
default = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
prometheus-hosts = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "List of hosts acting aas prometheus metric scrapers for hosts in this network.";
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
|
||||||
primary-nameserver = mkOption {
|
primary-nameserver = mkOption {
|
||||||
type = nullOr str;
|
type = nullOr str;
|
||||||
description = "Hostname of the primary nameserver for this domain.";
|
description = "Hostname of the primary nameserver for this domain.";
|
||||||
|
|
|
@ -4,14 +4,14 @@
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
cfg = config.fudo.grafana;
|
cfg = config.fudo.metrics.grafana;
|
||||||
|
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
domain-name = config.fudo.hosts.${hostname}.domain;
|
domain-name = config.fudo.hosts.${hostname}.domain;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
options.fudo.grafana = with types; {
|
options.fudo.metrics.grafana = with types; {
|
||||||
enable = mkEnableOption "Fudo Metrics Display Service";
|
enable = mkEnableOption "Fudo Metrics Display Service";
|
||||||
|
|
||||||
hostname = mkOption {
|
hostname = mkOption {
|
||||||
|
@ -88,72 +88,75 @@ in {
|
||||||
description = "Directory at which to store Grafana state data.";
|
description = "Directory at which to store Grafana state data.";
|
||||||
default = "/var/lib/grafana";
|
default = "/var/lib/grafana";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private-network = mkEnableOption "Network is private, no SSL.";
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
services.nginx = {
|
systemd.tmpfiles.rules = let
|
||||||
enable = true;
|
grafana-user = config.systemd.services.grafana.serviceConfig.User;
|
||||||
|
in [
|
||||||
|
"d ${cfg.state-directory} 0700 ${grafana-user} - - -"
|
||||||
|
];
|
||||||
|
|
||||||
virtualHosts = {
|
services = {
|
||||||
"${cfg.hostname}" = {
|
nginx = {
|
||||||
enableACME = true;
|
enable = true;
|
||||||
forceSSL = true;
|
recommendedOptimisation = true;
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
|
||||||
locations."/" = {
|
virtualHosts = {
|
||||||
proxyPass = "http://127.0.0.1:3000";
|
"${cfg.hostname}" = {
|
||||||
|
enableACME = ! cfg.private-network;
|
||||||
extraConfig = ''
|
forceSSL = ! cfg.private-network;
|
||||||
proxy_set_header Host $host;
|
locations."/".proxyPass = "http://127.0.0.1:3000";
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
services.grafana = {
|
grafana = {
|
||||||
enable = true;
|
|
||||||
|
|
||||||
addr = "127.0.0.1";
|
|
||||||
protocol = "http";
|
|
||||||
port = 3000;
|
|
||||||
domain = cfg.hostname;
|
|
||||||
rootUrl = "https://${cfg.hostname}/";
|
|
||||||
dataDir = cfg.state-directory;
|
|
||||||
|
|
||||||
security = {
|
|
||||||
adminPasswordFile = cfg.admin-password-file;
|
|
||||||
secretKeyFile = cfg.secret-key-file;
|
|
||||||
};
|
|
||||||
|
|
||||||
smtp = {
|
|
||||||
enable = true;
|
enable = true;
|
||||||
fromAddress = "metrics@fudo.org";
|
|
||||||
host = "mail.fudo.org:25";
|
|
||||||
user = cfg.smtp-username;
|
|
||||||
passwordFile = cfg.smtp-password-file;
|
|
||||||
};
|
|
||||||
|
|
||||||
database = {
|
addr = "127.0.0.1";
|
||||||
host = cfg.database.hostname;
|
protocol = "http";
|
||||||
name = cfg.database.name;
|
port = 3000;
|
||||||
user = cfg.database.user;
|
domain = cfg.hostname;
|
||||||
passwordFile = cfg.database.password-file;
|
rootUrl = let
|
||||||
type = "postgres";
|
scheme = if cfg.private-network then "http" else "https";
|
||||||
};
|
in "${scheme}://${cfg.hostname}/";
|
||||||
|
dataDir = cfg.state-directory;
|
||||||
|
|
||||||
provision.datasources = [
|
security = {
|
||||||
{
|
adminPasswordFile = cfg.admin-password-file;
|
||||||
|
secretKeyFile = cfg.secret-key-file;
|
||||||
|
};
|
||||||
|
|
||||||
|
smtp = {
|
||||||
|
enable = true;
|
||||||
|
fromAddress = "metrics@fudo.org";
|
||||||
|
host = "${cfg.smtp.hostname}:25";
|
||||||
|
user = cfg.smtp.username;
|
||||||
|
passwordFile = cfg.smtp.password-file;
|
||||||
|
};
|
||||||
|
|
||||||
|
database = {
|
||||||
|
host = cfg.database.hostname;
|
||||||
|
name = cfg.database.name;
|
||||||
|
user = cfg.database.user;
|
||||||
|
passwordFile = cfg.database.password-file;
|
||||||
|
type = "postgres";
|
||||||
|
};
|
||||||
|
|
||||||
|
provision.datasources = imap0 (i: host: {
|
||||||
editable = false;
|
editable = false;
|
||||||
isDefault = true;
|
isDefault = (i == 0);
|
||||||
name = cfg.prometheus-host;
|
name = builtins.trace "PROMETHEUS-HOST: ${host}" host;
|
||||||
type = "prometheus";
|
type = "prometheus";
|
||||||
url = "https://${cfg.prometheus-host}/";
|
url = let
|
||||||
}
|
scheme = if private-network then "http" else "https";
|
||||||
];
|
in "${scheme}://${host}/";
|
||||||
|
}) cfg.prometheus-hosts;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ in {
|
||||||
packages = map (p: "${p.name}")
|
packages = map (p: "${p.name}")
|
||||||
config.environment.systemPackages;
|
config.environment.systemPackages;
|
||||||
sorted-unique = sort lessThan (unique packages);
|
sorted-unique = sort lessThan (unique packages);
|
||||||
in concatStringsSep "\n" sorted-unique;
|
in "${concatStringsSep "\n" sorted-unique}\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
systemPackages = with pkgs;
|
systemPackages = with pkgs;
|
||||||
|
|
|
@ -32,8 +32,9 @@ in {
|
||||||
config = {
|
config = {
|
||||||
boot = mkIf (initrd-cfg != null) {
|
boot = mkIf (initrd-cfg != null) {
|
||||||
kernelParams = let
|
kernelParams = let
|
||||||
site = config.fudo.sites.${config.instance.local-site};
|
site-name = config.instance.local-site;
|
||||||
site-gateway = site.gateway-v4;
|
site = config.fudo.sites.${site-name};
|
||||||
|
site-gateway = pkgs.lib.network.site-gateway config site-name;
|
||||||
netmask =
|
netmask =
|
||||||
pkgs.lib.ip.maskFromV32Network site.network;
|
pkgs.lib.ip.maskFromV32Network site.network;
|
||||||
in [
|
in [
|
||||||
|
|
|
@ -337,11 +337,15 @@ in {
|
||||||
users = {
|
users = {
|
||||||
users.${cfg.user} = {
|
users.${cfg.user} = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
|
uid = 88;
|
||||||
home = state-directory;
|
home = state-directory;
|
||||||
group = cfg.group;
|
group = cfg.group;
|
||||||
};
|
};
|
||||||
|
|
||||||
groups.${cfg.group} = { members = [ cfg.user ]; };
|
groups.${cfg.group} = {
|
||||||
|
gid = 88;
|
||||||
|
members = [ cfg.user ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
krb5 = {
|
krb5 = {
|
||||||
|
|
|
@ -218,6 +218,15 @@ in {
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
|
users = {
|
||||||
|
users.openldap = {
|
||||||
|
uid = 389;
|
||||||
|
};
|
||||||
|
groups.openldap = {
|
||||||
|
gid = 389;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
etc = {
|
etc = {
|
||||||
"openldap/sasl2/slapd.conf" = mkIf (cfg.kerberos-keytab != null) {
|
"openldap/sasl2/slapd.conf" = mkIf (cfg.kerberos-keytab != null) {
|
||||||
|
|
|
@ -31,7 +31,13 @@ in {
|
||||||
|
|
||||||
dns-listen-ips = mkOption {
|
dns-listen-ips = mkOption {
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
description = "A list of IPs on which to server DNS queries.";
|
description = "A list of IPv4 addresses on which to server DNS queries.";
|
||||||
|
};
|
||||||
|
|
||||||
|
dns-listen-ipv6s = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "A list of IPv6 addresses on which to server DNS queries.";
|
||||||
|
default = [ ];
|
||||||
};
|
};
|
||||||
|
|
||||||
gateway = mkOption {
|
gateway = mkOption {
|
||||||
|
@ -61,10 +67,22 @@ in {
|
||||||
default = false;
|
default = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
recursive-resolver = mkOption {
|
# recursive-resolver = mkOption {
|
||||||
type = str;
|
# type = str;
|
||||||
description = "DNS nameserver to use for recursive resolution.";
|
# description = "DNS nameserver to use for recursive resolution.";
|
||||||
default = "1.1.1.1 port 53";
|
# default = "1.1.1.1 port 53";
|
||||||
|
# };
|
||||||
|
|
||||||
|
recursive-resolver = {
|
||||||
|
host = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "DNS server host or (preferably) IP.";
|
||||||
|
};
|
||||||
|
port = mkOption {
|
||||||
|
type = port;
|
||||||
|
description = "Remote host port for DNS queries.";
|
||||||
|
default = 53;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
search-domains = mkOption {
|
search-domains = mkOption {
|
||||||
|
@ -161,18 +179,22 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
ipToBlock = ip:
|
filterRedundantIps = official-hosts: hosts: let
|
||||||
|
host-by-ip = groupBy (hostOpts: hostOpts.ipv4-address) hosts;
|
||||||
|
in filter (hostOpts:
|
||||||
|
if (length (getAttr hostOpts.ipv4-address host-by-ip) == 1) then
|
||||||
|
true
|
||||||
|
else elem hostOpts.hostname official-hosts) hosts;
|
||||||
|
ipTo24Block = ip:
|
||||||
concatStringsSep "." (reverseList (take 3 (splitString "." ip)));
|
concatStringsSep "." (reverseList (take 3 (splitString "." ip)));
|
||||||
compactHosts =
|
hostsByBlock = official-hosts:
|
||||||
mapAttrsToList (host: data: data // { host = host; }) zone.hosts;
|
groupBy (host-data: ipTo24Block host-data.ipv4-address)
|
||||||
hostsByBlock =
|
(filterRedundantIps official-hosts (attrValues zone.hosts));
|
||||||
groupBy (host-data: ipToBlock host-data.ipv4-address) compactHosts;
|
|
||||||
hostPtrRecord = host-data:
|
hostPtrRecord = host-data:
|
||||||
"${
|
"${last (splitString "." host-data.ipv4-address)} IN PTR ${host-data.hostname}.${cfg.domain}.";
|
||||||
last (splitString "." host-data.ipv4-address)
|
|
||||||
} IN PTR ${host-data.host}.${cfg.domain}.";
|
|
||||||
|
|
||||||
blockZones = mapAttrsToList blockHostsToZone hostsByBlock;
|
blockZones = official-hosts:
|
||||||
|
mapAttrsToList blockHostsToZone (hostsByBlock official-hosts);
|
||||||
|
|
||||||
hostARecord = host: data: "${host} IN A ${data.ipv4-address}";
|
hostARecord = host: data: "${host} IN A ${data.ipv4-address}";
|
||||||
hostSshFpRecords = host: data:
|
hostSshFpRecords = host: data:
|
||||||
|
@ -189,13 +211,21 @@ in {
|
||||||
|
|
||||||
known-hosts = config.fudo.hosts;
|
known-hosts = config.fudo.hosts;
|
||||||
|
|
||||||
|
domain-name = config.instance.local-domain;
|
||||||
|
|
||||||
|
domain-hosts =
|
||||||
|
attrNames
|
||||||
|
(filterAttrs (_: hostOpts:
|
||||||
|
hostOpts.domain == domain-name)
|
||||||
|
config.fudo.hosts);
|
||||||
|
|
||||||
in {
|
in {
|
||||||
enable = true;
|
enable = true;
|
||||||
cacheNetworks = [ cfg.network "localhost" "localnets" ];
|
cacheNetworks = [ cfg.network "localhost" "localnets" ];
|
||||||
forwarders = [ cfg.recursive-resolver ];
|
forwarders = [ "${cfg.recursive-resolver.host} port ${toString cfg.recursive-resolver.port}" ];
|
||||||
listenOn = cfg.dns-listen-ips;
|
listenOn = cfg.dns-listen-ips;
|
||||||
|
listenOnIpv6 = cfg.dns-listen-ipv6s;
|
||||||
extraOptions = concatStringsSep "\n" [
|
extraOptions = concatStringsSep "\n" [
|
||||||
"dnssec-enable yes;"
|
|
||||||
"dnssec-validation yes;"
|
"dnssec-validation yes;"
|
||||||
"auth-nxdomain no;"
|
"auth-nxdomain no;"
|
||||||
"recursion yes;"
|
"recursion yes;"
|
||||||
|
@ -204,36 +234,44 @@ in {
|
||||||
zones = [{
|
zones = [{
|
||||||
master = true;
|
master = true;
|
||||||
name = cfg.domain;
|
name = cfg.domain;
|
||||||
file = pkgs.writeText "${cfg.domain}-zone" ''
|
file = let
|
||||||
@ IN SOA ns1.${cfg.domain}. hostmaster.${cfg.domain}. (
|
zone-data = pkgs.lib.dns.zoneToZonefile
|
||||||
${toString config.instance.build-timestamp}
|
config.instance.build-timestamp
|
||||||
5m
|
cfg.domain
|
||||||
2m
|
zone;
|
||||||
6w
|
in pkgs.writeText "zone-${cfg.domain}" zone-data;
|
||||||
5m)
|
# file = pkgs.writeText "${cfg.domain}-zone" ''
|
||||||
|
# @ IN SOA ns1.${cfg.domain}. hostmaster.${cfg.domain}. (
|
||||||
|
# ${toString config.instance.build-timestamp}
|
||||||
|
# 5m
|
||||||
|
# 2m
|
||||||
|
# 6w
|
||||||
|
# 5m)
|
||||||
|
|
||||||
$TTL 1h
|
# $TTL 1h
|
||||||
|
|
||||||
@ IN NS ns1.${cfg.domain}.
|
# @ IN NS ns1.${cfg.domain}.
|
||||||
|
|
||||||
$ORIGIN ${cfg.domain}.
|
# $ORIGIN ${cfg.domain}.
|
||||||
|
|
||||||
$TTL 30m
|
# $TTL 30m
|
||||||
|
|
||||||
${optionalString (zone.gssapi-realm != null)
|
# ${optionalString (zone.gssapi-realm != null)
|
||||||
''_kerberos IN TXT "${zone.gssapi-realm}"''}
|
# ''_kerberos IN TXT "${zone.gssapi-realm}"''}
|
||||||
|
|
||||||
${join-lines
|
# ${join-lines
|
||||||
(imap1 (i: server-ip: "ns${toString i} IN A ${server-ip}")
|
# (imap1 (i: server-ip: "ns${toString i} IN A ${server-ip}")
|
||||||
cfg.dns-servers)}
|
# cfg.dns-servers)}
|
||||||
${join-lines (mapAttrsToList hostARecord zone.hosts)}
|
# ${join-lines (mapAttrsToList hostARecord zone.hosts)}
|
||||||
${join-lines (mapAttrsToList hostSshFpRecords zone.hosts)}
|
# ${join-lines (mapAttrsToList hostSshFpRecords zone.hosts)}
|
||||||
${join-lines (mapAttrsToList cnameRecord zone.aliases)}
|
# ${join-lines (mapAttrsToList cnameRecord zone.aliases)}
|
||||||
${join-lines zone.verbatim-dns-records}
|
# ${join-lines zone.verbatim-dns-records}
|
||||||
${pkgs.lib.dns.srvRecordsToBindZone zone.srv-records}
|
# ${pkgs.lib.dns.srvRecordsToBindZone zone.srv-records}
|
||||||
${join-lines cfg.extra-records}
|
# ${join-lines cfg.extra-records}
|
||||||
'';
|
# '';
|
||||||
}] ++ blockZones;
|
}] ++ (optionals
|
||||||
|
cfg.enable-reverse-mappings
|
||||||
|
(blockZones domain-hosts));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,14 @@ with lib;
|
||||||
let
|
let
|
||||||
inherit (lib.strings) concatStringsSep;
|
inherit (lib.strings) concatStringsSep;
|
||||||
|
|
||||||
cfg = config.fudo.node-exporter;
|
cfg = config.fudo.metrics.node-exporter;
|
||||||
|
|
||||||
allow-network = network: "allow ${network};";
|
allow-network = network: "allow ${network};";
|
||||||
|
|
||||||
local-networks = config.instance.local-networks;
|
local-networks = config.instance.local-networks;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.node-exporter = with types; {
|
options.fudo.metrics.node-exporter = with types; {
|
||||||
enable = mkEnableOption "Enable a Prometheus node exporter with some reasonable settings.";
|
enable = mkEnableOption "Enable a Prometheus node exporter with some reasonable settings.";
|
||||||
|
|
||||||
hostname = mkOption {
|
hostname = mkOption {
|
||||||
|
@ -24,6 +24,8 @@ in {
|
||||||
description = "User as which to run the node exporter job.";
|
description = "User as which to run the node exporter job.";
|
||||||
default = "node-exporter";
|
default = "node-exporter";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private-network = mkEnableOption "Network is private.";
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
@ -45,10 +47,12 @@ in {
|
||||||
# list of trusted networks, with SSL protection.
|
# list of trusted networks, with SSL protection.
|
||||||
nginx = {
|
nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
recommendedOptimisation = true;
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
|
||||||
virtualHosts."${cfg.hostname}" = {
|
virtualHosts."${cfg.hostname}" = {
|
||||||
enableACME = true;
|
enableACME = ! cfg.private-network;
|
||||||
forceSSL = true;
|
forceSSL = ! cfg.private-network;
|
||||||
|
|
||||||
locations."/metrics/node" = {
|
locations."/metrics/node" = {
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
|
@ -57,7 +61,6 @@ in {
|
||||||
deny all;
|
deny all;
|
||||||
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $host;
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
proxyPass = "http://127.0.0.1:9100/metrics";
|
proxyPass = "http://127.0.0.1:9100/metrics";
|
||||||
|
|
|
@ -105,17 +105,22 @@ let
|
||||||
nameValuePair "DATABASE ${database}" databaseOpts.access) databases;
|
nameValuePair "DATABASE ${database}" databaseOpts.access) databases;
|
||||||
|
|
||||||
makeEntry = nw:
|
makeEntry = nw:
|
||||||
"host all all ${nw} gss include_realm=0 krb_realm=${gssapi-realm}";
|
"hostssl all all ${nw} gss include_realm=0 krb_realm=${gssapi-realm}";
|
||||||
|
|
||||||
makeNetworksEntry = networks: join-lines (map makeEntry networks);
|
makeNetworksEntry = networks: join-lines (map makeEntry networks);
|
||||||
|
|
||||||
makeLocalUserPasswordEntries = users:
|
makeLocalUserPasswordEntries = users: networks: let
|
||||||
join-lines (mapAttrsToList (user: opts:
|
network-entries = user: db:
|
||||||
join-lines (map (db: ''
|
join-lines
|
||||||
local ${db} ${user} md5
|
(map (network: "hostssl ${db} ${user} ${network} md5")
|
||||||
host ${db} ${user} 127.0.0.1/16 md5
|
networks);
|
||||||
host ${db} ${user} ::1/128 md5
|
in join-lines (mapAttrsToList (user: opts:
|
||||||
'') (attrNames opts.databases))) (filterPasswordedUsers users));
|
join-lines (map (db: ''
|
||||||
|
local ${db} ${user} md5
|
||||||
|
host ${db} ${user} 127.0.0.1/16 md5
|
||||||
|
host ${db} ${user} ::1/128 md5
|
||||||
|
${network-entries user db}
|
||||||
|
'') (attrNames opts.databases))) (filterPasswordedUsers users));
|
||||||
|
|
||||||
userTableAccessSql = user: entity: access:
|
userTableAccessSql = user: entity: access:
|
||||||
"GRANT ${access} ON ${entity} TO ${user};";
|
"GRANT ${access} ON ${entity} TO ${user};";
|
||||||
|
@ -134,18 +139,21 @@ in {
|
||||||
enable = mkEnableOption "Fudo PostgreSQL Server";
|
enable = mkEnableOption "Fudo PostgreSQL Server";
|
||||||
|
|
||||||
ssl-private-key = mkOption {
|
ssl-private-key = mkOption {
|
||||||
type = str;
|
type = nullOr str;
|
||||||
description = "Location of the server SSL private key.";
|
description = "Location of the server SSL private key.";
|
||||||
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
ssl-certificate = mkOption {
|
ssl-certificate = mkOption {
|
||||||
type = str;
|
type = nullOr str;
|
||||||
description = "Location of the server SSL certificate.";
|
description = "Location of the server SSL certificate.";
|
||||||
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
keytab = mkOption {
|
keytab = mkOption {
|
||||||
type = str;
|
type = nullOr str;
|
||||||
description = "Location of the server Kerberos keytab.";
|
description = "Location of the server Kerberos keytab.";
|
||||||
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
local-networks = mkOption {
|
local-networks = mkOption {
|
||||||
|
@ -224,32 +232,9 @@ in {
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
environment = {
|
networking.firewall.allowedTCPPorts = [ 5432 ];
|
||||||
systemPackages = with pkgs; [ postgresql_11_gssapi ];
|
|
||||||
|
|
||||||
# etc = {
|
environment.systemPackages = with pkgs; [ postgresql_11_gssapi ];
|
||||||
# "postgresql/private/privkey.pem" = {
|
|
||||||
# mode = "0400";
|
|
||||||
# user = "postgres";
|
|
||||||
# group = "postgres";
|
|
||||||
# source = cfg.ssl-private-key;
|
|
||||||
# };
|
|
||||||
|
|
||||||
# "postgresql/cert.pem" = {
|
|
||||||
# mode = "0444";
|
|
||||||
# user = "postgres";
|
|
||||||
# group = "postgres";
|
|
||||||
# source = cfg.ssl-certificate;
|
|
||||||
# };
|
|
||||||
|
|
||||||
# "postgresql/private/postgres.keytab" = {
|
|
||||||
# mode = "0400";
|
|
||||||
# user = "postgres";
|
|
||||||
# group = "postgres";
|
|
||||||
# source = cfg.keytab;
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
};
|
|
||||||
|
|
||||||
users.groups = {
|
users.groups = {
|
||||||
${cfg.socket-group} = { members = [ "postgres" ] ++ cfg.local-users; };
|
${cfg.socket-group} = { members = [ "postgres" ] ++ cfg.local-users; };
|
||||||
|
@ -269,12 +254,14 @@ in {
|
||||||
ensurePermissions = { "DATABASE ${database}" = "ALL PRIVILEGES"; };
|
ensurePermissions = { "DATABASE ${database}" = "ALL PRIVILEGES"; };
|
||||||
}) opts.users)) cfg.databases)));
|
}) opts.users)) cfg.databases)));
|
||||||
|
|
||||||
settings = {
|
settings = let
|
||||||
krb_server_keyfile = cfg.keytab;
|
ssl-enabled = cfg.ssl-certificate != null;
|
||||||
|
in {
|
||||||
|
krb_server_keyfile = mkIf (cfg.keytab != null) cfg.keytab;
|
||||||
|
|
||||||
ssl = true;
|
ssl = ssl-enabled;
|
||||||
ssl_cert_file = cfg.ssl-certificate;
|
ssl_cert_file = mkIf ssl-enabled cfg.ssl-certificate;
|
||||||
ssl_key_file = cfg.ssl-private-key;
|
ssl_key_file = mkIf ssl-enabled cfg.ssl-private-key;
|
||||||
|
|
||||||
unix_socket_directories = cfg.socket-directory;
|
unix_socket_directories = cfg.socket-directory;
|
||||||
unix_socket_group = cfg.socket-group;
|
unix_socket_group = cfg.socket-group;
|
||||||
|
@ -282,12 +269,12 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
authentication = lib.mkForce ''
|
authentication = lib.mkForce ''
|
||||||
${makeLocalUserPasswordEntries cfg.users}
|
${makeLocalUserPasswordEntries cfg.users cfg.local-networks}
|
||||||
|
|
||||||
local all all ident
|
local all all ident
|
||||||
|
|
||||||
# host-local
|
# host-local
|
||||||
host all all 127.0.0.1/32 gss include_realm=0 krb_realm=${gssapi-realm}
|
host all all 127.0.0.1/16 gss include_realm=0 krb_realm=${gssapi-realm}
|
||||||
host all all ::1/128 gss include_realm=0 krb_realm=${gssapi-realm}
|
host all all ::1/128 gss include_realm=0 krb_realm=${gssapi-realm}
|
||||||
|
|
||||||
# local networks
|
# local networks
|
||||||
|
@ -308,6 +295,22 @@ in {
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
paths = let
|
||||||
|
user-password-files = mapAttrsToList
|
||||||
|
(user: userOpts: userOpts.password-file)
|
||||||
|
cfg.users;
|
||||||
|
in {
|
||||||
|
postgresql-password-watcher = mkIf (length user-password-files > 0) {
|
||||||
|
wantedBy = [ "default.target" ];
|
||||||
|
description =
|
||||||
|
"Reset all user passwords if any changes occur.";
|
||||||
|
pathConfig = {
|
||||||
|
PathChanged = user-password-files;
|
||||||
|
Unit = "postgresql-password-setter.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
postgresql-password-setter = let
|
postgresql-password-setter = let
|
||||||
passwords-script = passwords-setter-script cfg.users;
|
passwords-script = passwords-setter-script cfg.users;
|
||||||
|
@ -350,22 +353,42 @@ in {
|
||||||
partOf = [ cfg.systemd-target ];
|
partOf = [ cfg.systemd-target ];
|
||||||
wants = [ "postgresql-password-setter.service" ];
|
wants = [ "postgresql-password-setter.service" ];
|
||||||
|
|
||||||
postStart = let
|
# postStart = let
|
||||||
|
# allow-user-login = user: "ALTER ROLE ${user} WITH LOGIN;";
|
||||||
|
|
||||||
|
# extra-settings-sql = pkgs.writeText "settings.sql" ''
|
||||||
|
# ${concatStringsSep "\n"
|
||||||
|
# (map allow-user-login (mapAttrsToList (key: val: key) cfg.users))}
|
||||||
|
# ${usersAccessSql cfg.users}
|
||||||
|
# '';
|
||||||
|
# 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*
|
||||||
|
# '';
|
||||||
|
|
||||||
|
postStop = concatStringsSep "\n" cfg.cleanup-tasks;
|
||||||
|
};
|
||||||
|
|
||||||
|
postgresql-finalizer = {
|
||||||
|
requires = [ "postgresql.target" ];
|
||||||
|
after = [ "postgresql.target" "postgresql-password-setter.target" ];
|
||||||
|
partOf = [ cfg.systemd-target ];
|
||||||
|
script = let
|
||||||
allow-user-login = user: "ALTER ROLE ${user} WITH LOGIN;";
|
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 ''
|
in ''
|
||||||
${pkgs.postgresql}/bin/psql --port ${
|
${pkgs.postgresql}/bin/psql --port ${
|
||||||
toString config.services.postgresql.port
|
toString config.services.postgresql.port
|
||||||
} -d postgres -f ${extra-settings-sql}
|
} -d postgres -f ${extra-settings-sql}
|
||||||
${pkgs.coreutils}/bin/chgrp ${cfg.socket-group} ${cfg.socket-directory}/.s.PGSQL*
|
${pkgs.coreutils}/bin/chgrp ${cfg.socket-group} ${cfg.socket-directory}/.s.PGSQL*
|
||||||
'';
|
'';
|
||||||
|
|
||||||
postStop = concatStringsSep "\n" cfg.cleanup-tasks;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
inherit (lib.strings) concatStringsSep;
|
cfg = config.fudo.metrics.prometheus;
|
||||||
cfg = config.fudo.prometheus;
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
options.fudo.prometheus = with types; {
|
options.fudo.metrics.prometheus = with types; {
|
||||||
enable = mkEnableOption "Fudo Prometheus Data-Gathering Server";
|
enable = mkEnableOption "Fudo Prometheus Data-Gathering Server";
|
||||||
|
|
||||||
service-discovery-dns = mkOption {
|
service-discovery-dns = mkOption {
|
||||||
|
@ -78,32 +77,33 @@ in {
|
||||||
description = "Directory at which to store Prometheus state.";
|
description = "Directory at which to store Prometheus state.";
|
||||||
default = "/var/lib/prometheus";
|
default = "/var/lib/prometheus";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private-network = mkEnableOption "Network is private.";
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d ${cfg.state-directory} 0700 ${config.systemd.services.prometheus.serviceConfig.User} - - -"
|
||||||
|
];
|
||||||
|
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
recommendedOptimisation = true;
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
|
||||||
virtualHosts = {
|
virtualHosts = {
|
||||||
"${cfg.hostname}" = {
|
"${cfg.hostname}" = {
|
||||||
enableACME = true;
|
enableACME = ! cfg.private-network;
|
||||||
forceSSL = true;
|
forceSSL = ! cfg.private-network;
|
||||||
|
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://127.0.0.1:9090";
|
proxyPass = "http://127.0.0.1:9090";
|
||||||
|
|
||||||
extraConfig = let
|
extraConfig = let
|
||||||
local-networks = config.instance.local-networks;
|
local-networks = config.instance.local-networks;
|
||||||
in ''
|
in "${optionalString ((length local-networks) > 0)
|
||||||
proxy_set_header Host $host;
|
(concatStringsSep "\n"
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
(map (network: "allow ${network};") local-networks)) + "\ndeny all;"}";
|
||||||
proxy_set_header X-Forwarded-By $server_addr:$server_port;
|
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
|
|
||||||
${optionalString ((length local-networks) > 0)
|
|
||||||
(concatStringsSep "\n" (map (network: "allow ${network};") local-networks)) + "\ndeny all;"}
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -118,85 +118,18 @@ in {
|
||||||
listenAddress = "127.0.0.1";
|
listenAddress = "127.0.0.1";
|
||||||
port = 9090;
|
port = 9090;
|
||||||
|
|
||||||
scrapeConfigs = [
|
scrapeConfigs = let
|
||||||
{
|
make-job = type: {
|
||||||
job_name = "docker";
|
job_name = type;
|
||||||
honor_labels = false;
|
honor_labels = false;
|
||||||
static_configs = [
|
scheme = if cfg.private-network then "http" else "https";
|
||||||
{
|
metrics_path = "/metrics/${type}";
|
||||||
targets = cfg.docker-hosts;
|
dns_sd_configs = if (hasAttr type cfg.service-discovery-dns) then
|
||||||
}
|
[ { names = cfg.service-discovery-dns.${type}; } ] else [];
|
||||||
];
|
static_configs = if (hasAttr type cfg.static-targets) then
|
||||||
}
|
[ { targets = cfg.static-targets.${type}; } ] else [];
|
||||||
|
};
|
||||||
{
|
in map make-job ["docker" "node" "dovecot" "postfix" "rspamd"];
|
||||||
job_name = "node";
|
|
||||||
scheme = "https";
|
|
||||||
metrics_path = "/metrics/node";
|
|
||||||
honor_labels = false;
|
|
||||||
dns_sd_configs = [
|
|
||||||
{
|
|
||||||
names = cfg.service-discovery-dns.node;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
static_configs = [
|
|
||||||
{
|
|
||||||
targets = cfg.static-targets.node;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
job_name = "dovecot";
|
|
||||||
scheme = "https";
|
|
||||||
metrics_path = "/metrics/dovecot";
|
|
||||||
honor_labels = false;
|
|
||||||
dns_sd_configs = [
|
|
||||||
{
|
|
||||||
names = cfg.service-discovery-dns.dovecot;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
static_configs = [
|
|
||||||
{
|
|
||||||
targets = cfg.static-targets.dovecot;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
job_name = "postfix";
|
|
||||||
scheme = "https";
|
|
||||||
metrics_path = "/metrics/postfix";
|
|
||||||
honor_labels = false;
|
|
||||||
dns_sd_configs = [
|
|
||||||
{
|
|
||||||
names = cfg.service-discovery-dns.postfix;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
static_configs = [
|
|
||||||
{
|
|
||||||
targets = cfg.static-targets.postfix;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
job_name = "rspamd";
|
|
||||||
scheme = "https";
|
|
||||||
metrics_path = "/metrics/rspamd";
|
|
||||||
honor_labels = false;
|
|
||||||
dns_sd_configs = [
|
|
||||||
{
|
|
||||||
names = cfg.service-discovery-dns.rspamd;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
static_configs = [
|
|
||||||
{
|
|
||||||
targets = cfg.static-targets.rspamd;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
pushgateway = {
|
pushgateway = {
|
||||||
enable = if (cfg.push-url != null) then true else false;
|
enable = if (cfg.push-url != null) then true else false;
|
||||||
|
|
|
@ -66,6 +66,7 @@ let
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "User (on target host) to which the file will belong.";
|
description = "User (on target host) to which the file will belong.";
|
||||||
|
default = "root";
|
||||||
};
|
};
|
||||||
|
|
||||||
group = mkOption {
|
group = mkOption {
|
||||||
|
|
|
@ -133,6 +133,12 @@ let
|
||||||
type = str;
|
type = str;
|
||||||
description = "Hostname of the mail server to use for this site.";
|
description = "Hostname of the mail server to use for this site.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
local-gateway = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description = "If this is a NAT site, this should point to the host acting as network gateway.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ let
|
||||||
"Level of protection to apply to the system for this service.";
|
"Level of protection to apply to the system for this service.";
|
||||||
};
|
};
|
||||||
addressFamilies = mkOption {
|
addressFamilies = mkOption {
|
||||||
type = listOf (enum address-families);
|
type = nullOr (listOf (enum address-families));
|
||||||
default = [ ];
|
default = [ ];
|
||||||
description = "List of address families which the service can use.";
|
description = "List of address families which the service can use.";
|
||||||
};
|
};
|
||||||
|
@ -435,7 +435,8 @@ in {
|
||||||
WorkingDirectory =
|
WorkingDirectory =
|
||||||
mkIf (opts.workingDirectory != null) opts.workingDirectory;
|
mkIf (opts.workingDirectory != null) opts.workingDirectory;
|
||||||
RestrictAddressFamilies =
|
RestrictAddressFamilies =
|
||||||
restrict-address-families opts.addressFamilies;
|
optionals (opts.addressFamilies != null)
|
||||||
|
(restrict-address-families opts.addressFamilies);
|
||||||
RestrictNamespaces = opts.restrictNamespaces;
|
RestrictNamespaces = opts.restrictNamespaces;
|
||||||
User = mkIf (opts.user != null) opts.user;
|
User = mkIf (opts.user != null) opts.user;
|
||||||
Group = mkIf (opts.group != null) opts.group;
|
Group = mkIf (opts.group != null) opts.group;
|
||||||
|
|
|
@ -161,7 +161,7 @@ in {
|
||||||
GEMINI_TEXTFILES_ROOT = cfg.textfiles-archive;
|
GEMINI_TEXTFILES_ROOT = cfg.textfiles-archive;
|
||||||
GEMINI_FEEDS = "${generate-feeds cfg.feeds}";
|
GEMINI_FEEDS = "${generate-feeds cfg.feeds}";
|
||||||
|
|
||||||
CL_SOURCE_REGISTRY = "${pkgs.lib.lisp.lisp-source-registry pkgs.cl-gemini}";
|
CL_SOURCE_REGISTRY = pkgs.lib.lisp.lisp-source-registry pkgs.cl-gemini;
|
||||||
};
|
};
|
||||||
|
|
||||||
path = with pkgs; [
|
path = with pkgs; [
|
||||||
|
|
|
@ -62,9 +62,21 @@ in {
|
||||||
description = "Networks which are considered local to this host, site, or domain.";
|
description = "Networks which are considered local to this host, site, or domain.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
service-home = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path to runtime home directories for services.";
|
||||||
|
default = "/run/service";
|
||||||
|
};
|
||||||
|
|
||||||
build-seed = mkOption {
|
build-seed = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Seed used to generate configuration.";
|
description = "Seed used to generate configuration.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d ${config.instance.service-home} 755 root root - -"
|
||||||
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ let
|
||||||
toString record.priority
|
toString record.priority
|
||||||
} ${
|
} ${
|
||||||
toString record.weight
|
toString record.weight
|
||||||
} ${record.host}.") records);
|
} ${toString record.port} ${record.host}.") records);
|
||||||
|
|
||||||
srvRecordOpts = with types; {
|
srvRecordOpts = with types; {
|
||||||
options = {
|
options = {
|
||||||
|
|
|
@ -44,8 +44,14 @@ let
|
||||||
not-null = o: o != null;
|
not-null = o: o != null;
|
||||||
in filter not-null [ ipv4 ipv6 ];
|
in filter not-null [ ipv4 ipv6 ];
|
||||||
|
|
||||||
|
site-gateway = config: site-name: let
|
||||||
|
site = config.fudo.sites.${site-name};
|
||||||
|
in if (site.local-gateway != null)
|
||||||
|
then host-ipv4 config site.local-gateway
|
||||||
|
else site.gateway-v4;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
inherit host-ipv4 host-ipv6 host-ips;
|
inherit host-ipv4 host-ipv6 host-ips site-gateway;
|
||||||
|
|
||||||
generate-mac-address = hostname: interface: let
|
generate-mac-address = hostname: interface: let
|
||||||
pkg = generate-mac-address hostname interface;
|
pkg = generate-mac-address hostname interface;
|
||||||
|
|
|
@ -12,12 +12,12 @@ let
|
||||||
installPhase = let
|
installPhase = let
|
||||||
passwd = removeSuffix "\n" (readFile passwd-file);
|
passwd = removeSuffix "\n" (readFile passwd-file);
|
||||||
in ''
|
in ''
|
||||||
slappasswd -s ${passwd} > $out
|
slappasswd -s ${passwd} | tr -d '\n' > $out
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
hash-ldap-passwd = name: passwd-file:
|
hash-ldap-passwd = name: passwd-file:
|
||||||
builtins.readFile "${hash-ldap-passwd-pkg name passwd-file}";
|
readFile "${hash-ldap-passwd-pkg name passwd-file}";
|
||||||
|
|
||||||
generate-random-passwd = name: length: pkgs.stdenv.mkDerivation {
|
generate-random-passwd = name: length: pkgs.stdenv.mkDerivation {
|
||||||
name = "${name}-random-passwd";
|
name = "${name}-random-passwd";
|
||||||
|
@ -27,10 +27,28 @@ let
|
||||||
buildInputs = with pkgs; [ pwgen ];
|
buildInputs = with pkgs; [ pwgen ];
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
pwgen --secure --num-passwords=1 ${toString length} > $out
|
pwgen --secure --num-passwords=1 ${toString length} | tr -d '\n' > $out
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bcrypt-passwd-pkg = name: passwd-file: pkgs.stdenv.mkDerivation {
|
||||||
|
name = "${name}-bcrypt";
|
||||||
|
|
||||||
|
phases = [ "installPhase" ];
|
||||||
|
|
||||||
|
buildInputs = with pkgs; [ apacheHttpd ];
|
||||||
|
|
||||||
|
installPhase = let
|
||||||
|
passwd = removeSuffix "\n" (readFile passwd-file);
|
||||||
|
in ''
|
||||||
|
htpasswd -bnBC 10 "" ${passwd} | tr -d ':\n' | sed 's/$2y/$2a/' > $out
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
bcrypt-passwd = name: passwd-file:
|
||||||
|
readFile "${bcrypt-passwd-pkg name passwd-file}";
|
||||||
|
|
||||||
|
|
||||||
generate-stablerandom-passwd = name: { seed, length ? 20, ... }:
|
generate-stablerandom-passwd = name: { seed, length ? 20, ... }:
|
||||||
pkgs.stdenv.mkDerivation {
|
pkgs.stdenv.mkDerivation {
|
||||||
name = "${name}-stablerandom-passwd";
|
name = "${name}-stablerandom-passwd";
|
||||||
|
@ -41,13 +59,15 @@ let
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
echo "${name}-${seed}" > seedfile
|
echo "${name}-${seed}" > seedfile
|
||||||
pwgen --secure --num-passwords=1 -H seedfile ${toString length} > $out
|
pwgen --secure --num-passwords=1 -H seedfile ${toString length} | tr -d '\n' > $out
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
hash-ldap-passwd = hash-ldap-passwd;
|
hash-ldap-passwd = hash-ldap-passwd;
|
||||||
|
|
||||||
|
bcrypt-passwd = bcrypt-passwd;
|
||||||
|
|
||||||
random-passwd-file = name: length:
|
random-passwd-file = name: length:
|
||||||
builtins.toPath "${generate-random-passwd name length}";
|
builtins.toPath "${generate-random-passwd name length}";
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
{
|
{ name, ... }: {
|
||||||
options = with types; {
|
options = with types; {
|
||||||
|
hostname = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Hostname.";
|
||||||
|
default = name;
|
||||||
|
};
|
||||||
ipv4-address = mkOption {
|
ipv4-address = mkOption {
|
||||||
type = nullOr str;
|
type = nullOr str;
|
||||||
description = "The V4 IP of a given host, if any.";
|
description = "The V4 IP of a given host, if any.";
|
||||||
|
|
Loading…
Reference in New Issue