nixos/security: add acme through dns challenge
few side refactors of this: - no more `dns.domain`, it all must rely on `fqdn`, prevents inconsistencies. - also added an specific host `tuxcord-acmetest` that uses the key zone for `nix.tuxcord.net` to test certificate pulling.
This commit is contained in:
@@ -0,0 +1,19 @@
|
|||||||
|
age-encryption.org/v1
|
||||||
|
-> ssh-ed25519 Wl2fDA sLlStq5Hzb2JNQubLtMk5/kyIp81aTyjUB/Ysv1gRR0
|
||||||
|
lTLWsvT5Oxk8ut/g+o9o0DMOIQVDmi9o4EO0fYeIToo
|
||||||
|
-> ssh-ed25519 zNC8SA G0XcS2gzF0RopI2DqkWaTYXwjUpkVtdrxSQ+p8bfE0w
|
||||||
|
pZVIg/1P8BbnpRfV5F0FG3xgLSiA8M+nosQ8iNeYmcU
|
||||||
|
-> ssh-ed25519 EiAAKw qWmO0IjKoUFVxbxFUx36JIhME2PU7lkD+3agKO7+6nA
|
||||||
|
yEIw8IzQmM8C9dZoPajtvdUOF5kJ/C+rtgLczcmP1bs
|
||||||
|
-> ssh-rsa eFi+Zw
|
||||||
|
O5XRvS+Y/1mm9nQ7IZmxEp7RmFjAH0OTKPkRTME7BybnePPZLL0l6wMP26hx88Nv
|
||||||
|
dOqdaS07Xb26EIgCS/4xCY4sPWZNEfAfnDVoF4/SNbmfbN0XpNpR981AWcxiTL35
|
||||||
|
Fngk0lPa1NtuUH4S4zTda21kXHE0zv2mYLNMuek8dTrUd2piC+Z0WJJdrG1LK0hN
|
||||||
|
dDuLzX/mNibNXDvYxyD6mtkO2S1wO9QL88ucNZptT29vcaD48EZM/SsAwgf3OoqH
|
||||||
|
kd7jSTTdZ/yk8ccTMiT5eskQ3ZZcqc7JaF+M2d88DP6LcSaJnNzyVSEMAHHfpoY1
|
||||||
|
/kHxZ88/ehwPDXrp0bL448jdPuWqPSerzCWyyZFbc8Jj6zRUtC5joL0Vq2Rqs+EH
|
||||||
|
rmKMfi1l2+utleGYfCyHI5/czsMhJ2jXLGPguWQQdixNtb/RWFw6DeRP9xdO9QJR
|
||||||
|
LkoAFgv0ykP+L+C6sA7bpJqIGNftl4x8OUQxrKtf3YQ8K2LhUZb23JPn4Ob/QXo/
|
||||||
|
|
||||||
|
--- W7eUDhB/RBUYV1gaM4ktPEOVU6l5IRgOoRDpKKpvAnM
|
||||||
|
O\òŒMúOýJä ÍÅ!ÒHûËÄpK¥Õ:gßÙ[6™M¡VÞÃbYæÌí;è€F'¡#ä7&Žs1„ 󨱉6º�²5_nÂ’mõÔ.¼qñ'à˜ƒq®6Êf-ÖÄW™w›½ß#5³¯6ˆ¼ŸêªrÒð�„Ð#œÅÄ€=�4EÎËlžÕÿ[
|
||||||
@@ -12,4 +12,6 @@ in
|
|||||||
|
|
||||||
"dns/tuxcord.test/tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
|
"dns/tuxcord.test/tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
|
||||||
"dns/tuxcord.test/sub.tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
|
"dns/tuxcord.test/sub.tuxcord.test.key.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
|
||||||
|
|
||||||
|
"dns/nix.tuxcord.net/nix.tuxcord.net.key.age".publicKeys = [ tuxcord-ca ] ++ builtins.attrValues users;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ in
|
|||||||
./vm.nix
|
./vm.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
age.secrets.ntfy.file = "${self}/agenix/ntfy.age";
|
||||||
|
|
||||||
nix = {
|
nix = {
|
||||||
package = inputs'.nix-super.packages.default;
|
package = inputs'.nix-super.packages.default;
|
||||||
|
|
||||||
|
|||||||
@@ -33,5 +33,6 @@ in
|
|||||||
tuxcord-ca = mkSystem "tuxcord-ca" "x86_64-linux";
|
tuxcord-ca = mkSystem "tuxcord-ca" "x86_64-linux";
|
||||||
|
|
||||||
tuxcord-test = mkSystem "tuxcord-test" "x86_64-linux";
|
tuxcord-test = mkSystem "tuxcord-test" "x86_64-linux";
|
||||||
|
tuxcord-acmetest = mkSystem "tuxcord-acmetest" "x86_64-linux";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
acme = {
|
||||||
|
enable = true;
|
||||||
|
rfc2136.nameserver = "tuxcord.net";
|
||||||
|
};
|
||||||
|
|
||||||
|
dns.enable = true;
|
||||||
|
networking.fqdn = "nix.tuxcord.net";
|
||||||
|
|
||||||
|
time.timeZone = "Europe/Madrid";
|
||||||
|
}
|
||||||
@@ -4,6 +4,11 @@
|
|||||||
./storage.nix
|
./storage.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
acme = {
|
||||||
|
enable = true;
|
||||||
|
useSelfDns = true;
|
||||||
|
};
|
||||||
|
|
||||||
dns.enable = true;
|
dns.enable = true;
|
||||||
networking.fqdn = "tuxcord.net";
|
networking.fqdn = "tuxcord.net";
|
||||||
time.timeZone = "Canada/Eastern";
|
time.timeZone = "Canada/Eastern";
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
acme.enable = false;
|
||||||
dns.enable = true;
|
dns.enable = true;
|
||||||
networking.fqdn = "tuxcord.test";
|
networking.fqdn = "tuxcord.test";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.acme;
|
||||||
|
|
||||||
|
inherit (lib)
|
||||||
|
mkIf
|
||||||
|
mkEnableOption
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (config.networking) fqdn;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# we'll only support rfc2136 based challenges
|
||||||
|
options.acme = {
|
||||||
|
enable = mkEnableOption "" // {
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
useSelfDns = mkOption {
|
||||||
|
default = false;
|
||||||
|
description = "Sets values of the self DNS if enabled, otherwise requires manual `rfc2136` nameserver and key values.";
|
||||||
|
};
|
||||||
|
|
||||||
|
rfc2136 = {
|
||||||
|
key = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = config.age.secrets."dns/${fqdn}.key.age".path;
|
||||||
|
};
|
||||||
|
|
||||||
|
nameserver = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = if cfg.useSelfDns then fqdn else null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = with cfg.rfc2136; nameserver != null && key != null;
|
||||||
|
message = "ACME needs rfc2136 parameters to work, consider using `useSelfDns` option.";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.persistence."/persist".directories = [
|
||||||
|
{
|
||||||
|
directory = "/var/lib/acme";
|
||||||
|
group = "acme";
|
||||||
|
user = "acme";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
security.acme = {
|
||||||
|
acceptTerms = true;
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
email = "error@tuxcord.net";
|
||||||
|
reloadServices = [ "nginx" ];
|
||||||
|
postRun = ''
|
||||||
|
source ${config.age.secrets.ntfy.path}
|
||||||
|
${pkgs.ntfy-sh}/bin/ntfy publish -T recycle -t "${config.host.name}" "HTTPS certificate has been renewed"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
certs."${fqdn}" = {
|
||||||
|
dnsProvider = "rfc2136";
|
||||||
|
environmentFile =
|
||||||
|
with cfg.rfc2136;
|
||||||
|
builtins.toFile "dns-01-challenge.cfg" ''
|
||||||
|
RFC2136_NAMESERVER=${nameserver}
|
||||||
|
RFC2136_TSIG_FILE="${key}"
|
||||||
|
'';
|
||||||
|
extraDomainNames = [
|
||||||
|
"*.${fqdn}"
|
||||||
|
"${fqdn}"
|
||||||
|
];
|
||||||
|
|
||||||
|
inherit (config.services.nginx) group;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
|
./acme.nix
|
||||||
./dns.nix
|
./dns.nix
|
||||||
./fail2ban.nix
|
./fail2ban.nix
|
||||||
./gitea.nix
|
./gitea.nix
|
||||||
|
|||||||
+16
-10
@@ -1,6 +1,16 @@
|
|||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
let
|
let
|
||||||
agenixDnsDir = ../../agenix/dns + "/${config.dns.domain}";
|
cfg = config.dns;
|
||||||
|
|
||||||
|
inherit (lib)
|
||||||
|
mkEnableOption
|
||||||
|
mkIf
|
||||||
|
strings
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (config.networking) fqdn;
|
||||||
|
|
||||||
|
agenixDnsDir = "${self}/agenix/dns/${fqdn}";
|
||||||
agenixKeys = builtins.attrNames (builtins.readDir agenixDnsDir);
|
agenixKeys = builtins.attrNames (builtins.readDir agenixDnsDir);
|
||||||
|
|
||||||
keys = map (
|
keys = map (
|
||||||
@@ -18,7 +28,7 @@ let
|
|||||||
{
|
{
|
||||||
name = zoneDomain;
|
name = zoneDomain;
|
||||||
path = config.age.secrets."dns/${filename}".path;
|
path = config.age.secrets."dns/${filename}".path;
|
||||||
type = if zoneDomain == config.dns.domain then zonesub else subdomain;
|
type = if zoneDomain == fqdn then zonesub else subdomain;
|
||||||
}
|
}
|
||||||
) agenixKeys;
|
) agenixKeys;
|
||||||
|
|
||||||
@@ -34,11 +44,6 @@ in
|
|||||||
enable = mkEnableOption "" // {
|
enable = mkEnableOption "" // {
|
||||||
default = true;
|
default = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
domain = mkOption {
|
|
||||||
type = with lib.types; str;
|
|
||||||
default = config.networking.fqdn;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
@@ -53,7 +58,8 @@ in
|
|||||||
value = {
|
value = {
|
||||||
file = path;
|
file = path;
|
||||||
group = "named";
|
group = "named";
|
||||||
owner = "named";
|
owner = if config.acme.enable then "acme" else "named";
|
||||||
|
mode = "440";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
) agenixKeys
|
) agenixKeys
|
||||||
@@ -65,7 +71,7 @@ in
|
|||||||
extraConfig = builtins.concatStringsSep "\n" (map (key: "include \"${key.path}\";") keys);
|
extraConfig = builtins.concatStringsSep "\n" (map (key: "include \"${key.path}\";") keys);
|
||||||
|
|
||||||
zones = {
|
zones = {
|
||||||
"${config.dns.domain}" = {
|
"${fqdn}" = {
|
||||||
# grant "tuxcord.net" zonesub ANY;
|
# grant "tuxcord.net" zonesub ANY;
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
update-policy {
|
update-policy {
|
||||||
@@ -74,7 +80,7 @@ in
|
|||||||
)}
|
)}
|
||||||
};
|
};
|
||||||
'';
|
'';
|
||||||
file = "/var/dns/${config.dns.domain}.zone"; # need to put default stuff
|
file = "/var/dns/${fqdn}.zone"; # need to put default stuff
|
||||||
master = true;
|
master = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
inherit (config.networking) fqdn;
|
||||||
|
|
||||||
|
acmeEnabled = config.acme.enable;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
services.gitea = {
|
services.gitea = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -8,8 +13,8 @@
|
|||||||
|
|
||||||
lfs.enable = true;
|
lfs.enable = true;
|
||||||
|
|
||||||
settings.server.DOMAIN = config.networking.fqdn;
|
settings.server.DOMAIN = fqdn;
|
||||||
# settings.server.ROOT_URL = "https://git.tuxcord.net/"; ? would also depend on ssl status
|
settings.server.ROOT_URL = "${if isHTTPS then "https" else "http"}://${fqdn}/";
|
||||||
settings.server.HTTP_PORT = 3000;
|
settings.server.HTTP_PORT = 3000;
|
||||||
|
|
||||||
settings.service.DISABLE_REGISTRATION = true;
|
settings.service.DISABLE_REGISTRATION = true;
|
||||||
|
|||||||
@@ -4,8 +4,12 @@ let
|
|||||||
|
|
||||||
mkVhost =
|
mkVhost =
|
||||||
attrs:
|
attrs:
|
||||||
|
let
|
||||||
|
acmeEnabled = config.acme.enable;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
forceSSL = false; # TODO: tweak per host
|
forceSSL = acmeEnabled;
|
||||||
|
useACMEHost = if acmeEnabled then fqdn else null;
|
||||||
}
|
}
|
||||||
// attrs;
|
// attrs;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user