frumar: move from acme.sh to lego
parent
ca432e86f1
commit
734a2fc02f
|
@ -16,13 +16,13 @@
|
||||||
}) ];
|
}) ];
|
||||||
|
|
||||||
systemd.tmpfiles.rules = lib.mkAfter [
|
systemd.tmpfiles.rules = lib.mkAfter [
|
||||||
"d ${config.services.acme-sh.stateDir}/selfsign 0700 nginx nginx"
|
"d /var/lib/acme.sh/selfsign 0700 nginx nginx"
|
||||||
];
|
];
|
||||||
systemd.services."yori-selfsigned-ca" = {
|
systemd.services."yori-selfsigned-ca" = {
|
||||||
description = "Generate self-signed fallback";
|
description = "Generate self-signed fallback";
|
||||||
path = with pkgs; [ minica ];
|
path = with pkgs; [ minica ];
|
||||||
unitConfig = {
|
unitConfig = {
|
||||||
ConditionPathExists = "!${config.services.acme-sh.stateDir}/selfsign/selfsigned.local/key.pem";
|
ConditionPathExists = "!/var/lib/acme.sh/selfsign/selfsigned.local/key.pem";
|
||||||
StartLimitIntervalSec = 0;
|
StartLimitIntervalSec = 0;
|
||||||
};
|
};
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
UMask = "0077";
|
UMask = "0077";
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
PrivateTmp = true;
|
PrivateTmp = true;
|
||||||
WorkingDirectory = "${config.services.acme-sh.stateDir}/selfsign";
|
WorkingDirectory = "/var/lib/acme.sh/selfsign";
|
||||||
};
|
};
|
||||||
script = "minica --domains selfsigned.local";
|
script = "minica --domains selfsigned.local";
|
||||||
};
|
};
|
||||||
|
@ -40,19 +40,11 @@
|
||||||
after = [ "yori-selfsigned-ca.service" ];
|
after = [ "yori-selfsigned-ca.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx = let
|
services.nginx = {
|
||||||
cert = config.services.acme-sh.certs.wildcard-yori-cc;
|
|
||||||
sslCertificate = cert.certPath;
|
|
||||||
sslCertificateKey = cert.keyPath;
|
|
||||||
in {
|
|
||||||
enable = true;
|
enable = true;
|
||||||
recommendedOptimisation = true;
|
|
||||||
recommendedTlsSettings = true;
|
|
||||||
recommendedProxySettings = true;
|
|
||||||
recommendedGzipSettings = true;
|
|
||||||
virtualHosts."unifi.yori.cc" = {
|
virtualHosts."unifi.yori.cc" = {
|
||||||
onlySSL = true;
|
onlySSL = true;
|
||||||
inherit sslCertificate sslCertificateKey;
|
useACMEHost = "wildcard.yori.cc";
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "https://[::1]:8443";
|
proxyPass = "https://[::1]:8443";
|
||||||
proxyWebsockets = true;
|
proxyWebsockets = true;
|
||||||
|
@ -64,7 +56,7 @@
|
||||||
};
|
};
|
||||||
virtualHosts."home-assistant.yori.cc" = {
|
virtualHosts."home-assistant.yori.cc" = {
|
||||||
onlySSL = true;
|
onlySSL = true;
|
||||||
inherit sslCertificate sslCertificateKey;
|
useACMEHost = "wildcard.yori.cc";
|
||||||
locations."/" = {
|
locations."/" = {
|
||||||
proxyPass = "http://[::1]:8123";
|
proxyPass = "http://[::1]:8123";
|
||||||
proxyWebsockets = true;
|
proxyWebsockets = true;
|
||||||
|
@ -72,10 +64,8 @@
|
||||||
};
|
};
|
||||||
virtualHosts."frumar.yori.cc" = {
|
virtualHosts."frumar.yori.cc" = {
|
||||||
enableACME = lib.mkForce false;
|
enableACME = lib.mkForce false;
|
||||||
forceSSL = true;
|
|
||||||
sslCertificate = "/var/lib/acme.sh/selfsign/selfsigned.local/cert.pem";
|
sslCertificate = "/var/lib/acme.sh/selfsign/selfsigned.local/cert.pem";
|
||||||
sslCertificateKey = "/var/lib/acme.sh/selfsign/selfsigned.local/key.pem";
|
sslCertificateKey = "/var/lib/acme.sh/selfsign/selfsigned.local/key.pem";
|
||||||
default = true;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
boot.supportedFilesystems = [ "zfs" ];
|
boot.supportedFilesystems = [ "zfs" ];
|
||||||
|
@ -235,11 +225,10 @@
|
||||||
age.secrets = {
|
age.secrets = {
|
||||||
grafana.file = ../../../secrets/grafana.env.age;
|
grafana.file = ../../../secrets/grafana.env.age;
|
||||||
frumar-mail-pass.file = ../../../secrets/frumar-mail-pass.age;
|
frumar-mail-pass.file = ../../../secrets/frumar-mail-pass.age;
|
||||||
transip-key = {
|
acme-transip-key = {
|
||||||
file = ../../../secrets/transip-key.age;
|
file = ../../../secrets/transip-key.age;
|
||||||
mode = "770";
|
mode = "770";
|
||||||
owner = "nginx";
|
group = "acme";
|
||||||
group = "nginx";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
systemd.services.grafana.serviceConfig.EnvironmentFile = config.age.secrets.grafana.path;
|
systemd.services.grafana.serviceConfig.EnvironmentFile = config.age.secrets.grafana.path;
|
||||||
|
@ -324,16 +313,15 @@
|
||||||
unzip
|
unzip
|
||||||
yscripts.absorb
|
yscripts.absorb
|
||||||
];
|
];
|
||||||
services.acme-sh.certs.wildcard-yori-cc = {
|
security.acme.certs."wildcard.yori.cc" = {
|
||||||
mainDomain = "*.yori.cc";
|
domain = "*.yori.cc";
|
||||||
dns = "dns_transip";
|
dnsProvider = "transip";
|
||||||
production = true;
|
reloadServices = [ "nginx.service" ];
|
||||||
postRun = "systemctl reload nginx || true";
|
|
||||||
inherit (config.services.nginx) user group;
|
|
||||||
};
|
};
|
||||||
systemd.services.acme-sh-wildcard-yori-cc.environment = {
|
users.users.nginx.extraGroups = [ "acme" ];
|
||||||
TRANSIP_Username = "yorickvp";
|
systemd.services."acme-wildcard.yori.cc".environment = {
|
||||||
TRANSIP_Key_File = config.age.secrets.transip-key.path;
|
TRANSIP_ACCOUNT_NAME = "yorickvp";
|
||||||
|
TRANSIP_PRIVATE_KEY_PATH = config.age.secrets.acme-transip-key.path;
|
||||||
};
|
};
|
||||||
programs.msmtp = {
|
programs.msmtp = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
@ -1,166 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2020 Serokell <https://serokell.io/>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.services.acme-sh;
|
|
||||||
# todo: upstream into serokell.nix
|
|
||||||
dnstype = lib.types.enum [ "dns_aws" "dns_dnsimple" "dns_transip" ];
|
|
||||||
submod = with lib; config: {
|
|
||||||
domains = mkOption {
|
|
||||||
type = types.coercedTo
|
|
||||||
(types.listOf types.str)
|
|
||||||
(f: lib.genAttrs f (x: config.dns)) (types.attrsOf dnstype);
|
|
||||||
default = { "${config.mainDomain}" = config.dns; };
|
|
||||||
};
|
|
||||||
mainDomain = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "domain to use as primary domain for the cert";
|
|
||||||
};
|
|
||||||
postRun = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "true";
|
|
||||||
};
|
|
||||||
keyFile = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
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.";
|
|
||||||
};
|
|
||||||
|
|
||||||
server = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "letsencrypt";
|
|
||||||
description = "Certificate Authority to use";
|
|
||||||
};
|
|
||||||
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.str;
|
|
||||||
};
|
|
||||||
keyPath = mkOption {
|
|
||||||
readOnly = true;
|
|
||||||
type = types.str;
|
|
||||||
};
|
|
||||||
certPath = mkOption {
|
|
||||||
readOnly = true;
|
|
||||||
type = types.str;
|
|
||||||
};
|
|
||||||
consulLock = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
example = "vault";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.services.acme-sh = with lib; {
|
|
||||||
stateDir = lib.mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "/var/lib/acme.sh";
|
|
||||||
};
|
|
||||||
certs = lib.mkOption {
|
|
||||||
type = types.attrsOf (types.submodule ({config, name, ...}: (with config; {
|
|
||||||
options = submod config;
|
|
||||||
config.statePath = "${cfg.stateDir}/${name}";
|
|
||||||
config.keyPath = "${statePath}/${mainDomain}_ecc/${mainDomain}.key";
|
|
||||||
config.certPath = "${statePath}/${mainDomain}_ecc/fullchain.cer";
|
|
||||||
})));
|
|
||||||
default = {};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config = {
|
|
||||||
systemd.tmpfiles.rules = if cfg.certs != {} then [
|
|
||||||
"d ${cfg.stateDir} 0755 root root"
|
|
||||||
] else [];
|
|
||||||
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" ]
|
|
||||||
# wait for consul if we use it for locking
|
|
||||||
++ lib.optionals (consulLock != null) [ "consul.service" ];
|
|
||||||
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 util-linuxMinimal procps ];
|
|
||||||
preStart = ''
|
|
||||||
mkdir -p "${statePath}"
|
|
||||||
chown -R '${user}:${group}' "${statePath}"
|
|
||||||
chmod 750 "${statePath}"
|
|
||||||
rm -f "${statePath}/renewed"
|
|
||||||
'';
|
|
||||||
environment.LE_WORKING_DIR = statePath;
|
|
||||||
environment.SHELL = "${pkgs.bash}/bin/bash";
|
|
||||||
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)));
|
|
||||||
cmd = ''acme.sh --server ${server} --issue ${lib.optionalString (!production) "--test"} ${domainsStr} --reloadcmd "touch ${statePath}/renewed" --syslog 6 > /dev/null'';
|
|
||||||
in
|
|
||||||
if consulLock == null then ''
|
|
||||||
${cmd}
|
|
||||||
rm -f "$LE_WORKING_DIR/account.conf"
|
|
||||||
'' else ''
|
|
||||||
# consul lock does not expose the exit code, because of platform compatiblity or something
|
|
||||||
# write it to the 'ecode' file, or exit 1 if it fails altogether
|
|
||||||
if ${config.services.consul.package}/bin/consul lock -verbose "${consulLock}" '${cmd}; echo $? > ${statePath}/ecode'; then
|
|
||||||
rm -f "$LE_WORKING_DIR/account.conf"
|
|
||||||
exit $(cat ${statePath}/ecode)
|
|
||||||
else
|
|
||||||
rm -f "$LE_WORKING_DIR/account.conf"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,14 +1,6 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
let
|
|
||||||
sslcfg = dir: ''
|
|
||||||
ssl on;
|
|
||||||
ssl_certificate_key ${dir}/key.pem;
|
|
||||||
ssl_certificate ${dir}/fullchain.pem;
|
|
||||||
ssl_trusted_certificate ${dir}/fullchain.pem;
|
|
||||||
add_header Strict-Transport-Security max-age=15768000;
|
|
||||||
'';
|
|
||||||
|
|
||||||
in {
|
{
|
||||||
config = lib.mkIf config.services.nginx.enable {
|
config = lib.mkIf config.services.nginx.enable {
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
recommendedTlsSettings = true;
|
recommendedTlsSettings = true;
|
||||||
|
|
|
@ -5,7 +5,6 @@ let
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
inputs.agenix.nixosModules.default
|
inputs.agenix.nixosModules.default
|
||||||
../modules/acme-sh.nix
|
|
||||||
../modules/tor-hidden-service.nix
|
../modules/tor-hidden-service.nix
|
||||||
../modules/nginx.nix
|
../modules/nginx.nix
|
||||||
../modules/lumi-cache.nix
|
../modules/lumi-cache.nix
|
||||||
|
|
Loading…
Reference in New Issue