diff --git a/checks.nix b/checks.nix new file mode 100644 index 0000000..9505c35 --- /dev/null +++ b/checks.nix @@ -0,0 +1,20 @@ +{ + self, + flake-utils, + nixpkgs, + ... +}: +(flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + formatter = self.formatter.${system}; + in + { + checks = { + format = pkgs.runCommand "check-format" { + buildInputs = [ formatter ]; + } "${formatter}/bin/nixpkgs-fmt --check ${./.} && touch $out"; + }; + } +)).checks diff --git a/devshell.nix b/devshell.nix index 3931494..1fbad07 100644 --- a/devshell.nix +++ b/devshell.nix @@ -6,6 +6,7 @@ packages = with pkgs; [ agenix + nixpkgs-fmt nixos-rebuild ]; diff --git a/flake.lock b/flake.lock index 3d0d3f2..8c964f5 100644 --- a/flake.lock +++ b/flake.lock @@ -325,6 +325,22 @@ "type": "github" } }, + "nixpkgs-small": { + "locked": { + "lastModified": 1753505055, + "narHash": "sha256-jQKnNATDGDeuIeUf7r0yHnmirfYkYPHeF0N2Lv8rjPE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "7be0239edbf0783ff959f94f9728db414be73002", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable-small", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs-stable": { "locked": { "lastModified": 1730741070, @@ -381,6 +397,7 @@ "nixos-generators": "nixos-generators", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs", + "nixpkgs-small": "nixpkgs-small", "systems": "systems_2", "treefmt-nix": "treefmt-nix" } diff --git a/flake.nix b/flake.nix index 151f1b5..73686ce 100644 --- a/flake.nix +++ b/flake.nix @@ -2,6 +2,7 @@ description = "dadada's nix flake"; inputs = { + nixpkgs-small.url = "github:NixOS/nixpkgs/nixos-unstable-small"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; disko = { url = "github:nix-community/disko"; diff --git a/home/nixpkgs-config.nix b/home/nixpkgs-config.nix new file mode 100644 index 0000000..6a29a63 --- /dev/null +++ b/home/nixpkgs-config.nix @@ -0,0 +1,7 @@ +{ pkgs }: +{ + allowUnfree = true; + allowUnfreePredicate = pkg: true; + allowBroken = false; + android_sdk.accept_license = true; +} diff --git a/home/pkgs.nix b/home/pkgs.nix index e980614..7a707e1 100644 --- a/home/pkgs.nix +++ b/home/pkgs.nix @@ -125,6 +125,7 @@ with pkgs; spotify sqlite sshfs-fuse + steam taplo tcpdump tdesktop diff --git a/hydra-jobs.nix b/hydra-jobs.nix new file mode 100644 index 0000000..3369943 --- /dev/null +++ b/hydra-jobs.nix @@ -0,0 +1,4 @@ +{ self, nixpkgs, ... }: +(nixpkgs.lib.mapAttrs' ( + name: config: nixpkgs.lib.nameValuePair name config.config.system.build.toplevel +) self.nixosConfigurations) diff --git a/nixos/agares/configuration.nix b/nixos/agares/configuration.nix new file mode 100644 index 0000000..ba00c29 --- /dev/null +++ b/nixos/agares/configuration.nix @@ -0,0 +1,108 @@ +{ + config, + modulesPath, + pkgs, + ... +}: +{ + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ./ddns.nix + ./dns.nix + ./firewall.nix + ../modules/profiles/server.nix + ./network.nix + ./ntp.nix + ./ppp.nix + ]; + + fileSystems."/" = { + device = "/dev/sda1"; + fsType = "btrfs"; + options = [ "subvol=root" ]; + }; + + #fileSystems."/nix/store" = { + # device = "/dev/sda1"; + # fsType = "btrfs"; + # options = [ "subvol=/root/nix" "noatime" ]; + #}; + + fileSystems."/swap" = { + device = "/dev/sda1"; + fsType = "btrfs"; + options = [ + "subvol=/root/swap" + "noatime" + ]; + }; + + #swapDevices = [{ + # device = "/swap/swapfile"; + # size = 32 * 1024; # 32 GByte + #}]; + + hardware.cpu.amd.updateMicrocode = config.hardware.enableRedistributableFirmware; + + dadada = { + admin.enable = true; + }; + + services.smartd.enable = true; + + networking.hostName = "agares"; + networking.domain = "bs.dadada.li"; + + boot.initrd.availableKernelModules = [ + "xhci_pci" + "ahci" + "ehci_pci" + "usb_storage" + "sd_mod" + "sdhci_pci" + ]; + boot.initrd.kernelModules = [ "dm-snapshot" ]; + + # Use the GRUB 2 boot loader. + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/sda"; + boot.loader.grub.extraConfig = " + serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1 + terminal_input serial + terminal_output serial + "; + + boot.kernelParams = [ + "console=ttyS0,115200" + "amd_iommu=on" + "iommu=pt" + ]; + + boot.kernelModules = [ + "kvm-amd" + "vfio" + "vfio_iommu_type1" + "vfio_pci" + "vfio_virqfd" + ]; + + environment.systemPackages = with pkgs; [ + curl + flashrom + dmidecode + tcpdump + ]; + + services.munin-node = { + enable = true; + extraConfig = '' + host_name ${config.networking.hostName} + cidr_allow 10.3.3.3/32 + ''; + }; + + # Running router VM. They have to be restarted in the right order, so network comes up cleanly. Not ideal. + system.autoUpgrade.allowReboot = false; + + system.stateVersion = "23.05"; +} diff --git a/nixos/agares/ddns.nix b/nixos/agares/ddns.nix new file mode 100644 index 0000000..9a5948f --- /dev/null +++ b/nixos/agares/ddns.nix @@ -0,0 +1,13 @@ +{ config, ... }: +{ + dadada.ddns = { + domains = [ "vpn.dadada.li" ]; + credentialsPath = config.age.secrets."ddns-credentials".path; + interface = "ppp0"; + }; + + age.secrets."ddns-credentials" = { + file = "${config.dadada.secrets.path}/ddns-credentials.age"; + mode = "400"; + }; +} diff --git a/nixos/agares/dns.nix b/nixos/agares/dns.nix new file mode 100644 index 0000000..fe2843f --- /dev/null +++ b/nixos/agares/dns.nix @@ -0,0 +1,81 @@ +{ ... }: +{ + services.unbound = { + enable = true; + localControlSocketPath = "/run/unbound/unbound.ctl"; + settings = { + server = { + access-control = [ + "127.0.0.0/8 allow" + "127.0.0.1/32 allow_snoop" + "192.168.96.0/19 allow" + "192.168.1.0/24 allow" + "172.16.128.0/24 allow" + "::1/128 allow_snoop" + "fd42:9c3b:f96d::/48 allow" + ]; + interface = [ + "127.0.0.1" + "192.168.1.1" + "192.168.100.1" + "192.168.101.1" + "192.168.102.1" + "192.168.103.1" + "192.168.120.1" + "::1" + "fd42:9c3b:f96d:100::1" + "fd42:9c3b:f96d:101::1" + "fd42:9c3b:f96d:102::1" + "fd42:9c3b:f96d:103::1" + "fd42:9c3b:f96d:120::1" + ]; + prefer-ip6 = true; + prefetch = true; + prefetch-key = true; + serve-expired = false; + aggressive-nsec = true; + hide-identity = true; + hide-version = true; + use-caps-for-id = true; + val-permissive-mode = true; + local-data = [ + "\"agares.bs.dadada.li. 10800 IN A 192.168.101.1\"" + "\"danjal.bs.dadada.li. 10800 IN A 192.168.100.108\"" + "\"legion.bs.dadada.li. 10800 IN A 192.168.100.107\"" + "\"ninurta.bs.dadada.li. 10800 IN A 192.168.101.184\"" + "\"agares.bs.dadada.li. 10800 IN AAAA fd42:9c3b:f96d:101::1\"" + "\"ninurta.bs.dadada.li. 10800 IN AAAA fd42:9c3b:f96d:101:4a21:bff:fe3e:9cfe\"" + "\"backup1.dadada.li. 10800 IN AAAA fd42:9c3b:f96d:101:4a21:bff:fe3e:9cfe\"" + ]; + local-zone = [ + "\"168.192.in-addr.arpa.\" nodefault" + "\"d.f.ip6.arpa.\" nodefault" + ]; + }; + forward-zone = [ + { + name = "."; + forward-tls-upstream = "yes"; + forward-addr = [ + "2620:fe::fe@853#dns.quad9.net" + "2620:fe::9@853#dns.quad9.net" + "9.9.9.9@853#dns.quad9.net" + "149.112.112.112@853#dns.quad9.net" + ]; + } + ]; + stub-zone = + let + stubZone = name: addrs: { + name = "${name}"; + stub-addr = addrs; + }; + in + [ + #(stubZone "li.dadada.bs" ["192.168.128.220" "2a01:4f8:c010:a710::1"]) + #(stubZone "d.6.9.f.b.3.c.9.2.4.d.f.ip6.arpa" ["192.168.101.220" "2a01:4f8:c010:a710::1"]) + #(stubZone "168.192.in-addr.arpa" ["192.168.128.220" "2a01:4f8:c010:a710::1"]) + ]; + }; + }; +} diff --git a/nixos/agares/firewall.nix b/nixos/agares/firewall.nix new file mode 100644 index 0000000..569259f --- /dev/null +++ b/nixos/agares/firewall.nix @@ -0,0 +1,13 @@ +{ ... }: +{ + networking = { + useDHCP = false; + nat.enable = false; + firewall.enable = false; + nftables = { + enable = true; + checkRuleset = true; + ruleset = builtins.readFile ./rules.nft; + }; + }; +} diff --git a/nixos/agares/network.nix b/nixos/agares/network.nix new file mode 100644 index 0000000..6d86d22 --- /dev/null +++ b/nixos/agares/network.nix @@ -0,0 +1,323 @@ +{ config, lib, ... }: +let + ulaPrefix = "fd42:9c3b:f96d"; # fd42:9c3b:f96d::/48 + ipv4Prefix = "192.168"; # 192.168.96.0/19 + domain = "bs.dadada.li"; +in +{ + networking.useDHCP = false; + systemd.network = { + enable = true; + links = { + "10-persistent" = { + matchConfig.OriginalName = [ + "enp1s0" + "enp2s0" + ]; # takes search domains from the [Network] + linkConfig.MACAddressPolicy = "persistent"; + }; + }; + netdevs = { + # QoS concentrator + "ifb4ppp0" = { + netdevConfig = { + Kind = "ifb"; + Name = "ifb4ppp0"; + }; + }; + "20-lan" = { + netdevConfig = { + Kind = "vlan"; + Name = "lan.10"; + }; + vlanConfig = { + Id = 10; + }; + }; + "20-freifunk" = { + netdevConfig = { + Kind = "vlan"; + Name = "ff.11"; + }; + vlanConfig = { + Id = 11; + }; + }; + "20-roadw" = { + netdevConfig = { + Kind = "wireguard"; + Name = "roadw"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets."wg-privkey-vpn-dadada-li".path; + ListenPort = 51234; + }; + wireguardPeers = [ + { + wireguardPeerConfig = + let + peerAddresses = i: [ + "${ipv4Prefix}.120.${i}/32" + "${ulaPrefix}:120::${i}/128" + ]; + in + { + PublicKey = "0eWP1hzkyoXlrjPSOq+6Y1u8tnFH+SejBJs8f8lf+iU="; + AllowedIPs = peerAddresses "3"; + }; + } + ]; + }; + "20-wg0" = { + netdevConfig = { + Kind = "wireguard"; + Name = "wg0"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets."wg-privkey-wg0".path; + ListenPort = 51235; + }; + wireguardPeers = lib.singleton { + wireguardPeerConfig = { + PublicKey = "Kw2HVRb1zeA7NAzBvI3UzmOj45VqM358EBuZWdlAUDE="; + AllowedIPs = [ + "10.3.3.3/32" + "fd42:9c3b:f96d:121::3/128" + "fd42:9c3b:f96d:101:4a21:bff:fe3e:9cfe/128" + ]; + }; + }; + }; + }; + networks = + let + subnet = name: subnetId: { + matchConfig.Name = name; + addresses = [ + { addressConfig.Address = "${ipv4Prefix}.${subnetId}.1/24"; } + { addressConfig.Address = "${ulaPrefix}:${subnetId}::1/64"; } + ]; + dhcpPrefixDelegationConfig = { + SubnetId = "auto"; + }; + ipv6Prefixes = [ + { + ipv6PrefixConfig.Prefix = "${ulaPrefix}:${subnetId}::/64"; + } + ]; + dhcpServerConfig = { + DNS = "_server_address"; + NTP = "_server_address"; + EmitDNS = true; + EmitNTP = true; + EmitRouter = true; + PoolOffset = 100; + PoolSize = 100; + }; + ipv6SendRAConfig = { + EmitDNS = true; + DNS = "_link_local"; + EmitDomains = true; # takes search domains from the [Network] + }; + linkConfig = { + RequiredForOnline = false; + }; + networkConfig = { + Domains = domain; + EmitLLDP = "yes"; + IPv6SendRA = true; + IPv6AcceptRA = false; + DHCPPrefixDelegation = true; + DHCPServer = true; + }; + extraConfig = '' + [CAKE] + OverheadBytes = 38 + Bandwidth = 1G + RTT = lan + ''; + }; + in + { + "10-mgmt" = lib.mkMerge [ + (subnet "enp1s0" "100") + { + networkConfig.VLAN = [ + "lan.10" + "ff.11" + ]; + dhcpServerStaticLeases = [ + { + # legion + dhcpServerStaticLeaseConfig = { + Address = "192.168.100.107"; + MACAddress = "80:CC:9C:95:4A:60"; + }; + } + { + # danyal + dhcpServerStaticLeaseConfig = { + Address = "192.168.100.108"; + MACAddress = "c8:9e:43:a3:3d:7f"; + }; + } + ]; + } + ]; + "30-wg0" = { + matchConfig.Name = "wg0"; + address = [ + "10.3.3.2/32" + "fd42:9c3b:f96d:121::2/128" + ]; + DHCP = "no"; + networkConfig.IPv6AcceptRA = false; + linkConfig.RequiredForOnline = false; + routes = [ + { + routeConfig = { + Destination = "10.3.3.1/24"; + }; + } + { + routeConfig = { + Destination = "fd42:9c3b:f96d:121::1/64"; + }; + } + ]; + }; + "30-lan" = subnet "lan.10" "101" // { + dhcpServerStaticLeases = [ + { + # ninurta + dhcpServerStaticLeaseConfig = { + Address = "192.168.101.184"; + MACAddress = "48:21:0B:3E:9C:FE"; + }; + } + { + # crocell + dhcpServerStaticLeaseConfig = { + Address = "192.168.101.122"; + MACAddress = "9C:C9:EB:4F:3F:0E"; + }; + } + { + # gorgon + dhcpServerStaticLeaseConfig = { + Address = "192.168.101.205"; + MACAddress = "8C:C6:81:6A:39:2F"; + }; + } + ]; + }; + + "30-ff" = subnet "ff.11" "102"; + + "30-ifb4ppp0" = { + name = "ifb4ppp0"; + extraConfig = '' + [CAKE] + OverheadBytes = 65 + Bandwidth = 100M + FlowIsolationMode = triple + RTT = internet + ''; + linkConfig = { + RequiredForOnline = false; + }; + }; + + "30-ppp0" = { + name = "ppp*"; + linkConfig = { + RequiredForOnline = "routable"; + }; + networkConfig = { + KeepConfiguration = "static"; + DefaultRouteOnDevice = true; + LinkLocalAddressing = "ipv6"; + DHCP = "ipv6"; + }; + extraConfig = '' + [CAKE] + OverheadBytes = 65 + Bandwidth = 40M + FlowIsolationMode = triple + NAT=true + RTT = internet + + [DHCPv6] + PrefixDelegationHint= ::/56 + UseAddress = false + UseDelegatedPrefix = true + WithoutRA = solicit + + [DHCPPrefixDelegation] + UplinkInterface=:self + ''; + ipv6SendRAConfig = { + # Let networkd know that we would very much like to use DHCPv6 + # to obtain the "managed" information. Not sure why they can't + # just take that from the upstream RAs. + Managed = true; + }; + }; + # Talk to modem for management + "enp2s0" = { + name = "enp2s0"; + linkConfig = { + RequiredForOnline = false; + }; + networkConfig = { + Address = "192.168.1.254/24"; + EmitLLDP = "yes"; + }; + }; + "10-roadw" = { + matchConfig.Name = "roadw"; + addresses = [ + { addressConfig.Address = "${ipv4Prefix}.120.1/24"; } + { addressConfig.Address = "${ulaPrefix}:120::1/64"; } + ]; + DHCP = "no"; + networkConfig.IPv6AcceptRA = false; + linkConfig.RequiredForOnline = false; + routes = [ + { + routeConfig = { + Destination = "${ipv4Prefix}.120.1/24"; + }; + } + { + routeConfig = { + Destination = "${ulaPrefix}::120:1/64"; + }; + } + ]; + }; + }; + }; + + age.secrets."wg-privkey-vpn-dadada-li" = { + file = "${config.dadada.secrets.path}/wg-privkey-vpn-dadada-li.age"; + owner = "systemd-network"; + }; + + age.secrets."wg-privkey-wg0" = { + file = "${config.dadada.secrets.path}/agares-wg0-key.age"; + owner = "systemd-network"; + }; + + boot.kernel.sysctl = { + # Enable forwarding for interface + "net.ipv4.conf.all.forwarding" = "1"; + "net.ipv6.conf.all.forwarding" = "1"; + "net.ipv6.conf.all.accept_ra" = "0"; + "net.ipv6.conf.all.autoconf" = "0"; + # Set via systemd-networkd + #"net.ipv6.conf.${intf}.use_tempaddr" = "0"; + }; + + powerManagement.cpuFreqGovernor = lib.mkDefault "schedutil"; +} diff --git a/nixos/agares/ntp.nix b/nixos/agares/ntp.nix new file mode 100644 index 0000000..c3ec49b --- /dev/null +++ b/nixos/agares/ntp.nix @@ -0,0 +1,12 @@ +{ ... }: +{ + services.chrony = { + enable = true; + extraConfig = '' + allow 192.168.1 + allow 192.168.100 + allow 192.168.101 + allow 192.168.102 + ''; + }; +} diff --git a/nixos/agares/ppp.nix b/nixos/agares/ppp.nix new file mode 100644 index 0000000..ffa5bc4 --- /dev/null +++ b/nixos/agares/ppp.nix @@ -0,0 +1,68 @@ +{ + pkgs, + lib, + config, + ... +}: +let + secretsPath = config.dadada.secrets.path; +in +{ + # PPPoE + services.pppd = { + enable = true; + peers = { + telekom = { + enable = true; + autostart = true; + config = '' + debug + + plugin pppoe.so enp2s0 + + noauth + hide-password + call telekom-secret + + linkname ppp0 + + persist + maxfail 0 + holdoff 5 + + noipdefault + defaultroute + + lcp-echo-interval 15 + lcp-echo-failure 3 + ''; + }; + }; + }; + + age.secrets."etc-ppp-telekom-secret" = { + file = "${secretsPath}/etc-ppp-telekom-secret.age"; + owner = "root"; + mode = "700"; + path = "/etc/ppp/peers/telekom-secret"; + }; + + age.secrets."etc-ppp-pap-secrets" = { + # format: client server passphrase + file = "${secretsPath}/etc-ppp-chap-secrets.age"; + owner = "root"; + mode = "700"; + path = "/etc/ppp/pap-secrets"; + }; + + # Hook for QoS via Intermediate Functional Block + environment.etc."ppp/ip-up" = { + mode = "755"; + text = with lib; '' + #!/usr/bin/env sh + ${getBin pkgs.iproute2}/bin/tc qdisc del dev $1 ingress + ${getBin pkgs.iproute2}/bin/tc qdisc add dev $1 handle ffff: ingress + ${getBin pkgs.iproute2}/bin/tc filter add dev $1 parent ffff: matchall action mirred egress redirect dev ifb4ppp0 + ''; + }; +} diff --git a/nixos/agares/rules.nft b/nixos/agares/rules.nft new file mode 100644 index 0000000..4b41bea --- /dev/null +++ b/nixos/agares/rules.nft @@ -0,0 +1,136 @@ +flush ruleset + +define IF_MGMT = "enp1s0" +define IF_FF = "ff.11" +define IF_LAN = "lan.10" +define IF_WAN = "ppp0" + +# Modem uses this for internet uplink via our WAN +define IF_MODEM = "enp2s0" + +define IF_ROADW = "roadw" + +table inet filter { + # Will give "no such file or directory if hardware does not support flow offloading" + # flowtable f { + # hook ingress priority 0; devices = { enp1s0, enp2s0 }; flags offload; + # } + + chain input_local { + ip6 saddr != ::1/128 log prefix "Dropped IPv6 nonlocalhost packet on loopback:" drop + accept comment "Accept traffic to loopback interface" + } + + chain input_icmp_untrusted { + # Allow ICMP echo + ip protocol icmp icmp type { echo-request } limit rate 1000/second burst 5 packets accept comment "Accept echo request" + + # Allow some ICMPv6 + icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, echo-request, echo-reply, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-done, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld2-listener-report } limit rate 1000/second burst 5 packets accept comment "Allow some ICMPv6" + } + + chain input_modem { + jump input_icmp_untrusted + } + + chain input_wan { + # DHCPv6 client + meta nfproto ipv6 udp sport 547 accept comment "Allow DHCPv6 client" + + jump input_icmp_untrusted + + udp dport 51234 accept comment "Wireguard roadwarriors" + } + + chain input_lan { + counter accept comment "Accept all traffic from LAN" + } + + chain input_mgmt { + counter accept comment "Accept all traffic from MGMT" + } + + chain input_roadw { + counter accept comment "Accept all traffic from roadwarriors" + } + + chain input_ff { + jump input_icmp_untrusted + + # DHCP + meta nfproto ipv6 udp dport 547 accept comment "Allow DHCPv6 client" + + # Allow DNS and DHCP from Freifunk + udp dport { 53, 67 } accept comment "Allow DNS and DHCP from Freifunk" + } + + chain input_wg0 { + tcp dport 4949 accept comment "Munin node" + } + + chain input { + type filter hook input priority filter; policy drop; + + ct state {established, related} counter accept comment "Accept packets from established and related connections" + ct state invalid counter drop comment "Early drop of invalid packets" + + iifname vmap { lo : accept, $IF_WAN : jump input_wan, $IF_LAN : jump input_lan, $IF_FF : jump input_ff, $IF_ROADW : jump input_roadw, $IF_MODEM : jump input_modem, $IF_MGMT : jump input_mgmt, wg0 : jump input_wg0 } + } + +# Only works if hardware flow offloading is available +# chain offload { +# type filter hook forward priority -100; policy accept; +# ip protocol tcp flow add @f +# counter packets 0 bytes 0 +# } + + chain forward { + type filter hook forward priority filter; policy drop; + + # Accept connections tracked by destination NAT + ct status dnat counter accept comment "Accept connections tracked by DNAT" + + # TCP options + tcp flags syn tcp option maxseg size set rt mtu comment "Remove TCP maximum segment size and set a size based on route information" + + # ICMPv6 + icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, echo-request, echo-reply, parameter-problem } limit rate 5/second counter accept comment "Forward up to five ICMP messages of allowed types per second" + meta l4proto ipv6-icmp accept comment "Forward ICMP in IPv6" + + # mgmt <-> * + iifname { $IF_LAN, $IF_ROADW } oifname $IF_MGMT counter reject comment "Reject traffic from LAN and roadwarrior to MGMT" + iifname $IF_MGMT oifname { $IF_LAN, $IF_ROADW } counter reject comment "Reject traffic from MGMT to LAN and roadwarrior" + # drop (instead of reject) everything else to MGMT + + # LAN, ROADW -> * (except mgmt) + iifname { $IF_LAN, $IF_ROADW } counter accept comment "Allow all traffic forwarding from LAN and roadwarrior to all interfaces, except to mgmt" + + # FF -> WAN + iifname { $IF_FF } oifname $IF_WAN counter accept comment "Allow all traffic forwarding from Freifunk and services to WAN" + + # { WAN } -> { FF, LAN, RW } + iifname { $IF_WAN } oifname { $IF_FF, $IF_LAN, $IF_ROADW } ct state established,related counter accept comment "Allow established back from WAN" + } + + chain output { + type filter hook output priority 100; policy accept; + } +} + +table ip nat { + chain prerouting { + type nat hook prerouting priority dstnat; policy accept; + } + + chain postrouting { + type nat hook postrouting priority srcnat; policy accept; + ip saddr { 192.168.96.0/19 } oifname { $IF_WAN } masquerade comment "Masquerade traffic from LANs" + } +} + +table arp filter { + chain input { + type filter hook input priority filter; policy drop; + iifname { $IF_MGMT, $IF_LAN, $IF_FF, $IF_MODEM } limit rate 1/second burst 2 packets accept comment "Limit number of ARP messages from LAN, FF, MGMT, modem" + } +} diff --git a/nixos/configurations.nix b/nixos/configurations.nix index 877c6a9..95b894e 100644 --- a/nixos/configurations.nix +++ b/nixos/configurations.nix @@ -8,84 +8,127 @@ nixos-hardware, nixos-generators, nixpkgs, + nixpkgs-small, ... }@inputs: let - # create a new instance allowing some unfree packages - nixpkgsx86 = import nixpkgs { - system = "x86_64-linux"; - config.allowUnfreePredicate = - pkg: - builtins.elem (nixpkgs.lib.getName pkg) [ - "aspell-dict-en-science" - "brgenml1lpr" - "saleae-logic-2" - "spotify" - ]; - }; - nixosSystem = nixpkgs.lib.nixosSystem; - baseModule = - { lib, ... }: + nixosSystem = { - _module.args.inputs = inputs; - imports = [ - inputs.agenix.nixosModules.age - inputs.disko.nixosModules.disko - inputs.home-manager.nixosModules.home-manager + nixpkgs, + system ? "x86_64-linux", + extraModules ? [ ], + }: + nixpkgs.lib.nixosSystem { + inherit system; + + modules = [ + { + nixpkgs.overlays = nixpkgs.lib.attrValues self.overlays; + } + ] + ++ (nixpkgs.lib.attrValues self.nixosModules) + ++ [ agenix.nixosModules.age ] + ++ extraModules; + }; +in +{ + stolas = + let + system = "x86_64-linux"; + in + nixosSystem { + inherit nixpkgs system; + + extraModules = [ + lanzaboote.nixosModules.lanzaboote + disko.nixosModules.disko + { + nixpkgs.overlays = nixpkgs.lib.attrValues self.overlays; + dadada.pkgs = self.packages.${system}; + dadada.inputs = inputs // { + dadada = self; + }; + } + nixos-hardware.nixosModules.framework-amd-ai-300-series + home-manager.nixosModules.home-manager ( { pkgs, ... }: { - dadada.homepage.package = homepage; - dadada.pkgs = inputs.self.packages.${pkgs.system}; - dadada.inputs = inputs // { - dadada = inputs.self; - }; + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.sharedModules = (nixpkgs.lib.attrValues self.hmModules) ++ [ + { dadada.home.helix.package = pkgs.helix; } + ]; + home-manager.users.dadada = import ../home; } ) - inputs.lanzaboote.nixosModules.lanzaboote - ] - ++ (lib.attrValues inputs.self.nixosModules); + ./stolas + ]; }; - homeModule = ./modules/profiles/home.nix; -in -{ - stolas = nixosSystem { - modules = [ - { nixpkgs.pkgs = nixpkgsx86; } - baseModule - nixos-hardware.nixosModules.framework-amd-ai-300-series - homeModule - ./stolas - ]; - }; - gorgon = nixosSystem { - modules = [ - { nixpkgs.pkgs = nixpkgsx86; } - baseModule - nixos-hardware.nixosModules.lenovo-thinkpad-t14s-amd-gen1 - homeModule - ./gorgon/configuration.nix - ]; - }; + gorgon = + let + system = "x86_64-linux"; + in + nixosSystem { + inherit nixpkgs system; + + extraModules = [ + { + nixpkgs.overlays = nixpkgs.lib.attrValues self.overlays; + dadada.pkgs = self.packages.${system}; + dadada.inputs = inputs // { + dadada = self; + }; + } + nixos-hardware.nixosModules.lenovo-thinkpad-t14s-amd-gen1 + home-manager.nixosModules.home-manager + ( + { pkgs, ... }: + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.sharedModules = (nixpkgs.lib.attrValues self.hmModules) ++ [ + { dadada.home.helix.package = pkgs.helix; } + { manual.manpages.enable = false; } + ]; + home-manager.users.dadada = import ../home; + } + ) + ./gorgon/configuration.nix + ]; + }; surgat = nixosSystem { - modules = [ - { nixpkgs.pkgs = nixpkgsx86; } - baseModule + nixpkgs = nixpkgs-small; + system = "x86_64-linux"; + extraModules = [ + { + dadada.homepage.package = homepage; + } + ./modules/profiles/server.nix ./surgat/configuration.nix ]; }; - installer = nixosSystem { - modules = [ - nixos-generators.nixosModules.install-iso - inputs.self.nixosModules.admin - ( - { lib, ... }: + agares = nixosSystem { + nixpkgs = nixpkgs-small; + extraModules = [ + ./agares/configuration.nix + ]; + }; + + installer = + let + nixpkgs = nixpkgs-small; + in + nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + nixos-generators.nixosModules.install-iso + self.nixosModules.admin { - nixpkgs.pkgs = nixpkgs.legacyPackages."x86_64-linux"; - isoImage.isoName = lib.mkForce "dadada-nixos-installer.iso"; + isoImage.isoName = nixpkgs.lib.mkForce "dadada-nixos-installer.iso"; networking.tempAddresses = "disabled"; dadada.admin.enable = true; documentation.enable = true; @@ -96,14 +139,12 @@ in keyMap = "us"; }; } - ) - ]; - }; + ]; + }; ninurta = nixosSystem { - modules = [ - { nixpkgs.pkgs = nixpkgsx86; } - baseModule + nixpkgs = nixpkgs-small; + extraModules = [ ./ninurta/configuration.nix ]; }; diff --git a/nixos/gorgon/configuration.nix b/nixos/gorgon/configuration.nix index 69e7588..16f8130 100644 --- a/nixos/gorgon/configuration.nix +++ b/nixos/gorgon/configuration.nix @@ -52,6 +52,8 @@ in age.secrets."${config.networking.hostName}-backup-passphrase-gs".file = "${secretsPath}/${config.networking.hostName}-backup-passphrase-gs.age"; + nixpkgs.config.android_sdk.accept_license = true; + programs.ssh.startAgent = true; nix.extraOptions = '' @@ -83,7 +85,7 @@ in networking.hostName = "gorgon"; dadada = { - steam.enable = false; + steam.enable = true; yubikey.enable = true; }; @@ -152,6 +154,7 @@ in #]; environment.systemPackages = with pkgs; [ + android-studio ghostscript smartmontools @@ -261,7 +264,7 @@ in xdg.portal.wlr.enable = false; hardware.bluetooth.enable = true; - hardware.graphics = { + hardware.opengl = { enable = true; extraPackages = with pkgs; [ vaapiVdpau diff --git a/nixos/modules/nixpkgs.nix b/nixos/modules/nixpkgs.nix new file mode 100644 index 0000000..2c5849f --- /dev/null +++ b/nixos/modules/nixpkgs.nix @@ -0,0 +1,3 @@ +{ + nixpkgs.config.allowUnfreePredicate = pkg: true; +} diff --git a/nixos/modules/profiles/cloud.nix b/nixos/modules/profiles/cloud.nix index 1ddbb1e..de57714 100644 --- a/nixos/modules/profiles/cloud.nix +++ b/nixos/modules/profiles/cloud.nix @@ -4,10 +4,6 @@ let initrdHostKey = "${config.networking.hostName}-ssh_host_ed25519_key"; in { - imports = [ - ./server.nix - ]; - boot.initrd.availableKernelModules = [ "virtio-pci" ]; boot.kernelParams = [ diff --git a/nixos/modules/profiles/home.nix b/nixos/modules/profiles/home.nix deleted file mode 100644 index a695e8b..0000000 --- a/nixos/modules/profiles/home.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ pkgs, inputs, ... }: -{ - home-manager.useGlobalPkgs = true; - home-manager.useUserPackages = true; - home-manager.sharedModules = pkgs.lib.attrValues inputs.self.hmModules; - home-manager.users.dadada = inputs.self.hmConfigurations.dadada; -} diff --git a/nixos/modules/steam.nix b/nixos/modules/steam.nix index e14add3..b6b0846 100644 --- a/nixos/modules/steam.nix +++ b/nixos/modules/steam.nix @@ -15,8 +15,11 @@ in }; }; config = mkIf cfg.enable { - hardware.graphics = { + nixpkgs.config.allowUnfree = true; + + hardware.opengl = { enable = true; + driSupport32Bit = true; extraPackages32 = with pkgs.pkgsi686Linux; [ libva ]; }; diff --git a/nixos/modules/yubikey.nix b/nixos/modules/yubikey.nix index 47699e1..4be4492 100644 --- a/nixos/modules/yubikey.nix +++ b/nixos/modules/yubikey.nix @@ -34,7 +34,7 @@ in }; u2f = { control = "sufficient"; - settings.cue = true; + cue = true; }; }; diff --git a/nixos/ninurta/configuration.nix b/nixos/ninurta/configuration.nix index d4a7bb9..39bdca7 100644 --- a/nixos/ninurta/configuration.nix +++ b/nixos/ninurta/configuration.nix @@ -14,6 +14,7 @@ let uwuPrivKey = "pruflas-wg0-key"; wgHydraPrivKey = "pruflas-wg-hydra-key"; uwuPresharedKey = "pruflas-wg0-preshared-key"; + hydraGitHubAuth = "hydra-github-authorization"; initrdSshKey = "/etc/ssh/ssh_initrd_ed25519_key"; softServePort = 23231; in @@ -153,6 +154,34 @@ in mode = "400"; }; + age.secrets.${hydraGitHubAuth} = { + file = "${secretsPath}/${hydraGitHubAuth}.age"; + mode = "440"; + owner = "hydra-www"; + group = "hydra"; + }; + + services.hydra = { + enable = false; + package = pkgs.hydra; + hydraURL = "https://hydra.dadada.li"; + notificationSender = "hydra@localhost"; + buildMachinesFiles = [ ]; + useSubstitutes = true; + port = 3000; + listenHost = "10.3.3.3"; + extraConfig = '' + Include ${config.age.secrets."${hydraGitHubAuth}".path} + + + jobs = nix-config:main.* + inputs = nix-config + excludeBuildFromContext = 1 + useShortContext = 1 + + ''; + }; + nix.buildMachines = [ { hostName = "localhost"; @@ -270,10 +299,14 @@ in linkConfig.RequiredForOnline = false; routes = [ { - Destination = "10.3.3.1/24"; + routeConfig = { + Destination = "10.3.3.1/24"; + }; } { - Destination = "fd42:9c3b:f96d:121::1/64"; + routeConfig = { + Destination = "fd42:9c3b:f96d:121::1/64"; + }; } ]; }; @@ -290,10 +323,14 @@ in linkConfig.RequiredForOnline = false; routes = [ { - Destination = "10.11.0.0/22"; + routeConfig = { + Destination = "10.11.0.0/22"; + }; } { - Destination = "fc00:1337:dead:beef::10.11.0.0/118"; + routeConfig = { + Destination = "fc00:1337:dead:beef::10.11.0.0/118"; + }; } ]; }; @@ -333,21 +370,25 @@ in }; wireguardPeers = [ { - PublicKey = "KzL+PKlv4LktIqqTqC9Esw8dkSZN2qSn/vq76UHbOlY="; - AllowedIPs = [ - "10.3.3.1/32" - "fd42:9c3b:f96d:121::1/128" - ]; - PersistentKeepalive = 25; - Endpoint = "surgat.dadada.li:51235"; + wireguardPeerConfig = { + PublicKey = "KzL+PKlv4LktIqqTqC9Esw8dkSZN2qSn/vq76UHbOlY="; + AllowedIPs = [ + "10.3.3.1/32" + "fd42:9c3b:f96d:121::1/128" + ]; + PersistentKeepalive = 25; + Endpoint = "surgat.dadada.li:51235"; + }; } { - PublicKey = "INfv++4R+Kd2jdh/3CooM70ZeeoN6aeU6mo+T4C8gWU="; - AllowedIPs = [ - "10.3.3.2/32" - "fd42:9c3b:f96d:121::2/128" - ]; - Endpoint = "192.168.101.1:51235"; + wireguardPeerConfig = { + PublicKey = "INfv++4R+Kd2jdh/3CooM70ZeeoN6aeU6mo+T4C8gWU="; + AllowedIPs = [ + "10.3.3.2/32" + "fd42:9c3b:f96d:121::2/128" + ]; + Endpoint = "192.168.101.1:51235"; + }; } ]; }; @@ -361,15 +402,17 @@ in }; wireguardPeers = [ { - PublicKey = "tuoiOWqgHz/lrgTcLjX+xIhvxh9jDH6gmDw2ZMvX5T8="; - AllowedIPs = [ - "10.11.0.0/22" - "fc00:1337:dead:beef::10.11.0.0/118" - "192.168.178.0/23" - ]; - PersistentKeepalive = 25; - PresharedKeyFile = config.age.secrets.${uwuPresharedKey}.path; - Endpoint = "53c70r.de:51820"; + wireguardPeerConfig = { + PublicKey = "tuoiOWqgHz/lrgTcLjX+xIhvxh9jDH6gmDw2ZMvX5T8="; + AllowedIPs = [ + "10.11.0.0/22" + "fc00:1337:dead:beef::10.11.0.0/118" + "192.168.178.0/23" + ]; + PersistentKeepalive = 25; + PresharedKeyFile = config.age.secrets.${uwuPresharedKey}.path; + Endpoint = "53c70r.de:51820"; + }; } ]; }; @@ -429,7 +472,7 @@ in }) ]; - services.pulseaudio.enable = false; + hardware.pulseaudio.enable = false; environment.systemPackages = with pkgs; [ smartmontools diff --git a/nixos/stolas/default.nix b/nixos/stolas/default.nix index 1c5cc9b..696f55f 100644 --- a/nixos/stolas/default.nix +++ b/nixos/stolas/default.nix @@ -12,20 +12,18 @@ ./paperless.nix ]; + nixpkgs = { + hostPlatform = "x86_64-linux"; + config.allowUnfree = true; + }; + boot = { lanzaboote = { enable = true; pkiBundle = "/var/lib/sbctl"; }; kernelModules = [ "kvm-amd" ]; - # Hopefully fixes suspend issues with wifi card - kernelPackages = pkgs.linuxPackages_latest; - kernelParams = [ - "resume=UUID=81dfbfa5-d578-479c-b11c-3ee5abd6848a" - "resume_offset=79859524" - "zswap.enabled=1" - ]; - extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ]; + extraModulePackages = [ pkgs.linuxPackages.v4l2loopback ]; # Lanzaboote currently replaces the systemd-boot module. # This setting is usually set to true in configuration.nix # generated at installation time. So we force it to false @@ -53,7 +51,7 @@ # NOTE: hardware.framework.enableKmod requires kernel patching, but enables access to some EC features bluetooth.enable = true; cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; - enableRedistributableFirmware = true; + enableAllFirmware = true; framework.laptop13.audioEnhancement.enable = true; graphics = { enable = true; @@ -67,6 +65,10 @@ powerManagement = { enable = true; cpuFreqGovernor = "schedutil"; + # TODO: Limit charge of battery, does this work without kernel patches from hardware.frameworkenableKmod? + powerUpCommands = '' + echo 80 > /sys/class/power_supply/BAT0/charge_control_stop_threshold + ''; }; networking = { @@ -172,6 +174,10 @@ "dbus-org.freedesktop.ModemManager1".enable = lib.mkForce false; }; + systemd.sleep.extraConfig = '' + HibernateDelaySec=1h + ''; + systemd.tmpfiles.rules = [ "v /var/.snapshots 0755 root root - -" "v /var/paperless/.snapshots 0755 root root - -" @@ -199,7 +205,20 @@ "wireshark" "paperless" ]; + shell = "/run/current-system/sw/bin/zsh"; }; }; }; + + # TODO + # age.secrets = { + # paperless = { + # file = "${config.dadada.secrets.path}/paperless.age"; + # mode = "700"; + # owner = "paperless"; + # }; + # }; + + # Create compressing swap space in RAM + zramSwap.enable = true; } diff --git a/nixos/stolas/disks.nix b/nixos/stolas/disks.nix index eff5680..01cf635 100644 --- a/nixos/stolas/disks.nix +++ b/nixos/stolas/disks.nix @@ -86,7 +86,7 @@ }; "/swap" = { mountpoint = "/.swapvol"; - swap.swapfile.size = "128G"; + swap.swapfile.size = "64G"; }; }; }; diff --git a/nixos/surgat/configuration.nix b/nixos/surgat/configuration.nix index 5ddef7f..5cd9596 100644 --- a/nixos/surgat/configuration.nix +++ b/nixos/surgat/configuration.nix @@ -74,10 +74,12 @@ in "2a01:4f8:c17:1d70::/64" ]; routes = [ - { Gateway = "fe80::1"; } + { routeConfig.Gateway = "fe80::1"; } { - Gateway = "172.31.1.1"; - GatewayOnLink = true; + routeConfig = { + Gateway = "172.31.1.1"; + GatewayOnLink = true; + }; } ]; linkConfig.RequiredForOnline = "routable"; @@ -93,13 +95,19 @@ in linkConfig.RequiredForOnline = "no"; routes = [ { - Destination = "10.3.3.3/24"; + routeConfig = { + Destination = "10.3.3.3/24"; + }; } { - Destination = "fd42:9c3b:f96d:121::/64"; + routeConfig = { + Destination = "fd42:9c3b:f96d:121::/64"; + }; } { - Destination = "fd42:9c3b:f96d:101::/64"; + routeConfig = { + Destination = "fd42:9c3b:f96d:101::/64"; + }; } ]; }; @@ -116,12 +124,14 @@ in }; wireguardPeers = [ { - PublicKey = "Kw2HVRb1zeA7NAzBvI3UzmOj45VqM358EBuZWdlAUDE="; - AllowedIPs = [ - "10.3.3.3/32" - "fd42:9c3b:f96d:121::3/128" - "fd42:9c3b:f96d:101:4a21:bff:fe3e:9cfe/128" - ]; + wireguardPeerConfig = { + PublicKey = "Kw2HVRb1zeA7NAzBvI3UzmOj45VqM358EBuZWdlAUDE="; + AllowedIPs = [ + "10.3.3.3/32" + "fd42:9c3b:f96d:121::3/128" + "fd42:9c3b:f96d:101:4a21:bff:fe3e:9cfe/128" + ]; + }; } ]; }; diff --git a/outputs.nix b/outputs.nix index ef7a742..c860d3c 100644 --- a/outputs.nix +++ b/outputs.nix @@ -1,3 +1,4 @@ +# Adapted from Mic92/dotfiles { self, flake-utils, @@ -10,7 +11,7 @@ (flake-utils.lib.eachDefaultSystem ( system: let - pkgs = nixpkgs.legacyPackages.${system}; + pkgs = import nixpkgs { inherit system; }; treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix; in { @@ -27,22 +28,23 @@ in import ./devshell.nix { inherit pkgs extraModules; }; - checks = { - formatting = treefmtEval.config.build.check self; - }; - formatter = treefmtEval.config.build.wrapper; packages = import ./pkgs { inherit pkgs; } // { - installer-iso = inputs.self.nixosConfigurations.installer.config.system.build.isoImage; + installer-iso = self.nixosConfigurations.installer.config.system.build.isoImage; }; } )) // { hmModules = import ./home/modules.nix { lib = nixpkgs.lib; }; - hmConfigurations = { - dadada = import ./home; - }; + nixosConfigurations = import ./nixos/configurations.nix inputs; + nixosModules = import ./nixos/modules { lib = nixpkgs.lib; }; + + overlays = import ./overlays.nix; + + hydraJobs = import ./hydra-jobs.nix inputs; + + checks = import ./checks.nix inputs; } diff --git a/overlays.nix b/overlays.nix new file mode 100644 index 0000000..ffcd441 --- /dev/null +++ b/overlays.nix @@ -0,0 +1 @@ +{ } diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 50dd263..f449646 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -1,6 +1,7 @@ let dadada = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN+bBJptw2H35vMPV7Mfj9oaepR7cHCQH8ZsvL8qnj+r dadada (nix-config-secrets) "; systems = { + agares = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPcbuLtU9/VhFy5VAp/ZI0T+gr7kExG73hmjjvno10gP root@nixos"; gorgon = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDCcwG8BkqjZJ1bPdFbLYfXeBgaI10+gyVs1r1aNJ49H root@gorgon"; ifrit = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEYO4L5EvKRtVUB6YHtHN7R980fwH9kKVt0V3kj6rORS root@nixos"; ninurta = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO8TDCzjVVO7A4k6rp+srMj0HHc5gmUOlskTBOvhMkEc root@nixos"; @@ -62,16 +63,24 @@ in dadada ]; "ddns-credentials.age".publicKeys = [ + systems.agares systems.ninurta dadada ]; "etc-ppp-chap-secrets.age".publicKeys = [ + systems.agares dadada ]; "etc-ppp-telekom-secret.age".publicKeys = [ + systems.agares dadada ]; "wg-privkey-vpn-dadada-li.age".publicKeys = [ + systems.agares + dadada + ]; + "agares-wg0-key.age".publicKeys = [ + systems.agares dadada ]; } @@ -80,4 +89,5 @@ in // backupSecrets "ifrit" // backupSecrets "pruflas" // backupSecrets "surgat" +// backupSecrets "agares" // backupSecrets "stolas"