The decision to remove zone-based firewall syntax in VyOS 1.4-rolling-202308040557

For those of us using Vyos in large production networks, taking away the zone based syntax is going to be devastating.

  1. I have applied this to several firewalls so far and seen the rule sets increase in size dramatically. This makes the rule sets much longer and much harder to follow. Depending on the rule set, I have seen the total number of config lines increase on the order of 40-70%. If this was a small home firewall with 30 lines on config, that might be fine. It is not. The firewalls that I use Vyos on have 1000+ lines of config. I have This increase in rule-set complexity is going to increase the number of mistakes made by the teams of people who share responsibility for these firewalls.

  2. The increase in rule set size now requires more commands to be run to achieve the same outcome. In addition to increasing the likelihood of human error, this is definitely going to cost us time. The amount of time that will now need to be spent to make changes to the rule-sets will increase, making it a much harder sell when pitching the use us Vyos. Time is money. The ability to make changes in a clear, direct, succinct way is critical in selecting a product to use within the enterprise.

3 . The old zone syntax was very similar to firewalls of other vendors. It was very similar to JunOS. This made it very easy to deploy Vyos in large enterprise networks where network engineers could pick it up and manage complex rule sets with minimal training. It may be rather uncommon to find Vyos on the resume of a new-hire, but it is easy to find JunOS on a resume. This concept used to be one of the selling points I would use when implementing Vyos for the many companies I have deployed it for.

I really hope you re-consider these changes before this release becomes stable. With this new change in place, Vyos is no longer positioned as the competitor to traditional appliance firewalls that it was previously. So many of the recent changes have been excellent and really helped bring 1.4 in line to be a serious enterprise firewall contender. Changes such as configuration sync in HA, which is a huge time saver and mistake preventer! I was really looking forward to 1.4 stable, but this change to how firewall rules are configured turn my excitement into dread.

Please reconsider this change.

6 Likes

Hi, @James2012!

Your feelings are understandable - there are both pros and contra to the firewall CLI change. And we are open to suggestions and requests, as always.

Zone-based firewall is one of the most significant changes and we may expect that some specific types of configuration may look new and scary for the first time.

Let me provide you with some feedback.

  1. Yes, we expect that the total number of lines in the config will grow, but 40-70% sounds very unexpected. We would be really grateful for your firewall configuration example (before migration). Maybe we can use it to improve migration logic and reduce total lines in config as a result.
  2. Increasing config lines is not the only factor that can increase the risk of human mistakes. In recent years we have seen a lot of improper configurations done by our customers with a zone-based firewall because they did not understand how to use this tool properly. Therefore, the new CLI style increases this risk by adding more lines but decreases it because of a more straightforward style of config.
  3. Well… This one is the most sensitive topic. We provided more or less the “same” type of firewall, very familiar for people who have worked with hardware routers, for a long time. But this becomes more and more painful. The real problem is that in hardware traffic control is done by an ASIC, which is good because of speed but bad because of limited flexibility. And we had this limitation with no real technical reasons all the time, just because we tried to be familiar. In VyOS/Linux we control traffic using nftables, which provides way more possibilities than we can get with the old CLI style, and the CLI change is only the first step to uncover all of them. So, the real thing is - you will get a lot of benefits later because a firewall config does not need to look like in a classical hardware router anymore.

You mentioned several times using VyOS in large enterprise networks, and actually, all the new changes are oriented to make VyOS better for real enterprises. They allow us to offer more than we can before, including combinations of features not available in hardware devices. Our pre-sales and support teams are very happy to show how to use this power and assist with specific configurations.

We still improving the usability level and preparing a list of explanations, examples, and recommendations for the new firewall. I hope the more we talk about this, the more obvious will be a new style and new benefits from it.

I share some of the opposition to the new changes, I really liked the zone-based firewall for the same reasons (I’m very comfortable with JunOS). However I’m pretty open to the change, I also just run it at home and for some side projects, so definitely not as big of an impact as if it were used in production. Totally understand that.

