Files
harmony/examples/opnsense_vm_integration/setup-libvirt.sh
Jean-Gabriel Gill-Couture 3fd333caa3 fix(opnsense-vm-integration): detect and fix Docker+libvirt FORWARD conflict
Docker sets iptables FORWARD policy to DROP, which blocks libvirt's
NAT networking (libvirt defaults to nftables which doesn't interact
with Docker's iptables chain).

Fix: setup-libvirt.sh now detects Docker and offers to switch libvirt
to the iptables firewall backend, so both sets of rules coexist.
The --check command warns about this mismatch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:08:03 -04:00

141 lines
5.3 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
# Setup sudo-less libvirt access for KVM-based harmony examples.
#
# Run once on a fresh machine. After this, all KVM operations work
# without sudo — libvirt authenticates via group membership.
#
# Usage:
# ./setup-libvirt.sh # interactive, asks before each step
# ./setup-libvirt.sh --yes # non-interactive, runs everything
USER="${USER:-$(whoami)}"
AUTO_YES=false
[[ "${1:-}" == "--yes" ]] && AUTO_YES=true
green() { printf '\033[32m%s\033[0m\n' "$*"; }
red() { printf '\033[31m%s\033[0m\n' "$*"; }
bold() { printf '\033[1m%s\033[0m\n' "$*"; }
confirm() {
if $AUTO_YES; then return 0; fi
read -rp "$1 [Y/n] " answer
[[ -z "$answer" || "$answer" =~ ^[Yy] ]]
}
bold "Harmony KVM/libvirt setup"
echo
# ── Step 1: Install packages ────────────────────────────────────────────
echo "Checking required packages..."
MISSING=()
for pkg in qemu-full libvirt dnsmasq ebtables; do
if ! pacman -Qi "$pkg" &>/dev/null; then
MISSING+=("$pkg")
fi
done
if [[ ${#MISSING[@]} -gt 0 ]]; then
echo "Missing packages: ${MISSING[*]}"
if confirm "Install them?"; then
sudo pacman -S --needed "${MISSING[@]}"
else
red "Skipped package installation"
fi
else
green "[ok] All packages installed"
fi
# ── Step 2: Add user to libvirt group ────────────────────────────────────
if groups "$USER" 2>/dev/null | grep -qw libvirt; then
green "[ok] $USER is in libvirt group"
else
echo "$USER is NOT in the libvirt group"
if confirm "Add $USER to libvirt group?"; then
sudo usermod -aG libvirt "$USER"
green "[ok] Added $USER to libvirt group"
echo " Note: you need to log out and back in (or run 'newgrp libvirt') for this to take effect"
fi
fi
# ── Step 3: Start libvirtd ───────────────────────────────────────────────
if systemctl is-active --quiet libvirtd; then
green "[ok] libvirtd is running"
else
echo "libvirtd is not running"
if confirm "Enable and start libvirtd?"; then
sudo systemctl enable --now libvirtd
green "[ok] libvirtd started"
fi
fi
# ── Step 4: Default storage pool ─────────────────────────────────────────
if virsh -c qemu:///system pool-info default &>/dev/null; then
green "[ok] Default storage pool exists"
else
echo "Default storage pool does not exist"
if confirm "Create default storage pool at /var/lib/libvirt/images?"; then
sudo virsh pool-define-as default dir --target /var/lib/libvirt/images
sudo virsh pool-autostart default
sudo virsh pool-start default
green "[ok] Default storage pool created"
fi
fi
# ── Step 5: Fix Docker + libvirt FORWARD conflict ────────────────────────
# Docker sets iptables FORWARD policy to DROP, which blocks libvirt NAT.
# Libvirt defaults to nftables which doesn't interact with Docker's iptables.
# Fix: switch libvirt to iptables backend so rules coexist with Docker.
if docker info &>/dev/null; then
echo "Docker detected."
NETCONF="/etc/libvirt/network.conf"
if grep -q '^firewall_backend' "$NETCONF" 2>/dev/null; then
CURRENT=$(grep '^firewall_backend' "$NETCONF" | head -1)
if echo "$CURRENT" | grep -q 'iptables'; then
green "[ok] libvirt firewall_backend is already iptables"
else
echo "libvirt firewall_backend is: $CURRENT"
echo "Docker's iptables FORWARD DROP will block libvirt NAT."
if confirm "Switch libvirt to iptables backend?"; then
sudo sed -i 's/^firewall_backend.*/firewall_backend = "iptables"/' "$NETCONF"
echo "Restarting libvirtd to apply..."
sudo systemctl restart libvirtd
green "[ok] Switched to iptables backend"
fi
fi
else
echo "libvirt uses nftables (default), but Docker's iptables FORWARD DROP blocks NAT."
if confirm "Set libvirt to use iptables backend (recommended with Docker)?"; then
echo 'firewall_backend = "iptables"' | sudo tee -a "$NETCONF" >/dev/null
echo "Restarting libvirtd to apply..."
sudo systemctl restart libvirtd
# Re-activate networks so they get iptables rules
for net in $(virsh -c qemu:///system net-list --name 2>/dev/null); do
virsh -c qemu:///system net-destroy "$net" 2>/dev/null
virsh -c qemu:///system net-start "$net" 2>/dev/null
done
green "[ok] Switched to iptables backend and restarted networks"
fi
fi
else
green "[ok] Docker not detected, no FORWARD conflict"
fi
# ── Done ─────────────────────────────────────────────────────────────────
echo
bold "Setup complete."
echo
echo "If you were added to the libvirt group, apply it now:"
echo " newgrp libvirt"
echo
echo "Then verify:"
echo " cargo run -p opnsense-vm-integration -- --check"