virtuelle Netzwerke mit QEMU/KVM unter CentOS 6
Nach der Grundinstallation unseres CentOS 6 Wirtsystemes und anschließender Installation der Virtualisierungsumgebung stellt uns das System einen virtuelln Switch zur Verfügung.
vHost mit NAT
Die Einfachste Variante für die Vernetzung und Anbindung der virtuellen Gastsysteme ist die Nutzung von NAT1) mit Hilfe von libvirt.
Netzwerkbeispiel / -übersicht
Diese einfache Variante der Vernetzung, die uns die Basisinstallation von Haus aus mitbringt, zeigt beispielshaft die nachfolgende Graphik.
Konfigurationen
Auf unserem Wirt finden also breits unser default virtual network, welches wir bei der Standardinstallation von libvirt, vor.
Ein Blick „unter die Haube“ zeigt uns auch das entsprechende Netzwerk an.
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 100 link/ether 00:25:90:13:ba:a0 brd ff:ff:ff:ff:ff:ff inet 192.168.101.233/24 brd 192.168.10.255 scope global eth0 inet6 fe80::225:90ff:fe13:baa0/64 scope link valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 00:25:90:13:ba:a1 brd ff:ff:ff:ff:ff:ff 4: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN link/ether fe:54:00:0b:4a:75 brd ff:ff:ff:ff:ff:ff inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
Neben dem loopbackdevice und den beiden physikalischen Netzwerkschnittstellen unseres Wirtsystems haben wir also bereits das Netzwerkgerät virbr0 in unserem System.
Mit virsh können wir auch überprüfen, ob das NAT-Defaultnetzwerk aktiv ist.
# virsh net-list --all
Name Status Automatischer Start ----------------------------------------- default Aktiv yes
Sobald unser default network läuft, sehen wir unsere Netzwerk-Bridge, bei dem natürlich ohne ein Gastsystem weder eine physikalische Netzwerkschnittstelle verbunden, noch ein Gastsystem mit einer Virtuellen Schniottstelle angebunden ist (wie auch, denn wir haben noch keinen Gast installiert). Über dieses Netzwerk-Device können dank NAT und IP-Forwardingwir Verbindungen der vHOSTs zur Außenwelt aufbauen.
# brctl show
bridge name bridge id STP enabled interfaces virbr0 8000.fe54000b4a75 yes
vHost mit bridged NIC
Netzwerkbeispiel / -übersicht
Konfigurationen
Auf unserem Wirt-System haben wir in Summe drei Netzwerkinterfaces:
- eth0 : Unser Interface für die NAT-Anbindung von virtuellen Maschinen
- eth1 : Die Netzwerkschnittstelle die wir für das gebridgde Netzwerk verwenden
- IPMI : Netzwerk-Port füf das Managemnt via IPMI (Webbrowser und/oder SSH)
eth1
Die Konfiguration des Bridging-Interfaces nehmen wir direkt an der Konfikuartionsdatei im Verzeichnis /etc/sysconfig/network-scripts/ vor, da wir uns entschlossen haben auf den NetzwerkManager zu verzichten. Diese hat ja auch auf einem (Virtualisierungs-)Server wenig zu suchen.
# vim /etc/sysconfig/network-scripts/ifcfg-eth1
# Django: 2011-08-04 Konfiguration für Bridging-Interface DEVICE="eth1" HWADDR=00:25:90:13:BA:A1 ONBOOT="yes" BRIDGE=br0 MTU=9000
br0
Für die Verknüpfung der physikalischen Netzwerkschnittstelle eth1 des Wirt-Systemes mit einer virtuellen Netzwerkschnittstelle eines Gastsystems/vHOSTs definieren wir uns nun ein neues Netzwerkdevice br0.
# vim /etc/sysconfig/network-scripts/ifcfg-br0
# Django: 2011-08-04 Konfiguration des Bridging-Interfaces von eth1 zu einm vHOST via br0 DEVICE=br0 TYPE=Bridge ONBOOT=yes DELAY=0
Aktivierung
Nach Definition der beiden Netzwerkschnittstellen aktivieren wir das geänderte bzw. des neu erstellte Netzwerkgerät, indem wir den Dienst network durchstarten.
# service network restart
Damit nun auch noch die Virtualisierungs-API libvirt Kenntnis von unserem geänderten Netzwerk hat, bedarf es auch hier eines Neustarts des betreffenden Dienstes.
# service libvirtd restart
Neben dem bereits vorhandenem Netzwerkgerät virbr0 aus unserer Standardkonfigurationsumgebung vHOST mit NAT haben wir nun weitere Interfaces, die wir wie gewohnt abfragen können.
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 100 link/ether 00:25:90:13:ba:a0 brd ff:ff:ff:ff:ff:ff inet 192.168.10.13/24 brd 192.168.10.255 scope global eth0 inet6 fe80::225:90ff:fe13:baa0/64 scope link valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 9000 qdisc pfifo_fast state UP qlen 100 link/ether 00:25:90:13:ba:a1 brd ff:ff:ff:ff:ff:ff inet6 fe80::225:90ff:fe13:baa1/64 scope link valid_lft forever preferred_lft forever 4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UNKNOWN link/ether 00:25:90:13:ba:a1 brd ff:ff:ff:ff:ff:ff inet 192.168.10.212/24 brd 192.168.10.255 scope global br0 inet6 fe80::225:90ff:fe13:baa1/64 scope link valid_lft forever preferred_lft forever 5: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN link/ether ca:d2:dc:46:a5:fe brd ff:ff:ff:ff:ff:ff inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
Über das Device br0 haben nun die vHOSTS einen direkten Zugriff auf die Netzwerk-Schnittstelle eth1 auf unserem Server. Diese Schnittstelle werden wir dann in einer späteren Konfigurationsschritt als Uplink zu unserem ISP benutzen. Unsere nunmehr beiden Bridges könen wir auch mit Hilfe der Ethernet Bridge Ddministration Tools brctl aus dem RPM-Paket bridge-utils abfragen.
# brctl show
bridge name bridge id STP enabled interfaces br0 8000.00259013baa1 no eth1 vnet0 virbr0 8000.000000000000 yes
vHosts mit bridged NIC und interner Bridge
Als weitere Steigerung zum vorgenannten Konfigurationsbeispiel, wollen wir nun einen vHOST als Gateway/Paketfilter benutzen und für einige virtuellen Gastsysteme einen virtuellen Switch einrichten. Die vHOSTS können dann untereinander über diesen Switch Daten austauschen und kommunizieren. Den Weg nach Außen müssen dies jedoch immer über einen dedizierten vHOST nehmen, der über das direkt gebridgete Netzwerkinterface br0 die Verbindung zur realen physischen Netzwerkinfrastruktur aufbaut. Das nachfolgende Schaubild zeigt exemplarische den Netzwerkaufbau an Hand von zwei vHOSTs.
Netzwerkbeispiel / -übersicht
Konfigurationen am Wirtsystem
brdmz
Neben dem Interface br0 aus dem vorgenannten Beispiel legen wir uns auf unserem Wirtsystem eine weitere Netzwerkschnittstelle an, die den internen Switch mit dem Namen brdmz2) abbilden soll.
# vim /etc/sysconfig/network-scripts/ifcfg-brdmz
# Django: 2011-08-04 Konfiguration des Bridging-Interfaces DEVICE=brdmz TYPE=Bridge ONBOOT=yes DELAY=0
Aktivierung
Für die Aktivierung des neuen Netzwerkinterfaces starten wir nun den Dienst network und auch den Dienst libvirt einmal durch.
# service network restart && service libvirtd restart
Für die Weiterleitung der IP-Pakete durch die Bridge erweiteren wir noch unseren Paketfilterregelsatz.
# iptables -I FORWARD -m physdev --physdev-is-bridged -j ACCEPT
Anschließend speichern wir die gänderten iptables-Regeln ab, damit sie bbei einem späteren Neustart wieder zur Verfügung stehen.
# service iptables save iptables: Saving firewall rules to /etc/sysconfig/iptables:[ OK ]
Neben dem bereits vorhandenem Netzwerkgerät virbr0 aus unserer Standardkonfigurationsumgebung vHOST mit NAT haben wir nun weitere Interfaces, die wir wie gewont abfragen können.
# ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 100 link/ether 00:25:90:13:ba:a0 brd ff:ff:ff:ff:ff:ff inet 192.168.10.13/24 brd 192.168.10.255 scope global eth0 inet6 fe80::225:90ff:fe13:baa0/64 scope link valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 9000 qdisc pfifo_fast state UP qlen 100 link/ether 00:25:90:13:ba:a1 brd ff:ff:ff:ff:ff:ff inet6 fe80::225:90ff:fe13:baa1/64 scope link valid_lft forever preferred_lft forever 4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UNKNOWN link/ether 00:25:90:13:ba:a1 brd ff:ff:ff:ff:ff:ff inet 192.168.10.212/24 brd 192.168.10.255 scope global br0 inet6 fe80::225:90ff:fe13:baa1/64 scope link valid_lft forever preferred_lft forever 5: brdmz: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN link/ether fe:54:00:0a:f0:a7 brd ff:ff:ff:ff:ff:ff inet6 fe80::fc54:ff:fe0a:f0a7/64 scope link valid_lft forever preferred_lft forever 6: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN link/ether ca:d2:dc:46:a5:fe brd ff:ff:ff:ff:ff:ff inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
Über das Device br0 haben nun die vHOSTS einen direkten Zugriff auf die Netzwerk-Schnittstelle eth1 auf unserem Server. Diese Schnittstelle werden wir dann in einer späteren Konfigurationsschritt als Uplink zu unserem ISP benutzen. Das Device brdmz nutzen wir nun ausschließlich für die Vernetzung der betreffenden DMZ-vHOSTS in unserer Virtualiiserungsumgebung. Die drei Bridges könen wir auch mit Hilfe der Ethernet Bridge Ddministration Tools brctl aus dem RPM-Paket bridge-utils abfragen.
# brctl show
bridge name bridge id STP enabled interfaces br0 8000.00259013baa1 no eth1 vnet0 brdmz 8000.fe54000af0a7 no vnet1 vnet2 virbr0 8000.000000000000 yes
Konfigurationen auf dem Gastsystem
Erstellen einer zweiten Netzwerkkarte
Unser vHOST der die Trennung der DMZ-Umgebung mit der Außenwelt herstellt, definieren wir uns bei der Installation einfach eine weitere Netzwerkschnittstelle. Beim letzten Konfigurationsfenster beim Anlegen eines neuen vHOSTs wählen wir nun unter dem Punkt Erweiterete Optionen unser Bridge br0 an, da der Host eine direkte Verbindung zur eth1 des Wirt-systemes bekommen soll.
Weiterhin setzen wir noch das Häkchen bei Konfiguration vor der Instalation anpassen, weil wirgleich noch eine weitere Netzwerkschnittstelle für den internen virtuellen Switch brdmz definieren möchten. Auf dem folgenden Fenster wählen wir dann die Schaltfläche Hardware hinzufügen.
Da wir eine neue Netzwerkkarte hinzufügen möchten fällt die nachfolgende Auswahl nicht schwer.
Auf dem nun folgenden Konfigurationsfenster wäheln wir bei dem Punkt Host Gerät unseren internen Switch brdmz aus, da die weitere Netzwerkschnittstelle mit dieser verbunden werden soll.
Zu guter letzt werden un nochmals alle relevanten Konfigurationsdaten unserer zweiten virtuellen Netzwerkkarte angezeigt.
Anschließend beenden wir die Konfiguration mit einem klick auf den grünen Haken Installation abschließen links oben und beginnen wir gewohnt mit der Installation unseres Gast-Betriebssystemes.
Konfiguration an vHOST
Da wir auf die Dienste des NetworkManagers auf unserem virtuellen Serversystem verzichten, bearbeiten wir unsere Netzwerkschnittstellen wie gewohnt direkt im System.
eth0 (untrust network)
Für die Anbindung an die Außenwelt benutzen wir die bei der Installation festgelegten Netzwerkschnittstelle eth0, welche die Verbindung zur Außenwelt (untrusted network) herstellt.
# vim /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE="eth0" NM_CONTROLLED="yes" ONBOOT=yes HWADDR=52:54:00:C0:15:C4 TYPE=Ethernet BOOTPROTO=dhcp DEFROUTE=yes PEERDNS=yes PEERROUTES=yes IPV4_FAILURE_FATAL=yes IPV6INIT=no NAME="System eth0" UUID=5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03
eth1 (trusted network)
Die Verbindung zu unserem vertrauenswürdigen interenen Netzwerk ermöglichen wir über die zweite Netzwerkschnittstelle eth1 die wir bei der Definition unseres vHOSTs mit der Bridge brdmz verbunden hatten.
# vim /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE="eth1" NM_CONTROLLED="yes" ONBOOT=yes TYPE=Ethernet BOOTPROTO=none IPADDR=10.0.0.10 PREFIX=24 DNS1=192.168.10.1 DOMAIN=dmz.nausch.org DEFROUTE=yes IPV4_FAILURE_FATAL=yes IPV6INIT=no NAME="System eth1" UUID=9c92fad9-6ecb-3e6c-eb4d-8a47c6f50c04 HWADDR=52:54:00:0A:FA:3E
Port Forwarding und iptables Regeln
Damit unser neuer vHOST nun die IP-Pakete auds dem internen Netzwerk brdmz auch an die Schnittstelle eth0, also zum untrusted Netwok weiterreichen kann, aktivieren wir noch das Portforwarding für IPv4, indem wir in die betreffende Konfigurationsdatei einfach eine logische 1 eintragen.
# vim /etc/sysctl.conf
# Kernel sysctl configuration file for Red Hat Linux
#
# For binary values, 0 is disabled, 1 is enabled. See sysctl(8) and
# sysctl.conf(5) for more details.
# Controls IP packet forwarding
# Django : 2011-08-04 Portforwarding aktiviert
# default : net.ipv4.ip_forward = 0
net.ipv4.ip_forward = 1
# Controls source route verification
net.ipv4.conf.default.rp_filter = 1
# Do not accept source routing
net.ipv4.conf.default.accept_source_route = 0
# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0
# Controls whether core dumps will append the PID to the core filename.
# Useful for debugging multi-threaded applications.
kernel.core_uses_pid = 1
# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1
# Disable netfilter on bridges.
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0
Die beiden Themen Masquerading und Portforwarding erschlagen wir nun mit der Erweiterung des bestehenden iptables-Regelwerkes.
- Masquerading
-A POSTROUTING -o eth0 -j MASQUERADE
- IP Forwarding (ankommend)
-A FORWARD -i eth0 -o eth1 -m state –state RELATED,ESTABLISHED -j ACCEPT
- IP Forwarding (abgehend)
-A FORWARD -i eth1 -o eth0 -j ACCEPT
Beides tragen wir nun in unsere Konfigurationsdatei des Paketfilters iptables ein.
# vim /etc/sysconfig/iptables
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
# Django : 2011-08-04 Masquerading aktiviert
-A POSTROUTING -o eth0 -j MASQUERADE
# Django : end
COMMIT
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -p icmp -j ACCEPT
-A FORWARD -i lo -j ACCEPT
# Django : 2011-08-04 Portforwarding aktiviert eth0 = untrusted und eth1 trusted
-A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1 -o eth0 -j ACCEPT
# Django : end
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
Anschließend aktivieren wir unser geändertes Regelwerk durch einen Neustart des Systemdienstes iptables.
Sobald nun weitere vHOSTs über die interne Netzwerk-Bridge brdmz aktiviert werden, können diese über unseren Firewall-HOST Daten nach außen schicken und natürlich auch die gewünschten Antwortpakete empfangen.