Edited: 2022-06-30, added capability to block multiple subnets.
First things first!
|  |  | 
Preface
Until I learn how to tame VXLAN for a virtualization cluster, I need a dirty way of seperating infrastructure network and the VM network.
The solution presented in this post is to apply libvirt’s network filters (nwfilter) to drop packages from and to the “uplink”, namely home LAN (10.0.0.0/18), for any guest connected to the NAT (192.168.123.0/24). This approach is analogous to setting firewall rules on a router, it just is virtual. Remember to adjust your subnets!
Disclaimer: I make use of sudo while running virsh this may not be necessary if you have added yourself to proper groups, I did not bother.If so, kindly delete them before executing.
Pitfalls
Firstly, make sure you don’t make a typo unlike me (looking at you “<filterref type=‘drop-subnet’>”).
Secondly, make use of virsh dumpxml (or virt-manager’s XML tab under NIC) to validate your filter was indeed applied to VM definition.
Lastly, ensure you have a single filter applied per NIC (at least I could not apply two of them). Define an umbrella filter which includes all rules and other filters.
Shortcomings
I suppose, given enough eagerness, one could find a way of proxying the connection between the two subnets, namely “home LAN” and “guest NAT”.
One such case would be using the public IP address of a DMZ host, however, one would assume the DMZ host to be already hardened. Yet, be warned to think of such cases before implementing your internet-connected virus test lab.
Virtual NAT Firewall (nwfilter)
Let us define a parametrized filter, named drop-subnet, to be tested shortly after.
nwfilter-drop-subnet.xml:
|  |  | 
Define the filter:
|  |  | 
For more details see chapter nwfilter concepts, better read it all tough.
Preparations
1. Define a seperate NAT network to be filtered
I chose to disable DHCP and DNS as I would be using static IPs and enforcing against spoofing using. See disabling DNS in Libvirt, disabling DHCP in Libvirt and especially virtual network docs for more.
net-nat-filtered.xml:
|  |  | 
You can omit <mac> and <nat> as well as commented dhcp example. Remember to change enp1s0 into what your physical interface or bridge is. Could be eth1, enp3s0, br0, etc.
Now let us import the XML:
|  |  | 
Lastly, activate and enable it:
|  |  | 
P.S. Do not to use KVM’s default (192.168.122.0/24) or any other existing network’s IP block.
2. Create a VM
It is assumed that you prepared a VM connected to the network nat-filtered with name guest-01 and IP 192.168.123.11.
If in need of assistance, can follow Server World’s tutorials (select OS of your choice at Other OS Configs). I spun one up with GUI application virt-manager.
Now, one could make use of either of the below:
- virsh edit
- virsh dumpxmlfollowed by- virsh define
I will go for the latter out of personal preference (seems easier to script if need ever arises).
|  |  | 
Below use of ... is to denote numerous lines irrelevant to the task at hand.
vm-guest-01.xml:
|  |  | 
Your interface type might be a bridge or ethernet (e.g. <interface type='bridge'>) as described in nwfilter concepts, it is irrelevant.
Now make the addendum into existing <interface>:
|  |  | 
See my answer to “libvirt nwfilter, multiple parameters” for more insight.
At this point, shut down the VM if already running:
|  |  | 
Then, (re)define VM using the xml:
|  |  | 
Start it to start testing:
|  |  | 
Testing
Connect to guest-01 one way or another. Below is accessing serial console from the hypervisor:
|  |  | 
Test NAT-local connectivity, should work:
|  |  | 
Test internet connectivity, should work unless DNS is 1.1.1.1:
|  |  | 
Test connectivity to blacklisted subnet (home LAN: 10.0.0.0/18), should not work:
|  |  | 
Test DNS at 1.1.1.1/32:
|  |  | 
That’s it.
If you wish to test spoofing as well, change the IP address of guest-01 and try pinging the NAT-local gateway.
“This does not float my boat!”
If this approach isn’t suitable, you might try setting up an OPNSense/ VyOS/ IPFire guest with multiple NICs to act as a properly virtualized router/ firewall OS. This would put a bit more overhead, but might be more apt for more complicated requirements. Of course an isolated network must be used in such a case. To refresh your color-coded zone knowlegde: IPFire’s color table (red, green, orange, blue).
Cheers !