Windows Dev Environment using YubiKeys

Sun May 31 2020

One of the things that usually prevents me from starting a side project or exploring a new technical concept on my machine is my lack of a good development environment.

Previously, I essentially installed everything directly on my machine. This included npm, Python environments (2.7 vs 3.5 in my case), SQL databases, and other command line utilities.

As one could imagine, I would frequently run into lots of environmental issues, and with what precious time I had left after work, I simply didn’t have enough bandwidth to properly sort these problems out.

I then began thinking about how to remedy this problem, and the immediate solution for me was to use containers, using Docker. In my opinion, the great thing about using Docker and other containerization technologies is that it allows you to have reproducible environments.

During the development cycle, reproducibility is paramount in finding out root causes. This avoids leads to the often joked about “but it works on my machine” quip that gets said when software breaks outside of a local environment, which commonly ends up being some kind of configuration or dependency version issue. With containerization, you essentially eliminate that issue since there is a commonality amongst all environments, so the scope of potential suspect is narrowed significantly.

As is, my home machine is a Windows Home box. We’re already off to a rough start.

When trying to install Docker for Desktop, I quickly found out that the Windows version is NOT available for the Home edition - only Pro and Enterprise editions had it out of the box. Support for the Home edition was, at the time of writing, was only available on Windows 10 Version 2004, which only people with Windows Insider access could get. I was running Windows 10 Version 1903.

As a workaround I decided to install Ubuntu 20.04 on a VirtualBox VM. I opted for this since Docker runs natively on Linux, and I’m already familiar with working on Linux based machines.

So far this is working great! I’ve got a Linux machine that I can boot and begin working with immediately, and not have to deal with Windows eccentricities during development.

Except, I run into another problem - my VirtualBox machine has EXTREMELY slow download times when installing packages. Attempting to run the following:

sudo snap install --classic code took nearly 10 minutes before I called it quits from being impatient. I was getting download speeds in range of 70-140 kbps in the VM, which was completely unacceptable to me.

Tweaking the VM’s network settings helped marginally, but still took far too long to my liking. One could interject here and say that I just needed to be more patient, but a rapid development cycle is very important to me ;)

In the end, I decided to install Visual Studio on my host machine, and simply SFTP my repository files to my VM. While not the most streamlined solution, it’s an acceptable enough solution for me since the actual file transfer from my Windows host machine -> Ubuntu guest machine is still fast. There’s a really nice VSCode extension called SFTP by liximomo that I’ve found very useful for my particular case.

After supplying the SSH credentials to my VM I can SFTP files directly from VSCode - no need for a dedicated SFTP client. It can also be configured to upload on save, which I found VERY useful. I have a habit of saving files frequently, so this is a great way to make sure that my VM has the most up to date version of my code.

The final part of getting my development cycle put together was figuring out how to communicate my git commits to GitHub or GitLab. Normally I would’ve just used regular password based SSH authentication using ssh-keygen, but I decided to take it one step further using GPG instead.

While I know how to use SSH, I don’t know exactly know how to provision my own credentials, so I took the opportunity to explore the features of GPG, with the ultimate goal of being able to SSH using a GPG key that I generated on my YubiKey.

So, since I’m working on a Windows box, my first step was to install Gpg4win, so I could use the GPG toolkit on my host machine. Since I am SFTPing files from my host -> guest, it makes sense to also commit code from my host as well.

Using a fresh YubiKey 5 NFC, I followed the relevant Yubico support article and opted to generate the key directly on the key. It’s worth noting that by generating the private keys directly on the YubiKey, I run the risk of losing SSH access completely if I lose this key. But lucky for me, I’ve made a few backup keys already, so I happen to lose one key, I can still regain access using the other ones.

Once I generated the master GPG key, the next step is to generate the authentication subkey. I followed Linode’s docs on generating an authentication subkey to do this.

At this point, I figured that I could just export the SSH key and be done with it, but that wasn’t the case at all! I think I ended up running into a problem where the ssh-agent wouldn’t be forwarding the requests to gpg-agent. To try and solve this, I updated my gpg-agent.conf settings with the following options:

enable-ssh-support
enable-putty-support
default-cache-ttl 60
max-cache-ttl 120

This supposedly allows GPG to support both SSH and PuTTY when they ask for a key? I’d have to digest the docs a lot more to understand it! The cache parameters essentially boil down to a default cache lifespan of 1 minute, and expiring after 2 minutes.

I figured that this would be all that I need to then SSH, but I then encountered another interesting issue where typing ssh-add -L with my YubiKey plugged in would throw the following error:

Error connecting to agent: No such file or directory Googling around similar Windows setups revealed that Windows comes with their own version of OpenSSH, which could be interfering with the way I had configured SSH!

The solution ends up being to delete OpenSSH from System32 in Windows. Deleting things in System32 always feels dirty, but after deleting it and restarting my computer, it works well.

In the end, my development workflow ends up looking like so:

  1. Spin up Ubuntu 20.04 on my VirtualBox VM
  2. Write code on Windows host machine in VSCode
  3. Save changes so SFTP extension sends code to guest VM
  4. Navigate to web browser and enter in IP address of VM
  5. If changes look good, plug in YubiKey and commit code to remote repository

My initial runs with this setup have been pretty satisfactory so far, so I hope that whoever stumbles upon this post will find it useful :)