diff --git a/config/hardware/clunk.nix b/config/hardware/clunk.nix index 564e778..685b213 100644 --- a/config/hardware/clunk.nix +++ b/config/hardware/clunk.nix @@ -38,8 +38,6 @@ nix.maxJobs = lib.mkDefault 4; - powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; - hardware.bluetooth.enable = false; networking = { diff --git a/config/hosts/clunk.nix b/config/hosts/clunk.nix index 7d59f4a..c455ca7 100644 --- a/config/hosts/clunk.nix +++ b/config/hosts/clunk.nix @@ -3,7 +3,8 @@ with lib; let primary-ip = "10.0.0.1"; - dns-proxy-ip = "10.0.0.2"; + + dns-proxy-port = 5335; site-name = config.fudo.hosts.${config.instance.hostname}.site; site = config.fudo.site.${site-name}; @@ -65,16 +66,10 @@ in { intif0 = { useDHCP = false; - ipv4.addresses = [ - { - address = primary-ip; - prefixLength = 22; - } - { - address = dns-proxy-ip; - prefixLength = 32; - } - ]; + ipv4.addresses = [{ + address = primary-ip; + prefixLength = 22; + }]; }; }; @@ -93,11 +88,13 @@ in { secure-dns-proxy = { enable = true; - listen-port = 53; + listen-port = dns-proxy-port; upstream-dns = [ "https://1.1.1.1/dns-query" "https://1.0.0.1/dns-query" ]; bootstrap-dns = "1.1.1.1"; - listen-ips = [ dns-proxy-ip ]; + allowed-networks = + [ "1.1.1.1/32" "1.0.0.1/32" "10.0.0.0/16" "localhost" "link-local" ]; + listen-ips = [ primary-ip ]; }; }; @@ -112,13 +109,13 @@ in { backend = "docker"; containers = { pihole = { - image = "pihole/pihole:v5.1.2"; + image = "pihole/pihole:v5.7"; autoStart = true; ports = [ "5353:53/tcp" "5353:53/udp" "3080:80/tcp" ]; environment = { - ServerIP = primary-ip; + # ServerIP = primary-ip; VIRTUAL_HOST = "dns-hole.rus.selby.ca"; - DNS1 = dns-proxy-ip; + DNS1 = "${primary-ip}#${toString dns-proxy-port}"; }; volumes = [ "/srv/pihole/etc-pihole/:/etc/pihole/" diff --git a/config/profiles/server.nix b/config/profiles/server.nix index 6993817..2a74151 100644 --- a/config/profiles/server.nix +++ b/config/profiles/server.nix @@ -78,5 +78,14 @@ in { sound.enable = false; hardware.pulseaudio.enable = false; + + powerManagement.enable = false; + + systemd.targets = { + sleep.enable = false; + suspend.enable = false; + hibernate.enable = false; + hybrid-sleep.enable = false; + }; }; } diff --git a/configuration.nix b/configuration.nix index 92d48ab..d989c33 100644 --- a/configuration.nix +++ b/configuration.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, pkgs, ... }: let local = import ../host-config.nix; @@ -15,6 +15,7 @@ in { url = "https://github.com/nix-community/home-manager.git"; ref = "release-20.09"; }; + pkgs = pkgs; }) ]; } diff --git a/initialize.nix b/initialize.nix index dba470e..4546557 100644 --- a/initialize.nix +++ b/initialize.nix @@ -1,4 +1,4 @@ -{ hostname, profile, domain, site, home-manager-package, ... }: +{ hostname, profile, domain, site, home-manager-package, pkgs, ... }: { imports = [ diff --git a/lib/default.nix b/lib/default.nix index bad6bcf..50bf886 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -1,9 +1,6 @@ { lib, config, pkgs, ... }: with lib; { - - lib = lib // { fudo = import ./lib/lib.nix { inherit lib; }; }; - imports = [ ../config ../packages diff --git a/lib/lib/dns.nix b/lib/dns.nix similarity index 100% rename from lib/lib/dns.nix rename to lib/dns.nix diff --git a/lib/fudo-lib.nix b/lib/fudo-lib.nix new file mode 100644 index 0000000..3371561 --- /dev/null +++ b/lib/fudo-lib.nix @@ -0,0 +1,7 @@ +{ lib, ... }: + +{ + ip = import ./ip.nix { inherit lib; }; + dns = import ./dns.nix { inherit lib; }; + system = import ./system.nix { inherit lib; }; +} diff --git a/lib/fudo/ldap.nix b/lib/fudo/ldap.nix index cbc3759..660495e 100644 --- a/lib/fudo/ldap.nix +++ b/lib/fudo/ldap.nix @@ -297,7 +297,7 @@ in { mode = "0400"; user = "openldap"; group = "openldap"; - # FIXME: take arguments! + # FIXME: take arguments! text = '' mech_list: gssapi external keytab: /etc/ldap/ldap.keytab diff --git a/lib/fudo/local-network.nix b/lib/fudo/local-network.nix index a806a6f..5ad444d 100644 --- a/lib/fudo/local-network.nix +++ b/lib/fudo/local-network.nix @@ -5,13 +5,12 @@ with lib; let cfg = config.fudo.local-network; - dns = import ../lib/dns.nix { inherit lib; }; - ip = import ../lib/ip.nix { inherit lib; }; - join-lines = concatStringsSep "\n"; traceout = out: builtins.trace out out; + fudo-lib = import ../fudo-lib.nix { inherit lib; }; + in { options.fudo.local-network = with types; { @@ -103,20 +102,20 @@ in { interfaces = cfg.dhcp-interfaces; extraConfig = '' - subnet ${ip.getNetworkBase cfg.network} netmask ${ - ip.maskFromV32Network cfg.network + subnet ${fudo-lib.ip.getNetworkBase cfg.network} netmask ${ + fudo-lib.ip.maskFromV32Network cfg.network } { authoritative; - option subnet-mask ${ip.maskFromV32Network cfg.network}; - option broadcast-address ${ip.networkMaxIp cfg.network}; + option subnet-mask ${fudo-lib.ip.maskFromV32Network cfg.network}; + option broadcast-address ${fudo-lib.ip.networkMaxIp cfg.network}; option routers ${cfg.gateway}; option domain-name-servers ${concatStringsSep " " cfg.dns-servers}; option domain-name "${cfg.domain}"; option domain-search "${ concatStringsSep " " ([ cfg.domain ] ++ cfg.search-domains) }"; - range ${ip.networkMinIp cfg.dhcp-dynamic-network} ${ - ip.networkMaxButOneIp cfg.dhcp-dynamic-network + range ${fudo-lib.ip.networkMinIp cfg.dhcp-dynamic-network} ${ + fudo-lib.ip.networkMaxButOneIp cfg.dhcp-dynamic-network }; } ''; @@ -218,7 +217,7 @@ in { ${join-lines (mapAttrsToList hostSshFpRecords network.hosts)} ${join-lines (mapAttrsToList cnameRecord network.aliases)} ${join-lines network.verbatim-dns-records} - ${dns.srvRecordsToBindZone network.srv-records} + ${fudo-lib.dns.srvRecordsToBindZone network.srv-records} ''; }] ++ blockZones; }; diff --git a/lib/fudo/secure-dns-proxy.nix b/lib/fudo/secure-dns-proxy.nix index ee6678d..c433d56 100644 --- a/lib/fudo/secure-dns-proxy.nix +++ b/lib/fudo/secure-dns-proxy.nix @@ -1,21 +1,24 @@ { lib, pkgs, config, ... }: with lib; -let cfg = config.fudo.secure-dns-proxy; +let + cfg = config.fudo.secure-dns-proxy; + + fudo-lib = import ../fudo-lib.nix { lib = lib; }; in { - options.fudo.secure-dns-proxy = { + options.fudo.secure-dns-proxy = with types; { enable = mkEnableOption "Enable a DNS server using an encrypted upstream source."; listen-port = mkOption { - type = types.port; + type = port; description = "Port on which to listen for DNS queries."; default = 53; }; upstream-dns = mkOption { - type = with types; listOf str; + type = listOf str; description = '' The upstream DNS services to use, in a format useable by dnsproxy. @@ -25,37 +28,47 @@ in { }; bootstrap-dns = mkOption { - type = types.str; + type = str; description = "A simple DNS server from which HTTPS DNS can be bootstrapped, if necessary."; default = "1.1.1.1"; }; listen-ips = mkOption { - type = with types; listOf str; + type = listOf str; description = "A list of local IP addresses on which to listen."; default = [ "0.0.0.0" ]; }; + + allowed-networks = mkOption { + type = nullOr (listOf str); + description = + "List of networks with which this job is allowed to communicate."; + default = null; + }; }; config = mkIf cfg.enable { environment.systemPackages = with pkgs; [ dnsproxy ]; - systemd.services.secure-dns-proxy = { - enable = true; + systemd.services.secure-dns-proxy = fudo-lib.system.default-service { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - description = "DNS Proxy for secure DNS lookups"; - serviceConfig = let + description = "DNS Proxy for secure DNS-over-HTTPS lookups."; + privateNetwork = false; + requiredCapabilities = [ ]; + restartWhen = "always"; + addressFamilies = [ "AF_INET" "AF_INET6" ]; + networkWhitelist = cfg.allowed-networks; + + execStart = let upstreams = map (upstream: "-u ${upstream}") cfg.upstream-dns; upstream-line = concatStringsSep " " upstreams; listen-line = concatStringsSep " " (map (listen: "-l ${listen}") cfg.listen-ips); - cmd = "${pkgs.dnsproxy}/bin/dnsproxy -p ${ - toString cfg.listen-port - } ${upstream-line} ${listen-line} -b ${cfg.bootstrap-dns}"; - - in { ExecStart = cmd; }; + in "${pkgs.dnsproxy}/bin/dnsproxy -p ${ + toString cfg.listen-port + } ${upstream-line} ${listen-line} -b ${cfg.bootstrap-dns}"; }; }; } diff --git a/lib/lib/ip.nix b/lib/ip.nix similarity index 100% rename from lib/lib/ip.nix rename to lib/ip.nix diff --git a/lib/system.nix b/lib/system.nix new file mode 100644 index 0000000..b25c2d7 --- /dev/null +++ b/lib/system.nix @@ -0,0 +1,125 @@ +{ lib, ... }: + +with lib; +let + # See: man capabilities(7) + capabilities = [ + "CAP_AUDIT_CONTROL" + "CAP_AUDIT_READ" + "CAP_AUDIT_WRITE" + "CAP_BLOCK_SUSPEND" + "CAP_BPF" + "CAP_CHECKPOINT_RESTORE" + "CAP_CHOWN" + "CAP_DAC_OVERRIDE" + "CAP_DAC_READ_SEARCH" + "CAP_FOWNER" + "CAP_FSETID" + "CAP_IPC_LOCK" + "CAP_IPC_OWNER" + "CAP_KILL" + "CAP_LEASE" + "CAP_LINUX_IMMUTABLE" + "CAP_MAC_ADMIN" + "CAP_MAC_OVERRIDE" + "CAP_MKNOD" + "CAP_NET_ADMIN" + "CAP_NET_BIND_SERVICE" + "CAP_NET_BROADCAST" + "CAP_NET_RAW" + "CAP_PERFMON" + "CAP_SETGID" + "CAP_SETFCAP" + "CAP_SETPCAP" + "CAP_SETUID" + "CAP_SYS_ADMIN" + "CAP_SYS_BOOT" + "CAP_SYS_CHROOT" + "CAP_SYS_MODULE" + "CAP_SYS_NICE" + "CAP_SYS_PACCT" + "CAP_SYS_PTRACE" + "CAP_SYS_RAWIO" + "CAP_SYS_RESOURCE" + "CAP_SYS_TIME" + "CAP_SYS_TTY_CONFIG" + "CAP_SYSLOG" + "CAP_WAKE_ALARM" + ]; + + restrict-capabilities = allowed: + if (allowed == [ ]) then + "~${concatStringsSep " " capabilities}" + else + concatStringsSep " " allowed; + +in { + timed-service = { ... }: false; + + default-service = { after ? [ ], script ? null, reloadScript ? null + , before ? [ ], requires ? [ ], preStart ? null, postStop ? null + , preStop ? null, postStart ? null, requiredBy ? [ ], environment ? { } + , description, restartIfChanged ? true, confine ? false, path ? [ ] + , privateNetwork ? true, dynamicUser ? true, privateUsers ? true + , privateDevices ? true, privateTmp ? true, protectControlGroups ? true + , restrictSuidSgid ? true, protectKernelTunables ? true + , privateMounts ? true, protectKernelModules ? true, protectHome ? true + , protectHostname ? true, keyringMode ? "private" + , requiredCapabilities ? [ ], restartWhen ? "on-failure", restartSec ? "10" + , execStart ? null, protectSystem ? "full", addressFamilies ? null + , wantedBy ? [ ], workingDirectory ? null, user ? null, group ? null + , type ? "simple", partOf ? [ ], standardOutput ? "journal", pidFile ? null + , lockPersonality ? true, restrictRealtime ? true, networkWhitelist ? null + , memoryDenyWriteExecute ? true, ... }: { + enable = true; + script = mkIf (script != null) script; + reload = mkIf (reloadScript != null) reloadScript; + after = after; + before = before; + requires = requires; + wantedBy = wantedBy; + preStart = mkIf (preStart != null) preStart; + postStart = mkIf (postStart != null) postStart; + postStop = mkIf (postStop != null) postStop; + preStop = mkIf (preStop != null) preStop; + partOf = partOf; + requiredBy = requiredBy; + environment = environment; + description = description; + restartIfChanged = restartIfChanged; + confinement = mkIf confine { enable = true; }; + path = path; + serviceConfig = { + PrivateNetwork = privateNetwork; + PrivateUsers = privateUsers; + PrivateDevices = privateDevices; + PrivateTmp = privateTmp; + PrivateMounts = privateMounts; + ProtectControlGroups = protectControlGroups; + ProtectKernelTunables = protectKernelTunables; + ProtectKernelModules = protectKernelModules; + ProtectSystem = protectSystem; + ProtectHostname = protectHostname; + ProtectHome = protectHome; + KeyringMode = keyringMode; + # This is more complicated than it looks... + CapabilityBoundingSet = restrict-capabilities requiredCapabilities; + DynamicUser = dynamicUser; + Restart = restartWhen; + WorkingDirectory = mkIf (workingDirectory != null) workingDirectory; + RestrictAddressFamilies = + mkIf (addressFamilies != null) (concatStringsSep " " addressFamilies); + User = mkIf (user != null) user; + Group = mkIf (group != null) group; + Type = type; + StandardOutput = standardOutput; + PIDFile = mkIf (pidFile != null) pidFile; + LockPersonality = lockPersonality; + RestrictRealtime = restrictRealtime; + IpAddressAllow = mkIf (networkWhitelist != null) networkWhitelist; + IpAddressDeny = mkIf (networkWhitelist != null) "any"; + ExecStart = mkIf (execStart != null) execStart; + MemoryDenyWriteExecute = memoryDenyWriteExecute; + }; + }; +} diff --git a/nixops/common.nix b/nixops/lib/hosts.nix similarity index 77% rename from nixops/common.nix rename to nixops/lib/hosts.nix index 86b948c..94a2791 100644 --- a/nixops/common.nix +++ b/nixops/lib/hosts.nix @@ -1,15 +1,17 @@ +{ nixos-version, ... }: + let home-manager-package = builtins.fetchGit { url = "https://github.com/nix-community/home-manager.git"; - ref = "release-20.09"; + ref = "release-${nixos-version}"; }; pkgs = builtins.fetchGit { url = "https://github.com/NixOS/nixpkgs.git"; - ref = "release-20.09"; + ref = "release-${nixos-version}"; }; - initialize = import ../initialize.nix; + initialize = import ../../initialize.nix; host-config = ip: config: { ... }: { @@ -20,6 +22,7 @@ let site = config.site; domain = config.domain; home-manager-package = home-manager-package; + pkgs = pkgs; }) ]; diff --git a/nixops/russell.nix b/nixops/russell.nix index 5263146..0ddd192 100644 --- a/nixops/russell.nix +++ b/nixops/russell.nix @@ -1,19 +1,16 @@ let - common = import ./common.nix; - domain = "rus.selby.ca"; - site = "russell"; + nixos-version = "20.09"; - russell-host-config = ip: hostname: profile: - common.host-config ip { - hostname = hostname; - profile = profile; - domain = domain; - site = site; - }; + hosts = import ./lib/hosts.nix { inherit nixos-version; }; + russell-host = ip: hostname: profile: + let + site = "russell"; + domain = "rus.selby.ca"; + in hosts.host-config ip { inherit hostname profile domain site; }; in { network.description = "Russell home network."; - clunk = russell-host-config "10.0.0.1" "clunk" "server"; - plato = russell-host-config "10.0.0.102" "plato" "server"; + clunk = russell-host "10.0.0.1" "clunk" "server"; + plato = russell-host "10.0.0.102" "plato" "server"; } diff --git a/nixops/seattle.nix b/nixops/seattle.nix new file mode 100644 index 0000000..c39e128 --- /dev/null +++ b/nixops/seattle.nix @@ -0,0 +1,18 @@ +let + nixos-version = "20.09"; + + hosts = import ./lib/hosts.nix { inherit nix-version; }; + seattle-host = ip: hostname: profile: + let + site = "seattle"; + domain = "sea.fudo.org"; + in hosts.host-config ip { inherit hostname profile domain site; }; + +in { + network.description = "Seattle home network."; + + nostromo = seattle-host "10.0.0.1" "nostromo" "server"; + lambda = seattle-host "10.0.0.3" "lambda" "server"; + spark = seattle-host "10.0.0.108" "spark" "desktop"; + zbox = seattle-host "10.0.0.110" "zbox" "desktop"; +}