Big commit

This commit is contained in:
2023-12-04 17:10:57 -08:00
parent 44589ddc77
commit 0027566304
29 changed files with 1582 additions and 521 deletions
+152 -74
View File
@@ -6,51 +6,133 @@ let
cfg = config.fudo.services.authoritative-dns;
inherit (pkgs.lib)
getHostIps getSiteGatewayV4 getSiteV4PrefixLength getSiteV6PrefixLength;
hostSecrets = config.fudo.secrets.host-secrets."${hostname}";
domainName = config.instance.local-domain;
primaryZone = config.fudo.domains."${domainName}".zone;
siteName = config.instance.local-site;
zoneKeySecret = zone: "${zone}-ksk";
networkHostOpts = {
options = with types; {
hostname = mkOption {
type = str;
description = "Hostname.";
};
ipv4-address = mkOption {
type = nullOr str;
description = "The V4 IP of a given host, if any.";
default = null;
};
containerModule = { pkgs, config, ... }: {
config = mkIf (cfg.enable && !isNull cfg.container) {
containers.nameserver = let
securedZones =
filterAttrs (_: zoneOpts: !isNull zoneOpts.ksk) cfg.zones;
in {
autoStart = true;
additionalCapabilities = [ "CAP_NET_ADMIN" ];
macvlans = [ cfg.container.interface ];
bindMounts = {
"/var/lib/nsd" = {
hostPath = cfg.state-directory;
isReadOnly = false;
};
} // (mapAttrs' (zoneName: _:
let zoneKeyName = zoneKeySecret zoneName;
in nameValuePair "/run/nsd/keys/${zoneKeyName}" {
hostPath = hostSecrets."${zoneKeyName}".target-file;
}) securedZones);
config = let
nameserverHost = cfg.container.hostname;
nameserverDeets =
config.fudo.zones."${primaryZone}".hosts."${nameserverHost}";
in {
imports = [ pkgs.moduleRegistry.authoritativeDns ];
nixpkgs.pkgs = pkgs;
networking = {
defaultGateway = {
address = getSiteGatewayV4 siteName;
interface = "mv-${cfg.container.interface}";
};
firewall = {
enable = true;
allowedTCPPorts = [ 53 ];
allowedUDPPorts = [ 53 ];
};
interfaces."mv-${cfg.container.interface}" = {
ipv4.addresses = optional (nameserverDeets.ipv4-address != null) {
address = trace "IP ADDRESS: ${nameserverDeets.ipv4-address}"
nameserverDeets.ipv4-address;
prefixLength = getSiteV4PrefixLength siteName;
};
ipv6.addresses = optional (nameserverDeets.ipv6-address != null) {
address = nameserverDeets.ipv6-address;
prefixLength = getSiteV6PrefixLength siteName;
};
};
};
services.authoritative-dns = {
enable = true;
ipv6-address = mkOption {
type = nullOr str;
description = "The V6 IP of a given host, if any.";
default = null;
};
identity = "${nameserverHost}.${primaryZone}";
mac-address = mkOption {
type = nullOr str;
description =
"The MAC address of a given host, if desired for IP reservation.";
default = null;
};
listen-ips = getHostIps nameserverHost;
description = mkOption {
type = nullOr str;
description = "Description of the host.";
default = null;
};
state-directory = "/var/lib/nsd";
sshfp-records = mkOption {
type = listOf str;
description = "List of SSHFP records for this host.";
default = [ ];
timestamp = toString config.instance.build-timestamp;
ip-host-map = cfg.ip-host-map;
domains = mapAttrs' (zoneName: zoneCfg:
nameValuePair zoneCfg.domain {
ksk.key-file = "/run/nsd/keys/${zoneKeySecret zoneName}";
reverse-zones = zoneCfg.reverse-zones;
notify = mkIf cfg.enable-notifications {
ipv4 = concatMap
(ns: optional (ns.ipv4-address != null) ns.ipv4-address)
cfg.nameservers.external;
ipv6 = concatMap
(ns: optional (ns.ipv6-address != null) ns.ipv6-address)
cfg.nameservers.external;
};
zone = config.fudo.zones."${zoneName}";
}) cfg.zones;
};
};
};
};
};
hostModule = { config, ... }: {
config.services.authoritative-dns =
mkIf (cfg.enable && isNull cfg.container) {
enable = true;
identity = "${hostname}.${primaryZone}";
listen-ips = getHostIps hostname;
state-directory = "/var/lib/nsd";
timestamp = toString config.instance.build-timestamp;
ip-host-map = cfg.ip-host-map;
domains = mapAttrs' (zoneName: zoneCfg:
nameValuePair zoneCfg.domain {
ksk.key-file = mkIf (hasAttr (zoneKeySecret zoneName) hostSecrets)
hostSecrets."${zoneKeySecret zoneName}".target-file;
reverse-zones = zoneCfg.reverse-zones;
notify = mkIf cfg.enable-notifications {
ipv4 = concatMap
(ns: optional (ns.ipv4-address != null) ns.ipv4-address)
cfg.nameservers.external;
ipv6 = concatMap
(ns: optional (ns.ipv6-address != null) ns.ipv6-address)
cfg.nameservers.external;
};
zone = config.fudo.zones."${zoneName}";
}) cfg.zones;
};
};
zoneOpts = { name, ... }:
let zoneName = name;
in {
@@ -62,7 +144,7 @@ let
};
default-host = mkOption {
type = nullOr (submodule networkHostOpts);
type = nullOr (submodule pkgs.lib.fudo-types.networkHost);
description =
"Host which will respond to requests for the base domain.";
default = null;
@@ -123,6 +205,27 @@ in {
options.fudo.services.authoritative-dns = with types; {
enable = mkEnableOption "Enable Authoritative DNS server.";
container = mkOption {
type = nullOr (submodule {
options = {
interface = mkOption {
type = str;
description = "Interface on which to listen for DNS traffic.";
};
hostname = mkOption {
type = str;
description = ''
Hostname (in the zone) of the container nameserver.
The associated IP(s) will be assigned to the container,
and must be accessible.
'';
};
};
});
};
enable-notifications =
mkEnableOption "Enable notifications to secondary servers.";
@@ -152,7 +255,7 @@ in {
};
external = mkOption {
type = listOf (submodule networkHostOpts);
type = listOf (submodule pkgs.lib.fudo-types.networkHost);
description = "List of external secondary nameserver attributes.";
default = [ ];
};
@@ -165,15 +268,23 @@ in {
};
};
config = {
imports = [ hostModule containerModule ];
config = mkIf cfg.enable {
systemd.tmpfiles.rules = [ "d ${cfg.state-directory} 700 root root - -" ];
fileSystems."/var/lib/nsd" = mkIf (isNull cfg.container) {
device = cfg.state-directory;
options = [ "bind" ];
};
fudo = {
secrets.host-secrets."${hostname}" = mkIf cfg.enable (mapAttrs'
(zone: zoneCfg:
nameValuePair (zoneKeySecret zone) {
source-file = zoneCfg.ksk.private-key;
target-file = "/run/nsd/${baseNameOf zoneCfg.ksk.private-key}";
user = config.fudo.nsd.user;
}) (filterAttrs (_: zoneCfg: zoneCfg.ksk != null) cfg.zones));
secrets.host-secrets."${hostname}" = mapAttrs' (zone: zoneCfg:
nameValuePair (zoneKeySecret zone) {
source-file = zoneCfg.ksk.private-key;
target-file = "/run/nsd/${baseNameOf zoneCfg.ksk.private-key}";
user = config.fudo.nsd.user;
}) (filterAttrs (_: zoneCfg: zoneCfg.ksk != null) cfg.zones);
zones = mapAttrs (zone-name: zoneCfg:
let
@@ -256,38 +367,5 @@ in {
];
}) cfg.zones;
};
services = {
authoritative-dns = {
enable = cfg.enable;
identity = "${hostname}.${domainName}";
listen-ips =
optionals cfg.enable (pkgs.lib.network.host-ips config hostname);
state-directory = cfg.state-directory;
timestamp = toString config.instance.build-timestamp;
ip-host-map = cfg.ip-host-map;
domains = mapAttrs' (zoneName: zoneCfg:
nameValuePair zoneCfg.domain {
ksk.key-file = mkIf (hasAttr (zoneKeySecret zoneName) hostSecrets)
hostSecrets."${zoneKeySecret zoneName}".target-file;
reverse-zones = zoneCfg.reverse-zones;
notify = mkIf cfg.enable-notifications {
ipv4 = concatMap
(ns: optional (ns.ipv4-address != null) ns.ipv4-address)
cfg.nameservers.external;
ipv6 = concatMap
(ns: optional (ns.ipv6-address != null) ns.ipv6-address)
cfg.nameservers.external;
};
zone = config.fudo.zones."${zoneName}";
}) cfg.zones;
};
};
};
}
+208
View File
@@ -0,0 +1,208 @@
{ config, lib, pkgs, ... }:
with lib;
let cfg = config.fudo.services.gitea-container;
in {
options.fudo.services.gitea-container = with types; {
enable = mkEnableOption "Enable Gitea running in a container.";
site-name = mkOption {
type = str;
description = "Name of this Gitea instance.";
};
hostname = mkOption {
type = str;
description = "Hostname at which the server is reachable.";
};
state-directory = mkOption {
type = str;
description = "Path at which to store Gitea state.";
};
secret-key-file = mkOption {
type = str;
description =
"Path to file containing Gitea secret key, for encrypting secrets.";
};
trusted-networks = mkOption {
type = listOf str;
description =
"List of networks to be considered trusted (for metrics access).";
default = [ ];
};
openid-urls = mkOption {
type = listOf str;
description = "List of authorized OpenID providers.";
};
networking = {
interface = mkOption {
type = str;
description = "Parent host interface on which to listen.";
};
ipv4 = mkOption {
type = nullOr (submodule {
options = {
address = mkOption {
type = str;
description = "IP address.";
};
prefixLength = mkOption {
type = int;
description = "Significant bits in the address.";
};
};
});
default = null;
};
ipv6 = mkOption {
type = nullOr (submodule {
options = {
address = mkOption {
type = str;
description = "IP address.";
};
prefixLength = mkOption {
type = int;
description = "Significant bits in the address.";
};
};
});
default = null;
};
};
};
config = mkIf cfg.enable {
systemd.tmpfiles.rules = [ "d ${cfg.state-directory} 700 root root - -" ];
containers.gitea = {
autoStart = true;
additionalCapabilities = [ "CAP_NET_ADMIN" ];
macvlans = [ cfg.networking.interface ];
bindMounts = {
"/state" = {
hostPath = cfg.state-directory;
isReadOnly = false;
};
};
config = {
nixpkgs.pkgs = pkgs;
systemd = { tmpfiles.rules = [ "d /state 0755 root root - -" ]; };
networking = {
defaultGateway = config.networking.defaultGateway;
enableIPv6 = !isNull cfg.networking.ipv6;
firewall = {
enable = true;
allowedTCPPorts = [ 22 80 443 ];
};
interfaces."mv-${cfg.networking.interface}" = {
ipv4.addresses = optional (!isNull cfg.networking.ipv4) {
address = cfg.networking.ipv4.address;
prefixLength = cfg.networking.ipv4.prefixLength;
};
ipv6.addresses = optional (!isNull cfg.networking.ipv6) {
address = cfg.networking.ipv6.address;
prefixLength = cfg.networking.ipv6.prefixLength;
};
};
};
services = {
gitea = {
enable = true;
appName = cfg.site-name;
database = {
createDatabase = true;
type = "sqlite3";
};
repositoryRoot = "/state/repositories";
stateDir = "/state/gitea";
settings = {
service.DISABLE_REGISTRATION = true;
security = {
INSTALL_LOCK = true;
SECRET_KEY = "file:${cfg.secret-key-file}";
LOGIN_REMEMBER_DAYS = 30;
};
metrics.ENABLED = cfg.trusted-networks != [ ];
server = {
START_SSH_SERVER = true;
# Host & port to display in the clone URL
SSH_DOMAIN = cfg.hostname;
SSH_PORT = 22;
SSH_LISTEN_PORT = 2222;
SSH_LISTEN_HOST = "0.0.0.0";
DOMAIN = cfg.hostname;
ROOT_URL = "https://${cfg.hostname}";
HTTP_ADDR = "127.0.0.1";
HTTP_PORT = 8080;
};
openid = {
ENABLE_OPENID_SIGNIN = true;
WHITELISTED_URIS = cfg.openid-urls;
};
oauth2_client = {
REGISTER_EMAIL_CONFIRM = false;
OPENID_CONNECT_SCOPES = [ "email" "profile" ];
ENABLE_AUTO_REGISTRATION = true;
USERNAME = "email";
UPDATE_AVATAR = true;
ACCOUNT_LINKING = "login";
};
};
};
xinetd = {
enable = true;
services = [{
name = "ssh";
# port = 22;
# protocol = "tcp";
extraConfig = ''
redirect = localhost 2222
wait = no
socket_type = stream
'';
user = "nobody";
# Must be defined, but not used
server = "/usr/bin/env";
# unlisted = true;
}];
};
nginx = {
enable = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
recommendedGzipSettings = true;
virtualHosts."${cfg.hostname}" = {
# enableACME = true;
# forceSSL = true;
locations."/".proxyPass = "http://127.0.0.1:8080";
locations."/metrics" = mkIf (cfg.trusted-networks != [ ]) (let
networkAllowClauses =
map (net: "allow ${net};") cfg.trusted-networks;
in concatStringsSep "\n"
(networkAllowClauses ++ [ "deny all;" ]));
};
};
};
};
};
};
}
+2 -1
View File
@@ -134,11 +134,12 @@ in {
dns = {
listen-ips = [ "127.0.0.1" ];
listen-port = agp.dns-listen-port;
reverse-dns = [ (host-ipv4 gateway-host) ];
};
local-domain-name = domain-name;
};
zones.${zone-name} = {
zones."${zone-name}" = {
aliases = {
"${agp.http-host-alias}" = mkIf (agp.enable) (fqdn gateway-host);
ns = (fqdn nameserver-host);
+5 -5
View File
@@ -38,8 +38,8 @@ in {
config = mkIf postgresEnabled {
fudo = {
acme.host-domains.${hostname} = mkIf (publicNetwork && isPostgresHost) {
${postgresql-hostname}.local-copies = {
acme.host-domains."${hostname}" = mkIf (publicNetwork && isPostgresHost) {
"${postgresql-hostname}".local-copies = {
postgresql = {
user = postgresUser;
dependent-services = [ "postgresql.service" ];
@@ -48,15 +48,15 @@ in {
};
};
secrets.host-secrets.${hostname}.postgres-keytab =
secrets.host-secrets."${hostname}".postgres-keytab =
mkIf (cfg.keytab != null) {
source-file = cfg.keytab;
target-file = "/run/postgresql/postgres.keytab";
user = postgresUser;
};
zones.${zone-name}.aliases.postgresql =
"${domain.postgresql-server}.${domain-name}.";
zones."${zone-name}".aliases.postgresql =
pkgs.lib.getHostFqdn domain.postgresql-server;
postgresql = mkIf isPostgresHost (let
ssl-config = optionalAttrs publicNetwork (let
+2
View File
@@ -38,6 +38,8 @@ in {
};
config = mkIf cfg.enable {
systemd.services.snooper.after = mkIf isSnooper [ "fudo-secrets.target" ];
fudo = {
secrets.host-secrets."${hostname}" = {
snooper-passwd = mkIf isSnooper {