VMs von ESXi nach Proxmox migrieren

Dieser Eintrag behandelt die Migration von VMs von einer existierend VMware ESXi Installation zu einer Proxmox Installation auf der gleichen Hardware. Dabei wird der ESXi Server vollständig formatiert.

Genutzt wurde VMware ESXi 7.0 u2 und als Ziel wurde Proxmox 8.0 verwendet.

 

Backup erstellen

Zunächst muss ein Backup erstellt werden. Hier gibt es mehrere Wege dies zu tun.

Option 1 – Für ESXi Hosts mit Lizenz

Diese Option beinhaltet die kürzeste Downtime, erfordert aber dass der ESXi Host mit einer Kauf-Lizenz ausgestattet ist.

Das Vorgehen ist hier wie folgt:
Zunächst ein Backup-System installieren und dort eine Backupsoftware installieren. Ich habe dazu auf einem PC eine VM mit Windows 10 erstellt und dort Veeam Backup and Recovery installiert. Veeam lässt sich mit einer Testlizenz 30 Tage kostenlos nutzen. Zu Veeam habe ich dann den ESXi Host verbunden und von allen VMs jeweils ein Backup erstellt. Je nach Größe der VMs und Geschwindigkeit der Internetleitung dauert dies natürlich eine Weile. Nachdem die erste Vollsicherung aller VMs durchgelaufen ist, habe ich gleich die nächste Sicherung gestartet um eine inkrementelle Sicherung auszuführen. Diese sichert nur noch die Unterschiede, wodurch das Backup in der Regel innerhalb weniger Minuten durch ist. Dann habe ich eine VM nach der Anderen zunächst heruntergefahren und anschließend, nachdem diese aus war, erneut ein Backup erstellt. Die Reihenfolge der VMs sollte von unwichtig nach wichtig sein, wobei die wichtigste VM zuletzt bearbeitet wird. Somit ist das Backup auf dem letzten Stand der jeweiligen VMs. WICHTIG: Achtet darauf, dass VOR dem letzten Backup die VMs keine Snapshots mehr haben. Ansonsten haben wir später ein Problem.
In Veeam können dann die VMs unter Restore => VMware vSphere => Restore from backup => Disk restore => VM files restore (VMX, NVRAM) die VMs mit allen Dateien wiederhergestellt werden. Dies geht jetzt superschnell, da die VMs jetzt nicht mehr über die Internetleitung übertragen werden müssen. Anschließend haben wir die VM Dateien in dem Restore Ordner liegen.

Option 2 – Ohne Lizenz Variante 1

Hier benötigen wir keine ESXi Lizenz, müssen dafür aber mehr Downtime einberechnen, da wir die „Vorabübertragung“ der Daten, was in Option 1 durch Veeam erledigt wird, nicht durchführen können.

Das Vorgehen ist für jede VM wie folgt. Dabei sollte von der unwichtigsten (längste Downtime) zur wichtigsten (kürzeste Downtime) vorgegangen werden. Die Downtime wird für alle VMs dennoch signifikant sein.
Je VM zunächst die VM herunterfahren und sicherstellen, dass kein Snapshot mehr existiert. Anschließend in der ESXi Verwaltung auf den Datastore der VM gehen und alle Dateien der VM in einen lokalen Ordner herunterladen. Dabei darauf achten, dass die VM komplett auf dem einen Datastore liegt. Ist dies nicht so, auch die Dateien der anderen Datastores herunterladen.
Dies nach und nach für jede VM ausführen. Anschließend haben wir die VM Dateien in dem Restore Ordner liegen.

Option 3 – Ohne Lizenz Variante 2

Hier benötigen wir keine ESXi Lizenz, müssen dafür genau so viel Downtime einberechnen, wie bei Option 2, da wir die „Vorabübertragung“ der Daten, was in Option 1 durch Veeam erledigt wird, nicht durchführen können.

