original in en Erdal Mutlu
en to de Hermann-Josef Beckers
Erdal ist einer der t�rkischen LF-Editoren. Derzeit arbeitet er als System-Administrator f�r Linotype Library. Da er seit seiner Universit�tszeit ein gro�er Linux-Fan ist, liebt er es, in dieser Umgebung zu arbeiten und zu entwickeln.
Um diesem Artikel folgen zu k�nnen, ben�tigen Sie grundlegende Kenntnisse �ber Shell-Programmierung. Wegen weiterer Informationen zur Shell-Programmierung schauen Sie sich den Artikel Shell Programmierung von Katja und Guido Socher an. Sie ben�tigen auch Wissen �ber die ssh-Programme wie ssh-keygen, ssh-add, ssh, scp oder sftp. Es gibt eine freie Implementation des SSH-Protokolls unter Linux OpenSSH, die alle diese Programme enth�lt. Au�erdem gibt es auch Handbuch-Seiten dazu.
scp /path/to/the/file/file1 user@remote_host:/remotedir/newfile
In diesem Beispiel wird die Datei file1 aus dem lokalen Ordner auf den entfernten Rechner (dies kann die IP-Adresse oder der Rechnername sein) in das Verzeichnis /remotedir unter dem Namen newfile kopiert. Sie werden aufgefordert, sich als 'user' zu authentifizieren. Wenn die Authentifizierung erfolgreich ist und der entfernte Benutzer die entsprechenden Rechte besitzt, wird die Datei kopiert. Man kann den Ziel-Dateinamen auslassen, dann wird die Datei mit dem gleichen Namen kopiert. Kurz gesagt, man kann Dateien w�hrend des Kopierens umbennen.scp user@remote_host:/remotedir/file /path/to/local/folder/newfile
Der scp-Befehl hat noch eine sehr nette Eigenschaft: Sie k�nnen Verzeichnisse mit der '-r'-Option rekursiv kopieren.scp -r user@remote_host:/remotedir .
Der obige Befehl kopiert das Verzeichnis 'remotedir' und alle darunterliegenden Verzeichnisse und Dateien vom entfernten Rechner in das aktuelle Verzeichnis mit dem gleichen Namen.Hinweis: Dabei wird angenommen, dass Sie auf dem entfernten Rechner den sshd-D�mon gestartet haben.
ssh [email protected] df -H
Die Syntax entspricht sehr dem remote-login-Befehl. Der einzige Unterschied ist der Teil nach dem Rechnernamen. Der Befehl (in diesem Beispiel 'df -H') wird zur Ausf�hrung an den entfernten Rechner �bergeben. Die Ausgabe des Befehls wird auf Ihrem Terminal angezeigt.ssh-keygen -b 1024 -t dsa
Sie werden nach dem Namen Ihres privaten Schl�ssels gefragt. Normalerweise ist der Name des �ffentlichen Schl�ssels gleich dem privaten Schl�ssel, jedoch um '.pub' erg�nzt. '-b 1024' bezeichnet hier die Anzahl der Bits in dem zu erstellenden Schl�ssel. Wenn Sie diesen Wert nicht spezifizieren, wird ein Fehlwert eingesetzt. '-t dsa' dient zur Angabe des Schl�sseltyps. Die m�glichen Werte sind 'rsa1' f�r Protokollversion 1 und 'rsa' oder 'dsa' f�r Protokollversion 2. Ich empfehle, Protokollversion 2 zu benutzen. Aber wenn Sie �ltere Server haben, die nur Version 1 unterst�tzen, m�ssen Sie '-t rsa1' angeben und ein weiteres Schl�sselpaar erzeugen. Sie k�nnen ssh dazu zwingen, Protokollversion 1 oder Protokollversion 2 zu nutzen, indem Sie entweder '-1' oder '-2' angeben.Um Ihren Schl�ssel zu nutzen, sollten Sie Ihren �ffentlichen Schl�ssel auf dem entfernten Rechner installieren. Der Inhalt der Datei mit dem �ffentlichen Schl�ssel sollte kopiert oder angeh�ngt werden auf die Dateien $HOME/.ssh/authorized_keys oder $HOME/.ssh/authorized_keys2. Seien Sie vorsichtig und mischen Sie keine Schl�ssel f�r verschiedene Protokollversionen. F�r Protokollversion 1 wird authorized_keys und f�r Protokollversion 2 authorized_keys2 genutzt. Wenn Sie Ihren �ffentlichen Schl�ssel korrekt installiert haben, werden Sie bei der n�chsten Verbindung zu diesem Computer zun�chst nach Ihrer Passphrase gefragt und, wenn dies fehlschl�gt, nach dem Passwort der entfernten Benutzerin. Sie k�nnen die Verbindungen zu Ihren Systemen auf Authentifizierung mit �ffentlichen Schl�sseln beschr�nken, indem Sie die sshd-Konfigurationsdatei editieren. Der Dateiname ist /etc/ssh/sshd_config und der entsprechende Parameter ist 'PasswordAuthentification'. �ndern Sie diesen Parameterwert auf no (PasswordAuthentification no) und starten Sie sshd neu.
Bis zu diesem Punkt ist alles okay. Wir haben einen sicheren Weg zum Kopieren und Ausf�hren von Befehlen auf entfernten Systemen. Aber zum Automatisieren einiger Jobs sollten wir keine Passw�rter oder Passphrasen eingeben m�ssen. Sonst k�nnen wir nichts automatisieren. Eine L�sung k�nnte sein, die erforderlichen Angaben in jedem Skript einzutragen, was auf keinen Fall eine gute Idee ist. Der bessere Weg ist es, den Schl�sselagenten zur Behandlung unserer Passphrasen zu nutzen. Ssh-agent ist ein Programm, um f�r Authentifizierung durch �ffentliche Schl�ssel benutzte private Schl�ssel aufzunehmen. Sie sollten einen Schl�sselagenten starten:
ssh-agent $BASH
und ihm Ihre privaten Schl�ssel hinzuf�gen mittelsssh-add .ssh/id_dsa
oderssh-add .ssh/identity
Id_dsa ist die DSA-Datei mit privaten Schl�sseln und identity die RSA1-Datei mit privaten Schl�sseln. Dies sind die Standard-Dateinamen, die w�hrend der Schl�ssel-Erstellung mittels ssh-keygen verwandt werden. Nat�rlich werden Sie nach Ihrer Passphrase gefragt, bevor ssh-add Ihren Schl�ssel dem ssh-agent hinzuf�gt. Sie k�nnen mit dem folgenden Befehl auflisten, welche Schl�ssel hinzugef�gt wurden:ssh-add -l
Wenn Sie sich nun mit einem entfernten Rechner verbinden, der Ihren Schl�ssel in der autorisierten Datei enth�lt, werden Sie verbunden, ohne irgendetwas eingeben zu m�ssen! Der ssh-agent k�mmert sich um den Authentifizierungsprozess.
Wenn Sie ssh-agent wie oben beschrieben nutzen, k�nnen Sie es nur in dem Terminal benutzen, indem es gestartet wurde. Wenn Sie ssh-agent von jedem Terminal nutzen m�chten, das Sie �ffnen, m�ssen Sie etwas mehr tun. Ich habe das folgende kleine Skript zum Starten des Agenten geschrieben:
#!/bin/sh # # Erdal mutlu # # Starting an ssh-agent for batch jobs usage. agent_info_file=~/.ssh/agent_info if [ -f $agent_info_file ]; then echo "Agent info file : $agent_info_file exists." echo "make sure that no ssh-agent is running and then delete this file." exit 1 fi ssh-agent | head -2 > $agent_info_file chmod 600 $agent_info_file exit 0
Das Skript testet auf das Vorhandensein einer Datei namens agent_info im Start-Verzeichnis der Benutzerin, wo sich normalerweise ssh-bezogene Dateien finden. In unserem Fall ist dies das Verzeichnis '.ssh'. Wenn die Datei existiert, wird der Benutzer wegen des Vorhandenseins der Datei gewarnt und er erh�lt eine kleine Nachricht dazu, was getan werden kann. Wenn ssh-agent nicht schon l�uft, muss die Datei gel�scht werden und das Skript erneut gestartet werden. Das Skript startet ssh-agent und speichert die zwei ersten Zeilen der Ausgabe in die Datei agent_info. Diese Information wird von den anderen ssh-Programmen benutzt. Die n�chste Zeile �ndert den Modus der Datei, so dass nur die Eigent�merin der Datei diese lesen und beschreiben kann.
Wenn Ihr Agent l�uft, k�nnen Sie ihm Ihre Schl�ssel hinzuf�gen. Vorher m�ssen Sie jedoch die agent_info-Datei in Ihre aktuelle Umgebung einf�gen (sourcen), damit die ssh-Programme wissen, wo sich Ihr Agent befindet:
source ~/.ssh/agent_info or . ~/.ssh/agent_info
Und f�gen Sie dann Ihre Schl�ssel mittels ssh-add hinzu. Sie k�nnen die folgenden Zeilen Ihrer .bashrc-Datei hinzuf�gen, so dass bei jeder neuen Terminal-Sitzung die Datei agent_info eingelesen wird:
if [ -f .ssh/agent_info ]; then . .ssh/agent_info fi
WARNUNG: Sie m�ssen den Rechner sichern, von dem aus Sie ssh-agent und das hier beschriebene automatisierte Skript nutzen. Wenn ansonsten jemand Zugang auf Ihr Konto hat, kann diese Person auf alle Server zugreifen, die Sie mit Ihren ssh-Schl�sseln nutzen. Alles hat seinen Preis!
Nun ist es an der Zeit zu erkl�ren, wie wir einige Jobs eines System-Administrators automatisieren werden. Wir wollen eine Anzahl von Befehlen f�r eine gegebene Liste von Rechnern ausf�hren und einige Dateien von/zu diesen Rechnern abrufen/�bertragen. Das sind h�ufige Aufgaben einer Systemadministratorin. Hier ist das Skript:
#!/bin/sh # Installing anything using Secure SHELL and SSH agent # Erdal MUTLU # 11.03.2001 ################################################################## # Functions # ################################################################## ### Copy files between hosts copy_files() { if [ $files_file != "files_empty.txt" ];then cat $files_file | grep -v "#" | while read -r line do direction=`echo ${line} | cut -d " " -f 1` file1=`echo ${line} | cut -d " " -f 2` file2=`echo ${line} | cut -d " " -f 3` case ${direction} in "l2r") : ### From localhost to remote host echo "$file1 --> ${host}:${file2}" scp $file1 root@${host}:${file2} ;; "r2l") : ### From remote host to localhost echo "${host}:${file2} --> localhost:${file2}" scp root@${host}:${file1} ${file2} ;; *) echo "Unknown direction of copy : ${direction}" echo "Must be either local or remote." ;; esac done fi } ### Execute commands on remote hosts execute_commands() { if [ $commands_file != "commands_empty.txt" ];then cat $commands_file | grep -v "#" | while read -r line do command_str="${line}" echo "Executing $command_str ..." ssh -x -a root@${host} ${command_str} & wait $! echo "Execute $command_str OK." done fi } ### Wrapper function to execute_commands and copy_files functions doit() { cat $host_file | grep -v "#" | while read -r host do echo "host=$host processing..." case "${mode}" in "1") copy_files execute_commands ;; "2") execute_commands copy_files ;; *) echo "$0 : Unknown mode : ${mode}" ;; esac echo "host=$host ok." echo "------------------------------------------------------------------" done } ################################################################## ### Program starts here ################################################################## if [ $# -ne 4 ]; then echo "Usage : $0 mode host_file files_file commands_file" echo "" echo "mode is 1 or 2 " echo " 1 : first copy files and then execute commands." echo " 2 : first execute commands and then copy files." echo "If the name of files.txt is files_empty.txt then it is not processed." echo "If the name of commands.txt is commands_empty.txt then it is echo "not processed." exit fi mode=$1 host_file=$2 files_file=$3 commands_file=$4 agent_info_file=~/.ssh/agent_info if [ -f $agent_info_file ]; then . $agent_info_file fi if [ ! -f $host_file ]; then echo "Hosts file : $host_file does not exist!" exit 1 fi if [ $files_file != "files_empty.txt" -a ! -f $files_file ]; then echo "Files file : $files_file does not exist!" exit 1 fi if [ $commands_file != "commands_empty.txt" -a ! -f $commands_file ]; then echo "Commands file : $commands_file does not exist!" exit 1 fi #### Do everything there doit
Wir speichern dieses Skript als aiinstall.sh (automatisierte Installation) und starten es ohne Parameter. Wir erhalten die folgende Nachricht:
./ainstall.sh
Usage : ./ainstall.sh mode host_file files_file commands_file mode is 1 or 2 1 : first copy files and then execute commands. 2 : first execute commands and then copy files. If the name of files.txt is files_empty.txt then it is not processed. If the name of commands.txt is commands_empty.txt then it is not processed. |
Wie die Meldung besagt: Wenn Sie keine Befehle ausf�hren wollen, geben Sie commands_empty.txt als Argument commands_file an und wenn Sie keine Dateien �bertragen wollen, dann benutzen Sie files_empty.txt als Ersatz f�r das Argument files_file. Manchmal m�ssen Sie nur einige Befehle ausf�hren, ein anderes Mal nur Dateien �bertragen.
Bevor wir das Skript Zeile f�r Zeile erkl�ren, will ich eine Beispiel-Anwendung geben: Nehmen Sie an, dass Sie einen sekund�ren DNS-Server zu Ihrem Netzwerk hinzugef�gt haben und Sie diesen zur /etc/resolv.conf-Datei hinzuf�gen m�ssen. Der Einfachheit halber nehmen wir an, dass alle Ihre Rechner die gleiche resolv.conf-Datei verwenden. Das einzige, was Sie also tun m�ssen, ist, die neue resolv.conf-Datei auf alle Rechner zu kopieren.
Zuerst brauchen Sie eine Liste Ihrer Rechner. Wir schreiben alle Rechner in eine Datei namens hosts.txt. Das Format dieser Datei ist so, dass jede Zeile nur einen Hostnamen oder eine IP-Adresse enth�lt. Hier ist ein Beispiel:
########################################################################## #### Every line contains one hostname or IP address of a host. Lines that #### begin with or contain # character are ignored. ########################################################################## helvetica.fonts.de optima.fonts.de zaphino vectora #10.10.10.162 10.10.10.106 193.103.125.43 10.53.103.120 |
Wie Sie aus dem Beispiel sehen k�nnen, k�nnen Sie voll qualifizierte Hostnamen oder nur den Rechnernamen eingeben. Dann ben�tigen Sie eine Datei, in der Sie die zu �bertragenden Dateien angeben. Es gibt zwei m�gliche Transfer-Typen:
Die zu �bertragenden Dateien werden in einer weiteren Datei aufgelistet. Diese speichern wir als files_file.txt. Das Format der files_file.txt-Datei ist wie folgt: Jede Zeile enth�lt Informationen zum Kopieren jeweils einer Datei. Es gibt zwei m�gliche Kopierrichtungen: l2r (lokal to remote) und r2l (remote to lokal). L2r ist der Fall, wenn eine Datei vom lokalen Rechner zu einem entfernten Rechner kopiert wird. R2l bedeutet das Kopieren einer Datei vom entfernten Rechner zum lokalen Rechner. Felder werden durch Leerzeichen oder Tabs getrennt. Die erste Datei wird entsprechend dem Richtungsparameter zur zweiten kopiert. Der Name der Datei auf dem entfernten Rechners sollte den vollst�ndigen Pfad enthalten, da sie sonst in das Startverzeichnis des Benutzers root kopiert wird. Hier ist unsere Datei files_file.txt:
############################################################################ # The structure of this file is : # - The meaning of the fileds are : is l2r (localhost to remote) and r2l # (remote computer to local). # r2l file1 file2 # means copy file1 from remote (hosts specified in the # hosts.txt file) computer to localhost as file2. # l2r file1 file2 # means copy file1 from localhost to # remote (hosts specified in the hosts.txt file) computer as file2 # file1 and file2 are files on the corrsponding hosts. # # Note: the order of using local and remote specifies the direction # of the copy process. ############################################################################ l2r resolv.conf /etc/resolv.conf |
Wie Sie sehen, habe ich bereits eine Beschreibung der Dateistruktur eingef�gt. Normalerweise mache ich das f�r jede files_file-Datei, die ich benutze. Es ist eine einfache, aber gute L�sung f�r die Dokumentation. In unserem Beispiel wollen wir die resolv.conf-Datei als /etc/resolv.conf auf entfernte Rechner kopieren. Zu Demonstrationszwecken habe ich nach dem Kopiervorgang einige Befehle hinzugef�gt, um Eigent�mer und Berechtigungen der Datei zu �ndern und deren Inhalt anzuzeigen. Auszuf�hrende Befehle werden in einer separaten Datei eingetragen. Wir nennen unsere Befehlsdatei commands_file.txt. Hier ist ihr Inhalt:
########################################################################### # The structure of this file is : Every line contains a command to be # executed. Every command is treated seperately. ########################################################################### chown root.root /etc/resolv.conf chmod 644 /etc/resolv.conf cat /etc/resolv.conf |
Die Befehlsdatei enth�lt Befehle, die auf jedem der in der hosts.txt-Datei aufgef�hrten Rechner ausgef�hrt werden. Befehle werden in einer sequentiellen Reihenfolge abgearbeitet, d. h. chown ist der erste ausgef�hrte Befehl und danach kommt der n�chste.
Okay, nun haben wir alle Dateien, die wir f�r dieses einfache Beispiel ben�tigen. Das einzige, was noch spezifiert werden muss, ist die 'mode'-Option, die angibt, welche der beiden Dateien commands_file.txt oder files_file.txt zuerst verarbeitet werden muss. Man kann die in der files_file-Datei aufgef�hrten Dateien kopieren und dann alle Befehle auf den Zielrechnern ausf�hren, das ist Modus 1. Und das Gegenteil, Ausf�hren von Programmen und danach Datei�bertragung, entspricht 'mode=2'. Nun k�nnen Sie das Skript mit den ben�tigten Argumenten wie folgt ausf�hren:
./ainstall.sh 1 hosts.txt files_file.txt commands_file.txt
Ein kleiner Tip: Normalerweise benutze ich f�r files.txt den Prefix files_ und dann einen kurzen beschreibenden Namen, wie files_resolv.conf.txt. Die gleiche Technik benutze ich f�r hosts.txt und commands.txt.
Nun ist es an der Zeit, das Skript selbst etwas zu erl�utern. Das Programm �berpr�ft zun�chst die Anzahl der Argumente und wenn diese nicht 4 ist, erscheint der Benutzungshinweis. Wenn die Argumentanzahl richtig ist, werden die Argumente entsprechenden Variablen zugewiesen. Als n�chstes wird '~/.ssh/agent_info' eingelesen, wenn diese existiert. Diese Datei enth�lt Informationen �ber Ihren aktiven ssh-Agenten. Wenn Sie keinen Agenten nutzen, m�ssen Sie Passw�rter oder Passphrasen manuell eingeben, d. h. aber keine Automation:). Danach wird jede Parameterdatei (Rechner, Dateien und Befehle) auf Vorhandensein getestet. Es gibt auch einen speziellen Test f�r files_empty.txt und commands_empty.txt. Wenn Sie einen dieser Namen angeben, besteht kein Bedarf, auf dessen Vorhandensein zu testen. Diesen Teil des Skriptes habe ich w�hrend der Arbeit an diesem Artikel ge�ndert. Vorher war es nur:
if [ -f $host_file -a -f $files_file -a -f $commands_file ]; then echo "$host_file $files_file $commands_file" doit else echo "$host_file or $files_file or $commands_file does not exist" exit fi
In diesem Fall musste ich Dateien mit den Namen files_empty.txt und commands_empty.txt haben. Das war aber �berhaupt kein Problem, da ich nur in einem Verzeichnis gearbeitet habe.
Am Ende kommt der Aufruf der Funktion 'doit'. Alles wird in dieser Funktion gesteuert. Diese Funktion enth�lt eine aus 'cat' und 'while' bestehende Schleife, die f�r jeden in der $hosts_file-Datei aufgef�hrten Rechner copy_files und execute_commands entsprechend der Modus-Variablen aufruft. So wird f�r jeden Rechner der Auftrag ausgef�hrt. 'host' enth�lt den aktuellen Rechnernamen oder die IP-Adresse.
Wir sollten uns nun die Funktion copy_files ansehen. Diese Funktion testet zuerst, ob der Wert von 'files_file' gleich 'files_empty.txt' ist oder nicht. Bei Gleichheit wird nichts getan. Wenn nicht, dann enthalten die Variablen 'direction', 'file1' und 'file2' f�r jede Zeile aus '$files_file' die Kopierrichtung und den Namen der ersten bzw. zweiten Datei. Entsprechend der Kopierrichtung wird der Kopiervorgang mittels ssh durchgef�hrt.
Zum Schluss sollten wir uns anschauen, was in der Funktion execute_commands passiert. Die Funktion testet, ob der Wert von 'commands_file' gleich 'commands_empty' ist oder nicht. Bei Gleichheit geschieht wieder nichts. Wenn nicht, dann wird jeder Befehl aus der '$commands_file'-Datei auf den entfernten Rechnern mittels ssh im Hintergrund ausgef�hrt. Nach der Ausf�hrung des ssh-Befehls wird wait mit dem Parameter '$!' aufgerufen. Dieser Befehl stellt sicher, das jeder Befehl nach dem anderen ausgef�hrt wird. '$!' expandiert zur Prozess-ID des zuletzt ausgef�hrten Hintergrundbefehles.
Das wars. Einfach, nicht wahr?
Hier ist eine erweiterte Anwendung des Skriptes. Sinn ist es, eine Sicherung der Konfigurationsdateien Ihrer Rechner oder Server vorzunehmen. F�r diesen Zweck habe ich ein kleines Skript geschrieben, das aiinstall. sh benutzt:
#!/bin/sh server_dir=${HOME}/erdal/sh/ServerBackups if [ ! -d $server_dir ]; then echo "Directory : $server_dir does not exists." exit 1 fi cd $server_dir servers=ll_servers.txt prog=${HOME}/erdal/sh/einstall_sa.sh cat $servers | grep -v "#" | while read -r host do echo $host > host.txt $prog 1 host.txt files_empty.txt servers/${host}/commands_make_backup.txt $prog 1 host.txt files_getbackup.txt commands_empty.txt mv -f backup.tgz servers/${host}/backup/`date +%Y%m%d`.tgz rm -f host.txt done exit 0
Sie m�ssen ein Verzeichnis namens servers einrichten. Unter diesem Verzeichnis muss es zwei Dateien geben: files_getbackup.txt und ll_servers.txt. Hier ist 'files_getbackup.txt':
r2l /root/backup.tgz backup.tgz
'll_servers.txt' enth�lt die Namen oder IP-Adressen der zu sichernden Rechner. Jeder in der Datei 'll_servers.txt' enthaltene Rechner muss ein Verzeichnis mit dem gleichen Namen haben und unter diesem Verzeichnis muss eine Datei namens commands_make_backups.txt vorhanden sein, die einen Befehl enth�lt, um aus den Konfigurationsdateien auf dem Rechner ein /root/backup.tgz-Archiv zu erstellen. Alle Sicherungen dieses Rechners werden unter diesem Verzeichnis gespeichert. Wenn ll_servers.txt folgenden Inhalt hat:
fileserver dbserver 10.10.10.1 appserver |
dann muss die Verzeichnis-Struktur Ihres 'servers'-Verzeichnisses wie folgt aussehen:
servers |-- files_getbackup.txt |-- ll_servers.txt |-- make_server_backups.sh |-- 10.10.10.1 | |-- backup | `-- commands_make_backup.txt |-- appserver | |-- backup | `-- commands_make_backup.txt |-- dbserver | |-- backup | `-- commands_make_backup.txt |-- fileserver |-- backup `-- commands_make_backup.txt |
Und hier sind einige Beispiele f�r die Datei commands_make_backups.txt:
tar cfz /root/backup.tgz /etc/samba /etc/atalk /etc/named.conf /var/named/zones
Die obige commands_make_backup.txt wird zur Sicherung von samba-, atalk- und Nameserver-Konfigurationen und Zonendateien benutzt.
tar cfz /root/backup.tgz /etc/httpd /usr/local/apache
Diese commands_make_backup.txt wird zum Sichern einer Apache-Serverkonfiguration und der Konfigurationsdateien genutzt.
tar cfz /root/backup.tgz /etc/squid /etc/named.conf
Die obige commands_make_backup.txt wird zur Sicherung der Squid-Proxy-Serverkonfiguration und der Konfiguration von sekund�ren DNS-Servern benutzt.
Unter Benutzung des obigen Skriptes und dem Erstellen entsprechender commands_make_backup.txt-Dateien gem�� Ihren Bed�rfnissen k�nnen Sie Sicherungen Ihrer Serverkonfigurationen vornehmen.