It may be helpful to show an example of maybe a path forward that in my opinion replicates it very similarly

My solution really is just looking at it as interface-groups are the “zones”, and I have named them that, eg

firewall {
    group {
        interface-group ZONE_LAN {
            interface eth4
            interface eth4.2
            interface eth4.3
            interface eth4.4
            interface eth4.5
            interface eth4.6
            interface wg0
        }
        interface-group ZONE_WAN {
            interface eth0
            interface eth1
        }
    }
}

Then for each of the ipv4/ipv6 sections, with the forward, input, output I only have rules (besides very basic policies that jump to policies meant for the cross zone traffic

My thought/plan is that each zone will receive a number, eg 1000 is zone WAN, 2000 is zone LAN, etc. The first rule for the zone in the forward chain is the intra-zone policy, then the rules after are for inter-zone policies. This will give me 999 other inter-zone policies. Slightly different in the input/output because it only really concerns the LOCAL zone

firewall {
    ipv4 {
        forward {
            filter {
                default-action drop
                rule 1 {
                    action accept
                    state {
                        established enable
                    }
                }
                rule 2 {
                    action drop
                    state {
                        invalid enable
                    }
                }
                rule 3 {
                    action accept
                    state {
                        related enable
                    }
                }
                rule 1000 {
                    action jump
                    description "WAN intra-zone policy"
                    inbound-interface {
                        interface-group ZONE_WAN
                    }
                    jump-target WAN-to-WANv4
                    outbound-interface {
                        interface-group ZONE_WAN
                    }
                }
                rule 2000 {
                    action jump
                    description "LAN intra-zone policy"
                    inbound-interface {
                        interface-group ZONE_LAN
                    }
                    jump-target LAN-to-LANv4
                    outbound-interface {
                        interface-group ZONE_LAN
                    }
                }
                rule 2001 {
                    action jump
                    description "LAN to WAN policy"
                    inbound-interface {
                        interface-group ZONE_LAN
                    }
                    jump-target LAN-to-WANv4
                    outbound-interface {
                        interface-group ZONE_WAN
                    }
                }
            }
        }
        input {
            filter {
                default-action drop
                rule 1 {
                    action accept
                    state {
                        established enable
                    }
                }
                rule 2 {
                    action drop
                    state {
                        invalid enable
                    }
                }
                rule 3 {
                    action accept
                    state {
                        related enable
                    }
                }
                rule 50 {
                    action accept
                    description "Allow localhost"
                    inbound-interface {
                        interface-name lo
                    }
                }
                rule 1000 {
                    action jump
                    description "WAN to LOCAL policy"
                    inbound-interface {
                        interface-group ZONE_WAN
                    }
                    jump-target WAN-to-LOCALv4
                }
                rule 2000 {
                    action jump
                    description "LAN to LOCAL policy"
                    inbound-interface {
                        interface-group ZONE_LAN
                    }
                    jump-target LAN-to-LOCALv4
                }
            }
        }
        output {
            filter {
                default-action drop
                rule 1 {
                    action accept
                    state {
                        established enable
                    }
                }
                rule 2 {
                    action drop
                    state {
                        invalid enable
                    }
                }
                rule 3 {
                    action accept
                    state {
                        related enable
                    }
                }
                rule 50 {
                    action accept
                    description "Allow localhost"
                    outbound-interface {
                        interface-name lo
                    }
                }
                rule 1000 {
                    action jump
                    description "LOCAL to WAN policy"
                    jump-target LOCAL-to-WANv4
                    outbound-interface {
                        interface-group ZONE_WAN
                    }
                }
                rule 2000 {
                    action jump
                    description "LOCAL to LAN policy"
                    jump-target LOCAL-to-LANv4
                    outbound-interface {
                        interface-group ZONE_LAN
                    }
                }
            }
        }
    }
}

NOTE: The policies themselves in this example are super basic, but you should use your existing inter and intra-zone policies

firewall {
    ipv4 {
        name LAN-to-LANv4 {
            default-action accept
        }
        name LAN-to-LOCALv4 {
            default-action accept
        }
        name LAN-to-WANv4 {
            default-action accept
        }
        name LOCAL-to-LANv4 {
            default-action accept
        }
        name LOCAL-to-WANv4 {
            default-action accept
        }
        name WAN-to-LOCALv4 {
            default-action drop
            rule 10 {
                action accept
                description "Allow ICMP"
                protocol icmp
            }
        }
        name WAN-to-WANv4 {
            default-action accept
        }
    }
} 

After something like this is set up, you only ever really work in the specific inter/intra zone policies. If you add/remove a zone you then go back into the forward,input,output sections

1 Like

I think what we need is a couple of good enough basic templates when it comes to how to do zoning with the new firewall frontend. And have them thrown up not only as references in the manual regarding firewall but also in the “blueprint” section which have many other good examples.

My take is similar to yours, interface-groups are whats normally refered to as “zones”.

My change is that I only cover for traffic entering a zone (aka uses the zone as egress).

That is traffic towards LAN will be defined in “V4_TO_LAN” or “V6_TO_LAN” chain.

The below is work in progress but this is how it currently looks like:

Note that below currently uses default-action:accept (due to development), for production it would be recommended to use default-action:drop.

One could also argue that for optimization the xx_TO_ZONE chains should use drop (or accept) as default-action instead of return (no need to continue to match the packet if you already figured out its egressing V4_TO_LAN but got no hits in there).

The input/output chains doesnt (currently) have any zone definitions because thats what the VyOS itself does with its services (such as SSH (for management), DHCP, VRRP, RA, DHCPv6 and whatelse you might have running on the VyOS itself).

set firewall global-options all-ping 'enable'
set firewall global-options broadcast-ping 'disable'
set firewall global-options ip-src-route 'disable'
set firewall global-options ipv6-receive-redirects 'disable'
set firewall global-options ipv6-src-route 'disable'
set firewall global-options log-martians 'enable'
set firewall global-options receive-redirects 'disable'
set firewall global-options resolver-cache
set firewall global-options resolver-interval '60'
set firewall global-options send-redirects 'disable'
set firewall global-options source-validation 'strict'
set firewall global-options syn-cookies 'enable'
set firewall global-options twa-hazards-protection 'disable'

set firewall group interface-group DMZ interface 'eth2'
set firewall group interface-group LAN interface 'eth3'
set firewall group interface-group MGMT interface 'eth0'
set firewall group interface-group WAN interface 'eth1'

set firewall group network-group DMZ network '192.168.2.0/24'
set firewall group network-group LAN network '192.168.3.0/24'
set firewall group network-group MGMT network '192.168.0.0/24'
set firewall group network-group WAN network '192.168.1.0/24'

set firewall ipv4 forward filter default-action 'accept'
set firewall ipv4 forward filter rule 10 action 'drop'
set firewall ipv4 forward filter rule 10 state invalid 'enable'
set firewall ipv4 forward filter rule 20 action 'accept'
set firewall ipv4 forward filter rule 20 state established 'enable'
set firewall ipv4 forward filter rule 30 action 'accept'
set firewall ipv4 forward filter rule 30 state related 'enable'
set firewall ipv4 forward filter rule 40 action 'jump'
set firewall ipv4 forward filter rule 40 jump-target 'V4_TO_WAN'
set firewall ipv4 forward filter rule 40 outbound-interface interface-group 'WAN'
set firewall ipv4 forward filter rule 50 action 'jump'
set firewall ipv4 forward filter rule 50 jump-target 'V4_TO_DMZ'
set firewall ipv4 forward filter rule 50 outbound-interface interface-group 'DMZ'
set firewall ipv4 forward filter rule 60 action 'jump'
set firewall ipv4 forward filter rule 60 jump-target 'V4_TO_LAN'
set firewall ipv4 forward filter rule 60 outbound-interface interface-group 'LAN'
set firewall ipv4 input filter default-action 'accept'
set firewall ipv4 input filter rule 10 action 'drop'
set firewall ipv4 input filter rule 10 state invalid 'enable'
set firewall ipv4 input filter rule 20 action 'accept'
set firewall ipv4 input filter rule 20 state established 'enable'
set firewall ipv4 input filter rule 30 action 'accept'
set firewall ipv4 input filter rule 30 state related 'enable'
set firewall ipv4 name V4_TO_DMZ default-action 'return'
set firewall ipv4 name V4_TO_LAN default-action 'return'
set firewall ipv4 name V4_TO_WAN default-action 'return'
set firewall ipv4 output filter default-action 'accept'
set firewall ipv4 output filter rule 10 action 'drop'
set firewall ipv4 output filter rule 10 state invalid 'enable'
set firewall ipv4 output filter rule 20 action 'accept'
set firewall ipv4 output filter rule 20 state established 'enable'
set firewall ipv4 output filter rule 30 action 'accept'
set firewall ipv4 output filter rule 30 state related 'enable'

set firewall ipv6 forward filter default-action 'accept'
set firewall ipv6 forward filter rule 10 action 'drop'
set firewall ipv6 forward filter rule 10 state invalid 'enable'
set firewall ipv6 forward filter rule 20 action 'accept'
set firewall ipv6 forward filter rule 20 state established 'enable'
set firewall ipv6 forward filter rule 30 action 'accept'
set firewall ipv6 forward filter rule 30 state related 'enable'
set firewall ipv6 forward filter rule 40 action 'jump'
set firewall ipv6 forward filter rule 40 jump-target 'V6_TO_WAN'
set firewall ipv6 forward filter rule 40 outbound-interface interface-group 'WAN'
set firewall ipv6 forward filter rule 50 action 'jump'
set firewall ipv6 forward filter rule 50 jump-target 'V6_TO_DMZ'
set firewall ipv6 forward filter rule 50 outbound-interface interface-group 'DMZ'
set firewall ipv6 forward filter rule 60 action 'jump'
set firewall ipv6 forward filter rule 60 jump-target 'V6_TO_LAN'
set firewall ipv6 forward filter rule 60 outbound-interface interface-group 'LAN'
set firewall ipv6 input filter default-action 'accept'
set firewall ipv6 input filter rule 10 action 'drop'
set firewall ipv6 input filter rule 10 state invalid 'enable'
set firewall ipv6 input filter rule 20 action 'accept'
set firewall ipv6 input filter rule 20 state established 'enable'
set firewall ipv6 input filter rule 30 action 'accept'
set firewall ipv6 input filter rule 30 state related 'enable'
set firewall ipv6 name V6_TO_DMZ default-action 'return'
set firewall ipv6 name V6_TO_LAN default-action 'return'
set firewall ipv6 name V6_TO_WAN default-action 'return'
set firewall ipv6 output filter default-action 'accept'
set firewall ipv6 output filter rule 10 action 'drop'
set firewall ipv6 output filter rule 10 state invalid 'enable'
set firewall ipv6 output filter rule 20 action 'accept'
set firewall ipv6 output filter rule 20 state established 'enable'
set firewall ipv6 output filter rule 30 action 'accept'
set firewall ipv6 output filter rule 30 state related 'enable'
1 Like

[quote=“zsdc, post:2, topic:12014”]
Yes, we expect that the total number of lines in the config will grow, but 40-70% sounds very unexpected.[/quote]

My firewall tree went from 460 lines to 1300 lines, though that 460 doesn’t include the zone definitions. I’m not super familiar with nftables so I can hardly read the new format. Some homework for me I guess.

Conceptually I understand the benefits of doing this, but readability is not one of them…

I would also appreciate a rethink of this change.

It’s a move away from an extremely useful abstraction, which IMO, is one of the most valuable elements of a system like Vyos. Allowing a user to achieve complex setups while at the same time removing the need for the implementor to be a low-level expert in how this gets done deep in the back end.

My config went from circa 1300 to 1800 lines, now making fw changes requires updates to multiple sections, increasing the opportunity for error and reducing the readability of the new config many times compared with the older form, yet it’s doing the same thing. The OPs comment regarding industry skillset and experience is super important and this may make the choice to use (or even continue to use) Vyos much more difficult than it ought to be.

I do wonder how easy your clients with config in the 1000s of lines of code using ZBF are going to be able to accommodate such a profound change without significant investment in retraining and perhaps retooling existing workflows.

I don’t think your user base is afraid of change, it’s been one of the most attractive elements of Vyos as the platform has matured, stabilised and optimised, especially over the last couple of years. I hope there’s a smart balance that can be achieved offering all the benefits of the new capabilities and at the same time bringing back something akin to the ZBF syntax.

2 Likes

When you are mentioning number of lines of config.

Do you refer to show config or show config commands?

Since the later will bring approx half as many rows but the display format is better (and more compact) from a configuration point of view while the former is more “human readable”.

From my lab:

show config: 591 lines
show config commands: 261 lines

When running the show config command in cli you get approx 3:1 ratio depending on section.

For example the firewall section using show config will need three full screens in my case where the same amount of info with show config commands is displayed in just one screen (before you have to press space to see the next one).

I was on some june image, spend a day getting my config in order, then i updated my image and my configs doubled with the added input/forward/output rules. Kinda confused why it all sits on top of my already existing pair rules. Im not opposed to a new&improved way of doing things but i cant find the documentation about these features anywhere :confused:

Edit: apparently there are docs, ill check them out later today

You can find the documenation here: Firewall — VyOS 1.4.x (sagitta) documentation

I concur with all the points that @james2012 raised.

I understand the need for these changes so that you can align with the nftables feature set, although I do not particularly agree with some of the other points raised in response.

Particularly around the improper configurations done by your customers.
I’m not sure this new method is any easier to understand, or less prone to mistakes.

Some immediate frustrations appear to be:

  • The migration injects seemingly randomised rule numbers into the filter configuration with no descriptions. This will lead to immediate frustration if customers haven’t chosen to use descriptive firewall-names that are now used as jump-targets.
  • Previously “intra-zone permit” traffic is now made possible through an explicit rule statement with the source and destination interface groups, again - this isn’t particularly descriptive and the rule appears to end up “mixed” with other rule statements.
  • It is no longer easy to determine which rules apply to source/destination group of interfaces, EG “untrust to trust”, whereas before it was as simple as observing the named firewall policy
  • By default, there’s a default-action accept on all filters? Which, unless someone remembers to set a default-action on a named jump-target or apply an explicit drop at the bottom, will lead to unintentional allowing of traffic.
  • I would imagine the majority of VyOS users will have chosen the product due to it’s loose similarity to JunOS, especially SRX security policies. While I understand that this is ‘merely a coincidence’, it was still remarkably easy to understand if you’d already used zone policies on SRX devices. Now it doesn’t really resemble anything anyone is used to other than nftables.
  • I would imagine these changes are going to break a lot of automation.

Additionally, it appears that firewall compile times are noticeably longer since the new syntax was introduced. I imagine this is down to the increased configuration size?
This is particularly noticeable on lower-end systems such as Intel Atom based devices.
I can’t say for sure what the differences are as I did not take timings during firewall compilation on the hardware I use before I upgraded to 1.5. However it is definitely more than a few 10s of seconds longer.

It’s likely that this will become the norm in a few releases, and that as users and customers, we’ll need to fall in line and adapt one way or another.
However, I’d personally like to see a better migration path such as an option to enable legacy policies while continuing to benefit from the other enhancements being made in the future versions of VyOS.
Also, the documentation and reasoning behind what can be considered as “breaking changes” isn’t readily available, or easy to find.

Please feel free to correct me if this has been posted elsewhere, however the obvious places such as the VyOS blog and news pages don’t mention this change.

3 Likes