Browse Source

Many changes

master
niten 2 months ago
parent
commit
df53c13bb7
  1. 148
      lib/fudo/chat.nix
  2. 282
      lib/fudo/domains.nix
  3. 18
      lib/fudo/postgres.nix
  4. 67
      lib/lib/network.nix

148
lib/fudo/chat.nix

@ -102,7 +102,7 @@ in {
EmailSettings = {
RequireEmailVerification = true;
SMTPServer = cfg.smtp.server;
SMTPPort = 587;
SMTPPort = "587";
EnableSMTPAuth = true;
SMTPUsername = cfg.smtp.user;
SMTPPassword = "__SMTP_PASSWD__";
@ -113,22 +113,20 @@ in {
};
EnableEmailInvitations = true;
SqlSettings.DriverName = "postgres";
SqlSettings.DataSource = "postgres://${
cfg.database.user
}:__DATABASE_PASSWORD__@${
cfg.database.hostname
}:5432/${
cfg.database.name
}";
SqlSettings.DataSource =
"postgres://${cfg.database.user}:__DATABASE_PASSWORD__@${cfg.database.hostname}:5432/${cfg.database.name}";
};
mattermost-config-file-template =
pkgs.writeText "mattermost-config.json.template" (builtins.toJSON modified-config);
pkgs.writeText "mattermost-config.json.template"
(builtins.toJSON modified-config);
generate-mattermost-config = target: template: smtp-passwd-file: db-passwd-file:
generate-mattermost-config =
target: template: smtp-passwd-file: db-passwd-file:
pkgs.writeScript "mattermost-config-generator.sh" ''
rm ${target}
SMTP_PASSWD=$( cat ${smtp-passwd-file} )
DATABASE_PASSWORD=$( cat ${db-passwd-file} )
sed -e 's/__SMTP_PASSWD__/"$SMTP_PASSWD"/' -e 's/__DATABASE_PASSWORD__/"$DATABASE_PASSWORD"/' ${template} > ${target}
sed -e "s/__SMTP_PASSWD__/$SMTP_PASSWD/" -e "s/__DATABASE_PASSWORD__/$DATABASE_PASSWORD/" ${template} > ${target}
'';
in {
@ -136,10 +134,10 @@ in {
users = {
${cfg.user} = {
isSystemUser = true;
group = mattermost-group;
group = cfg.group;
};
};
groups.${cfg.group}.members = [ cfg.user ];
groups = { ${cfg.group} = { members = [ cfg.user ]; }; };
};
fudo.system.services.mattermost = {
@ -147,17 +145,25 @@ in {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
preStart = ''
${generate-mattermost-config
mattermost-config-target
mattermost-config-file-template
cfg.smtp.password-file
cfg.database.password-file}
cp ${cfg.smtp.password-file} ${cfg.state-directory}/config/config.json
cp -uRL ${pkg}/client ${cfg.state-directory}
chown ${cfg.user}:${cfg.group} ${cfg.state-directory}/client
chmod 0750 ${cfg.state-directory}/client
'';
preStart =
let config-target = "${cfg.state-directory}/config/config.json";
in ''
if [ ! -f ${config-target} ]; then
${
generate-mattermost-config mattermost-config-target
mattermost-config-file-template cfg.smtp.password-file
cfg.database.password-file
}
cp ${mattermost-config-target} ${config-target}
chown ${cfg.user}:${cfg.group} ${config-target}
chmod 640 ${config-target}
fi
if [ ! -e ${cfg.state-directory} ]; then
cp -uRL ${pkg}/client ${cfg.state-directory}
chown ${cfg.user}:${cfg.group} ${cfg.state-directory}/client
chmod 0750 ${cfg.state-directory}/client
fi
'';
execStart = "${pkg}/bin/mattermost";
workingDirectory = cfg.state-directory;
user = cfg.user;
@ -167,8 +173,9 @@ in {
systemd = {
tmpfiles.rules = [
"d ${cfg.state-directory} 0750 ${cfg.user} ${cfg.group} - -"
"d ${cfg.state-directory}/config 0750 ${cfg.user} ${cfg.group} - -"
"d ${cfg.state-directory} 0750 ${cfg.user} - - -"
"d ${cfg.state-directory}/config 0750 ${cfg.user} - - -"
"d ${dirOf mattermost-config-target} 0750 ${cfg.user} - - -"
"L ${cfg.state-directory}/bin - - - - ${pkg}/bin"
"L ${cfg.state-directory}/fonts - - - - ${pkg}/fonts"
"L ${cfg.state-directory}/i18n - - - - ${pkg}/i18n"
@ -183,6 +190,8 @@ in {
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mattermost_cache:10m max_size=3g inactive=120m use_temp_path=off;
'';
recommendedProxySettings = true;
virtualHosts = {
"${cfg.hostname}" = {
enableACME = true;
@ -190,51 +199,52 @@ in {
locations."/" = {
proxyPass = "http://127.0.0.1:8065";
extraConfig = ''
client_max_body_size 50M;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-By $server_addr:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_buffers 256 16k;
proxy_buffer_size 16k;
proxy_read_timeout 600s;
proxy_cache mattermost_cache;
proxy_cache_revalidate on;
proxy_cache_min_uses 2;
proxy_cache_use_stale timeout;
proxy_cache_lock on;
proxy_http_version 1.1;
'';
proxyWebsockets = true;
# extraConfig = ''
# client_max_body_size 50M;
# proxy_set_header Connection "";
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-By $server_addr:$server_port;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
# proxy_set_header X-Frame-Options SAMEORIGIN;
# proxy_buffers 256 16k;
# proxy_buffer_size 16k;
# proxy_read_timeout 600s;
# proxy_cache mattermost_cache;
# proxy_cache_revalidate on;
# proxy_cache_min_uses 2;
# proxy_cache_use_stale timeout;
# proxy_cache_lock on;
# proxy_http_version 1.1;
# '';
};
locations."~ /api/v[0-9]+/(users/)?websocket$" = {
proxyPass = "http://127.0.0.1:8065";
extraConfig = ''
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
client_max_body_size 50M;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-By $server_addr:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_buffers 256 16k;
proxy_buffer_size 16k;
client_body_timeout 60;
send_timeout 300;
lingering_timeout 5;
proxy_connect_timeout 90;
proxy_send_timeout 300;
proxy_read_timeout 90s;
'';
};
# locations."~ /api/v[0-9]+/(users/)?websocket$" = {
# proxyPass = "http://127.0.0.1:8065";
# extraConfig = ''
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade";
# client_max_body_size 50M;
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-By $server_addr:$server_port;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
# proxy_set_header X-Frame-Options SAMEORIGIN;
# proxy_buffers 256 16k;
# proxy_buffer_size 16k;
# client_body_timeout 60;
# send_timeout 300;
# lingering_timeout 5;
# proxy_connect_timeout 90;
# proxy_send_timeout 300;
# proxy_read_timeout 90s;
# '';
# };
};
};
};

282
lib/fudo/domains.nix

@ -5,171 +5,185 @@ let
hostname = config.instance.hostname;
domain = config.instance.local-domain;
domainOpts = { name, ... }: let
domain = name;
in {
options = with types; {
domain = mkOption {
type = str;
description = "Domain name.";
default = domain;
};
domainOpts = { name, ... }:
let domain = name;
in {
options = with types; {
domain = mkOption {
type = str;
description = "Domain name.";
default = domain;
};
local-networks = mkOption {
type = listOf str;
description =
"A list of networks to be considered trusted on this network.";
default = [ ];
};
local-networks = mkOption {
type = listOf str;
description =
"A list of networks to be considered trusted on this network.";
default = [ ];
};
local-users = mkOption {
type = listOf str;
description =
"A list of users who should have local (i.e. login) access to _all_ hosts in this domain.";
default = [ ];
};
local-users = mkOption {
type = listOf str;
description =
"A list of users who should have local (i.e. login) access to _all_ hosts in this domain.";
default = [ ];
};
local-admins = mkOption {
type = listOf str;
description =
"A list of users who should have admin access to _all_ hosts in this domain.";
default = [ ];
};
local-admins = mkOption {
type = listOf str;
description =
"A list of users who should have admin access to _all_ hosts in this domain.";
default = [ ];
};
local-groups = mkOption {
type = listOf str;
description = "List of groups which should exist within this domain.";
default = [ ];
};
local-groups = mkOption {
type = listOf str;
description = "List of groups which should exist within this domain.";
default = [ ];
};
admin-email = mkOption {
type = str;
description = "Email for the administrator of this domain.";
default = "admin@${domain}";
};
admin-email = mkOption {
type = str;
description = "Email for the administrator of this domain.";
default = "admin@${domain}";
};
grafana-hosts = mkOption {
type = listOf str;
description = "List of hosts acting as Grafana metric analyzers. Requires prometheus hosts as well.";
default = [];
};
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;
description = "Host which will accept incoming log pushes.";
default = null;
};
log-aggregator = mkOption {
type = nullOr str;
description = "Host which will accept incoming log pushes.";
default = null;
};
postgresql-server = mkOption {
type = nullOr str;
description = "Hostname acting as the local PostgreSQL server.";
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;
};
chat-server = mkOption {
type = nullOr str;
description =
"Hostname acting as the domain chat server (using Mattermost).";
default = null;
};
dns-service = mkOption {
type = nullOr str;
description = "DNS backplane service host.";
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;
};
domain = mkOption {
type = str;
description = "Domain name of the dynamic zone served by this server.";
};
wireguard = {
gateway = mkOption {
type = str;
description = "Host serving as WireGuard gateway for this domain.";
};
});
description = "Backplane configuration.";
default = null;
};
wireguard = {
gateway = mkOption {
type = str;
description = "Host serving as WireGuard gateway for this domain.";
network = mkOption {
type = str;
description = "IP subnet used for WireGuard clients.";
default = "172.16.0.0/16";
};
routed-network = mkOption {
type = nullOr str;
description = "Subnet of larger network for which we NAT traffic.";
default = "172.16.16.0/20";
};
};
network = mkOption {
gssapi-realm = mkOption {
type = str;
description = "IP subnet used for WireGuard clients.";
default = "172.16.0.0/16";
description = "GSSAPI (i.e. Kerberos) realm of this domain.";
};
routed-network = mkOption {
kerberos-master = mkOption {
type = nullOr str;
description = "Subnet of larger network for which we NAT traffic.";
default = "172.16.16.0/20";
description =
"Hostname of the Kerberos master server for the domain, if applicable.";
default = null;
};
};
gssapi-realm = mkOption {
type = str;
description = "GSSAPI (i.e. Kerberos) realm of this domain.";
};
kerberos-master = mkOption {
type = nullOr str;
description = "Hostname of the Kerberos master server for the domain, if applicable.";
default = null;
};
kerberos-slaves = mkOption {
type = listOf str;
description = "List of hosts acting as Kerberos slaves for the domain.";
default = [];
};
kerberos-slaves = mkOption {
type = listOf str;
description =
"List of hosts acting as Kerberos slaves for the domain.";
default = [ ];
};
ldap-servers = mkOption {
type = listOf str;
description = "List of hosts acting as LDAP authentication servers for the domain.";
default = [];
};
ldap-servers = mkOption {
type = listOf str;
description =
"List of hosts acting as LDAP authentication servers for the domain.";
default = [ ];
};
prometheus-hosts = mkOption {
type = listOf str;
description = "List of hosts acting aas prometheus metric scrapers for hosts in this network.";
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 {
type = nullOr str;
description = "Hostname of the primary nameserver for this domain.";
default = null;
};
primary-nameserver = mkOption {
type = nullOr str;
description = "Hostname of the primary nameserver for this domain.";
default = null;
};
secondary-nameservers = mkOption {
type = listOf str;
description = "List of hostnames of slave nameservers for this domain.";
default = [];
};
secondary-nameservers = mkOption {
type = listOf str;
description =
"List of hostnames of slave nameservers for this domain.";
default = [ ];
};
primary-mailserver = mkOption {
type = nullOr str;
description = "Hostname of the primary mail server for this domain.";
default = null;
};
primary-mailserver = mkOption {
type = nullOr str;
description = "Hostname of the primary mail server for this domain.";
default = null;
};
xmpp-servers = mkOption {
type = listOf str;
description = "Hostnames of the domain XMPP servers.";
default = [];
};
xmpp-servers = mkOption {
type = listOf str;
description = "Hostnames of the domain XMPP servers.";
default = [ ];
};
zone = mkOption {
type = nullOr str;
description = "Name of the DNS zone associated with domain.";
default = null;
zone = mkOption {
type = nullOr str;
description = "Name of the DNS zone associated with domain.";
default = null;
};
};
};
};
in {
options.fudo.domains = mkOption {

18
lib/fudo/postgres.nix

@ -64,6 +64,13 @@ let
"A list of users who should have full access to this database.";
default = [ ];
};
extensions = mkOption {
type = listOf str;
description =
"A list of extensions which should be created for this database.";
default = [ ];
};
};
};
@ -121,6 +128,13 @@ let
${network-entries user db}
'') (attrNames opts.databases))) (filterPasswordedUsers users));
enableExtensionSql = ext: ''CREATE EXTENSION IF NOT EXISTS "${ext}";'';
enableDatabaseExtensionsSql = database: databaseOpts: ''
\c ${database}
${join-lines (map enableExtensionSql databaseOpts.extensions)}
'';
userTableAccessSql = user: entity: access:
"GRANT ${access} ON ${entity} TO ${user};";
userDatabaseAccessSql = user: database: dbOpts: ''
@ -382,8 +396,12 @@ in {
allow-user-login = user: "ALTER ROLE ${user} WITH LOGIN;";
extra-settings-sql = pkgs.writeText "settings.sql" ''
${join-lines
(mapAttrsToList enableDatabaseExtensionsSql cfg.databases)}
${concatStringsSep "\n" (map allow-user-login
(mapAttrsToList (key: val: key) cfg.users))}
${usersAccessSql cfg.users}
'';
in pkgs.writeShellScript "postgresql-finalizer.sh" ''

67
lib/lib/network.nix

@ -2,13 +2,14 @@
with pkgs.lib;
let
generate-mac-address = hostname: interface: pkgs.stdenv.mkDerivation {
name = "mk-mac-${hostname}-${interface}";
phases = [ "installPhase" ];
installPhase = ''
echo ${hostname}-${interface} | sha1sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/' > $out
'';
};
generate-mac-address = hostname: interface:
pkgs.stdenv.mkDerivation {
name = "mk-mac-${hostname}-${interface}";
phases = [ "installPhase" ];
installPhase = ''
echo ${hostname}-${interface} | sha1sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/' > $out
'';
};
# dropUntil = pred: lst: let
# drop-until-helper = pred: lst:
@ -28,32 +29,40 @@ let
# (lib.reverseList lines-front-stripped));
# in concatStringsSep "\n" lines-rear-stripped;
host-ipv4 = config: hostname: let
domain = config.fudo.hosts.${hostname}.domain;
host-network = config.fudo.zones.${domain};
in host-network.hosts.${hostname}.ipv4-address;
host-ipv4 = config: hostname:
let
domain = config.fudo.hosts.${hostname}.domain;
host-network = config.fudo.zones.${domain};
in host-network.hosts.${hostname}.ipv4-address;
host-ipv6 = config: hostname: let
domain = config.fudo.hosts.${hostname}.domain;
host-network = config.fudo.zones.${domain};
in host-network.hosts.${hostname}.ipv6-address;
host-ipv6 = config: hostname:
let
domain = config.fudo.hosts.${hostname}.domain;
host-network = config.fudo.zones.${domain};
in host-network.hosts.${hostname}.ipv6-address;
host-ips = config: hostname: let
ipv4 = host-ipv4 config hostname;
ipv6 = host-ipv6 config hostname;
not-null = o: o != null;
in filter not-null [ ipv4 ipv6 ];
host-ips = config: hostname:
let
ipv4 = host-ipv4 config hostname;
ipv6 = host-ipv6 config hostname;
not-null = o: o != null;
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;
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;
host-fqdn = config: hostname:
let domain-name = config.fudo.hosts.${hostname}.domain;
in "${hostname}.${domain-name}";
in {
inherit host-ipv4 host-ipv6 host-ips site-gateway;
inherit host-ipv4 host-ipv6 host-ips site-gateway host-fqdn;
generate-mac-address = hostname: interface: let
pkg = generate-mac-address hostname interface;
in removeSuffix "\n" (builtins.readFile "${pkg}");
generate-mac-address = hostname: interface:
let pkg = generate-mac-address hostname interface;
in removeSuffix "\n" (builtins.readFile "${pkg}");
}
Loading…
Cancel
Save