SSH with PuTTY, Pageant and Plink from the Windows Command Line
I’ve recently started using Git for my revision control needs, switching from Mercurial that I’ve previously used for a number of years. I had mostly used Mercurial from a GUI, namely TortoiseHg, only occasionally dropping to the command line for ad-hoc Mercurial commands.
In switching to Git, I initially switched to an alternative GUI tool, namely SourceTree, however I very quickly decided that this time around, I wanted to try to use the command line as my main interface with the revision control tool. This was a bold move as the Git syntax is something that had always put me off Git and made me heavily favour Mercurial, due to Mercurial’s somewhat nicer command line syntax and generally “playing better” with Windows.
So, I dived straight in and tried to get my GitHub account all set up on a new PC, accessing Git via the brilliant ConEmu terminal and using SSH for all authentication with GitHub itself. As this is Windows, the SSH functionality was provided by PuTTY, and specifically by the PLink and Pageant utilities within the PuTTY solution.
I already had an SSH Key generated and registered with GitHub, and the private key was loaded into Pageant, which was running in the background on Windows. The first little stumbling block was to get the command line git tool to realise it had to use the PuTTY tools in order to retrieve the SSH Key that was to be used for authentication.
This required adding an environment variable called
GIT_SSH which points to the path of the PuTTY PLINK.exe program. Adding this tells Git that it must use PLink, which acts as a kind of “gateway” between the program that needs the SSH authentication, and the other program – in this case PuTTY’s Pageant – that is providing the SSH Key. This is a required step, and is not the default when using
Git on Windows as Git is really far more aligned to the Unix/Linux way of doing things. For SSH on Unix, this is most frequently provided by OpenSSH.
After having set up this environment variable, I could see that Git was attempting to use the PLINK.EXE program to retrieve the SSH key loaded into Pageant in order to authenticate with GitHub, however, there was a problem. Although I definitely had the correct SSH Key registered with GitHub, and I definitely had the correct SSH Key loaded in Pageant (and Pageant was definitely running in the background!), I was continually getting the following error:
The clue to what’s wrong is there in the error text – The server that we’re trying to connect to, in this case it’s github.com, does not have it’s RSA key “installed” on our local PC. I say “installed” as the PuTTY tools will cache remote server RSA keys in the Windows registry. If you’re using OpenSSH (either on Windows or more likely on Unix/Linux, they get cached in a completely different place).
Although the error indicates the problem, unfortunately it gives no indication of how to correct it.
The answer lies with the PLINK.exe program. We have to issue a special one-off PLINK command to have it connect to a remote server, retrieve that server’s RSA key, then cache (or “install”) the key in the registry to allow subsequent usage of PLINK as a “gateway” (i.e. when called from the git command line tool) to be able to authenticate the server machine first, before it even attempts to authenticate with our own SSH key.
The Plink command is simply:
plink.exe -v -agent email@example.com or plink.exe -v -agent firstname.lastname@example.org
(the email@example.com or firstname.lastname@example.org parts of the command are the specific email addresses required when authenticating with the github or bitbucket servers, respectively).
–v simply means verbose output and can be safely omitted. The real magic is in the
–agent switch which instructs Plink to use Pageant for the key:
Now we get the opportunity to actually “store” (i.e. cache or install) the key. If we say yes, this adds the key to our Windows Registry:
Once we’ve completed this step, we can return to our command window and attempt our usage of git against our remote repository on either GitHub or BitBucket once more. This time, we should have much more success:
And now everything works as it should!