Down a git-based rabbit hole

Part I: git vs QNAP NAS

I use a git repository to store my Docker containers/web app configurations. This makes it easy for me to edit the configs on my desktop desktop and push to my server to deploy new configs, as well as — more importantly — implicitly tracking changes so I can easily revert or see when/how I messed something up.

In the past, I’ve stored this repo on BitBucket, but I’ve been trying to move away from that platform — for my code repositories, I’ve been migrating to Github, but this one … even though I’m careful to not push any secrets, and keep it listed as a private repository, it still seems inappropriate to cloud-store it. So I cloned a bare copy of it to my QNAP NAS. That worked well-enough, but when I tried to clone/pull from that, I was getting a git error saying it couldn’t find git-upload-pack, which is used by git for efficiently transmitting its bulk files over a network.

sh: git-upload-pack: command not found
fatal: Could not read from remote repository.

My first thought was to try to find a way to configure git to not use git-upload-pack, but that was a dead end. Next, I ssh’d into the server searched to see if the file existed somewhere outside of $PATH.

$ find / -name git-upload-pack 2>/dev/null

This revealed a copy of it in a nonstandard location (actually two), but it’ll work. Or, well, it could, except git doesn’t know where to find it. There are various ways to force it into $PATH, but it can be tricky for the noninteractive shells used by git. And I have no idea if any changes I make on the server might be overwritten by the next QNAP upgrade. So instead, I looked for a client-side solution, and found two. For cloning, the --upload-pack option allows for specifying the path to the binary

git clone --upload-pack /share/MD0_DATA/.qpkg/git/repository/bin/git-upload-pack tardis.local:/share/Repositories/deployment/config.git

Et voilá — the repo clone succeeded! But I don’t want to have to do that every time I pull. Fortunately, git lets us configure the repository to make this the default for it

$ git config remote.origin.uploadpack /share/MD0_DATA/.qpkg/git/repository/bin/git-upload-pack
$ git config remote.origin.receivepack /share/MD0_DATA/.qpkg/git/repository/bin/git-receive-pack

And with that, we’re in business. git pull origin master works perfectly. Except…

Part II: sudo ssh key problems

For… reasons … I keep the configs git repo on my webserver owned by root, and thus need to use sudo to pull changes in. So it should just be sudo git pull origin master. And in fact, this does work, but it forces me to type in the password for my user account on the NAS. I have ssh keys set up to avoid that, so I’d like them to work here, too.

I don’t keep a copy of my private keys on every machine, just on my desktop(s). Then I use the ssh client ForwardAgent setting to enable ssh to share those keys to hosts I’m connected to, so that I can continue to ssh into other machines using the keys on my desktop. This works great, but breaks with the sudo privilege escalation.

Fortunately, there’s a workaround. ssh-agent (which is responsible for making the keys available) utilizes an environment variable $SSH_AUTH_SOCK which holds the value necessary for this sharing to work. As long as that value is set, ssh won’t need my passwords.

The simplest (but least secure) is therefore to use the -E flag, which imports my entire environment into the sudo command

$ sudo -E git pull origin master

But… this feels a bit like using a shotgun to swat a mosquito: it’s doing way more than I need or want. Looking further, sudo has an option --preserve-env=... to just import a single environment variable. Perfect!

$ sudo --preserve-env=SSH_AUTH_SOCK git pull origin master

Much better… but too verbose to be typing every time. I want sudo to just assume that’s what I always want. /etc/sudoers.d/ holds sudo configuration files sourced by the main sudo configuration (which we generally try to avoid modifying). So using visudo to create and edit a new configuration file just for this:

$ sudo visudo /etc/sudoers.d/forwardAgent

I just need to add a single line to this new file:

Defaults env_keep+=SSH_AUTH_SOCK

And now, finally, I can just do sudo git pull origin master, and it uses the right git-upload-pack tool AND uses my ssh keys which are shared over ssh and then made available to sudo’d commands


Leave a Reply

Your email address will not be published. Required fields are marked *