Last active
September 12, 2019 12:17
-
-
Save yorickvP/b98ea74a233c9d525f0904eff86b3699 to your computer and use it in GitHub Desktop.
acme.sh nix module, written at Serokell
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ config, lib, pkgs, ... }: | |
let | |
cfg = config.services.acme-sh; | |
dnstype = lib.types.enum [ "dns_aws" "dns_dnsimple" ]; | |
submod = with lib; { | |
domains = mkOption { | |
type = types.coercedTo (types.listOf types.string) | |
(f: lib.genAttrs f (x: cfg.dns)) (types.attrsOf dnstype); | |
default = { "${cfg.mainDomain}" = cfg.dns; }; | |
}; | |
mainDomain = mkOption { | |
type = types.string; | |
description = "domain to use as primary domain for the cert"; | |
}; | |
postRun = mkOption { | |
type = types.string; | |
default = "true"; | |
}; | |
keyFile = mkOption { | |
type = types.string; | |
default = "/dev/null"; | |
}; | |
user = mkOption { | |
type = types.str; | |
default = "root"; | |
description = "User running the ACME client."; | |
}; | |
group = mkOption { | |
type = types.str; | |
default = "root"; | |
description = "Group running the ACME client."; | |
}; | |
dns = mkOption { type = dnstype; }; | |
renewInterval = mkOption { | |
type = types.str; | |
default = "weekly"; | |
description = '' | |
Systemd calendar expression when to check for renewal. See | |
<citerefentry><refentrytitle>systemd.time</refentrytitle> | |
<manvolnum>7</manvolnum></citerefentry>. | |
''; | |
}; | |
production = mkOption { | |
type = types.bool; | |
default = true; | |
}; | |
statePath = mkOption { | |
readOnly = true; | |
type = types.string; | |
}; | |
keyPath = mkOption { | |
readOnly = true; | |
type = types.string; | |
}; | |
certPath = mkOption { | |
readOnly = true; | |
type = types.string; | |
}; | |
}; | |
in { | |
options.services.acme-sh = with lib; { | |
stateDir = lib.mkOption { | |
type = types.string; | |
default = "/var/lib/acme.sh"; | |
}; | |
certs = lib.mkOption { | |
type = types.attrsOf (types.submodule ({ config, name, ... }: | |
(with config; { | |
options = submod; | |
config.statePath = "${cfg.stateDir}/${name}"; | |
config.keyPath = "${statePath}/${mainDomain}/${mainDomain}.key"; | |
config.certPath = "${statePath}/${mainDomain}/fullchain.cer"; | |
}))); | |
default = { }; | |
}; | |
}; | |
config = { | |
systemd.services = lib.mapAttrs' (name: value: | |
lib.nameValuePair "acme-sh-${name}" (with value; { | |
description = "Renew ACME Certificate for ${name}"; | |
after = [ "network.target" "network-online.target" ]; | |
wants = [ "network-online.target" ]; | |
serviceConfig = { | |
Type = "oneshot"; | |
PermissionsStartOnly = true; | |
User = user; | |
Group = group; | |
PrivateTmp = true; | |
EnvironmentFile = keyFile; | |
SuccessExitStatus = "0 2"; | |
}; | |
path = with pkgs; [ acme-sh systemd utillinuxMinimal procps ]; | |
preStart = '' | |
mkdir -p ${cfg.stateDir} | |
chown 'root:root' ${cfg.stateDir} | |
chmod 755 ${cfg.stateDir} | |
mkdir -p "${statePath}" | |
chown -R '${user}:${group}' "${statePath}" | |
chmod 700 "${statePath}" | |
rm -f "${statePath}/renewed" | |
''; | |
environment.LE_WORKING_DIR = statePath; | |
script = let | |
mapDomain = name: dns: ''-d "${name}" --dns ${dns}''; | |
primary = mapDomain mainDomain domains."${mainDomain}"; | |
domainsStr = lib.concatStringsSep " " ([ primary ] | |
++ (lib.remove primary (lib.mapAttrsToList mapDomain domains))); | |
in '' | |
acme.sh --issue ${ | |
lib.optionalString (!production) "--test" | |
} ${domainsStr} --reloadcmd "touch ${statePath}/renewed" --syslog 6 > /dev/null | |
rm "$LE_WORKING_DIR/account.conf" | |
''; | |
postStart = '' | |
if [ -e "${statePath}/renewed" ]; then | |
${postRun} | |
rm -f "${statePath}/renewed" | |
fi | |
''; | |
})) cfg.certs; | |
systemd.timers = lib.mapAttrs' (name: value: | |
lib.nameValuePair "acme-sh-${name}" (with value; { | |
wantedBy = [ "timers.target" ]; | |
timerConfig = { | |
OnCalendar = renewInterval; | |
Unit = "acme-sh-${name}.service"; | |
Persistent = "yes"; | |
AccuracySec = "5m"; | |
RandomizedDelaySec = "1h"; | |
}; | |
})) cfg.certs; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment