Add firewall module
Also: tmproot tweaks
This commit is contained in:
parent
bb9a5b2536
commit
33c643f6d8
@ -8,7 +8,22 @@
|
||||
};
|
||||
};
|
||||
|
||||
networking = {};
|
||||
|
||||
my = {
|
||||
firewall = {
|
||||
trustedInterfaces = [ "blah" ];
|
||||
nat = {
|
||||
externalInterface = "eth0";
|
||||
forwardPorts = [
|
||||
{
|
||||
proto = "tcp";
|
||||
sourcePort = 2222;
|
||||
destination = "127.0.0.1:22";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
server.enable = true;
|
||||
};
|
||||
}
|
||||
|
6
flake.lock
generated
6
flake.lock
generated
@ -95,11 +95,11 @@
|
||||
},
|
||||
"impermanence": {
|
||||
"locked": {
|
||||
"lastModified": 1644585928,
|
||||
"narHash": "sha256-jOnLRLnzFI/YHE53bHgz/9QjR4Qt6dgIXLnTZOf5oLc=",
|
||||
"lastModified": 1644623728,
|
||||
"narHash": "sha256-aG+JnIaFXTM9YqcE5uyBgPlPrkmX4bs+yY5YCfA/vBQ=",
|
||||
"owner": "devplayer0",
|
||||
"repo": "impermanence",
|
||||
"rev": "47809005570ee4d5b504e382309f5b6dcc5999e5",
|
||||
"rev": "74be13a87a3bbcbbaf94aea66f9576a1163db4f0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -65,6 +65,7 @@
|
||||
common = "common.nix";
|
||||
build = "build.nix";
|
||||
tmproot = "tmproot.nix";
|
||||
firewall = "firewall.nix";
|
||||
server = "server.nix";
|
||||
};
|
||||
|
||||
|
@ -68,13 +68,23 @@
|
||||
};
|
||||
};
|
||||
|
||||
networking = {
|
||||
useDHCP = mkDefault false;
|
||||
enableIPv6 = mkDefault true;
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
bash-completion
|
||||
tree
|
||||
vim
|
||||
htop
|
||||
iperf3
|
||||
];
|
||||
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
system = {
|
||||
stateVersion = "21.11";
|
||||
configurationRevision = with inputs; mkIf (self ? rev) self.rev;
|
||||
|
166
modules/firewall.nix
Normal file
166
modules/firewall.nix
Normal file
@ -0,0 +1,166 @@
|
||||
{ lib, options, config, ... }:
|
||||
let
|
||||
inherit (lib) optionalString concatStringsSep concatMapStringsSep optionalAttrs mkIf mkDefault mkMerge mkOverride;
|
||||
inherit (lib.my) parseIPPort mkOpt mkBoolOpt dummyOption;
|
||||
|
||||
cfg = config.my.firewall;
|
||||
in {
|
||||
options.my.firewall = with lib.types; {
|
||||
enable = mkBoolOpt true;
|
||||
trustedInterfaces = options.networking.firewall.trustedInterfaces;
|
||||
tcp = {
|
||||
allowed = mkOpt (listOf (either port str)) [ "ssh" ];
|
||||
};
|
||||
udp = {
|
||||
allowed = mkOpt (listOf (either port str)) [];
|
||||
};
|
||||
extraRules = mkOpt lines "";
|
||||
|
||||
nat = with options.networking.nat; {
|
||||
enable = mkBoolOpt true;
|
||||
inherit externalInterface forwardPorts;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (mkMerge [
|
||||
{
|
||||
networking = {
|
||||
firewall.enable = false;
|
||||
nftables = {
|
||||
enable = true;
|
||||
ruleset =
|
||||
let
|
||||
trusted' = "{ ${concatStringsSep ", " cfg.trustedInterfaces} }";
|
||||
in
|
||||
''
|
||||
table inet filter {
|
||||
chain wan-tcp {
|
||||
${concatMapStringsSep "\n " (p: "tcp dport ${toString p} accept") cfg.tcp.allowed}
|
||||
}
|
||||
chain wan-udp {
|
||||
${concatMapStringsSep "\n " (p: "udp dport ${toString p} accept") cfg.udp.allowed}
|
||||
}
|
||||
|
||||
chain wan {
|
||||
ip6 nexthdr icmpv6 icmpv6 type {
|
||||
destination-unreachable,
|
||||
packet-too-big,
|
||||
time-exceeded,
|
||||
parameter-problem,
|
||||
mld-listener-query,
|
||||
mld-listener-report,
|
||||
mld-listener-reduction,
|
||||
nd-router-solicit,
|
||||
nd-router-advert,
|
||||
nd-neighbor-solicit,
|
||||
nd-neighbor-advert,
|
||||
ind-neighbor-solicit,
|
||||
ind-neighbor-advert,
|
||||
mld2-listener-report,
|
||||
echo-request
|
||||
} accept
|
||||
ip protocol icmp icmp type {
|
||||
destination-unreachable,
|
||||
router-solicitation,
|
||||
router-advertisement,
|
||||
time-exceeded,
|
||||
parameter-problem,
|
||||
echo-request
|
||||
} accept
|
||||
ip protocol igmp accept
|
||||
|
||||
ip protocol tcp tcp flags & (fin|syn|rst|ack) == syn ct state new jump wan-tcp
|
||||
ip protocol udp ct state new jump wan-udp
|
||||
}
|
||||
|
||||
chain input {
|
||||
type filter hook input priority 0; policy drop;
|
||||
|
||||
ct state established,related accept
|
||||
ct state invalid drop
|
||||
|
||||
iif lo accept
|
||||
${optionalString (cfg.trustedInterfaces != []) "iifname ${trusted'} accept\n"}
|
||||
jump wan
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy drop;
|
||||
${optionalString (cfg.trustedInterfaces != []) "\n iifname ${trusted'} accept\n"}
|
||||
ct state related,established accept
|
||||
}
|
||||
chain output {
|
||||
type filter hook output priority 0; policy accept;
|
||||
}
|
||||
}
|
||||
|
||||
table nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority 0;
|
||||
}
|
||||
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority 100;
|
||||
}
|
||||
}
|
||||
|
||||
${cfg.extraRules}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
(mkIf cfg.nat.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = (cfg.nat.forwardPorts != []) -> (cfg.nat.externalInterface != null);
|
||||
message = "my.firewall.nat.forwardPorts requires my.firewall.nat.externalInterface";
|
||||
}
|
||||
];
|
||||
|
||||
# Yoinked from nixpkgs/nixos/modules/services/networking/nat.nix
|
||||
boot = {
|
||||
kernel.sysctl = {
|
||||
"net.ipv4.conf.all.forwarding" = mkOverride 99 true;
|
||||
"net.ipv4.conf.default.forwarding" = mkOverride 99 true;
|
||||
} // optionalAttrs config.networking.enableIPv6 {
|
||||
# Do not prevent IPv6 autoconfiguration.
|
||||
# See <http://strugglers.net/~andy/blog/2011/09/04/linux-ipv6-router-advertisements-and-forwarding/>.
|
||||
"net.ipv6.conf.all.accept_ra" = mkOverride 99 2;
|
||||
"net.ipv6.conf.default.accept_ra" = mkOverride 99 2;
|
||||
|
||||
# Forward IPv6 packets.
|
||||
"net.ipv6.conf.all.forwarding" = mkOverride 99 true;
|
||||
"net.ipv6.conf.default.forwarding" = mkOverride 99 true;
|
||||
};
|
||||
};
|
||||
|
||||
my.firewall.extraRules =
|
||||
let
|
||||
makeFilter = f:
|
||||
let
|
||||
ipp = parseIPPort f.destination;
|
||||
in
|
||||
"ip${optionalString ipp.v6 "6"} daddr ${ipp.ip} ${f.proto} dport ${toString f.sourcePort} accept";
|
||||
makeForward = f: "${f.proto} dport ${toString f.sourcePort} dnat to ${f.destination}";
|
||||
in
|
||||
''
|
||||
table inet filter {
|
||||
chain filter-port-forwards {
|
||||
${concatMapStringsSep "\n " makeFilter cfg.nat.forwardPorts}
|
||||
}
|
||||
chain forward {
|
||||
iifname ${cfg.nat.externalInterface} jump filter-port-forwards
|
||||
}
|
||||
}
|
||||
|
||||
table nat {
|
||||
chain port-forward {
|
||||
${concatMapStringsSep "\n " makeForward cfg.nat.forwardPorts}
|
||||
}
|
||||
chain prerouting {
|
||||
iifname ${cfg.nat.externalInterface} jump port-forward
|
||||
}
|
||||
}
|
||||
'';
|
||||
})
|
||||
]);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{ lib, pkgs, inputs, config, ... }@args:
|
||||
{ lib, pkgs, inputs, config, ... }:
|
||||
let
|
||||
inherit (lib) any concatStringsSep mkIf mkDefault mkMerge mkVMOverride;
|
||||
inherit (lib) concatStringsSep mkIf mkDefault mkMerge mkVMOverride;
|
||||
inherit (lib.my) mkOpt mkBoolOpt mkVMOverride' dummyOption;
|
||||
|
||||
cfg = config.my.tmproot;
|
||||
@ -52,9 +52,10 @@
|
||||
options = [ "size=${cfg.size}" ];
|
||||
};
|
||||
in {
|
||||
imports = [ inputs.impermanence.nixosModules.impermanence ];
|
||||
imports = [ inputs.impermanence.nixosModule ];
|
||||
|
||||
options.my.tmproot = with lib.types; {
|
||||
options = {
|
||||
my.tmproot = with lib.types; {
|
||||
enable = mkBoolOpt true;
|
||||
persistDir = mkOpt str "/persist";
|
||||
size = mkOpt str "2G";
|
||||
@ -64,12 +65,13 @@
|
||||
};
|
||||
|
||||
# Forward declare options that won't exist until the VM module is actually imported
|
||||
options.virtualisation = {
|
||||
virtualisation = {
|
||||
diskImage = dummyOption;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
(mkIf cfg.enable {
|
||||
config = mkIf cfg.enable (mkMerge [
|
||||
{
|
||||
assertions = [
|
||||
{
|
||||
assertion = config.fileSystems ? "${cfg.persistDir}";
|
||||
@ -96,8 +98,8 @@
|
||||
virtualisation = {
|
||||
diskImage = "./.vms/${config.system.name}-persist.qcow2";
|
||||
};
|
||||
})
|
||||
(mkIf (cfg.enable && config.my.boot.isDevVM) {
|
||||
}
|
||||
(mkIf config.my.boot.isDevVM {
|
||||
fileSystems = mkVMOverride {
|
||||
"/" = mkVMOverride' rootDef;
|
||||
# Hijack the "root" device for persistence in the VM
|
||||
@ -107,5 +109,5 @@
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
]);
|
||||
}
|
||||
|
17
util.nix
17
util.nix
@ -1,9 +1,24 @@
|
||||
{ lib }:
|
||||
let
|
||||
inherit (builtins) replaceStrings elemAt;
|
||||
inherit (lib) genAttrs mapAttrs' types mkOption mkOverride;
|
||||
inherit (lib.flake) defaultSystems;
|
||||
in {
|
||||
in rec {
|
||||
addPrefix = prefix: mapAttrs' (n: v: { name = "${prefix}${n}"; value = v; });
|
||||
# Yoinked from nixpkgs/nixos/modules/services/networking/nat.nix
|
||||
isIPv6 = ip: builtins.length (lib.splitString ":" ip) > 2;
|
||||
parseIPPort = ipp:
|
||||
let
|
||||
v6 = isIPv6 ipp;
|
||||
matchIP = if v6 then "[[]([0-9a-fA-F:]+)[]]" else "([0-9.]+)";
|
||||
m = builtins.match "${matchIP}:([0-9-]+)" ipp;
|
||||
checked = v: if m == null then throw "bad ip:ports `${ipp}'" else v;
|
||||
in {
|
||||
inherit v6;
|
||||
ip = checked (elemAt m 0);
|
||||
ports = checked (replaceStrings ["-"] [":"] (elemAt m 1));
|
||||
};
|
||||
|
||||
mkPkgs = path: args: genAttrs defaultSystems (system: import path (args // { inherit system; }));
|
||||
|
||||
mkOpt = type: default: mkOption { inherit type default; };
|
||||
|
Loading…
Reference in New Issue
Block a user