Firewall rules and interface lists - best practice?

Hi everyone,

When building a firewall for a router with multiple networks with different access requirements (for example: VLANs), there are multiple ways to use firewall rules, including:

  1. Add a separate firewall rule per VLAN-interface. Multiple firewall rules for the same resource (example: allow DNS queries to router, rule repeated many times for different VLANs).
  2. Add a single firewall rule per service/resource, and use interface lists to determine membership of VLANs and whether that rule applies to them.

For example we can have option 1:

/interface/list
add name=Trusted
add name=Guest
add name=IoT
add name=Security

/interface/list/member
add interface=vlan10-trusted list=Trusted
add interface=vlan20-guest list=Guest
add interface=vlan30-iot list=IoT
add interface=vlan40-security list=Security

/ip/firewall/filter
add action=accept chain=input comment="accept DNS (UDP) from Trusted" dst-port=53 in-interface-list=Trusted protocol=udp
add action=accept chain=input comment="accept DNS (TCP) from Trusted" dst-port=53 in-interface-list=Trusted protocol=tcp
add action=accept chain=input comment="accept DNS (UDP) from Guest" dst-port=53 in-interface-list=Guest protocol=udp
add action=accept chain=input comment="accept DNS (TCP) from Guest" dst-port=53 in-interface-list=Guest protocol=tcp
add action=accept chain=forward comment"accept from Trusted to IoT" in-interface-list=Trusted out-interface-list=IoT
add action=accept chain=forward comment"accept from Trusted to Security" in-interface-list=Trusted out-interface-list=Security
add action=accept chain=forward comment"accept from Security to IoT" in-interface-list=Security out-interface-list=IoT


# etc...

And option 2:

/interface/list
add name=Trusted
add name=Guest
add name=IoT
add name=Security
# nested lists here to control access through membership:
add name=DNSAccess include=Trusted,Guest
add name=IoTAccess include=Trusted,Security
add name=SecurityAccess include=Trusted

/interface/list/member
add interface=vlan10-trusted list=Trusted
add interface=vlan20-guest list=Guest
add interface=vlan30-iot list=IoT
add interface=vlan40-security list=Security

/ip/firewall/filter
add action=accept chain=input comment="accept DNS (UDP) from DNSAccess" dst-port=53 in-interface-list=DNSAccess protocol=udp
add action=accept chain=input comment="accept DNS (TCP) from DNSAccess" dst-port=53 in-interface-list=DNSAccess protocol=tcp
add action=accept chain=forward comment"accept from IoTAccess to IoT" in-interface-list=IoTAccess out-interface-list=IoT
add action=accept chain=forward comment="accept from SecurityAccess to Security" in-interface-list=SecurityAccess out-interface-list=Security

# etc...

As you can see, option 1 has simpler interface list configuration, keeping firewall/access-control complexity in the firewall filter rules, but has more repetition of rules for the same service. If you add a VLAN or want to allow some access, you need to create potentially dozens of new firewall filter rules for the same services, you could end up with 50+ rules just to allow DNS access, repeating the same thing just for each VLAN that is allowed access. Becomes more complex with more interfaces, but access control is contained in firewall, and interface lists are simpler.

Option 2 has more complex interface list configuration, and a lot of access control has now moved there, but firewall filter rules are simplified and now policy is defined by membership of interface list, more similar to zone style (if member of DNSAccess, they have DNSAccess, etc...). Add a new interface and want it to have DNS, DHCP, etc...? Just add it to the appropriate interface list(s). You only need a single firewall rule per service (DNS, DHCP, etc...). You can control how coarse or fine-grained you want it by nesting/including lists and having a smaller number of "main" lists that control access to multiple services at once (InternetAccess, BasicServicesAccess, etc...). Firewall is simplified and easier to understand, but interface lists get more complex and the nested membership (using include=) might make it more difficult to quickly understand what is going on.

I want to find out what the MikroTik community's view on these methods are, if there's another method that's considered better.

Thank you!

For me,
the fact that the default rules aren't used as a starting point,
means it's already all wrong.

I think the default rules are good. I am familiar with the 12 rules of the MikroTik club, including rule 8 about using default firewall.

The examples I posted in my original post are to discuss the different methods of access control using vs. not using nested interface list membership. It is not a complete firewall. I can edit it to be based on the default rules if that makes it clearer to understand what I am asking?

For example,
why block DNS? (only 53? and DoH? DoT? DoQ? etc?)

If there’s a good reason to block it, then you block it: just one rule for that VLAN.
Otherwise, by default, it’s accessible from the LAN, IoT, and MGMT networks.

There’s a saying in Tuscany... I can't write it down here (doing something indecent... with brain).

Instead of doing something efficient,
you’re perfectly free to create all the groups, subgroups, and sub-subgroups you want.

I use default drop everything rules at the bottom of my firewall chains. I prefer drop everything by default, and accept only what is needed.

For example, some privileged interfaces can get an accept everything rule in input and forward chain (an unrestricted VLAN for example, which would then behave the same as default "LAN" interface list and firewall from default configuration).

VLANs like Guest only need Internet access, but no access to any other VLAN (forward chain accept all from Guest to WAN) and DHCP, DNS to router on input chain. Guests are free to use DoH/DoT/DoQ/whatever from Internet. There is no need for WinBox, WebFig/HTTPS, SSH, etc... to router. Drop all takes care of these things automatically for me.

I think I understand what you mean by that saying in Tuscany :slight_smile:

I think you might be interested in the jump action and custom chains.

I prefer the nested interface lists. However it's a pitty that currently RouterOS (including WinBox) does not offer an easy way to quickly see which interfaces are part of a list (that have nested lists). It would be great if a (read-only) "Current Interfaces" column is available that really lists all the members of a list.

image

By all means, I am no expert on firewall rules.

For our setup, we went with firewall zones (i.e. chains with jump rules). All of them have drop rules at the end and explicitly allow permitted things. I find that this makes reasoning about about a certain self-contained part of your network easier. That results in a bit more repetition because rules could be repeated for several zones. I would not use interface lists across different zones because it would make reasoning more complicated. I would have no problem using interface lists within a zone (i.e. for all VPN interfaces in a VPN networks zone).

For whatever reason, I found that for IPv4 that I tend to use interface based rules more. For IPv6 it turns out that it‘s more about subnets than interfaces.

There are some generic rules that could either be handled on global level (i.e. in chains input or forward). Or they could be handled through interface lists. These are things like ICMPv6 or DNS.

Hope that helps.