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:
Binary file not shown.
@@ -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