Inhaltsverzeichnis

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.

Wirt_SystemvSwitchvirbr0Link encap:EthernetHardware Adresse B1:4C:49:FC:DF:71inet Adresse:192.168.122.1Bcast:192.168.122.255Maske:255.255.255.0SwitchPhysikalischer Netzwerk-SwitchNetz 192.168.100.0/24

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

CentOS_6_Wirt_SystemvSwitchvirtuelle Netzwerkswitchmit NAT (virbr0)-----------Link encap:EthernetHardware Adresse FE:54:00:66:BF:0Cinet Adresse:192.168.122.1Bcast:192.168.122.255Maske:255.255.255.0DHCP-Range: 192.168.122.100-254vml000010vml000010.nausch.org-----------CPU: 1RAM: 1024/512 MBHD: 10240 MBImageformat qcow2-----------Link encap:EthernetHardware Adresse 52:54:00:c0:15:c4inet Adresse:192.168.100.100Uplink direkt an Switch via br0SwitchPhysikalischer Netzwerk-SwitchNetz 192.168.100.0/24

Konfigurationen

Auf unserem Wirt-System haben wir in Summe drei Netzwerkinterfaces:

  1. eth0 : Unser Interface für die NAT-Anbindung von virtuellen Maschinen
  2. eth1 : Die Netzwerkschnittstelle die wir für das gebridgde Netzwerk verwenden
  3. 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

CentOS_6_Wirt_SystemvSwitchvirtueller Netzwerkswitchmit NAT (virbr0)-----------Link encap:EthernetHardware Adresse FE:54:00:66:BF:0Cinet Adresse:192.168.122.1Bcast:192.168.122.255Maske:255.255.255.0DHCP-Range: 192.168.122.100-254brdmzvirtueller Netzwerkswitchnur innerhalb der DMZ (brdmz)-----------Link encap:EthernetNetz:10.0.0.0/24statische IP-Adressvergabevml000010vml000010.nausch.org-----------CPU: 1RAM: 1024/512 MBHD: 10240 MBImageformat qcow2-----------Link encap:EthernetHardware Adresse 52:54:00:c0:15:c4inet Adresse:192.168.100.100Uplink direkt an Switch via br0-----------Link encap:EthernetHardware Adresse 52:54:00:c0:15:c4inet Adresse:10.0.0.10Uplink an interne DMZ-Bridge (brdmz)vml000020vml000020.nausch.org-----------CPU: 1RAM: 1024/512 MBHD: 10240 MBImageformat qcow2-----------Link encap:EthernetHardware Adresse 52:54:00:c0:15:c4inet Adresse:10.0.0.20default Gateway: 10.0.0.10Uplink nur an interne DMZ-Bridge (brdmz)SwitchPhysikalischer Netzwerk-SwitchNetz 192.168.100.0/24

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.

Photo: Neue VM anlegen

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.

Photo: Neue Hardware hinzufügen

Da wir eine neue Netzwerkkarte hinzufügen möchten fällt die nachfolgende Auswahl nicht schwer.

Photo: Neue Netzwerk-Hardware hinzufügen

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.

Photo: Neue Netzwerk-Hardware hinzufügen

Zu guter letzt werden un nochmals alle relevanten Konfigurationsdaten unserer zweiten virtuellen Netzwerkkarte angezeigt.

Photo: Neue Netzwerk-Hardware fertigstellen

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.

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.

Links

1)
Network Adress Translation
2)
br = Bidge/switch - dmz = Demilitarized Zone