Dienstag, 7. Mai 2019

Windows von FHEM über ssh steuern

Windows OpenSSH Server installieren

Als ersten Schritt sollte man zunächst unabhängig von der Windows Version prüfen ob ein entsprechender Dienst schon läuft oder existiert:
Get-Service -Name *ssh*

Windows 10 + Server 2019

In den aktuellen Windows Versionen (ab dem Jahr 2019) ist der OpenSSH Server enthalten und kann einfach installiert werden.
Get-WindowsCapability -Online -Name OpenSSH.Server* | Add-WindowsCapability -Online
Get-Service -Name sshd | Set-Service -StartupType Automatic
Get-Service -Name sshd | Start-Service

Windows Server 2016, 2012 R2 und 2012

In früheren Windows Versionen kann der OpenSSH Server nur über ein extra download/Setup installiert werden.
Als Voraussetzung für die Installation muss die Ausführung von Powershellscripten erlaubt sein.
Set-Executionpolicy Remotesigned
Ich habe für die Installation ein komplettes Script auf GitHub  zur Verfügung gestellt.
Man kann es einfach herunterladen und starten.
Ergänzung 2021:  TLS1 kann nicht mehr verwendet werden, es kommt unter Umständen zur Fehlermeldung. Hier habe ich Abhilfe gefunden und eine zusätzliche Zeile eingebaut. Eventuell schafft ein .net Update Abhilfe.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]'Tls11,Tls12'
invoke-webrequest https://raw.githubusercontent.com/heinz-otto/Powershell/master/InstallLatestSshd64.ps1 -OutFile InstallLatestSshd64.ps1
.\InstallLatestSshd64.ps1
Das Script überprüft die Windows Server Version und installiert ein fehlendes
Windows Management Framework 5.1 (dann ist zwischendurch ein Reboot erforderlich). Es wird die aktuellste sshd Version heruntergeladen und die Anmeldung für die Administratoren Gruppe freigeschaltet.
Um bei dieser Installationsart anschließend die Programme wie ssh oder ssh-keygen einfach verwenden zu können, kann der Pfad erweitert werden. Hier die Powershell und die cmd Variante für die aktuelle Sitzung:
$Env:Path += "C:\Program Files\OpenSSH-Win64\;"
set PATH=C:\Program Files\OpenSSH-Win64\;%PATH%
Die Verwendung von Parametern in der Powershell kann fehlerhaft sein. Im Zweifel die CMD verwenden!
Das CMD Fenster unter Windows Server 2012 liefert für ssh nicht das richtige Terminal (conpty), eine interaktive Arbeit ist damit nicht wirklich möglich. Scripte können aber abgearbeitet werden.

Anmeldung am Windows OpenSSH Server

Man kann sich wie gewohnt von jedem System (Windows 10 Version 1803 hat den ssh Client aktiv) mit ssh user@host am SSH Server anmelden!
Der ssh Server akzeptiert nur den "Kurznamen". Windows kürzt den Anmeldenamen ein (z.B. bei einem Onlinekonto).
Man kann den Namen leicht in der Powershell Konsole ermitteln:
whoami

SSH Zugang mit Public Key einrichten

Achtung: Auch in Windows darf die Datei %USERPROFILE%\.ssh\authorized_keys nicht für jedermann zugreifbar sein. Nur DER Benutzer (Eigentümer), Administratoren und System darf Zugriff haben, sonst wird der Public Key abgelehnt!
Bitte den Hinweis am Ende des Artikels für die Gruppe der Administratoren beachten!
Bitte alle Schritte (Befehlszeilen) einzeln kopieren und ausführen!

Problem: Bei Windows als SSH Server versagt leider das Tool ssh-copy-id. Hier drei Szenarien für die Einrichtung des ssh Zuganges mit public key zu einem Windows Server.

Voraussetzung: Benutzer hat schon einen RSA Key. Wenn nicht muss er vorher erzeugt werden!
(ssh-keygen -f ~/.ssh/id_rsa -P "" -t rsa oder ssh-keygen -f %USERPROFILE%\.ssh/id_rsa -P "" -t rsa)

Linux Shell
ziel=user@host
pkey=$(cat ~/.ssh/id_rsa.pub)
ssh $ziel "findstr /c:\"$pkey\" .ssh\authorized_keys ||mkdir .ssh ||echo $pkey >>.ssh\authorized_keys"
Windows CMD
set ziel=user@host
set /p pkey=< %userprofile%\.ssh\id_rsa.pub
ssh %ziel% "findstr /c:""%pkey%"" .ssh\authorized_keys ||mkdir .ssh ||echo %pkey% >>.ssh\authorized_keys"
Windows Powershell
$ziel='user@host'
$pkey = $(type $env:userprofile\.ssh\id_rsa.pub)
ssh $ziel "findstr /c:`"`"$pkey`"`" .ssh\authorized_keys ||mkdir .ssh ||echo $pkey >>.ssh\authorized_keys"

Hinweis: Die Befehle nach ssh werden in der CMD von Windows abgearbeitet! Der Public Key wird direkt durch Variablen "Auflösung" mitgegeben. Der Trenner || ist eine bedingte Abarbeitung der folgenden Befehle. 

Ersteinrichtung
Alle Schritte in Kurzform für den Public Key Zugang für den User fhem zu einem Windows SSH-Remotesystem habe ich hier ausführlich gezeigt.