Zunächst benötigen wir von VMware das Tool „VMware Converter Standalone“. Nun sicherstellen, dass die VMs keine Snapshots beinhalten und anschließend die VMs nacheinander herunterfahren. Im VMware Converter dann unter „Convert machine“ als Source den ESXi Server konfigurieren und als Destination dann eine „VMware Workstation or other VMware virtual machine“. Diese dann in einen lokalen Ordner ablegen. Dies nach und nach für jede VM ausführen. Anschließend haben wir die VM Dateien in dem Restore Ordner liegen.

Proxmox installieren

Nun kann der ESXi-Server formatiert werden und durch Proxmox ersetzt werden.

VMDK normalisieren

Nach dem Wiederherstellen der VM-Dateien bzw. dem Kopieren, sind ist die VMDK ggf. noch als „-flat“ file vorhanden. Ist dies der Fall, müssen wir noch eine Konvertierung durchführen. Hierzu brauchen wir das Tool „VMware Converter Standalone“. Dort wählen wir als Source System „VMware Workstation or other VMware virtual machine“ und wählen dort den Ordner mit der vmx-Datei der VM aus. Als Destination System geben wir die gleichen Einstellung an, jedoch in einen eigenen Ausgabeordner. Ein Weiterer Vorteil dieser Methode: think provisioned VMDK Dateien werden so zu thin provisioned, was das Volumen ggf. deutlich reduziert. Wer wirklich thick provisioned benötigt, kann diese nach dem Upload auf dem Hypervisor wieder auf think konvertieren.
Nach dem normalisieren ist die -flat-Datei der VMDK verschwunden und die vmdk-Datei selbst ist so groß wie die Daten der VM.

VMDK konvertieren

Nun müssen wir die VMDK zum qcow2-Format konvertieren. Dazu benötigen wir eine Linux-VM mit dem qemu-img CLI-Programm. Dies geht in einer WSL-Instanz (Das Windows Subsystem for Linux) oder in einer weiteren VM z.B. mit Debian. In der VM dann folgenden Befehl nutzen um die VMDK zu formatieren:

qemu-img convert -f vmdk -O qcow yourfile.vmdk yourfile.qcow2

Proxmox konfigurieren

Unter Proxmox muss auf dem „local“-Datastore noch konfiguriert werden, dass dieser VM Disks speichert. Leider kann nicht direkt in die LVM-Datastores gespeichert werden.
In Proxmox im Menü „Datacenter“ => „Storage“ auswählen. Dort „local“ anklicken und unter „Edit“ den Haken zusätzlich bei „Disk image“ setzen. Nun können auch Disk images hier gespeichert werden.

QCOW2 Datei hochladen

Mittels folgendem Befehl kann dann qcow2-Datei zum Proxmox Server hochgeladen werden:

scp yourfile.qcow2 root@yourProxmoxIP:/var/lib/vz/images

Ggf. wird noch ein Passwort für den root-user verlangt sowie das Bestätigen des SSH Fingerprints.

VM erstellen und Disk verbinden

Erstelle in Proxmox die VM, wie du sie benötigst. Achte ggf. darauf UEFI als BIOS-Option einzustellen. Erstelle auch eine neue Disk. Wähle dazu den „local“-Datastore. Dies werden wir auf Dateisystemebene ersetzen. Nachdem die qcow2-Datei hochgeladen ist, gehen wir per SSH auf den Proxmox Server. Nun wechseln wir nach /var/lib/vz/images. Dort sehen wir unsere hochgeladene Datei und einen Ordner mit der ID der erstellten VM. In den Ordner gehen wir herein. Den Namen der dort vorhandenen Datei merken wir uns und löschen anschließend die Disk. Nun verschieben wir die hochgeladene Datei in den ID-Ordner und geben der Datei den Namen der gelöschten Disk.

VM starten

Starte nun die VM. Wenn UEFI/BIOS sowie der Storage Controller korrekt erkannt werden, ist die VM somit umgezogen.

 

