Firewall source/destination IPs

Is there a way to specify source or destination IPs in NixOS configuration?

It seems like networking.firewall.* is intended more for a single host firewall than something at the edge of a network. Am I correct in this observation or am I missing something?

I think it would be great if there were a NixOS option to cover this but I’m pretty sure you’re stuck with networking.firewall.extraCommands.

There is a support for Shorewall but I couldn’t find any examples. https://github.com/NixOS/nixpkgs/blob/007126eef72271480cb7670e19e501a1ad2c1ff2/nixos/modules/services/networking/shorewall.nix

Be warned, using networking.firewall.extraCommands will not work the way you expect. Let me explain:

What you would want from extraCommands is for it to add some configuration to iptables that is not dependent on what is already deployed on the NixOS box. However, what it really does is run whatever you put in extra commands on every deploy. This not only breaks reproducibility, it usually breaks all subsequent deployments or nixos-rebuild.

Don’t disrepair there is a workaround I figured out, its just hacky. There is another option called networking.firewall.extraStopCommands which runs before the next deploy and importantly before extraCommands. So, If you put your extraCommands iptable rules in their own chain and drop that chain in extraStopCommands you will somewhat get the right behavior of “overwriting” whatever you have in extraCommands.

Let me put an example:

{
  networking = {
    firewall = {
      extraCommands = ''
        iptables -N CHAIN_NAME_HERE
        iptables -A INPUT -j CHAIN_NAME_HERE
        iptables -A CHAIN_NAME_HERE -m comment -s IP_ADDRESS_HERE -m state --state NEW -m tcp -p tcp --dport PORT_HERE -j ACCEPT --comment "Optional Comment"
      '';
      #flush the chain then remove it
      extraStopCommands = ''
        iptables -D INPUT -j CHAIN_NAME_HERE
        iptables -F CHAIN_NAME_HERE
        iptables -X CHAIN_NAME_HERE
      '';
    };
  };
}

However, your iptables service will fail the first time you deploy this because switching systems (think nixos-rebuild switch) first updates the scripts used by iptables and then restarts the iptables service. The service will fail because the extraStopCommands will run before you have ever created those chains. You can fix this by either re-deploying (think nixos-rebuild switch) or restarting the iptables service. The second deploy or service restart will work because those iptables chain exists.

tl;dr add something like the example to your configuration.nix and run your deploy or nixos-rebild switch twice and it will work seamlessly after that.

In all honesty I think we need something like firewalld on NixOS to realistically make this a non-issue. I wouldn’t mind sponsoring someone to work on this issue, just not sure who would be interested given the non-trivial nature of adding firewalld to NixOS.

5 Likes

Found this topic while researching iptables.

I plan to try and configure firewall so that only whitelisted ipv6 addresses would be let in.
(So that I could maybe use yggdrasil as substitute for tailscale)
For now considering to try extraCommands and extraStopCommands

Would like to check in: is there any better way right now?

4 Likes