Nur mit Public Key
Man kann den Zugang sehr sicher machen und nur public key zulassen. Dazu muss man die Passwort Authentisierung abschalten indem in der Datei C:\ProgramData\ssh\sshd_config diese Zeile eingefügt wird:
PasswordAuthentication no
Hinweis: Die Config Datei enthält alle Optionen mit ihren Standardwerten als Kommentarzeilen. Jede Änderung in der Datei muss durch einen restart des sshd Services aktiviert werden.

Powershellscript von FHEM aus starten

Bei der Ausführung von Befehlen vom Linux System aus muss man beachten, dass der Backslash verdoppelt (geschützt) werden muss. Ansonsten kann man wie gewohnt Befehle absetzen und sogar Powershell Scripts mit Argumenten ausführen.
"ssh user\@host 'powershell C:\\Tools\\Scripts\\TestPsFhem.ps1' 'http://host:8083' 'DummyName'"
Oder auch mittels powershell cmdlets direkt starten
"ssh user\@host powershell -command stop-vm vmName"
{qx 'ssh user@host powershell -command get-service' }

Innerhalb von Powershell kann man auch mit einem Powershellscript über HTTP auf FHEM zugreifen.
Powershellbeispiel:
Fragt einen Dienst ab und schreibt Status und Displayname nach FHEM zurück in einen Dummy
<#
.SYNOPSIS
    This Script is for testing the FHEM Client for HTTP
.DESCRIPTION
    Give FHEM Server url and Dummy 
.NOTES
    Will give a State and Displayname of Service back
#>
#region Params
param(
    [Parameter(Mandatory=$true,Position=0,HelpMessage="-first 'Portnumber or URL'")]
    [String]$first,
    [Parameter(ValueFromPipeline=$true,ValueFromRemainingArguments=$true)]
    [String[]]$sec
)
#endregion 
$serv="wuauserv"

if (!(Test-Path .\fhemcl.ps1)) {
    Write-Output "fhemcl.ps1 fehlt"
    invoke-webrequest "https://raw.githubusercontent.com/heinz-otto/fhemcl/master/fhemcl.ps1" -OutFile "fhemcl.ps1"
}

$state=get-service $serv
.\fhemcl.ps1 $first "set $sec $($state.status)"
.\fhemcl.ps1 $first "setreading $sec Displayname $($state.DisplayName)"


Eigenheiten für Administratoren in einigen Windows Versionen?

Symptom:
Ein Mitglied der Gruppe administrators kann offenbar keine Anmeldung mit Public Key machen. Obwohl alles eingerichtet ist, wird das Passwort abgefragt. 
Das trifft zu für Windows Server Version 2012 und Windows 10 ab Version 2004.
Bei Windows Server 2012 R2, 2016 und 2019 war es bisher nicht so.

Neue Erkenntnis: Ist eventuell so gewollt und teilweise fehlerhaft implementiert: Link.

Eine Lösung:
Ich habe mir die Sache näher angeschaut und ich habe bei einigen Installationen Unterschiede in der aktiven sshd Konfigurationsdatei C:\ProgramData\ssh\sshd_config gefunden.
Kommentiert man dort am Ende der Datei den folgenden Eintrag mit einem # aus,
Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
funktioniert auch die Anmeldung für Mitglieder der Administratoren. Der Dienst ssd (OpenSSH SSH Server) muss dafür neu gestartet werden!
Hintergrund:
Es gibt zwei Erklärungen für diese Verhalten
  1. Es werden unterschiedliche Inhalte der Datei ausgeliefert - mit und ohne den beiden oben gezeigten Zeilen am Dateiende. 
  2. Der sshd vergleicht dabei die Klarnamen der Gruppenbezeichnung. Ich installiere gern für den Server EN Systeme und gebe Ihnen eine DE mui.
    • Ein 2012 EN System mit DE mui hat administrators - > match!
    • Alle späteren EN Systeme (2012 R2, 2016) mit DE mui haben Administratoren -> kein match!
Der folgende Code kommentiert die verantwortlichen Zeilen in der config aus. In meinem Setupscript für die älteren Serversysteme ist dieser Code bereits enthalten.
# Patch sshd config to allow administrators Group public Key logon
$Quelle="${Env:ProgramData}\ssh\sshd_config"
write-output "patch the sshd config on $Quelle"
Stop-Service -Name sshd
$Inhalt = Get-Content $Quelle
#search 2 lines contains administrators and insert commment sign
$Inhalt|foreach {if ($_ -match "administrators") {$Inhalt[$_.readcount-1]=$_.Insert(0,"#")}}
set-Content $Quelle $Inhalt
Start-Service -Name sshd
Alternative Lösung:
Die Schlüssel der entsprechenden User wirklich in die Datei c:\ProgramData\ssh\administrators_authorized_keys eintragen. Wie hier beschrieben, müssen dazu noch weitere Änderungen (Rechte an Datei und Inhalt C:\ProgramData\ssh\sshd_config) durchgeführt werden.

Den OpenSSH Server wieder loswerden

Stop-Service -Name sshd 
pushd
cd "${Env:ProgramFiles}\OpenSSH-Win64\" 
.\uninstall-sshd.ps1
popd
rm -recurse "${Env:ProgramFiles}\OpenSSH-Win64"
rm -recurse "${Env:ProgramData}\ssh"
Remove-NetFirewallRule -Name sshd

Zum Nachlesen

Ziel des Artikels war es, kurz und knapp alle Schritte zusammenzufassen.
Ausführlicher kann man in folgenden Artikeln nachlesen:
https://heinz-otto.blogspot.com/2018/06/windows-hat-jetzt-ssh.html
https://heinz-otto.blogspot.com/2017/01/per-ssh-remote-befehle-direkt-ausfuhren.html
https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_server_configuration



Keine Kommentare:

Kommentar veröffentlichen