Bug 1468914

Summary: Libvirt managed bridge won't use firewalld zone after reboot
Product: Red Hat Enterprise Linux 7 Reporter: Strahil Nikolov <hunter86_bg>
Component: libvirtAssignee: Laine Stump <laine>
Status: CLOSED WONTFIX QA Contact: yalzhang <yalzhang>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 7.3CC: dyuan, egarver, ejnersan, gpulido, hunter86_bg, jdenemar, laine, lmen, pkotvan, psutter, rh, xuzhang, zypA13510
Target Milestone: rc   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2019-04-03 12:19:18 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---

Description Strahil Nikolov 2017-07-09 22:29:56 UTC
Description of problem:
When assigning a libvirt managed bridge (virbr0) to a zone - the change won't work after a reboot until NetworkManager.service is restarted.

Version-Release number of selected component (if applicable):
libvirt-2.0.0-10.el7_3.9

How reproducible:
always

Steps to Reproduce:
1.firewall-cmd --permanent --zone=internal --change-interface=virbr0 
2.reboot
3.Internal zone has no interfaces defined until a "systemctl restart NetworkManager.service"

Actual results:
No interface is defined for internal firewalld zone after a reboot

Expected results:
Internal zone should contain virbr0 device in "interfaces:" section

Additional info:

Comment 2 Laine Stump 2017-07-10 01:43:45 UTC
My guess is that this is because firewalld isn't detecting when a new transient interface (one that's not in the host system's network config) is created, but is instead relying on "someone else" to tell it.

Back in 2013, Federico Simoncelli posted a patch to libvir-list that would add firewall zone to libvirt's network config, and set the zone for the network's bridge device each time the network is started:

  https://www.redhat.com/archives/libvir-list/2013-April/msg00880.html

We discussed it on IRC, but due to (if I recall correctly) a misunderstanding on my part about its purpose, I made some suggestions about widening the scope that didn't make sense, and the patch floundered. Some time later someone else asked about configuring firewalld zones of libvirt networks, and I asked Federico, but he has moved on to other things and had no time to spend on his old patch, and the person asking also didn't have the time/ability to do anything with it.

I think generally his idea would solve your problem, although the "fwzone" attribute should possibly be in a different location in the XML and be named differently (or maybe not; it needs thought).

Comment 3 Strahil Nikolov 2017-07-10 08:37:26 UTC
Dear Laine,

thank you for your reply.

As a workaround , I'm using the following method:
firewall-cmd --permanent --zone=internal \
--add-source="192.168.122.0/24" 

Is there any chance this patch gets into the packages?  After All, Red Hat are trying to push firewalld , and I really like the idea behind it - but recompiling libvirt for every update ... that will be too much.

Comment 4 Laine Stump 2017-07-10 13:52:48 UTC
Sure, I didn't mean to imply that carrying a local patch and continually doing a local build of libvirt was a proper solution; just doing a memory dump of everything I know about the history of the subject so that anybody else who reads the BZ will also have that info.

In the meantime, I'm curious if there is a downside to basing the zone on the IP address (as you've done in your workaround) rather than the interface.

Comment 5 Strahil Nikolov 2017-07-10 16:31:08 UTC
I haven't met any ... for now, but I will update this ticket if I meet any issues with that. At least it's working.
The strange thing is that libvirt is actually not reading the configuration in "/etc/sysconfig/network-scripts/ifcfg-virbr0", but NetworkManager do take it into consideration (once restarted).

Comment 6 Laine Stump 2017-07-11 02:13:08 UTC
> ...the configuration in "/etc/sysconfig/network-scripts/ifcfg-virbr0"...


Oh, is *that* what you're doing? You should never do that. Bridges created and managed by libvirt should not be referenced in ifcfg files (it now makes more sense that NetworkManager has an effect on the bridge - it should be leaving it completely untouched).

(very unexpected and bad things can happen when an ifcfg file exists for a libvirt-managed bridge - NM has been known to decide that its IP address should be changed, that it should be brought down, etc etc. Certain versions of NM have actually done some of these things even without an ifcfg file being present; when that happens we make sure to complain to NM people :-)) 

