Ken Muse

SSH and Multiple Git Credentials


An interesting challenge awaits teams that have unique security or service needs with their source control. If you have a single source control system or a single GitHub environment, then everything just works. You have one credential to work with, so it is generally seamless. When you have multiple environments, then it becomes more complex. For example, what if you are using GitHub Enterprise Cloud (GHEC) for your public contributions, Enterprise Managed User (GHEC-EMU) for private company activities, and GHAE or Enterprise Server for sensitive projects? This is where we can take advantage of configuration settings with SSH and Git.

To be clear, this is just one way to make this work. There are actually several approaches that can work well

SSH Configuration

First, you’ll want to create an alias in SSH (~/.ssh/config) for each environment that requires a distinct credential. The credential will be configured with a HOST value that you will use to identify the credentials to be used. Think of this value as an alias that will reference the login credentials and the actual server hostname. For example, I might configure four environments this way:


HOST ghec
    AddKeysToAgent yes
    HostName github.com
    IdentityFile ~/.ssh/ghec_rsa
    IdentitiesOnly yes
    User git
HOST ghae
    AddKeysToAgent yes
    HostName myco.ghe.com
    IdentityFile ~/.ssh/ghae_rsa
    IdentitiesOnly yes
    User git
HOST ghes
    AddKeysToAgent yes
    HostName ghes.myco.corp
    IdentityFile ~/.ssh/ghes_rsa
    IdentitiesOnly yes
    User git
HOST emu
    AddKeysToAgent yes
    HostName github.com
    IdentityFile ~/.ssh/emu_rsa
    IdentitiesOnly yes
    User git

Let’s quickly explore these settings:

  • HOST
    This configures an alias that we’ll use to represent each environment that requires a unique credential. It creates a mapping based on the provided host name. When this name is referenced, the associated configuration will be used.
  • AddKeysToAgent
    Indicates whether the key and passphrase should be automatically added to the ssh-agent to minimize the number of times a password is required.
  • HostName
    The fully-qualified domain name for the Git host. You may have multiple entries that have the same value (for example, using github.com for both EMU and non-EMU instances).
  • IdentityFile
    The file path to your SSH private key
  • IdentitiesOnly
    Only use the provided identity file, even if there might be other identities available
  • User
    The user name for authentication. With GitHub, this will always be git, so we can hardcode that value.

With that configured, we can now move on to configuring Git.

Git

The .gitconfig file allows us to bind things together. We take advantage of the url..insteadOf command to create our mappings. This works by matching the start of the connection URL and replacing it with something else. For example, we might use this for the GHAE configuration:

[url "ghae"]
  insteadOf = [email protected]

If a Git clone uses a URL that starts with [email protected] (for example [email protected]:some-org/my-repo.git), this entry will instruct Git to replace that string with the url value — ghae. The resulting URL, ghae:some-org/my-repo.git, will be stored as the origin for the repo. Next, this modified URL will be processed to create an SSH connection. Since the new host name appears to be ghae, it will match the second entry we created in the SSH config. This entry specifies that the hostname should be myco.ghe.com and the user should be git. This effectively causes it to create an SSH connection to retrieve [email protected]:some-org/my-repo.git. This approach also works with GitHub Enterprise Server (GHES).

If we only have a single GitHub.com enterprise, we can use the same approach. If we have both an EMU and a non-EMU enterprise, we need to do something extra. Because both of those environments have the same host name, that’s not enough to guarantee the match. In this case, we might also include the organization name as part of the matching configuration. For example, if we have this configuration:

EnvironmentURL
EMU[email protected]:ken-emu/internal.git
Non-EMU[email protected]:ken-notemu/public.git

We might configure this as follows:

[url "ghec:ken-notemu"]
    insteadOf = [email protected]:ken-notemu

[url "emu:ken-emu"]
    insteadOf = [email protected]:ken-emu

By including the organization name in the match, we can properly select the credential we want to use. In order for this to work, it’s important to make sure that the organization name is included in both the url and insteadOf fields.

The first URL [email protected]:ken-emu/internal.git is altered by the Git config to be ghec:ken-emu/internal.git. The SSH config matches the host, ghec, and finds the appropriate configuration. It replaces ghec with the actual user and host name, essentially recreating the original URL. It will then use the specified identity key to establish the connection. The second URL has the host specified as emu, so it will map to a different identity and the same host name, github.com.

Automation

It is possible to alter the .gitconfig from the Git command line. The command is simply: git config --global url.NEW_URL.insteadOf ORIGINAL_URL. For example, the configurations above are:

1git config --global url.ghae.insteadOf [email protected]
2git config --global url.ghec:ken-notemu.insteadOf [email protected]:ken-notemu
3git config --global url.emu:ken-emu.insteadOf [email protected]:ken-emu

Next Steps

There’s a lot more you can do with these files to configure your environments, and a lot of ways that they can be used to select an SSH identity for connection. There are other features which can support more complex needs. For example, if multiple insteadOf strings match the URL, the longest match is used. This could enable you to create catch-all patterns for common cases. Similarly, the SSH config has more complex matching options available (for example, MATCH).

It’s also important to consider that each approach has tradeoffs. Each approach will have strengths and weaknesses. In this approach, there are two important considerations:

  • If you’re using both EMU and non-EMU instances of GitHub.com (or needing two different identities for the same host name), you will need a mapping that includes more of the URL (such as the organization name) to ensure the right credential is selected.
  • The .gitconfig configuration modifies the origin for each matching cloned repo, changing the original URL that was provided.

With that in mind, try a few different approaches to see what works best for you!