{ lib, config, ... }: let services = { ssh = { tcp = [ 22 ]; }; dhcp = { udp = [ 67 68 ]; }; dns = { udp = [ 53 853 ]; tcp = [ 53 853 ]; }; web = { tcp = [ 80 443 ]; }; }; rulesForServices = enabledServices: lib.foldr (service: { allowedUDPPorts, allowedTCPPorts }: { allowedUDPPorts = allowedUDPPorts ++ services.${service}.udp or [ ]; allowedTCPPorts = allowedTCPPorts ++ services.${service}.tcp or [ ]; }) { allowedUDPPorts = [ ]; allowedTCPPorts = [ ]; } enabledServices; cfg = config.modules.firewall; in { options.modules.firewall = { enable = lib.mkEnableOption "Enable the firewall"; interfaces = lib.mkOption { type = lib.types.attrsOf (lib.types.listOf (lib.types.enum (lib.attrNames services))); default = { }; }; allInterfaces = lib.mkOption { type = lib.types.listOf (lib.types.enum (lib.attrNames services)); default = [ ]; }; }; config = lib.mkIf cfg.enable { networking.firewall = { enable = true; interfaces = lib.mapAttrs (_: enabledServices: rulesForServices enabledServices) cfg.interfaces; } // rulesForServices cfg.allInterfaces; }; }