Auto-switching SSH keys for work repos

I have a personal GitHub account and a corporate one, and I found it annoying to have to select the correct SSH key for work repos, so I configured git and SSH to pick the correct key for me. After initial setup, there are three config files to modify:

After the initial setup, there are three config files involved:

  1. Git URL rewrite (`~/.gitconfig`) — rewrites work org URLs to an SSH host alias
  2. SSH host alias (`~/.ssh/config`) — maps that alias to the right key (and port 443 if needed)
  3. Work-only Git identity (`~/.gitconfig.work`) — sets work email/name/signing key, loaded automatically for work repos

The mental model is:

  • Git rewrites git@github.com:my-org/...git@github.com-work:my-org/...
  • SSH sees github.com-work and uses the work SSH key (and optional port 443)
  • Git config loads your work identity/signing settings only when the repo is a work repo

I clone a work repo now and everything is already correct.

Generating the keys

SSH key first:

ssh-keygen -t ed25519 -C "you@work.com" -f ~/.ssh/work_id_ed25519

Give it a passphrase, then add the public key (~/.ssh/work_id_ed25519.pub) to your work GitHub account under Settings > SSH and GPG keys.

(Optional if you want commit signing) GPG key:

brew install gnupg # if not installed
gpg --full-generate-key

Pick RSA 4096 or ed25519, enter work email. Then grab the key ID:

gpg --list-secret-keys --keyid-format long

The hex string after the algorithm (e.g.ed25519/94DC844444530B75) is your signing key ID. Add the public key to GitHub too:

gpg --armor --export 94DC844444530B75

Paste that into Settings > SSH and GPG keys > New GPG key.

Git URL rewrite (~/.gitconfig)

Configure Git to map the work github host to a pseudo-hostname (a “hook” that SSH can match on):

[url "git@github.com-work:my-org/"]
    insteadOf = git@github.com:my-org/

Now whenever I clone, push etc. to a repo under my work org, git transparently rewrites the host to the pseudo-hostname.

SSH host alias (~/.ssh/config)

SSH resolves github.com-work here and connects to GitHub’s SSH-over-HTTPS endpoint with my work key.

Host github.com-work
    HostName ssh.github.com
    Port 443
    IdentityFile ~/.ssh/work_id_ed25519
    IdentitiesOnly yes
  • IdentitiesOnly yes stops the agent from trying my personal key.
  • It uses port 443 because corporate the firewall blocks 22.

Quickly check SSH config works:

❯ ssh -T git@github.com-work
Hi your-work-github-username! You've successfully authenticated, but GitHub does not provide shell access.

Configure work-specific git config

Create ~/.gitconfig.work with work identity:

[user]
    email = you@work.com
    name = Your Name
    signingkey = YOUR_GPG_KEY_ID
[github]
    user = your-work-github-username
[commit]
    # if you want signed commits
    gpgsign = true

Hook it up with includeIf so it auto-loads

This tells Git when to include the work config. Because the URL rewrite above changes work remotes to git@github.com-work:my-org/..., you can include your work identity only when a repo has a remote URL matching that pattern:

# ~/.gitconfig
[includeIf "hasconfig:remote.*.url:git@github.com-work:my-org/"]
    path = ~/.gitconfig.work

That tells Git: if any remote URL in this repo matches git@github.com-work:my-org/..., load ~/.gitconfig.work to set my work email/name/signing key.

All three files are templates gated on a machineRole variable in Chezmoi, which gets set during chezmoi init. On a personal machine, none of this renders.

I clone a work repo now and everything is already correct and i haven’t thought about it since setting it up.

Leave a Reply

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