diff --git a/README.md b/README.md index 526062c..e1adc23 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ then select the host in the fzf menu ## Stuff - Secrets can be created/edited by running `nix run .#edit-secret some/secret.age` -- Secrets can be rekeyed by running `nix run .#rekey` (you will be prompted to do so in an error message if neccessary) +- Secrets can be rekeyed by running `nix run .#rekey` (you will also be prompted to do so in an error message if neccessary) To be able to decrypt the repository-wide secrets transparently on a host that is _not_ managed by this config, you will need to (be me and) run @@ -110,10 +110,10 @@ all commands using these extra parameters, or permanently add the following the ## Misc -Generate self-signed cert: +Generate self-signed cert, e.g. for kanidm internal communication to proxy: ```bash openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \ - -keyout zackbiene-selfcert.key -out zackbiene-selfcert.crt -subj \ + -keyout selfcert.key -out selfcert.crt -subj \ "/CN=example.com" -addext "subjectAltName=DNS:example.com,DNS:sub1.example.com,DNS:sub2.example.com,IP:10.0.0.1" ``` diff --git a/hosts/common/core/impermanence.nix b/hosts/common/core/impermanence.nix index 07170fb..ad85bda 100644 --- a/hosts/common/core/impermanence.nix +++ b/hosts/common/core/impermanence.nix @@ -1,4 +1,8 @@ { + config, + lib, + ... +}: { # State that should be kept across reboots, but is otherwise # NOT important information in any way that needs to be backed up. #environment.persistence."/nix/state" = { @@ -20,10 +24,90 @@ "/etc/ssh/ssh_host_ed25519_key" "/etc/ssh/ssh_host_ed25519_key.pub" ]; - directories = [ - "/var/lib/nixos" - "/var/lib/systemd/coredump" - "/var/log" - ]; + directories = + [ + { + directory = "/var/lib/nixos"; + user = "root"; + group = "root"; + mode = "0755"; + } + { + directory = "/var/lib/systemd"; + user = "root"; + group = "root"; + mode = "0755"; + } + { + directory = "/var/log"; + user = "root"; + group = "root"; + mode = "0755"; + } + #{ directory = "/tmp"; user = "root"; group = "root"; mode = "1777"; } + #{ directory = "/var/tmp"; user = "root"; group = "root"; mode = "1777"; } + { + directory = "/var/spool"; + user = "root"; + group = "root"; + mode = "0777"; + } + ] + ++ lib.optionals config.networking.wireless.iwd.enable [ + { + directory = "/var/lib/iwd"; + user = "root"; + group = "root"; + mode = "0700"; + } + ] + ++ lib.optionals (config.services.kea.dhcp4.enable || config.services.kea.dhcp6.enable) [ + { + directory = "/var/lib/kea"; + user = "kea"; + group = "kea"; + mode = "0755"; + } + ] + ++ lib.optionals config.services.gitea.enable [ + { + directory = "/var/lib/gitea"; + user = "gitea"; + group = "gitea"; + mode = "0755"; + } + ] + ++ lib.optionals config.security.acme.acceptTerms [ + { + directory = "/var/lib/acme"; + user = "acme"; + group = "acme"; + mode = "0755"; + } + ] + ++ lib.optionals config.services.printing.enable [ + { + directory = "/var/lib/cups"; + user = "root"; + group = "root"; + mode = "0755"; + } + ] + ++ lib.optionals config.services.fail2ban.enable [ + { + directory = "/var/lib/fail2ban"; + user = "fail2ban"; + group = "fail2ban"; + mode = "0750"; + } + ] + ++ lib.optionals config.services.opendkim.enable [ + { + directory = "/var/lib/postgresql"; + user = "postgres"; + group = "postgres"; + mode = "0755"; + } + ]; }; } diff --git a/hosts/common/core/issue.nix b/hosts/common/core/issue.nix index ba51081..f324347 100644 --- a/hosts/common/core/issue.nix +++ b/hosts/common/core/issue.nix @@ -2,6 +2,7 @@ let # IP addresses: ${"${interface} \e{halfbright}\4{${interface}}\e{reset} \e{halfbright}\6{${interface}}\e{reset}"} issue_text = '' \d \t + \e{halfbright}\4\e{reset} \e{halfbright}\6\e{reset} This is \e{cyan}\n\e{reset} [\e{lightblue}\l\e{reset}] (\s \m \r) ''; diff --git a/hosts/ward/default.nix b/hosts/ward/default.nix index 844a0e3..95b75ce 100644 --- a/hosts/ward/default.nix +++ b/hosts/ward/default.nix @@ -3,7 +3,19 @@ nixos-hardware, pkgs, ... -}: { +}: let + # TODO byebyebye + # TODO byebyebye + # TODO byebyebye + # TODO byebyebye + # TODO byebyebye + # TODO byebyebye + # TODO byebyebye + # TODO byebyebye + # TODO byebyebye + inherit (config.repo.secrets.local) acme; + auth.domain = config.repo.secrets.local.auth.domain; +in { imports = [ nixos-hardware.common-cpu-intel nixos-hardware.common-pc-ssd @@ -33,15 +45,26 @@ }; in { test = defineVm 11; - - #nginx = defineVm 12; + #ddclient = defineVm 11; + nginx = defineVm 12; #kanidm = defineVm 13; #gitea = defineVm 14; #vaultwarden = defineVm 15; - #samba = defineVm 16; + #samba+wsdd = defineVm 16; #fasten-health = defineVm 17; #immich = defineVm 18; #paperless = defineVm 19; + #radicale = defineVm 20; + #minecraft = defineVm 21; + + #grafana + #loki + + #maddy = defineVm 19; + #anonaddy = defineVm 19; + + #automatic1111 = defineVm 19; + #invokeai = defineVm 19; #kanidm = defineVm 12 // { # configPath = ./vm-test.nix; @@ -51,4 +74,162 @@ microvm.vms.test.config = { rekey.hostPubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBXXjI6uB26xOF0DPy/QyLladoGIKfAtofyqPgIkCH/g"; }; + + microvm.vms.nginx.config = { + lib, + config, + parentNodeName, + ... + }: { + rekey.hostPubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN2TxWynLb8V9SP45kFqsoCWhe/dG8N1xWNuJG5VQndq"; + + rekey.secrets."kanidm-self-signed.crt" = { + file = ./secrets/kanidm-self-signed.crt.age; + mode = "440"; + owner = "nginx"; + group = "kanidm"; + }; + rekey.secrets."kanidm-self-signed.key" = { + file = ./secrets/kanidm-self-signed.key.age; + mode = "440"; + owner = "nginx"; + group = "kanidm"; + }; + rekey.secrets."dhparams.pem" = { + # TODO make own? + file = ../zackbiene/secrets/dhparams.pem.age; + mode = "440"; + group = "nginx"; + }; + + networking.hosts = { + "192.168.100.12" = [auth.domain]; + }; + + rekey.secrets.acme-credentials = { + file = ./secrets/acme-credentials.age; + mode = "440"; + group = "acme"; + }; + security.acme = { + acceptTerms = true; + defaults = { + inherit (acme) email; + dnsProvider = "cloudflare"; + credentialsFile = config.rekey.secrets.acme-credentials.path; + dnsPropagationCheck = true; + }; + certs = lib.genAttrs acme.domains (domain: { + extraDomainNames = ["*.${domain}"]; + }); + }; + users.groups.acme.members = ["nginx"]; + + # TODO needed in my current testing network that has no ipv6 connectivity + # TODO but these should use fallback......... something's wrong + systemd.network.networks."10-wan".networkConfig.DNS = ["1.1.1.1" "8.8.8.8"]; + + # TODO reload nginx when acme is renewed + + # TODO make default nginx config in core to reduce boilerplate? + services.nginx = let + # TODO not implemented well + # TODO not implemented well + # TODO not implemented well + # TODO not implemented well + # TODO not implemented well + # TODO not implemented well + # TODO not implemented well + # TODO not implemented well + # TODO (acme.domains is very specific) + # TODO (security.acme causes recursion) + matchingWildcardCert = domain: let + # Filter all certs that are wildcard certs and which match the given domain + matchingCerts = + lib.filter + (x: !lib.hasInfix "." (lib.removeSuffix ".${x}" domain)) + acme.domains; + in + assert lib.assertMsg (matchingCerts != []) "No wildcard certificate was defined that matches ${domain}"; + lib.head matchingCerts; + in { + enable = true; + + recommendedBrotliSettings = true; + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + + # SSL config + sslCiphers = "EECDH+AESGCM:EDH+AESGCM:!aNULL"; + sslDhparam = config.rekey.secrets."dhparams.pem".path; + commonHttpConfig = '' + error_log syslog:server=unix:/dev/log; + access_log syslog:server=unix:/dev/log; + ssl_ecdh_curve secp384r1; + ''; + + upstreams."kanidm" = { + servers."${config.extra.wireguard."${parentNodeName}-local-vms".ipv4}:8300" = {}; + extraConfig = '' + zone kanidm 64k; + keepalive 2; + ''; + }; + virtualHosts.${auth.domain} = { + forceSSL = true; + useACMEHost = matchingWildcardCert auth.domain; + locations."/".proxyPass = "https://kanidm"; + # Allow using self-signed certs to satisfy kanidm's requirement + # for TLS connections. (This is over wireguard anyway) + extraConfig = '' + proxy_ssl_verify off; + ''; + }; + }; + + networking.firewall.allowedTCPPorts = [80 443]; + + networking.nftables.firewall.rules = lib.mkForce { + local-vms-to-local.allowedTCPPorts = [8300]; + }; + + # systemd.services.kanidm = let + # cfg = config.services.kanidm; + # certName = config.services.nginx.virtualHosts.${cfg.serverSettings.domain}.useACMEHost; + # in { + # requires = [ "acme-finished-${certName}.target" ]; + # serviceConfig.LoadCredential = let + # certDir = config.security.acme.certs.${certName}.directory; + # in [ + # "fullchain.pem:${certDir}/fullchain.pem" + # "key.pem:${certDir}/key.pem" + # ]; + # }; + + services.kanidm = { + enableServer = true; + # enablePAM = true; + serverSettings = { + inherit (auth) domain; + origin = "https://${config.services.kanidm.serverSettings.domain}"; + #tls_chain = "/run/credentials/kanidm.service/fullchain.pem"; + #tls_key = "/run/credentials/kanidm.service/key.pem"; + tls_chain = config.rekey.secrets."kanidm-self-signed.crt".path; + tls_key = config.rekey.secrets."kanidm-self-signed.key".path; + bindaddress = "${config.extra.wireguard."${parentNodeName}-local-vms".ipv4}:8300"; + trust_x_forward_for = true; + }; + + enableClient = true; + clientSettings = { + uri = config.services.kanidm.serverSettings.origin; + verify_ca = true; + verify_hostnames = true; + }; + }; + + environment.systemPackages = [pkgs.kanidm]; + }; } diff --git a/hosts/ward/grafana.nix b/hosts/ward/grafana.nix deleted file mode 100644 index 0967ef4..0000000 --- a/hosts/ward/grafana.nix +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/hosts/ward/net.nix b/hosts/ward/net.nix index ef6ce5a..01dd033 100644 --- a/hosts/ward/net.nix +++ b/hosts/ward/net.nix @@ -3,7 +3,7 @@ lib, ... }: let - inherit (config.lib.net) ip cidr; + inherit (config.lib.net) cidr; lanCidrv4 = "192.168.100.0/24"; lanCidrv6 = "fd00::/64"; @@ -165,7 +165,7 @@ in { interface = "lan-self"; subnet = lanCidrv4; pools = [ - {pool = "${cidr.host 20 lanCidrv4} - ${cidr.host (-6) lanCidrv4}";} + {pool = "${cidr.host 40 lanCidrv4} - ${cidr.host (-6) lanCidrv4}";} ]; option-data = [ { diff --git a/hosts/ward/node_exporter.nix b/hosts/ward/node_exporter.nix deleted file mode 100644 index 0967ef4..0000000 --- a/hosts/ward/node_exporter.nix +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/hosts/ward/prometheus.nix b/hosts/ward/prometheus.nix deleted file mode 100644 index 0967ef4..0000000 --- a/hosts/ward/prometheus.nix +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/hosts/ward/samba.nix b/hosts/ward/samba.nix deleted file mode 100644 index 0967ef4..0000000 --- a/hosts/ward/samba.nix +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/hosts/ward/secrets/acme-credentials.age b/hosts/ward/secrets/acme-credentials.age new file mode 100644 index 0000000..2bbf452 Binary files /dev/null and b/hosts/ward/secrets/acme-credentials.age differ diff --git a/hosts/ward/secrets/kanidm-self-signed.crt.age b/hosts/ward/secrets/kanidm-self-signed.crt.age new file mode 100644 index 0000000..27fb4e8 Binary files /dev/null and b/hosts/ward/secrets/kanidm-self-signed.crt.age differ diff --git a/hosts/ward/secrets/kanidm-self-signed.key.age b/hosts/ward/secrets/kanidm-self-signed.key.age new file mode 100644 index 0000000..87add02 Binary files /dev/null and b/hosts/ward/secrets/kanidm-self-signed.key.age differ diff --git a/hosts/ward/secrets/local.nix.age b/hosts/ward/secrets/local.nix.age index b8e6bf8..18a02bf 100644 Binary files a/hosts/ward/secrets/local.nix.age and b/hosts/ward/secrets/local.nix.age differ diff --git a/hosts/ward/vaultwarden.nix b/hosts/ward/vaultwarden.nix index db04250..1ef30ae 100644 --- a/hosts/ward/vaultwarden.nix +++ b/hosts/ward/vaultwarden.nix @@ -42,14 +42,14 @@ services.nginx = { upstreams."vaultwarden" = { - servers = {"localhost:8012" = {};}; + servers."localhost:8012" = {}; extraConfig = '' zone vaultwarden 64k; keepalive 2; ''; }; upstreams."vaultwarden-websocket" = { - servers = {"localhost:3012" = {};}; + servers."localhost:3012" = {}; extraConfig = '' zone vaultwarden-websocket 64k; keepalive 2; diff --git a/hosts/zackbiene/esphome.nix b/hosts/zackbiene/esphome.nix index 19e32d3..ee16b8b 100644 --- a/hosts/zackbiene/esphome.nix +++ b/hosts/zackbiene/esphome.nix @@ -17,7 +17,7 @@ services.nginx = { upstreams."esphome" = { - servers = {"unix:/run/esphome/esphome.sock" = {};}; + servers."unix:/run/esphome/esphome.sock" = {}; extraConfig = '' zone esphome 64k; keepalive 2; diff --git a/hosts/zackbiene/home-assistant.nix b/hosts/zackbiene/home-assistant.nix index 7d469a7..4dbd9ae 100644 --- a/hosts/zackbiene/home-assistant.nix +++ b/hosts/zackbiene/home-assistant.nix @@ -108,7 +108,7 @@ in { services.nginx = { upstreams."homeassistant" = { - servers = {"localhost:${toString haPort}" = {};}; + servers."localhost:${toString haPort}" = {}; extraConfig = '' zone homeassistant 64k; keepalive 2; diff --git a/hosts/zackbiene/net.nix b/hosts/zackbiene/net.nix index 0d326f7..7faa067 100644 --- a/hosts/zackbiene/net.nix +++ b/hosts/zackbiene/net.nix @@ -5,8 +5,8 @@ }: let inherit (config.lib.net) cidr; - net.iot.ipv4cidr = "10.90.0.1/24"; - net.iot.ipv6cidr = "fd90::1/64"; + iotCidrv4 = "10.90.0.0/24"; + iotCidrv6 = "fd90::/64"; in { networking.hostId = config.repo.secrets.local.networking.hostId; @@ -23,7 +23,10 @@ in { linkConfig.RequiredForOnline = "routable"; }; "10-wlan1" = { - address = [net.iot.ipv4cidr net.iot.ipv6cidr]; + address = [ + (cidr.hostCidr 1 iotCidrv4) + (cidr.hostCidr 1 iotCidrv6) + ]; matchConfig.MACAddress = config.repo.secrets.local.networking.interfaces.wlan1.mac; linkConfig.RequiredForOnline = "no"; }; diff --git a/hosts/zackbiene/nginx.nix b/hosts/zackbiene/nginx.nix index 9fba23e..dd0dcb7 100644 --- a/hosts/zackbiene/nginx.nix +++ b/hosts/zackbiene/nginx.nix @@ -34,6 +34,8 @@ sslCiphers = "EECDH+AESGCM:EDH+AESGCM:!aNULL"; sslDhparam = config.rekey.secrets."dhparams.pem".path; commonHttpConfig = '' + error_log syslog:server=unix:/dev/log; + access_log syslog:server=unix:/dev/log; ssl_ecdh_curve secp384r1; ''; }; diff --git a/hosts/zackbiene/zigbee2mqtt.nix b/hosts/zackbiene/zigbee2mqtt.nix index 2a8390f..7f72959 100644 --- a/hosts/zackbiene/zigbee2mqtt.nix +++ b/hosts/zackbiene/zigbee2mqtt.nix @@ -32,7 +32,7 @@ services.nginx = { upstreams."zigbee2mqtt" = { - servers = {"localhost:8072" = {};}; + servers."localhost:8072" = {}; extraConfig = '' zone zigbee2mqtt 64k; keepalive 2; diff --git a/modules/microvms.nix b/modules/microvms.nix index 462e33f..8e99c97 100644 --- a/modules/microvms.nix +++ b/modules/microvms.nix @@ -32,6 +32,7 @@ types ; + parentConfig = config; cfg = config.extra.microvms; inherit (config.extra.microvms) vms; inherit (config.lib) net; @@ -103,7 +104,7 @@ // node.specialArgs; inherit (node) pkgs; inherit (vmCfg) autostart; - config = { + config = {config, ...}: { imports = [microvm.microvm] ++ cfg.commonImports ++ node.imports; microvm = { @@ -156,7 +157,7 @@ extra.networking.renameInterfacesByMac.${vmCfg.networking.mainLinkName} = mac; systemd.network.networks = let - wgConfig = config.extra.wireguard."${nodeName}-local-vms".unitConfName; + wgConfig = parentConfig.extra.wireguard."${nodeName}-local-vms".unitConfName; in { # Remove requirement for the wireguard interface to come online, # to allow microvms to be deployed more easily (otherwise they @@ -204,13 +205,19 @@ networking.nftables.firewall = { zones = mkForce { "${vmCfg.networking.mainLinkName}".interfaces = [vmCfg.networking.mainLinkName]; - local-vms.interfaces = ["local-vms"]; + local-vms.interfaces = [config.extra.wireguard."${nodeName}-local-vms".linkName]; }; rules = mkForce { "${vmCfg.networking.mainLinkName}-to-local" = { from = [vmCfg.networking.mainLinkName]; to = ["local"]; + + inherit + (config.networking.firewall) + allowedTCPPorts + allowedUDPPorts + ; }; local-vms-to-local = { diff --git a/secrets/wireguard/ward-local-vms/keys/ward-nginx.age b/secrets/wireguard/ward-local-vms/keys/ward-nginx.age new file mode 100644 index 0000000..cd1d621 --- /dev/null +++ b/secrets/wireguard/ward-local-vms/keys/ward-nginx.age @@ -0,0 +1,10 @@ +age-encryption.org/v1 +-> X25519 +S2DEXP2FxIlF3HeWNul/QHE4fuVwv7ausZO8C1Yvko +USoULC2zp6mkLEGQFc4ELAotOQkq85yjfC3ImZQe6g0 +-> piv-p256 xqSe8Q AuVsMp2nyVB5I6ae7X4rnTT6gH/AyOwkVH5C8qRzenCu +QLdaqASucS24wx5LuoFVD+LBdgsd+wGITMhJBOCrqpY +-> z&m(b4Nw-grease ,&}.>' UWDXz +adqzHHC2X08jrZz0h0y+MuJHM6/kuSUNad8+19cY88IRTF2ujQnoDVDS +--- 8dc8Ta84I8RY7YGIcEuZStaEncGXv1uwJw2ncy3QgtU +r}jEA]W4g3A"Ȥʚ +ru3_E /ztKߔ݈I/} * \ No newline at end of file diff --git a/secrets/wireguard/ward-local-vms/keys/ward-nginx.pub b/secrets/wireguard/ward-local-vms/keys/ward-nginx.pub new file mode 100644 index 0000000..478d9b8 --- /dev/null +++ b/secrets/wireguard/ward-local-vms/keys/ward-nginx.pub @@ -0,0 +1 @@ +Zs0W99JiuCv1F3NMTp/PcMBrt1bzWttJWNEh00Freyw= diff --git a/secrets/wireguard/ward-local-vms/psks/ward+ward-nginx.age b/secrets/wireguard/ward-local-vms/psks/ward+ward-nginx.age new file mode 100644 index 0000000..27d85ff Binary files /dev/null and b/secrets/wireguard/ward-local-vms/psks/ward+ward-nginx.age differ diff --git a/secrets/wireguard/ward-local-vms/psks/ward-nginx+ward-test.age b/secrets/wireguard/ward-local-vms/psks/ward-nginx+ward-test.age new file mode 100644 index 0000000..1d66e76 --- /dev/null +++ b/secrets/wireguard/ward-local-vms/psks/ward-nginx+ward-test.age @@ -0,0 +1,9 @@ +age-encryption.org/v1 +-> X25519 95jd7mMbmilIpQbvDmu48FfMFZZbkioExF8KTw3fNXI +CxWXmbD6kArjmJ2Y4lYVcwaQghWyJzS6DsQ4djspUf4 +-> piv-p256 xqSe8Q A13AOGXe31ASOihylki3jl8xCxp2bh2lYnzQC44Rbe10 ++R8gYDIFyANNPLvdQcq8+67dy+tFcVqS/7rYAbN7pz8 +-> 6q.AXp(-grease +GJOOcphfNDKW +--- E/iTzPRKqfS52YBWVcbVAak5koIxmdanzTXRt/5MZnM +۸6Wn?W}7Jp[Bo|T:T]YkBo޽6zqV?+ ^M*/  \ No newline at end of file