# SPDX-FileCopyrightText: 2022 Richard Brežák # # SPDX-License-Identifier: LGPL-3.0-or-later { inputs, lib', config, secret, ... }: let inherit (lib') flip mapAttrs singleton loadSecrets mkAfter; config' = config; in { flake.nixosConfigurations.omen = inputs.nixpkgs.lib.nixosSystem { system = "x86_64-linux"; lib = lib'; specialArgs = { config' = config'; inputs' = inputs; secret = loadSecrets inputs.secret; }; modules = singleton ({ pkgs, lib, config, ... }: { imports = [ ./xserver.nix ../../common/steam.nix ./grub.nix ./networking.nix ./filesystems.nix ./hardware.nix ./users.nix ./nixpkgs.nix ../../common/sound.nix # ./test-vm.nix inputs.dwarffs.nixosModules.dwarffs inputs.microvm.nixosModules.host inputs.notnft.nixosModules.default inputs.self.nixosModules.notnft inputs.self.nixosModules.microvm-extras-host ]; _module.args.nixinate = { host = secret.network.ips.omen.vpn or ""; sshUser = "main"; buildOn = "local"; substituteOnTarget = true; hermetic = false; nixOptions = [ "--override-input secret path://$HOME/dotfiles/secret" ]; }; services.fwupd.enable = true; services.syncthing = { enable = true; user = "main"; group = "main"; }; services.sshd.enable = true; # Makes QEMU recompile https://github.com/NixOS/nixpkgs/issues/221056 boot.binfmt.emulatedSystems = [ "aarch64-linux" "riscv64-linux" ]; time.timeZone = "Europe/Amsterdam"; system.stateVersion = "20.09"; virtualisation.podman.enable = true; virtualisation.podman.dockerCompat = true; nixpkgs.overlays = [ (final: prev: let nixpkgs = final.fetchFromGitHub { owner = "NixOS"; repo = "nixpkgs"; rev = "2ca2346b60f72fc75bcc570367e24e1d68d55b18"; sha256 = "sha256-GNUI2MRZGe8rm27DgY503aLyXRm/Dfcao6McHrHkA7s="; }; pkgs = import nixpkgs { system = final.stdenv.system; }; virtiofsd = pkgs.virtiofsd; in { virtiofsd = final.writeShellScriptBin "virtiofsd" '' ok_args=() while [[ $# -gt 0 ]] ; do case "$1" in --posix-acl) ;; *) ok_args+=("$1") ;; esac shift 1 done exec ${lib.getExe virtiofsd} "''${ok_args[@]}" ''; } ) ]; # networking.nftables = { # enable = true; # rulesetFile = networking.notnft.rules = let notnft = (inputs.notnft.lib.${pkgs.stdenv.system}); logRule = with notnft.dsl; with payload; prefix: [ (log { prefix = "${prefix} dropped: "; flags = (f: [ f.all ]); } ) ]; traceChain = with notnft.dsl; with payload; add chain [ (is.eq th.dport 53) (mangle meta.nftrace 1) ] [ (is.eq th.dport 53) (mangle meta.nftrace 1) ] [ (is.eq th.dport 22) (mangle meta.nftrace 1) ] [ (is.eq th.sport 22) (mangle meta.nftrace 1) ] [ (is.eq meta.oifname "mvm0") (mangle meta.nftrace 1) ] [ (is.eq meta.iifname "mvm0") (mangle meta.nftrace 1) ]; in # pkgs.writeText "nftables.json" (builtins.toJSON (with notnft.dsl; with payload; ruleset with notnft.dsl; with payload; ruleset { filter = add table { family = f: f.inet; } { trace = traceChain; ### lo input-lo = add chain [ (is.ne ip.saddr (set [ "127.0.0.1" "127.0.0.53" ])) drop ] [ (is.ne ip.daddr (set [ "127.0.0.1" "127.0.0.53" ])) drop ] [ accept ]; output-lo = add chain [ accept ]; ### ### mvm input-mvm = add chain [ (is.eq ip.protocol (f: f.icmp)) accept ]; output-mvm = add chain [ (is.eq ip.protocol (f: f.icmp)) (is.eq ip.saddr "10.80.1.1") (is.eq ip.daddr "10.80.1.2") accept ] [ (is.eq ip.protocol (f: f.icmp)) (is.eq ip.saddr "10.80.1.2") (is.eq ip.daddr "10.80.1.1") accept ] [ (is.eq ip.protocol (f: with f; set [ tcp ])) (is.eq th.dport 22) (is.eq ip.saddr "10.80.1.1") (is.eq ip.daddr "10.80.1.2") accept ] [ (is.eq ip.protocol (f: with f; set [ tcp ])) (is.eq th.dport 80) (is.eq ip.saddr "10.80.1.1") (is.eq ip.daddr "10.80.1.2") accept ]; ### ### wlan0 input-wlan0 = add chain [ drop ]; output-wlan0 = add chain [ (is.ne ip.daddr (secret.network.ips.blowhole.ip or "")) (is.eq ip.protocol (f: with f; set [ tcp udp ])) (is.eq th.dport 53) drop ] [ accept ]; ### ### wlan0 input-eth0 = add chain [ drop ]; output-eth0 = add chain [ (is.ne ip.daddr (secret.network.ips.blowhole.ip or "")) (is.eq ip.protocol (f: with f; set [ tcp udp ])) (is.eq th.dport 53) drop ] [ accept ]; ### ### wg0 input-wg0 = add chain # accept syncthing sharing [ (is.eq ip.protocol (f: f.udp)) (is.eq th.sport "22000") (is.eq th.dport "22000") accept ] [ (is.eq ip.protocol (f: f.tcp)) (is.eq th.dport "22000") accept ] [ (is.eq ip.protocol (f: f.icmp)) accept ]; output-wg0 = add chain # TCP, UDP 53 to blowhole [ (is.eq ip.protocol (f: with f; set [ udp tcp ])) (is.eq th.dport 53) (is.eq ip.saddr (secret.network.ips.omen.vpn or "")) (is.eq ip.daddr (secret.network.ips.blowhole.ip or "")) accep t] # TCP 22, 80, 4646, 8200, 8500, 2049 to blowhole [ (is.eq ip.protocol (f: with f; set [ tcp ])) (is.eq th.dport (set [ 22 80 4646 8200 8500 2049 ])) (is.eq ip.saddr (secret.network.ips.omen.vpn or "")) (is.eq ip.daddr (secret.network.ips.blowhole.ip or "")) accept ] # ICMP to blowhole, toothpick [ (is.eq ip.protocol (f: f.icmp)) (is.eq ip.saddr (secret.network.ips.omen.vpn or "")) (is.eq ip.daddr (set [ (secret.network.ips.toothpick or "") (secret.network.ips.blowhole.ip or "") ])) accept ] # accept syncthing sharing [ (is.eq ip.protocol (f: f.udp)) (is.eq th.sport "22000") (is.eq th.dport "22000") accept ] [ (is.eq ip.protocol (f: f.tcp)) (is.eq th.dport "22000") accept ] ; ### input = add chain { type = f: f.filter; hook = f: f.input; prio = -300; policy = f: f.drop; } # accept related, established and drop invalid [ (vmap ct.state { established = accept; related = accept; invalid = drop; }) ] # # accept icmp between the same IP # [ (is.eq ip.protocol (f: f.icmp)) (is.eq ip.daddr ip.saddr) accept ] [ (jump "trace") ] [ (is.eq meta.iifname "wlan0") (jump "input-wlan0") ] [ (is.eq meta.iifname "eth0") (jump "input-eth0") ] [ (is.eq meta.iifname "mvm0") (jump "input-mvm") ] [ (is.eq meta.iifname "lo") (jump "input-lo") ] [ (is.eq meta.iifname "wg0") (jump "input-wg0") ] [ (is.eq ip.protocol (f: f.icmp)) accept ] (logRule "Input"); output = add chain { type = f: f.filter; hook = f: f.output; prio = -300; policy = f: f.drop; } [ (jump "trace") ] [ (is.eq meta.oifname "wlan0") (jump "output-wlan0") ] [ (is.eq meta.oifname "eth0") (jump "output-eth0") ] [ (is.eq meta.oifname "lo") (jump "output-lo") ] [ (is.eq meta.oifname "mvm0") (jump "output-mvm") ] [ (is.eq meta.oifname "wg0") (jump "output-wg0") ] (logRule "Output"); forward = add chain { type = f: f.filter; hook = f: f.forward; prio = -300; policy = f: f.drop; } [ (jump "trace") ] # accept masquaraded packets incoming from wg0 [ (is.eq meta.iifname "wg0") (vmap ct.state { established = accept; related = accept; }) ] # accept TCP, UDP 53 from 10.80.1.2 to blowhole [ (is.eq meta.iifname "mvm0") (is.eq meta.oifname "wg0") (is.eq ip.protocol (f: with f; set [ tcp udp ])) (is.eq th.dport 53) (is.eq ip.saddr "10.80.1.2") (is.eq ip.daddr (secret.network.ips.blowhole.ip or "")) accept ] (logRule "Forward"); prerouting = add chain { type = f: f.nat; hook = f: f.prerouting; prio = -199; policy = f: f.accept; } ; postrouting = add chain { type = f: f.nat; hook = f: f.postrouting; prio = -199; policy = f: f.accept; } # masquarade from 10.80.1.2 heading to wg0 [ (is.eq meta.iifname "mvm0") (is.eq meta.oifname "wg0") (is.eq ip.saddr (set [ "10.80.1.2" ])) masquerade ]; }; bridge-t = add table { family = f: f.bridge; } { trace = traceChain; input-body = add chain; input = add chain { type = f: f.filter; hook = f: f.input; prio = -300; policy = f: f.drop; } [ (jump "trace") ] [ (vmap ct.state { established = accept; related = accept; invalid = drop; }) ] [ (is.eq meta.protocol (f: f.arp)) accept ] [ (jump "input-body") ] (logRule "Bridge input"); output-body = add chain; output = add chain { type = f: f.filter; hook = f: f.output; prio = -300; policy = f: f.drop; } [ (jump "trace") ] [ (is.eq ether.type (f: f.arp)) accept ] [ (jump "output-body") ] (logRule "Bridge output"); forward-body = add chain; forward = add chain { type = f: f.filter; hook = f: f.forward; prio = -300; policy = f: f.drop; } [ (jump "trace") ] [ (jump "forward-body") ] (logRule "Bridge forward"); prerouting = add chain { type = f: f.filter; hook = f: f.prerouting; prio = -300; policy = f: f.accept; } ; postrouting = add chain { type = f: f.filter; hook = f: f.postrouting; prio = -300; policy = f: f.accept; } ; }; }; # )); # }; systemd.network.netdevs."mvm0" = { netdevConfig = { Name = "mvm0"; Kind = "bridge"; }; }; systemd.network.networks."10-mvm0" = { matchConfig.Name = "mvm0"; networkConfig.Address = "10.80.1.1/24"; linkConfig.RequiredForOnline = "yes"; }; systemd.network.networks."11-mvm-test" = { matchConfig.Name = "mvm-test"; networkConfig.Bridge = "mvm0"; linkConfig.RequiredForOnline = "no"; }; microvm.services.tcpUdp.test-ssh = { hostName = "test"; port = 22; protocol = [ "tcp" ]; }; microvm.services.http.test = { hostName = "test"; port = 80; }; microvm.services.icmp.test = { hostName = "test"; }; microvm.connections.http = [ { target = "test"; } ]; microvm.connections.tcpUdp = [ { target = "test-ssh"; } ]; microvm.connections.icmp = [ { target = "test"; } ]; microvm.vms = { test.config = { imports = [ inputs.self.nixosModules.microvm-extras ]; microvm = { hostName = "test"; hostsHostName = "omen"; groupId = 1; taskId = 2; }; microvm.hypervisor = "cloud-hypervisor"; microvm.shares = [{ source = "/nix/store"; mountPoint = "/nix/.ro-store"; tag = "ro-store"; proto = "virtiofs"; }]; microvm.storeOnDisk = false; networking.firewall.allowedTCPPorts = [ 80 22 ]; services.nginx = { enable = true; virtualHosts."example.com" = { root = "/var/www/blog"; }; }; users.users.root.password = ""; services.getty.helpLine = '' Log in as "root" with an empty password. ''; services.openssh = { enable = true; settings.PermitRootLogin = "yes"; }; }; }; }); }; }