blob: b1c05888cf999ff172a1e1c9f0b6c603f5781248 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
{ config, lib, customUtils, pkgs, ... }:
with lib;
let
tsigSecretName = domain: "${domain}_tsig-secret";
tsigKey = domain:
let
tsigKeyPath = ./tsig_keys + "/${domain}";
in assert assertMsg (pathExists tsigKeyPath) "‘${domain}’ does not exist in `tls/tsig_keys` -- is this a new ACME domain and you forgot to generate the TSIG key? If so, run `gup tls/tsig_keys/${domain}`"; tsigKeyPath;
cfg = config.security.acme;
in {
options = {
security.acme = {
# This file introduces an additional nixos module option
# `security.acme.rfc2136Domains`.
# The new option is an attrset of domain names mapping to
# additional settings.
rfc2136Domains = mkOption {
type = types.attrsOf (types.submodule {
options = {
wildcard = mkOption {
type = types.bool;
default = false;
};
restartUnits = mkOption {
type = types.listOf types.str;
default = [];
};
};
});
default = {};
};
};
};
config = {
security.acme = {
# Some default/global ACME settings
acceptTerms = true;
# DNS challenge is slow
preliminarySelfsigned = true;
defaults = {
email = "phikeebaogobaegh@141.li";
# We don't like NIST curves and Let's Encrypt doesn't support
# anything better
keyType = "rsa4096";
};
# For each domain specified in
# `config.security.acme.rfc2136Domains`, configure an additional
# entry in `config.security.acme.certs` containing appropriate
# settings to provision the certificate via DNS-01
certs = mapAttrs (domain: domainCfg: {
inherit domain;
extraDomainNames = optional domainCfg.wildcard "*.${domain}";
dnsResolver = "127.0.0.1:53";
dnsProvider = "rfc2136";
credentialsFile = pkgs.writeText "${domain}_credentials.env" ''
RFC2136_NAMESERVER=127.0.0.1:53
RFC2136_TSIG_ALGORITHM=hmac-sha256.
RFC2136_TSIG_KEY=${domain}_acme_key
RFC2136_TSIG_SECRET_FILE=/run/credentials/acme-${domain}.service/${tsigSecretName domain}
RFC2136_TTL=0
RFC2136_PROPAGATION_TIMEOUT=60
RFC2136_POLLING_INTERVAL=2
RFC2136_SEQUENCE_INTERVAL=1
'';
dnsPropagationCheck = false;
postRun = mkIf (domainCfg.restartUnits != []) ''
systemctl --no-block try-restart ${escapeShellArgs domainCfg.restartUnits}
'';
}) cfg.rfc2136Domains;
};
# Decrypt all `tsig_keys/*` at runtime
sops.secrets = mapAttrs' (domain: domainCfg: nameValuePair (tsigSecretName domain) {
format = "binary";
sopsFile = tsigKey domain;
restartUnits = [ "acme-${domain}.service" ];
}) cfg.rfc2136Domains;
# Provide appropriate `tsig_key/*` to systemd service performing
# certificate provisioning
systemd.services = mapAttrs' (domain: domainCfg: nameValuePair "acme-${domain}" {
after = [ "knot.service" ];
bindsTo = [ "knot.service" ];
serviceConfig = {
LoadCredential = [ "${tsigSecretName domain}:${config.sops.secrets.${tsigSecretName domain}.path}" ];
SystemCallFilter = mkForce [ "@system-service" "~@privileged" "@chown" ];
};
}) cfg.rfc2136Domains;
};
}
|