nixos/acme: Remove all systemd-tmpfiles usage
- Added an ExecPostStart to acme-$cert.service when webroot is defined to create the acme-challenge directory and fix required permissions. Lego always tries to create .well-known and acme-challenge, thus if any permissions in that tree are wrong it will crash and break cert renewal. - acme-fixperms now configured with acme User and Group, however the script still runs as root. This ensures the StateDirectories are owned by the acme user. - Switched to list syntax for systemd options where multiple values are specified.
This commit is contained in:
parent
bfe07e2179
commit
92a3a37153
@ -62,24 +62,30 @@ let
|
|||||||
# Ensures that directories which are shared across all certs
|
# Ensures that directories which are shared across all certs
|
||||||
# exist and have the correct user and group, since group
|
# exist and have the correct user and group, since group
|
||||||
# is configurable on a per-cert basis.
|
# is configurable on a per-cert basis.
|
||||||
userMigrationService = {
|
userMigrationService = let
|
||||||
description = "Fix owner and group of all ACME certificates";
|
|
||||||
|
|
||||||
script = with builtins; concatStringsSep "\n" (mapAttrsToList (cert: data: ''
|
script = with builtins; concatStringsSep "\n" (mapAttrsToList (cert: data: ''
|
||||||
for fixpath in /var/lib/acme/${escapeShellArg cert} /var/lib/acme/.lego/${escapeShellArg cert}; do
|
chown -R acme .lego/accounts
|
||||||
|
for fixpath in ${escapeShellArg cert} .lego/${escapeShellArg cert}; do
|
||||||
if [ -d "$fixpath" ]; then
|
if [ -d "$fixpath" ]; then
|
||||||
chmod -R u=rwX,g=rX,o= "$fixpath"
|
chmod -R u=rwX,g=rX,o= "$fixpath"
|
||||||
chown -R acme:${data.group} "$fixpath"
|
chown -R acme:${data.group} "$fixpath"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
'') certConfigs);
|
'') certConfigs);
|
||||||
|
in {
|
||||||
|
description = "Fix owner and group of all ACME certificates";
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = commonServiceConfig // {
|
||||||
# We don't want this to run every time a renewal happens
|
# We don't want this to run every time a renewal happens
|
||||||
RemainAfterExit = true;
|
RemainAfterExit = true;
|
||||||
|
|
||||||
# These StateDirectory entries negate the need for tmpfiles
|
# These StateDirectory entries negate the need for tmpfiles
|
||||||
StateDirectory = "acme acme/.lego acme/.lego/accounts";
|
StateDirectory = [ "acme" "acme/.lego" "acme/.lego/accounts" ];
|
||||||
|
StateDirectoryMode = 755;
|
||||||
|
WorkingDirectory = "/var/lib/acme";
|
||||||
|
|
||||||
|
# Run the start script as root
|
||||||
|
ExecStart = "+" + (pkgs.writeShellScript "acme-fixperms" script);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -153,7 +159,6 @@ let
|
|||||||
in {
|
in {
|
||||||
inherit accountHash cert selfsignedDeps;
|
inherit accountHash cert selfsignedDeps;
|
||||||
|
|
||||||
webroot = data.webroot;
|
|
||||||
group = data.group;
|
group = data.group;
|
||||||
|
|
||||||
renewTimer = {
|
renewTimer = {
|
||||||
@ -193,7 +198,10 @@ let
|
|||||||
|
|
||||||
StateDirectory = "acme/${cert}";
|
StateDirectory = "acme/${cert}";
|
||||||
|
|
||||||
BindPaths = "/var/lib/acme/.minica:/tmp/ca /var/lib/acme/${cert}:/tmp/${keyName}";
|
BindPaths = [
|
||||||
|
"/var/lib/acme/.minica:/tmp/ca"
|
||||||
|
"/var/lib/acme/${cert}:/tmp/${keyName}"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Working directory will be /tmp
|
# Working directory will be /tmp
|
||||||
@ -234,17 +242,19 @@ let
|
|||||||
# Keep in mind that these directories will be deleted if the user runs
|
# Keep in mind that these directories will be deleted if the user runs
|
||||||
# systemctl clean --what=state
|
# systemctl clean --what=state
|
||||||
# acme/.lego/${cert} is listed for this reason.
|
# acme/.lego/${cert} is listed for this reason.
|
||||||
StateDirectory =
|
StateDirectory = [
|
||||||
"acme/${cert} " +
|
"acme/${cert}"
|
||||||
"acme/.lego/${cert} " +
|
"acme/.lego/${cert}"
|
||||||
"acme/.lego/${cert}/${certDir} " +
|
"acme/.lego/${cert}/${certDir}"
|
||||||
"acme/.lego/accounts/${accountHash} ";
|
"acme/.lego/accounts/${accountHash}"
|
||||||
|
];
|
||||||
|
|
||||||
# Needs to be space separated, but can't use a multiline string because that'll include newlines
|
# Needs to be space separated, but can't use a multiline string because that'll include newlines
|
||||||
BindPaths =
|
BindPaths = [
|
||||||
"${accountDir}:/tmp/accounts " +
|
"${accountDir}:/tmp/accounts"
|
||||||
"/var/lib/acme/${cert}:/tmp/out " +
|
"/var/lib/acme/${cert}:/tmp/out"
|
||||||
"/var/lib/acme/.lego/${cert}/${certDir}:/tmp/certificates ";
|
"/var/lib/acme/.lego/${cert}/${certDir}:/tmp/certificates"
|
||||||
|
];
|
||||||
|
|
||||||
# Only try loading the credentialsFile if the dns challenge is enabled
|
# Only try loading the credentialsFile if the dns challenge is enabled
|
||||||
EnvironmentFile = mkIf useDns data.credentialsFile;
|
EnvironmentFile = mkIf useDns data.credentialsFile;
|
||||||
@ -257,7 +267,16 @@ let
|
|||||||
${data.postRun}
|
${data.postRun}
|
||||||
fi
|
fi
|
||||||
'');
|
'');
|
||||||
};
|
|
||||||
|
} // (optionalAttrs (data.webroot != null) {
|
||||||
|
# Lego always tries to create .well-known/acme-challenge, but if webroot is owned
|
||||||
|
# by the wrong user then it will crash and break cert renewal.
|
||||||
|
ExecStartPre = "+" + pkgs.writeShellScript "acme-${cert}-make-webroot" ''
|
||||||
|
mkdir -p '${data.webroot}/.well-known/acme-challenge'
|
||||||
|
cd '${data.webroot}'
|
||||||
|
chown 'acme:${data.group}' . .well-known .well-known/acme-challenge
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
# Working directory will be /tmp
|
# Working directory will be /tmp
|
||||||
script = ''
|
script = ''
|
||||||
@ -676,15 +695,6 @@ in {
|
|||||||
|
|
||||||
systemd.timers = mapAttrs' (cert: conf: nameValuePair "acme-${cert}" conf.renewTimer) certConfigs;
|
systemd.timers = mapAttrs' (cert: conf: nameValuePair "acme-${cert}" conf.renewTimer) certConfigs;
|
||||||
|
|
||||||
systemd.tmpfiles.rules = unique (
|
|
||||||
flatten (
|
|
||||||
mapAttrsToList (
|
|
||||||
cert: conf:
|
|
||||||
optional (conf.webroot != null) "d ${conf.webroot}/.well-known/acme-challenge - acme ${conf.group}"
|
|
||||||
) certConfigs
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
systemd.targets = let
|
systemd.targets = let
|
||||||
# Create some targets which can be depended on to be "active" after cert renewals
|
# Create some targets which can be depended on to be "active" after cert renewals
|
||||||
finishedTargets = mapAttrs' (cert: conf: nameValuePair "acme-finished-${cert}" {
|
finishedTargets = mapAttrs' (cert: conf: nameValuePair "acme-finished-${cert}" {
|
||||||
|
Loading…
Reference in New Issue
Block a user