(I actually had never noticed that the zone of an interface was set in the ifcfg file - I'd blindly assumed that it was saved in firewalld's own config. Surely that's what happens if you set a zone according to IP address rather than interface name?)

Comment 7 Strahil Nikolov 2017-07-11 13:50:55 UTC
Actually when you pass :
"firewall-cmd --permanent --zone=internal --change-interface=virbr0"
firewalld creates a "ZONE=internal" in the "/etc/sysconfig/network-scripts/ifcfg-virbr0" configuration file , which obviously libvirt completely ignores.
As per the previously mentioned patch - the "fwzone" option in the xml file should do everything I need.
When using:
firewall-cmd --permanent --zone=internal \
--add-source="192.168.122.0/24"
The ifcfg-virbr0 file do not have a "ZONE=internal" but all sources from the 192.168.122.0/24 will be processed as per the rules of the internal zone.

Comment 8 Laine Stump 2017-07-12 18:35:23 UTC
(In reply to Strahil Nikolov from comment #7)
> Actually when you pass :
> "firewall-cmd --permanent --zone=internal --change-interface=virbr0"
> firewalld creates a "ZONE=internal" in the
> "/etc/sysconfig/network-scripts/ifcfg-virbr0" configuration file 

Eww. That's.... good to know.


> When using:
> firewall-cmd --permanent --zone=internal \
> --add-source="192.168.122.0/24"
> The ifcfg-virbr0 file do not have a "ZONE=internal"

I just tried it out and looked for the config - it's saved in /etc/firewalld/zones/${zonename}.xml

> but all sources from the
> 192.168.122.0/24 will be processed as per the rules of the internal zone.

And I guess the ipfilter rules to implement this are created when firewalld starts rather than waiting for a particular interface to be online. I wonder if the created rules are any more or less efficient...

Comment 9 Strahil Nikolov 2017-07-13 07:20:45 UTC
(In reply to Laine Stump from comment #8)
>
> > but all sources from the
> > 192.168.122.0/24 will be processed as per the rules of the internal zone.
> 
> And I guess the ipfilter rules to implement this are created when firewalld
> starts rather than waiting for a particular interface to be online. I wonder
> if the created rules are any more or less efficient...

It does the trick ,as the host is also working as an NFS and FTP server , and also allows the VMs to fence the other virtual machines(fence_virtd.service listens on 1229/udp).

Here is a short list:

[root@Desktop ~]# iptables -L IN_internal ;iptables -L IN_internal_allow -n ; iptables -L IN_internal_deny ; iptables -L IN_internal_log
Chain IN_internal (2 references)
target     prot opt source               destination         
IN_internal_log  all  --  anywhere             anywhere            
IN_internal_deny  all  --  anywhere             anywhere            
IN_internal_allow  all  --  anywhere             anywhere            
ACCEPT     icmp --  anywhere             anywhere            
Chain IN_internal_allow (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22 ctstate NEW
ACCEPT     udp  --  0.0.0.0/0            224.0.0.251          udp dpt:5353 ctstate NEW
ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:137 ctstate NEW
ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:138 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:2049 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:111 ctstate NEW
ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:111 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:20048 ctstate NEW
ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:20048 ctstate NEW
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:25 ctstate NEW
ACCEPT     udp  --  192.168.122.0/24     0.0.0.0/0            udp dpt:1229 ctstate NEW
Chain IN_internal_deny (1 references)
target     prot opt source               destination         
Chain IN_internal_log (1 references)
target     prot opt source               destination

Comment 10 Yuping Zuo 2017-10-06 10:54:19 UTC
Any update on this? I'm now in a similar situation. And while Strahil's workaround is indeed helpful, it is but a workaround. We need a way to set firewall zone to the virtual interface permanently, like what you would do to an actual device by adding 'ZONE=<zone name>' to its ifcfg.

Comment 12 Strahil Nikolov 2018-04-09 20:23:23 UTC
Dear Laine,

is there anything I can try to do in order to get this useful feature into the packages ?

Comment 13 Ejner Fergo 2018-08-07 09:57:48 UTC
I am also looking for an update on this.

Despite the intention of libvirt and firewalld working together, there are still a few disconnects in the implementation. Will we see this fixed in the RHEL7 series, or is this planned for RHEL8?

Comment 15 yalzhang@redhat.com 2018-12-27 07:16:44 UTC
When I try to reproduce it on rhel7.3, the behavior is different with comment 0, even restart NetworkManager, the interface still not in any zone. And the /etc/firewalld/internal.xml has no changes after the "firewall-cmd --change-interface" command. 
I think maybe it is because the package version of firewalld, NetworkManager is not the same in my env as I don't know the correct one in comment 0, and I believe it is not libvirt's fault.

On latest rhel7 and rhel8 with new firewalld package, the issue is fixed.

on rhel7:
# rpm -q libvirt firewalld NetworkManager
libvirt-4.5.0-10.el7_6.3.x86_64
firewalld-0.5.3-5.el7.noarch
NetworkManager-1.12.0-6.el7.x86_64

on rhel8:
#  rpm -q libvirt-daemon firewalld NetworkManager
libvirt-daemon-4.10.0-1.module+el8+2317+367e35b5.x86_64
firewalld-0.6.3-5.el8.noarch
NetworkManager-1.14.0-10.el8.x86_64

1.
# systemctl enable firewalld
# systemctl enable NetworkManager
# systemctl start firewalld
# systemctl start NetworkManager

2.
# systemctl restart libvirtd
# nmcli con
NAME    UUID                                  TYPE      DEVICE
virbr0  22f4af96-1c9c-4716-9c90-e9fee4456f13  bridge    virbr0 

3.
# firewall-cmd --permanent --zone=internal --change-interface=virbr0
success

# cat  /etc/firewalld/zones/internal.xml | grep virbr0
  <interface name="virbr0"/>

4.
# reboot

no need to restart NetworkManager, the interface is there
# firewall-cmd --list-interface --zone=internal
virbr0

Comment 16 Strahil Nikolov 2018-12-27 08:40:56 UTC
I will give a try with latest packages, but your reply really sound good.

Comment 17 Laine Stump 2019-03-05 20:24:34 UTC
Beginning with libvirt-5.1.0 (and also with the libvirt-5.0.0 that is in RHEL8.0) libvirt's behavior wrt firewalld zones has been changed/enhanced (following is an excerpt from the libvirt NEWS file 5.1.0 section):


   network: support setting a firewalld "zone" for virtual network bridges
   -----------------------------------------------------------------------

   All libvirt virtual networks with bridges managed by libvirt
   (i.e. those with forward mode of "nat", "route", "open", or
   no forward mode) will now be placed in a special firewalld
   zone called "libvirt" by default. The zone of any network
   bridge can be changed using the <code>zone</code> attribute
   of the network's <code>bridge</code> element.

   network: fix virtual networks on systems using firewalld+nftables
   -----------------------------------------------------------------

   Because of the transitional state of firewalld's new support
   for nftables, not all iptables features required by libvirt
   are yet available, so libvirt must continue to use iptables
   for its own packet filtering rules even when the firewalld
   backend is set to use nftables. However, due to the way
   iptables support is implemented in kernels using nftables
   (iptables rules are converted to nftables rules and
   processed in a separate hook from the native nftables
   rules), guest networking was broken on hosts with firewalld
   configured to use nftables as the backend. This has been
   fixed by putting libvirt-managed bridges in their own
   firewalld zone, so that guest traffic can be forwarded
   beyond the host and host services can be exposed to guests
   on the virtual network without opening up those same
   services to the rest of the physical network. This means
   that host access from virtual machines is no longer
   controlled by the firewalld default zone (usually "public"),
   but rather by the new firewalld zone called "libvirt"
   (unless configured otherwise using the new zone
   attribute of the network bridge element).

More details about this change can be found in Bug 1650320 and Bug 12638342 (both of these are RHEL8 BZs)

If RHEL7 libvirt is ever rebased to libvirt-5.1.0+, it will get this updated functionality (although its purpose will be different, since RHEL7 will almost surely never get the updates to firewalld and the kernel to support using nftables as a backend for firewalld, or to support "rich rule priorities" in firewalld. However, it will fulfill the functionality requested here (the ability to permanently set a firewalld zone for a network;  this will be done by adding a "zone='xyz'" attribute to the <bridge> element of the libvirt network definition.)

Comment 18 Laine Stump 2019-03-05 20:25:21 UTC
Oops, the 2nd bug reference in the last comment should be Bug 1638342.

Comment 20 Strahil Nikolov 2019-03-06 04:42:40 UTC
Thanks Laine.
I guess this BZ can be closed.

Comment 21 Laine Stump 2019-03-06 17:27:31 UTC
Since the patches are in upstream already, I'm going to leave it in POST in case there is another libvirt rebase for RHEL7. If there is a rebase, then it will be marked CLOSED/ERRATA, otherwise we can mark it CLOSED/WONTFIX.

Comment 22 RHEL Product and Program Management 2019-04-03 12:19:18 UTC
Development Management has reviewed and declined this request. You may appeal this decision by reopening this request.