Only launch ejabberd if env is available

This commit is contained in:
niten 2023-10-15 21:10:05 -07:00
parent c629223e85
commit 356c452d66
1 changed files with 76 additions and 87 deletions

View File

@ -5,47 +5,46 @@ let
hostname = config.instance.hostname; hostname = config.instance.hostname;
host-secrets = config.fudo.secrets.host-secrets.${hostname}; host-secrets = config.fudo.secrets.host-secrets.${hostname};
siteOpts = { ... }: with types; {
options = {
enableACME = mkOption {
type = bool;
description = "Use ACME to get SSL certificates for this site.";
default = true;
};
hostname = mkOption { siteOpts = { ... }:
type = str; with types; {
description = "Hostname of this server."; options = {
}; enableACME = mkOption {
type = bool;
site-config = mkOption { description = "Use ACME to get SSL certificates for this site.";
type = attrs; default = true;
description = "Site-specific configuration."; };
hostname = mkOption {
type = str;
description = "Hostname of this server.";
};
site-config = mkOption {
type = attrs;
description = "Site-specific configuration.";
};
}; };
}; };
};
config-dir = dirOf cfg.config-file; config-dir = dirOf cfg.config-file;
concatMapAttrs = f: attrs: concatMapAttrs = f: attrs: foldr (a: b: a // b) { } (mapAttrs f attrs);
foldr (a: b: a // b) {} (mapAttrs f attrs);
concatMapAttrsToList = f: attr: concatMapAttrsToList = f: attr:
concatMap (i: i) (attrValues (mapAttrs f attr)); concatMap (i: i) (attrValues (mapAttrs f attr));
host-domains = config.fudo.acme.host-domains.${hostname}; host-domains = config.fudo.acme.host-domains.${hostname};
hostCerts = host: let hostCerts = host:
cert-copy = host-domains.${host}.local-copies.ejabberd; let cert-copy = host-domains.${host}.local-copies.ejabberd;
in [ in [
cert-copy.certificate cert-copy.certificate
cert-copy.private-key cert-copy.private-key
# cert-copy.full-certificate # cert-copy.full-certificate
]; ];
hostCertService = host: hostCertService = host: host-domains.${host}.local-copies.ejabberd.service;
host-domains.${host}.local-copies.ejabberd.service;
config-file-template = let config-file-template = let
jabber-config = { jabber-config = {
@ -60,8 +59,7 @@ let
acl.admin = { acl.admin = {
user = concatMap user = concatMap
(admin: map (site: "${admin}@${site}") (admin: map (site: "${admin}@${site}") (attrNames cfg.sites))
(attrNames cfg.sites))
cfg.admins; cfg.admins;
}; };
@ -77,48 +75,41 @@ let
starttls = true; starttls = true;
starttls_required = true; starttls_required = true;
}; };
in in if (cfg.listen-ips != null) then
if (cfg.listen-ips != null) then map (ip: { ip = ip; } // common) cfg.listen-ips
map (ip: { ip = ip; } // common) else
cfg.listen-ips [ common ];
else [ common ];
certfiles = concatMapAttrsToList certfiles = concatMapAttrsToList (site: siteOpts:
(site: siteOpts: if (siteOpts.enableACME) then (hostCerts siteOpts.hostname) else [ ])
if (siteOpts.enableACME) then
(hostCerts siteOpts.hostname)
else [])
cfg.sites; cfg.sites;
host_config = host_config = mapAttrs (site: siteOpts: siteOpts.site-config) cfg.sites;
mapAttrs (site: siteOpts: siteOpts.site-config)
cfg.sites;
}; };
config-file = builtins.toJSON jabber-config; config-file = builtins.toJSON jabber-config;
in pkgs.lib.text.format-json-file in pkgs.lib.text.format-json-file
(pkgs.writeText "ejabberd.config.yml.template" config-file); (pkgs.writeText "ejabberd.config.yml.template" config-file);
enter-secrets = template: secrets: target: let enter-secrets = template: secrets: target:
secret-swappers = map let
(secret: "sed s/${secret}/\$${secret}/g") secret-swappers = map (secret: "sed s/${secret}/\$${secret}/g") secrets;
secrets; swapper = concatStringsSep " | " secret-swappers;
swapper = concatStringsSep " | " secret-swappers; in pkgs.writeShellScript "ejabberd-generate-config.sh" ''
in pkgs.writeShellScript "ejabberd-generate-config.sh" '' [ -f \$''${target} ] && rm -f ${target}
[ -f \$${target} ] && rm -f ${target} echo "Copying from ${template} to ${target}"
echo "Copying from ${template} to ${target}" touch ${target}
touch ${target} chmod go-rwx ${target}
chmod go-rwx ${target} chmod u+rw ${target}
chmod u+rw ${target} cat ${template} | ${swapper} > ${target}
cat ${template} | ${swapper} > ${target} echo "Copying from ${template} to ${target} completed"
echo "Copying from ${template} to ${target} completed" '';
'';
cfg = config.fudo.jabber; cfg = config.fudo.jabber;
log-dir = "${cfg.state-directory}/logs"; log-dir = "${cfg.state-directory}/logs";
spool-dir = "${cfg.state-directory}/spool"; spool-dir = "${cfg.state-directory}/spool";
in { in {
options.fudo.jabber = with types; { options.fudo.jabber = with types; {
enable = mkEnableOption "Enable ejabberd server."; enable = mkEnableOption "Enable ejabberd server.";
@ -128,7 +119,7 @@ in {
description = "IPs on which to listen for Jabber connections."; description = "IPs on which to listen for Jabber connections.";
default = null; default = null;
}; };
port = mkOption { port = mkOption {
type = port; type = port;
description = "Port on which to listen for Jabber connections."; description = "Port on which to listen for Jabber connections.";
@ -150,7 +141,7 @@ in {
admins = mkOption { admins = mkOption {
type = listOf str; type = listOf str;
description = "List of admin users for the server."; description = "List of admin users for the server.";
default = []; default = [ ];
}; };
sites = mkOption { sites = mkOption {
@ -160,8 +151,9 @@ in {
secret-files = mkOption { secret-files = mkOption {
type = attrsOf str; type = attrsOf str;
description = "Map of secret-name to file. File contents will be subbed for the name in the config."; description =
default = {}; "Map of secret-name to file. File contents will be subbed for the name in the config.";
default = { };
}; };
config-file = mkOption { config-file = mkOption {
@ -189,27 +181,20 @@ in {
environment = mkOption { environment = mkOption {
type = attrsOf str; type = attrsOf str;
description = "Environment variables to set for the ejabberd daemon."; description = "Environment variables to set for the ejabberd daemon.";
default = {}; default = { };
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
users = { users = {
users.${cfg.user} = { users.${cfg.user} = { isSystemUser = true; };
isSystemUser = true;
};
groups.${cfg.group} = { groups.${cfg.group} = { members = [ cfg.user ]; };
members = [ cfg.user ];
};
}; };
networking.firewall = { networking.firewall = { allowedTCPPorts = [ 5222 5223 5269 8010 ]; };
allowedTCPPorts = [ 5222 5223 5269 8010 ];
};
fudo = let fudo = let host-fqdn = config.instance.host-fqdn;
host-fqdn = config.instance.host-fqdn;
in { in {
acme.host-domains.${hostname} = mapAttrs' (site: siteOpts: acme.host-domains.${hostname} = mapAttrs' (site: siteOpts:
nameValuePair siteOpts.hostname { nameValuePair siteOpts.hostname {
@ -235,35 +220,39 @@ in {
"d ${config-dir} 0700 ${cfg.user} ${cfg.group} - -" "d ${config-dir} 0700 ${cfg.user} ${cfg.group} - -"
"d ${cfg.state-directory} 0750 ${cfg.user} ${cfg.group} - -" "d ${cfg.state-directory} 0750 ${cfg.user} ${cfg.group} - -"
]; ];
services = { services = {
ejabberd = { ejabberd = {
wants = wants = map hostCertService
map hostCertService (mapAttrsToList (_: siteOpts: siteOpts.hostname) cfg.sites);
(mapAttrsToList (_: siteOpts: siteOpts.hostname) cfg.sites);
requires = [ "ejabberd-config-generator.service" ]; requires = [ "ejabberd-config-generator.service" ];
environment = cfg.environment; environment = cfg.environment;
}; };
ejabberd-config-generator = let ejabberd-config-generator = let
config-generator = config-generator =
enter-secrets config-file-template (attrNames cfg.secret-files) cfg.config-file; enter-secrets config-file-template (attrNames cfg.secret-files)
cfg.config-file;
in { in {
description = "Generate ejabberd config file containing passwords."; description = "Generate ejabberd config file containing passwords.";
serviceConfig = { serviceConfig = {
User = cfg.user; User = cfg.user;
ExecStart = "${config-generator}"; ExecStart = "${config-generator}";
ExecStartPost = pkgs.writeShellScript "protect-ejabberd-config.sh" '' ExecStartPost =
chown ${cfg.user}:${cfg.group} ${cfg.config-file} pkgs.writeShellScript "protect-ejabberd-config.sh" ''
chmod 0400 ${cfg.config-file} chown ${cfg.user}:${cfg.group} ${cfg.config-file}
''; chmod 0400 ${cfg.config-file}
'';
EnvironmentFile = host-secrets.ejabberd-password-env.target-file; EnvironmentFile = host-secrets.ejabberd-password-env.target-file;
}; };
unitConfig.ConditionPathExists =
[ host-secrets.ejabberd-password-env.target-file ];
requires = [ host-secrets.ejabberd-password-env.service ]; requires = [ host-secrets.ejabberd-password-env.service ];
after = [ host-secrets.ejabberd-password-env.service ];
}; };
}; };
}; };
services.ejabberd = { services.ejabberd = {
enable = true; enable = true;