SSH Keys sinnvoll unter Windows/Git Bash nutzen


ComFreek

Mod | @comfreek
Moderator
Hallo Forumsgemeinde,

nachdem ich aktuell wieder damit konfrontiert bin und ich schon in der Vergangenheit nie eine akzeptable Lösung gefunden habe, wende ich mich mal hier hin.

Problem: Ich möchte ein SVN Repository mit Autorisierung per einem verschlüsselten SSH Key unter Windows nutzen.

Ich habe Git, insbesondere Git Bash und SVN installiert. Mit ssh-keygen habe ich in der Git Bash einen verschlüsselten SSH-Key erstellt.
Damit SVN den Key findet, muss ich jedes Mal, wenn ich die Git Bash öffne, lästigerweise "ssh-add [path to key]" eingeben und daraufhin das Passwort dafür. Gibt es einen Weg, den Key automatisch im SSH Agent registriert zu haben, sodass das PW in einer Session nur dann abgefragt wird, wenn der Schlüssel das erste Mal benutzt wird?
Die bisher gelesenen Suchergebnisse schlagen meist eine der folgenden Optionen vor:
  • "ssh-add" in die .bashrc aufzunehmen.
    Dann wird jedoch bei jedem Start der Git Bash das PW abgefragt. Nicht bei jedem Start möchte ich auch beim betreffenden SVN Repository Änderungen vornehmen.
  • "ssh-add -K" mit der -K Option. Dies ist nur unter macOS verfügbar.

Danke im Voraus ;)
 

Bratkartoffel

gebratene Kartoffel
Premium-User
Hi,

soweit ich weiss kann zumindest git mit dem putty pageant kommunizieren.
Persönlich bevorzuge ich aber Keepass mit KeeAgent als Plugin. Somit steht der Key nicht ungeschützt irgendwo rum, sondern wird durch den ohnehin immer geöffneten Keepass zur Verfügung gestellt.

Habe bisher allerdings nur mit git gearbeitet, aber ich denke dass svn das auch kann.

Grüsse,
BK
 

ComFreek

Mod | @comfreek
Moderator
KeeAgent klingt perfekt! Ich nutze bereits Keepass und habe einige Private Keys auch drin rumliegen.
Und dann gab es noch ein KeeAgent Chocolatey Package, wow :)

Meine C:\Users\ComFreek\.bashrc der Git Bash:
Code:
SSH_ENV=$HOME/.ssh/environment
SSH_AUTH_SOCK="/d/Documents/keepass-keeagent-msys-socket"
(Den Pfad mit D:\ beginnen zu lassen - so wie in der KeeAgent Doku, hat bei mir übrigens nicht funktioniert. Der file-Befehl unten hat die Datei dann gar nicht erst gefunden.)

In Keepass unter Options, Tab KeeAgent ist derselbe Pfad auch in "Create msysGit compatible socket file" eingetragen. Außerdem läuft KeeAgent im Agent Mode.

In der Git-Bash gibt mir "file $SSH_AUTH_SOCK" korrekterweise auch "socket" aus. ssh-add -l kommt mit diesem allerdings nicht zurecht:
Code:
Could not open a connection to your authentication agent.
Beim Aufruf von bspw. "svn update" wird dieser Key auch nicht berücksichtigt.

Probiert habe ich auch, anstatt einese msysGit Sockets einen Cygwin-kompatiblen Socket zu erstellen und diesen in der .bashrc anzugeben. Es kommt bei ssh-add -l dieselbe Fehlermeldung.

Wie sieht deine funktionierende Konfiguration aus?


Von https://lechnology.com/software/keeagent/usage/options-and-settings/:
In addition to creating a file, KeeAgent also listens on the loopback network interface (127.0.0.1) for connections when either of these options are enabled. The network sockets have no authentication mechanism. This is a limitation of the implementation in Cygwin/MSYS. This means that other users of the same computer can use any keys loaded in KeeAgent. Therefore, it is not recommended to use this feature on a shared computer.

Ich kenne mich mit dem Protokoll eines SSH Agents nicht aus. Ist der Server auf 127.0.0.1 zusätzlich zur Socketdatei wirklich notwendig?
 

Bratkartoffel

gebratene Kartoffel
Premium-User
Hi,

Für git habe ich nur die Umgebungsvariable GIT_SSH auf "C:\Program Files (x86)\PuTTY\plink.exe" gestellt, dann gings. Putty / PLink kann nativ direkt mit dem Keepass Agent kommunizieren. Also ohne Socket und sonstigen Anpassungen.

