Vagrant and libvirt work just fine together when using the standard iptables firewalling, but I wanted to move to the simpler (IMO) nftables. However, getting everything working properly was no simple task, so here is the process of how I got it all to work (finally).
In Arch Linux first you need to install both nftables
and iptables-nft
. The iptables-nft
package allows libvirt to write rules using both the iptables and ebtables syntax. Without this nothing will work at all.
Next, get your base set of firewall rules for nftables in place. On my machine I only want SSH open to the world. The caveat here is that you need a rule for the virbr0
interface to accept traffic as well. Your interface might be named differently, but this is the interface that libvirt created for your NAT network. Here is my current nftables.conf
:
#!/usr/bin/nft -f
# ipv4/ipv6 Simple & Safe Firewall
# you can find examples in /usr/share/nftables/
table inet filter {
chain input {
type filter hook input priority 0;
# allow established/related connections
ct state {established, related} accept
# early drop of invalid connections
ct state invalid drop
# allow from loopback
iifname lo accept
# allow icmp
ip protocol icmp accept
meta l4proto ipv6-icmp accept
# allow ssh
tcp dport ssh accept
# allow libvirt nat
iif virbr0 accept
# everything else
reject with icmpx type port-unreachable
}
}
# vim:set ts=2 sw=2 et:
Next, start the nftables systemd service. Check that your rules have been applied with nft list ruleset
. You should see a very small set of rules that matches your basic ruleset:
table inet filter {
chain input {
type filter hook input priority filter; policy accept;
ct state { established, related } accept
ct state invalid drop
iifname "lo" accept
ip protocol icmp accept
meta l4proto ipv6-icmp accept
tcp dport 22 accept
iif "virbr0" accept
reject
}
}
Now, start the libvirtd
systemd service. When checking nft list ruleset
you should see a much more robust set of rules, because libvirt
has now been able to write to your firewall for the NAT forwarding. I’m not going to show the output here, but it will be very noticable that there are changes to your ruleset.
For spinning up machines just using virsh
or virt-manager
you are now done and they will get IP addresses and work as you would expect them to. However, for Vagrant your machines will hang when trying to get an IP address. This is because Vagrant wants to create it’s own “management” network which has not been added to the firewall ruleset. The easiest way around this is to add a section to your Vagrant configuration telling it to use your normal network as the “management” network:
config.vm.provider "libvirt" do |libvirt|
libvirt.cpus = 4
libvirt.memory = 4096
libvirt.management_network_name = "default"
libvirt.management_network_address = "192.168.100.0/24"
end
In the example above my libvirt network name is “default”. If you don’t know your network name you can find it by running virsh net-list --all
:
Name State Autostart Persistent
--------------------------------------------
default active no yes
At this point everything should work as intended.