Cheat Sheet: Englisches US-Tastaturlayout auf Deutscher Tastatur

Dieses Cheat Sheet hilft auf einer Deutschen Tastatur einen Buchstaben zu finden, wenn im Betriebssystem ein EN-US Tastaturlayout eingestellt ist:

Zeichen
Taste
Anmerkung
Y Z Y + Z ist vertauscht
Z Y Y + Z ist vertauscht
@ Shift + 2
? Shift + – (Bindestrich)
( Shift + 9
) Shift + 0
ß  Tipp: Auf dem Numpad das Minuszeichen geht auch
_ Shift + ß
: Shift + Ö
; Ö
Shift + Ä
# Shift + 3
Ä
+ Shift + ´ (Apostroph) Tipp: Auf dem Numpad das Plus-Zeichen geht auch
| Shift + #
< Shift + , (Komma) Auch auf den Standard-Tasten für das Deutsche Layout
> Shift + . (Punkt) Auch auf den Standard-Tasten für das Deutsche Layout
/ – (Bindestrich) Tipp: Auf dem Numpad das Divisionszeichen geht auch
\ #
* Shift + 8 Tipp: Auf dem Numpad das Multiplikationszeichen geht auch
° Alt + 0186 Nicht auf der US-Tastatur
^ Shift + 6
& Shift + 7
´ Alt + 0180 Nicht auf der US-Tastatur
` ^
~ Shift + ^
= ´ (Apostroph)
[ Ü
] +
{ Shift + Ü
} Shift + *
Alt + 0128 Nicht auf der US-Tastatur

VMware vCenter Zertifikat erneuern

Ich musste gerade das Zertifikat meiner VMware-Laborumgebung mit vCenter aktualisieren und habe nach einer guten Anleitung dazu gesucht. Ich habe keine vollständige Anleitung gefunden, also habe ich mich entschlossen, hier eine zu veröffentlichen.

So geht’s:

  1. Melden Sie sich mit SSH auf dem vCenter Server an (Sie müssen SSH aktivieren, wenn es deaktiviert ist)
  2. Geben Sie shell in die Konsole ein.
  3. Erstellen Sie ein Verzeichnis, in dem wir alles speichern werden: mkdir /tmp/cert
  4. Führen Sie chsh -s /bin/bash root aus, um später eine Verbindung über WinSCP zu ermöglichen
  5. Starten Sie den Zertifikatsmanager: /usr/lib/vmware-vmca/bin/certificate-manager
  6. Wählen Sie die erste Option („Replace Machine SSL certificate with custom certificate“)
  7. Geben Sie den lokalen Administrator ein (d.h. standardmäßig administrator@vsphere.local)
  8. Wählen Sie die erste Option („1. generate Certificate Signing Request(s) and Key(s) for Machine SSL certificate“)
  9. Geben Sie den Pfad zu dem in Schritt 3 erstellten Ordner ein (/tmp/cert)
  10. Geben Sie die Parameter des Zertifikats an. Für die Optionen „Name“ und „Hostname“ müssen Sie den FQDN des Servers angeben
  11. Die CSR zur Erstellung des Zertifikats durch Ihre CA wird im Ausgabeverzeichnis gespeichert
  12. Laden Sie den CSR über WinSCP herunter und erstellen Sie auf dieser Basis ein Zertifikat. Das Zertifikat muss im Base64-Format vorliegen und Sie benötigen das öffentliche Stammzertifikat Ihrer CA.
  13. Laden Sie das Zertifikat und das Wurzelzertifikat in den /tmp/cert-Ordner hoch
  14. Setzen Sie den Dialog fort (Option 1) oder wenn Sie etwas Zeit dazwischen hatten, können Sie nach dem Start des Zertifikatsmanagers statt Option 1 auch Option 2 wählen.
  15. Nun müssen Sie die Pfade zu dem Zertifikat, dem Schlüssel und dem Stammzertifikat Ihrer CA angeben
  16. Ist dies geschehen, installiert der Assistent das Zertifikat. Dies dauert eine Weile und wird fast alle Dienste neu konfigurieren und neu starten.

Getestet auf vCenter 6.5 und vCenter 6.7

VMware Remote Console (VMRC) silent installieren

Nachdem ich mich einige Stunden damit herumgeschlagen hatte, fand ich schließlich den folgenden Befehl heraus, um VMRC ohne Neustart und mit deaktivierten automatischen Software-Aktualisierungsverfahren zu installieren. Mit diesem Befehl:

VMware-VMRC-10.0.2-7096020.exe /s /v "/qn REBOOT=R EULAS_AGREED=1 AUTOSOFTWAREUPDATE=0 ATACOLLECTION=0"

Zur Deinstallation verwende diesen Befehl (die GUID kann bei anderen VMRC-Versionen anders lauten):

MsiExec.exe /X{09E3AC7C-395C-47C6-9F66-4B9FB8325341} /qn /norestart

 

Automatisch IP Adressen von Angreifern mit der Windows Firewall blockieren

Durch Zufall habe ich entdeckt, dass in einem meiner Ereignisprotokolle („Applications and Services Logs\Microsoft\Windows\RemoteDesktopServices-RdpCoreTS\Operational“) mehrere Einträge mit der ID 140 vorhanden sind. Diese Ereignisse protokollieren die Versuche von Benutzern, sich über RDP auf meinem Server anzumelden versuchen, aber mit falschen Anmeldeinformationen. Natürlich sollte es keine Versuche geben oder vielleicht nur einen oder zwei von mir selbst. Aber in meinem Fall sind es Hunderte.

Zuerst habe ich überprüft, ob mein lokales und mein Domänenadministratorkonto beide deaktiviert sind. Dies war der Fall, so dass die meisten Anmeldeversuche ebenfalls fehlschlagen, weil der jeweilige Benutzer deaktiviert ist. Ich nehme an, dass die meisten versuchen, diese Benutzer zu verwenden. Der Benutzer wird durch die Versuche nicht gesperrt, da zwischen den Wiederholungsversuchen genügend Zeit liegt.

Der Text des Anmeldeversuchs im Ereignisprotokoll lautet „A connection from the client computer with an IP address of xxx.xxx.xxx.xxx failed because the user name or password is not correct.“.

Also habe ich ein PowerShell-Skript erstellt, das diese Meldungen ausliest, die IP daraus filtert und in die Blacklist der Windows Firewall aufnimmt.
Voraussetzung dafür ist, dass es bereits eine Firewall-Regel mit mindestens 2 blockierten IP-Adressen gibt. Ich war einfach zu faul, dies in meinem Skript zu lösen. Um diese Regel zu erstellen, starten Sie die Windows Firewall Einstellungen und erstellen Sie eine neue Regel unter „Eingehende Regeln“.

Wählen Sie „Benutzerdefiniert“ aus. Lassen Sie „Alle Programme“ stehen (klicken Sie einfach auf „Weiter“). Beliebigen Protokolltyp und Port belassen (einfach „Weiter“ klicken). Wählen Sie im Abschnitt „Anwendungsbereich“ unter „Für welche entfernten IP-Adressen gilt diese Regel?“ die Option „Diese IP-Adressen“ und fügen Sie zwei Dummy-Adressen hinzu, z. B. 1.2.3.4 und 1.2.3.5. Wir brauchen mindestens zwei Adressen für das Skript. Klicken Sie auf „Weiter“.

Wählen Sie „Die Verbindung blockieren“.

Bei „Profil“ kreuzen Sie alle Profile an. Auf der letzten Seite geben Sie einen guten Namen für Ihre Regel ein. Wir werden den Namen in unserem Skript benötigen. Nun ist Ihre Regelkonfiguration abgeschlossen.

Jetzt das Skript. Dies ist der Code, der mit den bereits genannten Voraussetzungen arbeitet. Kopieren Sie den Text in eine Datei mit der Endung .ps1.

### Variables ###
# The name of the firewall rule in Windows Firewall
$firewallRuleName = "Block RDP Attackers"

# IPs that will not be blacklisted. i.e. your home IP if you are using Dyndns or any other static IP
$whiteList = @(
[System.Net.Dns]::GetHostAddresses("myhome.dyndns.org").IPAddressToString, #Example for DNS entry
"89.20.58.68" #Example for IP
)


### Script ###
Write-Host "Running at $(Get-Date)"
$regExIp = "\d\d?\d?.\d\d?\d?.\d\d?\d?.\d\d?\d?"
$regExIp6 = "((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?"

# Get the current Eventlogs with the 140 event
$currentAttackers = @(Get-Winevent Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational | Where-Object {$_.Id -eq 140} | Select Message -ExpandProperty Message)

# If there is no response, there are no attacks
if ($currentAttackers -eq $null) {
Write-Host "No current attackers"
return
}

# Get each attackermessage and filter the IP from it using the regex above
for ($i = 0; $i -lt $currentAttackers.Count; $i++) {
if ($currentAttackers[$i] -match $regExIp -or $currentAttackers[$i] -match $regExIp6){
$currentAttackers[$i] = $Matches[0]
} 
}

# Get the already known attackers from the firewall rule
$knownAttackers = (Get-NetFirewallRule -DisplayName $firewallRuleName | Get-NetFirewallAddressFilter).RemoteAddress
if ($knownAttackers -eq $null){
$knownAttackers = @()
}
$knownAttackers = $knownAttackers | Sort-Object -Unique

# Check each logged attacker and check if it is already known
foreach($newAttacker in $currentAttackers) {
if ($knownAttackers.Contains($newAttacker)) { #If it is known, don't do anything
continue
}
elseif ($whiteList -contains $newAttacker) { #If it is whitelisted, don't do anything
Write-Host "$newAttacker is dynamically whitelisted"
continue
}
else{ #otherwise it is a new attacker and add it to the blacklist
$knownAttackers += $newAttacker
Write-Host "Added $newAttacker"
}
}

# remove dublicates (should not be there, but anyway...)
$knownAttackers = $knownAttackers | Sort-Object -Unique
Write-Host "$($knownAttackers.Count) IPs on blacklist"

# Setting Firwall rules with all known and all new attackers
Set-NetFirewallRule -DisplayName $firewallRuleName -RemoteAddress $knownAttackers
Write-Host ""

Letzte Änderungen: (23.01.2021) IPv6 hinzugefügt und ein Problem behoben, wenn nur ein Event existiert. Dank an Joachim

Wenn Sie einen anderen Namen als „Block RDP Attackers“ für die Firewall-Regel haben, müssen Sie die Zeile „$firewallRuleName = „Block RDP Attackers““ in Ihren Regelnamen ändern.

Führen Sie das Skript „als Administrator“ aus. Es wird Ihr Ereignisprotokoll durchsuchen und alle IPs ermitteln, die in den Ereignissen mit der ID 140 im entsprechenden Protokoll erwähnt werden. Diese IPs werden zu der zuvor erstellten Regel hinzugefügt und blockieren diese IPs in Zukunft.

Ich habe eine geplante Aufgabe für dieses Skript, um es regelmäßig auszuführen. In einem Zeitraum von nur wenigen Stunden sind bereits etwa 600 IP-Adressen auf meiner Blockliste. Wenn Sie die geplante Aufgabe konfigurieren, achten Sie darauf, dass das Kontrollkästchen „mit höchsten Rechten ausführen“ aktiviert ist.

Übersetzt mit www.DeepL.com/Translator (kostenlose Version)