Vielleicht gibt es für SVN auch so eine Variable?
// Edit: Würde es analog git mit SVN_SSH versuchen: http://stackoverflow.com/a/4455449/1164913 oder hier: http://stackoverflow.com/a/10609603/1164913

Grüsse,
BK
 

ComFreek

Mod | @comfreek
Moderator
Vielen Dank!
Das funktioniert so schon fast perfekt, ich habe nur 2 Mängel festgestellt:

Das 1. Problem
Wenn ich im KeeAgent die manuelle Auswahl der Schlüssel deaktivere, so sucht KeeAgent bei einem bestimmten Host (visualstudio.com Team Services) immer den falschen Schlüssel zum Verbindungsaufbau aus.

Sowohl die Nutzernamen der Passworteinträge als auch die Comments der SSH-Keys sind unterschiedlich.

Das 2. Problem

Wenn ich mich zu einem neuen Host verbunden habe, dessen Fingerprint Putty noch nicht gespeichert hat, und ich gleich "git pull", "svn update" o. Ä. aufrufe, dann hängt die Konsole sich auf:
The server's host key is not cached in the registry. You
have no guarantee that the server is the computer you
think it is.
The server's rsa2 key fingerprint is:
ssh-rsa 2048 [fingerprint]
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
connection.
Store key in cache? (y/n)
Egal was ich drücke (y, n, Return), es läuft nicht weiter. Ich kann es nur noch mit Ctrl-C abbrechen.

Das Problem, dass Git und SVN die Standardeingabe nicht an den erzeugten Prozess weiterleiten, ist wohl bekannt:

Leider finden sich nur Workarounds wie Putty vorher zu öffnen oder Plink sich vorher zu dem Host verbinden zu lassen.
Ich dachte da an ein PowerShell-Skript, welches ein GUI-Dialog einblendet und die Nutzerwahl an stdin des Plink-Prozesses weiterleitet:
Code:
# $args | Out-File "D:\Desktop\blub.txt"
$args[0] = '-P'

Add-Type -AssemblyName PresentationFramework

# From http://stackoverflow.com/a/28440479/603003
$StartInfo = New-Object System.Diagnostics.ProcessStartInfo -Property @{
	FileName = 'plink.exe'
	Arguments = $args
	UseShellExecute = $false
	RedirectStandardInput = $true
	RedirectStandardOutput = $true
	RedirectStandardError = $true
}

$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $StartInfo

# Register Object Events for stdin\stdout reading
$OutEvent = Register-ObjectEvent -InputObject $Process -EventName OutputDataReceived -Action {
	Write-Output $Event.SourceEventArgs.Data
}

[void]$Process.Start()

# Required for asynchronous reading
$Process.BeginOutputReadLine()

$unknownServer = $false

# Beware of deadlocks: https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput.aspx
while (($line = $Process.StandardError.ReadLine())) {
	Write-Error $line

	if ($line.StartsWith("The server's host key is not cached in the registry.")) {
		$unknownServer = $true
	}
	elseif ($unknownServer -and $line.StartsWith("connection.")) {
		# The question "Store key in cache? (y/n)" comes hereafter.
		$storeKeyAnswer = [System.Windows.MessageBox]::Show('Would you like to store the key in cache?', 'Unknown host', 'YesNoCancel', 'Error')
		switch  ($storeKeyAnswer) {
			'Yes' {
				Write-Host "[Plink Wrapper] Key stored in cache."
				$Process.StandardInput.WriteLine("y")
			}
			'No' {
				Write-Host "[Plink Wrapper] Key not stored in cache, but continuing this time."
				$Process.StandardInput.WriteLine("n")
			}
			'Cancel' {
				Write-Host "[Plink Wrapper] Cancelled."
				# Empty line makes Plink cancel
				$Process.StandardInput.WriteLine("")
			}
		}
		exit
	}
}

$Process.StandardError.ReadToEnd()
$Process.WaitForExit()

Unregister-Event -SourceIdentifier $OutEvent.Name

Setze GIT_SSH_COMMAND="powershell D:/path/to/script/with-forward-slashes". Leider hängt das Skript, auch nach Entfernen von ReadToEnd() und WaitForExit().
Komischerweise überträgt Git auch "-p 22" per Kommandozeilenparameter an mein Skript, obwohl Plink ein großes -P erwartet. Deswegen muss ich dies manuell fixen. Wenn ich hingegen GIT_SSH_COMMAND="plink" setze, so funktioniert alles, ob da Git wohl ein -p überträgt? Komisch.

Ein anderes Problem ist, dass SVN anscheinend kein SVN_SSH_COMMAND kennt, man also keine Parameter übergeben kann. Da müsste ich wohl eine native exe-Datei oder bat schreiben, die das PowerShell-Skript dann aufruft.