I am looking for a recommendation about the proper way to set up SSH keys for connecting to Git on our Jenkins master and slaves. There are other similar questions here about Git, Jenkins, and SSH (the closest being this) but none seems to answer this question with a specific recommendation about the right way to do this.
Background & Testing
I am working on a prototype implementation of Jenkins with on-premise GitLab. We have a few years of experience with Jenkins, but integrating it with Git is new for us. This is also the first time we've configured any slave nodes. At this point, we're just trying to get simple polling to work, no fancy push notifications.
The master Jenkins instance is running on Linux (RHEL 6). There are currently 3 slaves: one other RHEL Linux server, and two servers running Windows Server 2012 R2. The Jenkins slave on the Windows servers runs as a Windows service. The master and all slaves are running up-to-date Git v2.10.0 (64-bit).
We're intending to use SSH to access GitLab. I created an SSH key with a passphrase and saved it on disk on the master. Then, I configured the public key as a deploy key for my test project in GitLab. Finally, I added a new credential in Jenkins.
In my first test project in Jenkins, I configured the GitLab repository URL and selected the Jenkins credentials created above. Then I built the project on the master. Jenkins made the SSH connection to GitLab with no problem and the build succeeded. Then I forced the build over to the Linux slave, with the same results.
Unfortunately, when forcing the build over to either of the Windows slaves, the build doesn't work like it does on Linux.
Errors on Windows
(Edited from my original question, based on further research.)
I initially got this error, which prevented any SSH connections from happening:
stderr: Unable to negotiate with xxxx port 22: no matching host key type found. Their offer: ssh-dss
This has to do with negotiation at the SSH level. The newer SSH client bundled with Git won't use
ssh-dss by default, and that's all my relatively old SSH server is capable of offering.
To get past this, I added
%HOME%/.ssh/config containing the following lines, as documented by OpenSSH under Legacy Options:
This forces the git SSH client to accept
Around the same time, I was struggling with how to get verbose SSH output out of the Windows SSH client bundled with git, because the usual suggestion to set
GIT_SSH='ssh -vvv' doesn't work on Windows. Based on an AskUbuntu question and a similar StackOverflow question, I ultimately ended up with this in
Having the debug output available gave me a better clue about what is going on. In the end, I can make a build succeed on Windows, but only if the SSH key that I use does not have a passphrase. The hint is here in the debug output:
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password,hostbased
debug3: start over, passed a different list publickey,gssapi-keyex,gssapi-with-mic,password,hostbased
debug3: preferred publickey,keyboard-interactive,password
debug3: authmethod_lookup publickey
debug3: remaining preferred: keyboard-interactive,password
debug3: authmethod_is_enabled publickey
debug1: Next authentication method: publickey
debug1: Trying private key: C:\\Users\\JENKIN~1.TMS\\AppData\\Local\\Temp\\ssh2489775972592020656key
debug1: read_passphrase: can't open /dev/tty: No such device or address
debug2: no passphrase given, try next key
debug2: we did not send a packet, disable method
For some reason, Jenkins is failing to setup the the SSH key with the proper passphrase on Windows, where it works just fine on Linux. Unfortunately, Jenkins doesn't dump the debug output from SSH except when the command fails, so I can't see exactly what the Linux build is doing differently.
The (possibly-naive) way I am trying to do this clearly works on Linux but not on Windows. Is it supposed to work on Windows?
Is this the correct way to manage SSH keys for my situation, or is there some better way to do it? I was hoping to avoid having to manage key files on disk for every slave as this infrastructure grows.
Assuming this is the correct mechanism to use, can someone point me at instructions or an answer that definitively explains how to get this working? I feel like I must be missing something obvious...?