Der aktuelle Linux-Server muss neu aufgesetzt werden, weil entweder die Hardware zu alt ist, die Konfiguration neu aufgesetzt oder eine andere Linux-Distribution verwendet werden soll. Die Gründe sind zahlreich und unterschiedlich, aber immer wieder gilt die Anforderung, die vorhandenen Benutzer inklusive Passwort von dem alten auf den neuen Server zu migrieren.
In diesem Artikel wird gezeigt, wie man Linux User inklusive Passwort migriert. Zusätzlich bringen wir etwas Komfort in den Migrationsprozess, indem man mittels dialog die Benutzer bequem selektieren kann. Somit werden nur die ausgewählten Benutzer auf den neuen Server migriert.
Auf einem Linux System befinden sich alle User in der Datei /etc/passwd. Pro Zeile werden die unterschiedlichen Informationen mit einem ":" getrennt, welche Angaben zum Username, Shell usw. enthalten.
# nano /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
[...]
peter:x:1000:1000:peter,,,:/home/boss:/bin/bash
sshd:x:106:65534::/var/run/sshd:/usr/sbin/nologin
vboxadd:x:999:1::/var/run/vboxadd:/bin/false
Die dazugehörigen Passwörter findet man in der Datei /etc/shadow. Das Passwort ist natürlich verschlüsselt und nicht im Klartext zu sehen. Der Aufbau ist ähnlich zur /etc/passwd, nämlich mit ":" getrennt und es werden zusätzliche Infos wie Ablaufdatum dort hinterlegt.
nano /etc/shadow
root:$6$Zo8Hcgw6$2aZSh49...LwlfOtjce6Tv.:17281:0:99999:7:::
daemon:*:17281:0:99999:7:::
bin:*:17281:0:99999:7:::
sys:*:17281:0:99999:7:::
[...]
peter:$6$92pGq1ec$lAek1bUn...305apHq8TpthM63WqrN.:17281:0:99999:7:::
sshd:*:17512:0:99999:7:::
vboxadd:!:17594::::::
Die Migration ist also relativ einfach. Man muss lediglich die Einträge aus /etc/passwd und /etc/shadow auf den neuen Linux-Server kopieren. That's it.
Etwas aufwendiger und was in diesem Artikel nicht behandelt wird, ist die Migration der Gruppen. Die migrierten Benutzer werden auf dem neuen Linux-System keinen oder falschen Gruppen zugewiesen sein, da diese nicht vorhanden oder unter anderen IDs verfügbar sind.
Starten wir mit einem theoretischen Durchlauf, was das Skript können soll:
Starten wir nun mit der Praxis und dem Einlesen bzw. Prüfen der /etc/passwd und /etc/shadow. Man speichert die genannten Files des alten Servers in ein beliebiges Verzeichnis auf dem Zielserver (in diesem Beispiel unter /home/develop/linux-user-migration). Der folgende Part prüft nun, ob die Dateien vorhanden sind und durchläuft alle Einträge aus /etc/passwd.
# Variable für Verzeichnis, wo die Dateien liegen
CONFIG_WORKING_DIR=/home/develop/linux-user-migration
# Prüfe, ob die Quell-Dateien passwd und shadow vorhanden sind
if [ -z "${CONFIG_WORKING_DIR}/etc/passwd" ] || [ -z "${CONFIG_WORKING_DIR}/etc/shadow" ]; then
echo "Could not find user or password files (/etc/passwd or /etc/shadow)"
fi
#
# Jede Zeile aus /etc/passwd wird durchlaufen.
#
echo "read user and password"
userlist=""
n=1
while read -r pass ; do
# Extrahiere Benutzername
username=$(echo ${pass} | cut -d":" -f1)
# Generiere Liste für Dialog Anzeige
userlist="$userlist $username $n off"
n=$[n+1]
done < <(cat ${CONFIG_WORKING_DIR}/etc/passwd)
Das Ergebnis ist eine Liste $userlist, welche wir für die Dialog-Box verwenden:
#
# Dialog-Fenster erzeugen mit der zuvor erstellten Liste $userlist
#
choices=$(dialog --stdout --checklist 'Select users which should be migrated.' 0 0 10 $userlist)
Der Anwender kann nun alle gewünschten User selektieren oder den Vorgang auch abbrechen. Im Skript wird die Eingabe wie folgt verarbeitet:
#
# Grundgerüst: verarbeite Auswahl Dialogbox
#
if [ $? -eq 0 ]
then
for username in $choices
do
echo "tue was mit ${username}"
done
else
echo "cancel selected"
exit 1
fi
Hat der der Anwender ein oder mehrere Linux-User zur Migration selektiert, beginnen wir mit einigen einfachen Prüfungen, damit bei der Migration fehlerhafte Datensätze kopiert werden:
#
# Prüfe, ob User auf Zielsystem existiert:
# - grep: suche nach Eintrag beginnend mit username:
# - speichere in Variable $checkHostPasswd
# - wenn vorhanden, dann continue = skip
#
checkHostPasswd=$(cat /etc/passwd | grep -E "^${username}:(.*?)")
if [ "$checkHostPasswd" != "" ]; then
echo "User $username still exists on system. Skip."
continue
fi
#
# Prüfe, ob Passworteintrag in Quell-Datei /etc/shadow
#
checkBackupShadow=$(cat ${CONFIG_WORKING_DIR}/etc/shadow | grep -E "^${username}:(.*?)")
if [ "$checkBackupShadow" == "" ]; then
warn "No password found for $username. Skip."
continue
fi
Waren alle Prüfungen erfolgreich, werden die Zeilen aus den alten Dateien passwd und shadow auf das neue Systeme kopiert. Das ist quasi der eigentliche Migrationsprozess.
#
# Kopiere Zeilen auf Zielsystem in /etc/passwd und /etc/shadow
#
echo ${checkBackupPasswd} >> /etc/passwd
echo "... user created."
echo ${checkBackupShadow} >> /etc/shadow
echo "... password set."
Anschließend sollte es möglich sein, sich mit den migrierten Usern auf dem neuen System anzumelden.
CONFIG_WORKING_DIR=/home/develop/linux-user-migration
echo "read user and password"
if [ -z "${CONFIG_WORKING_DIR}/etc/passwd" ] || [ -z "${CONFIG_WORKING_DIR}/etc/shadow" ]; then
echo "Could not find user or password files (/etc/passwd or /etc/shadow)"
fi
userlist=""
n=1
while read -r pass ; do
username=$(echo ${pass} | cut -d":" -f1)
userlist="$userlist $username $n off"
n=$[n+1]
done < <(cat ${CONFIG_WORKING_DIR}/etc/passwd)
choices=$(dialog --stdout --checklist 'Select users which should be migrated' 0 0 10 $userlist)
clear
echo ""
if [ $? -eq 0 ]
then
for username in $choices
do
echo "migrating \033[0;36m$username\033[0m"
checkHostPasswd=$(cat /etc/passwd | grep -E "^${username}:(.*?)")
if [ "$checkHostPasswd" != "" ]; then
echo "User $username still exists on system. Skip."
continue
fi
checkBackupShadow=$(cat ${CONFIG_WORKING_DIR}/etc/shadow | grep -E "^${username}:(.*?)")
if [ "$checkBackupShadow" == "" ]; then
echo "No password found for $username. Skip."
continue
fi
echo ${checkBackupPasswd} >> /etc/passwd
echo "... user created."
echo ${checkBackupShadow} >> /etc/shadow
echo "... password set."
usermod -g www-data -G ftp,www-data,users,ssh ${username}
echo "...set groups."
done
else
echo cancel selected
exit 1
fi