Home Assistant ausgehende SSH-Verbindungen

Beim Betrieb des Home Assistant kommt man unweigerlich zu den Punkt, an dem man eine SSH-Verbindung vom Home Assistant zu einem externen Gerät aufbauen muss.

Als Beispiel sei das sichere Herunterfahren eines Linux-Servers oder einer WD My Cloud EX Ultra genannt.

Generell gibt es bei ausgehenden SSH-Verbindungen zwei Möglichkeiten zu Authentifizierung am Entfernten System:

Beide Möglichkeiten haben im Home Assistant Fallstricke. Hinterlegte SSH-Keys und Host-Keys im Standardverzeichnis gehen bei jedem Update des Home Assistant verloren und dem „ssh“ Befehl kann kein Passwort mitgegeben werden.

Hier zeige ich zwei Möglichkeiten auf wie es – dauerhaft – doch geht.

Voraussetzungen

Für diese Anleitung ist es notwendig per SSH auf den Home Assistant zugreifen und Dateien ablegen zu können. Bei Home Assistant OS bietet ich hierzu das „Advanced SSH & Web Terminal“ und das „Samba share“ Add-on an.

Ausgehende SSH-Verbindungen mit SSH-Keys

Normalerweise werden SSH-Key-Dateien in einem Verzeichnis namens „.ssh“ im Home-Verzeichnis eines Benutzers abgelegt. Da der Home Assistant als Benutzer „root“ ausgeführt wird wäre der Verzeichnispfad daher „/root/.ssh“.

Nun ist es so, dass der Home Assistant in einem Docker Container ausgeführt wird und das Home-Verzeichnis „root“ ebenfalls innerhalb des Containers existiert. Wird nun ein Update des Home Assistant durchgeführt wird der Docker Container verworfen und ein neuer gebaut. Dadurch werden eventuell abgelegte SSH-Key-Dateien ebenfalls verworfen. Die SSH-Key-Dateien müssen also in einem Verzeichnis abgelegt werden, welches ein Update übersteht. Hier bietet sich das „/config“ Verzeichnis an.

Wir legen also unter „/config“ das Verzeichnis „.ssh“ an:

mkdir /config/.ssh

In diesem Verzeichnis legen wir die SSH-Datei unseres Private Keys und eine leere Datei mit dem Namen „known_hosts“ ab.

Wichtig ist hier, dass die Zugriffsrechte korrekt gesetzt werden:

chmod 700 /config/.ssh
chmod 600 /config/.ssh/known_hosts
chmod 600 /config/.ssh/<Dateiname Private Key>

Normalerweise würde nun ein SSH-Aufruf um den Hostnamen des Remotesystems auszugeben wie folgt aussehen:

ssh <Benutzername>@<Server> <Befehl>

ssh tom@BrummelServer hostname

Da aber unsere SSH-Dateien nicht im Home-Verzeichnis liegen wird der Befehl scheitern.

Wir müssen daher dem SSH-Befehl mitteilen wo sich die Datei „known_hosts“ mit den bekannten Host-Keys und die Datei mit dem Private Keys befinden. Dies geschieht wie folgt:

ssh -o UserKnownHostsFile=<Pfad und Dateiname der known_hosts Datei> -i <Pfad und Dateiname des SSH-Private-Keys> <Benutzername>@<Server> <Befehl>

ssh -o UserKnownHostsFile=/config/.ssh/known_hosts -i /config/.ssh/id_ed25519 tom@BrummelServer hostname

Die Datei „known_hosts“ muss alle Host-Keys aller Zielserver enthalten. Entweder legt man eine bereits gefüllte Datei ab oder man baut zu jedem Zielserver manuell eine Verbindung auf und bestätigt den jeweiligen Host-Key.

ssh -o UserKnownHostsFile=<Pfad und Dateiname der known_hosts Datei> -i <Pfad und Dateiname des SSH-Private-Keys> <Benutzername>@<Server>

ssh -o UserKnownHostsFile=/config/.ssh/known_hosts -i /config/.ssh/id_ed25519 tom@BrummelServer

Da unsere „known_hosts“ im „/config“ Verzeichnis liegt, ist es egal ob die SSH-Befehle im Docker Container von Home Assistant oder des „Advanced SSH & Web Terminal“ ausgeführt werden. Das Verzeichnis ist dabei immer dasselbe.

Hinweis: Werden die SSH-Befehle in der „Shell Command“ Integration eingesetzt ist zu beachten, dass bei einer Änderung der YAML-Datei kein schneller Neustart ausreicht! Hier ist immer ein vollständiger Neustart erforderlich.

Ausgehende SSH-Verbindungen mit Passwort

Heikles Thema: Ausgehende SSH-Verbindungen die sich mit einem Passwort authentifizieren, sollten niemals wirklich NIEMALS durch Skripte aufgebaut werden! Das Problem: das Passwort wird im Klartext im Skript stehen. Jeder der das Skript einsehen kann kennt dann das Passwort.

So viel zur Theorie.

Praktisch gibt es jedoch noch immer genügend Geräte auf dem Mark, welche eine Authentifizierung über SSH-Key nicht zulassen. Möchte man nun eine Aktion automatisiert auf solchen Geräten durchführen, bleibt einem nur das Passwort im Skript zu hinterlegen.

Ein Beispiel sei hier meine WD My Cloud EX2 Ultra genannt. Mangels einer geeigneten Integration kann ich diese automatisiert nur über einen SSH-Befehl herunterfahren

Nun ist es so, dass man dem Befehl „ssh“ kein Passwort mitgeben kann. Um dieses Problem zu lösen existiert das Programm „sshpass“. Dieses kann einfach nachinstalliert werden. Es muss jedoch im Docker Container des Home Assistant verfügbar sein und hier stoßen wir wieder auf das Problem, dass bei einem Update das Programm wieder verschwindet.

Damit dieses nicht mehr passiert installieren wir das Paket zunächst im Docker Container des „Advanced SSH & Web Terminal“, kopieren es dann in ein Unterverzeichnis unter „/config“ und rufen es dann von dort aus auf. Die Installation im „Advanced SSH & Web Terminal“ kann dann wieder rückgängig gemacht werden.

Los geht’s:

Zuerst wird das „Advanced SSH & Web Terminal“ geöffnet. Darin Installieren wir „sshpass“:

apk add --update --no-cache sshpass

Danach legen wir in Unterverzeichnis im „/config“ Verzeichnis an, in dem wir „sshpass“ ablegen werden:

mkdir /config/user_cmds

Nun suchen wir nach dem Installationsort des „sshpass“. In der Regel wird dies „/usr/bin/sshpass“ sein:

$ which sshpass
/usr/bin/sshpass

Jetzt kann das Programm in das vorbereitete Verzeichnis kopiert werden:

cp -p /usr/bin/sshpass /config/user_cmds/

Optional kann nun „sshpass“ wieder deinstalliert werden. Dies ist nicht notwendig, da beim nächsten Update die Installation verschwindet.

apk del sshpass

Nun ist es möglich in einem Skript eine SSH-Verbindung mit Passwortauthentifizierung aufzubauen:

/config/user_cmds/sshpass -p '<Passwort>' ssh -o UserKnownHostsFile=<Pfad und Dateiname der known_hosts Datei> -i <Pfad und Dateiname des SSH-Private-Keys> <Benutzername>@<Server> <Befehl>

/config/user_cmds/sshpass -p '1234' ssh -o UserKnownHostsFile=/config/.ssh/known_hosts sshd@myCloud hostname