Written by Rick Hanson, Senior Operations Research Analyst, CANA, LLC.
In this short article, we will outline a useful method of organizing access to version control repositories (“repos”) on remote machines while needing to use more than one set of credentials. The context for using this method is the following.
You use the git version control system but work on various projects that require different credentials to access the private upstream repos for each of these projects. Any credential you use is not a user-password pair, as you would normally use to access systems, but a PKI key pair consisting of a public and private key. Since git uses ssh (the Secure Shell program) to access the upstream repo, these keys are often referred to as “an ssh key” (when you are using one of the key pair) or “ssh keys” (when using both). The pair of public and private key is sometimes referred to as an identity in the ssh manual.
Now, the issue is: how do you manage the access to these various repos with these various keys/identities? For instance, at work I use a set of ssh keys to access all the repos under my company’s organization in GitHub; also, I have another ssh key pair that I use for my personal projects; I have yet other ssh keys, one for each of the volunteer organizations to which I belong.
I used to run a program called an ssh key agent, as a background process, which sorted out the multiple keys for me but the method lacked the fine-grain control over which keys should be used for which repos and often would fail to pick the correct key and so my access to the repo would fail.
Yet, there is a simpler method to sort all this out that only involves setting up git configuration files in the most minimal way and also has the added benefit of not needing to run the ssh key agent program.
Setting up the configuration for the user’s name and email
Git allows one to set up configuration options at (i) the global level (also called the user level) and (ii) at the repo level. If you only need one identity (and thus one set of credentials to access the remote repo), the solution is simple: set up your user information and credentials at the global level. This is done by setting your name and email in the .gitconfig file located in your user’s home directory.
You can edit this file directly; however, a better way is to use the following two git commands at the command line interface (or the shell).
Just replace the great running back’s name and email with yours.
These two git commands will end up writing the following lines into the .gitconfig file located in your/Barry’s user home directory.
Setting up the configuration for the user’s ssh identity
There are several ways to configure the user’s ssh identity. One way is to load a program in the background that manages the ssh keys (the key manager); then, when git calls ssh to authenticate you to the remote (located on a central server like github.com), the key manager program will handle passing the key/identity to the ssh client so that you can gain access to the remote. But as mentioned above, this method sometimes fails to associate the correct identity with a particular repo (when you need to use multiple identities).
Another more direct way of doing this is to set up this association in the git configuration itself and to not bother running the key manager. We’ll start using this new method by setting up a key association at the global config level in git. The following command is an example of how to do this.
That command tells git that when it calls ssh to gain access to the remote, it should use the identity (-i) defined by Barry’s ssh key located at the path ~/.ssh/my-personal-key. (The ~ part of the path is an alias for the home directory, which for Barry could be /Users/barry on his computer.)
After the git command, the following lines will be written to the .gitconfig file located in the user’s home directory.
What are multiple identities?
So now, by the above, git knows which one identity/key to associate to all repos governed by git. That’s not exactly what we want yet. Now, we need to take one more step to configure git to make an association of a different identity (from the global one) to a particular subset of git repos.
Now, let’s say Barry Sanders gets hired at CANA, LLC. Before being hired, he has already been using git with his personal ssh key (identity). Now, he needs another identity for his access to CANA git remote repos. This identity is now located at ~/.ssh/my-work-key. Now, Barry has multiple identities and he has separated his work credentials from his personal credentials.
At this point, how can Barry indicate to git that when he is in a CANA repo on his machine, to use the work identity to access the remote and to use the personal identity to access his other repos’ remotes?
Here is the method. Barry creates a directory under his home directory called CANA and now has the directory /Users/barry/CANA on his system. His CANA git repos will now be located in any subdirectory under this directory.
Before he clones a work repo, he creates a .gitconfig file in /Users/barry/CANA with the following contents.
Then he edits the global/user git config file at ~/.gitconfig by adding the following lines at the end.
This tells git to include the lines in the configuration file located at ~/CANA/.gitconfig for all git repos located in any subdirectory under ~/CANA/ – which on Barry’s machine is shorthand for /Users/barry/CANA. This effectively overrides the values of user.name and user.email as well as core.sshCommand when Barry is executing git commands anywhere under the ~/CANA directory.
Finally, Barry can start cloning git repos from his employer’s github without having to manually enter credentials. And, as long as Barry issues git commands such as clone, push, pull, and fetch, under the ~/CANA/ or any of its subdirectories, git will know which credentials to apply and the entire remote processing is completely simple and seamless for Barry.
As an added bonus, this configuration setup also works when Barry is using the git integration layer in his IDE or editor, because the integration layer is using the same commands, behind the scenes, that Barry was just using from the command line.
There is one more level of granularity for git configurations and that is at the repo level. Indeed, at the beginning of this article, we mentioned that the two levels of configuration were at (i) the global, or user, level and (ii) the repo level.
The method described above has essentially added another (intermediate) level in between those two levels. We could informally call it the “all work repos” level. This intermediate level only obtained when the user runs git commands – that access the remote(s) – from a directory located at or under the primary work directory (in Barry’s case, ~/CANA).
We did not need to change any git configurations at the repo level when using this method. In fact, if we were to work on many projects at work, we might have scores of repos, and in this case, it’s much easier and more simple to handle repo access at the “all work repos” level, rather than at the repo level.
In summary, when multiple identities are needed to access git remote repos, we were able to replace a common method of managing these identities — by running the memory-resident ssh key manager — which is sufficiently error-prone in matching the correct identity with a particular repo, by a simple method of configuring git that always matches the correct identity with the repo.