Letzte Woche hab ich versucht einige Befehle über ein Webinterface auf einer Linux-Server auszuführen. Dabei wollte ich die Authentifizierung nicht über ein simples Passwort laufen lassen, sondern über ein Public/Private Key Pair. Ich werde hier nicht im Detail die Einrichtung eines Key Pairs vorstellen, da es viele und sehr ausführliche Anleitung für die Nutzung von ssh-keygen oder PuTTYgen und das Hinzufügen des Public-Keys in die ~/.ssh/authorized_keys gibt.
Zu Beginn hab ich mich mit den normalen PHP Funktionen auseinander gesetzt. In PHP wird hier erst Mal zwischen dem Verbindungsaufbau und der Authentifizierung unterschieden. Der Verbindungsaufbau wird mit ssh2_connect() initialisiert:
ssh2_connect ( string $host [, int $port = 22 [, array $methods [, array $callbacks ]]] )
Für die Authentifizierung stehen hier für die verschiedenen Möglichkeiten auch entsprechende Funktionen zur Verfügung: ssh2_auth_password(), ssh2_auth_hostbased_file(), ssh2_auth_agent(), …
Die für uns wichtige Methode ist hier ssh2_auth_pubkey_file(). Hier fällt auf das diese Funktion einen Private- und Public-Key benötigt und bei beiden Keys ein gültiger Pfad im Dateisystem benötigt wird. Der zweite Punkt ist für mich besonders Problematisch, da mein Key nicht zwingend als Datei vorhanden sein wird. Das für die Authentifizierung nun beide Keys benötigt werden, ist für mich komplett unverständlich, da dies das Prinzip der Key Pairs überflüssig macht.
ssh2_auth_pubkey_file ( resource $session , string $username , string $pubkeyfile , string $privkeyfile [, string $passphrase ] )
Auf der Suche nach einer Alternative bin ich auf die Bibliothek phpseclib gestoßen. Die API der Bibliothek bietet eine komfortable Möglichkeit über SSH mit einem Server zu kommunizieren. Beim Einlesen des Private-Keys haben wir hier absolute Freiheit woher wir Inhalt des Keys beziehen, da hier nur ein String benötigt wird.
$ssh = new Net_SSH2('www.domain.tld'); $key = new Crypt_RSA(); $key->loadKey(file_get_contents('privatekey')); if (!$ssh->login('username', $key)) { exit('Login Failed'); } echo $ssh->exec('pwd'); echo $ssh->exec('ls -la');
Für alle Symfony Nutzer kann ich hier auch das SkyDiabloPHPSecLibBundle empfehlen. Das Bundle schlüsselt die Abhängigkeit zu phpseclib auf und bringt auch einen Autoloader für die Bibliothek mit. Für die Installation muss die composer.json und app/appKernel.php erweitert werden:
{ "require": { ... "skydiablo/phpseclib-bundle": "dev-master" ... } }
$bundles = array( ... new SkyDiablo\PHPSecLibBundle\SkyDiabloPHPSecLibBundle(); ... );