diff --git a/nixos/systems/omen/default.nix b/nixos/systems/omen/default.nix index 75336b2..3a2cba1 100644 --- a/nixos/systems/omen/default.nix +++ b/nixos/systems/omen/default.nix @@ -36,6 +36,8 @@ in ./users.nix ./nixpkgs.nix ../../common/sound.nix + ./firewall.nix + ./microvm.nix ./impermenance.nix # ./test-vm.nix @@ -80,299 +82,6 @@ in 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" virtiofsd} "''${ok_args[@]}" - ''; - } - ) - ]; - - 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 "")) accept ] - - # 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"; - }; - }; - }; }); }; } diff --git a/nixos/systems/omen/firewall.nix b/nixos/systems/omen/firewall.nix new file mode 100644 index 0000000..3e4a014 --- /dev/null +++ b/nixos/systems/omen/firewall.nix @@ -0,0 +1,177 @@ +{ secret, inputs', pkgs, ... }: +{ + 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 "")) accept ] + + # 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 ] + + # TCP 22 toothpick + [ (is.eq ip.protocol (f: with f; set [ tcp ])) (is.eq th.dport (set [ 22 ])) (is.eq ip.saddr (secret.network.ips.omen.vpn or "")) (is.eq ip.daddr (secret.network.ips.toothpick or "")) accept ] + + # TCP 22 altra + [ (is.eq ip.protocol (f: with f; set [ tcp ])) (is.eq th.dport (set [ 22 ])) (is.eq ip.saddr (secret.network.ips.omen.vpn or "")) (is.eq ip.daddr (secret.network.ips.altra.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.altra.ip 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; } + ; + }; + }; +} diff --git a/nixos/systems/omen/microvm.nix b/nixos/systems/omen/microvm.nix new file mode 100644 index 0000000..eca3300 --- /dev/null +++ b/nixos/systems/omen/microvm.nix @@ -0,0 +1,92 @@ +{ inputs', ... }: +{ + 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"; + }; + }; + }; +} diff --git a/nixos/systems/omen/nixpkgs.nix b/nixos/systems/omen/nixpkgs.nix index fabbe49..b78e9a8 100644 --- a/nixos/systems/omen/nixpkgs.nix +++ b/nixos/systems/omen/nixpkgs.nix @@ -12,6 +12,7 @@ emacs-rofi tree-sitter-grammars emacs-master-nativecomp + virtiofsd-zfs ]) ++ (with inputs'.nixng.overlays; [