Protect Your Github Commits

Did you know that anyone who knows the email you used in github could make a push as if they were you?

Securing Git Commits

No, this is NOT a security flaw in github. This is the very design of git. Git is meant to be decentralized with no central repository to speak of, but habits are hard to break and control is something that enterprises want over its assets. And centralizing a decentralized system was born on top of git. Git’s original design was such that we only pull from and push to trusted peers. And trusted peers are easy to get to agree to follow conventions.

TLDR;

The official git documentation provides a comprehensive sign your work article in using GPG.

Why Sign Your Work

Why Sign? Because anyone can make a commit as you if they know one or two of the emails you use to contribute work for either private or public git managed source codes.

A malicious individual can submit code under your name and email, contributing poor quality or malicious code.

Assumption & Requirements

Assumption

This article assumes you are on MacOS and is familiar with executing commands via Terminal.app

If you are on Linux, WSL, Android, or BusyBox, installation of:

  • Git Credential Manager (GCM)
  • GPG
  • pinentry

is out of scope of this article. It should however be really simple to find the apt, yum, rpm, dpkg, *pkg, dnf, synaptic, pacman, or portage equivalents.

Install Requirements

brew install git git-credential-manager gpg pinentry pinentry-mac 

Github Setup 1

You might be wondering why “Github Setup 1”, obviously there will be “Github Setup 2”. The reason is that the steps in this article is ordered in a manner with which you need the information as if you follow the steps mentioned as you red.

In this step, we need to configure our Github account to let us use a github provided email. This is an important to ensure that scripts that parse git repositories will not be able to collect our email and expose that email to spam or phishing attempts. This is also part of what will help us protect and secure our git commits.

Visit https://github.com/settings/emails and find the following pattern @users.noreply.github.com on the page. Take note of this email as you need this in the next step. I will call this github pemail

Make sure that the checkbox Keep my email addresses private together with Block command line pushes that expose my email is checked.

GPG Key Generation

Signing a commit will require an SSH key or GPG key. We will use GPG key in this process.

gpg --full-generate-key

Choose the defaults or ECC (sign and encrypt), Curve 25519, and 1y.

I strongly suggest setting an expiry date. End of the year, if you will.

Fill in the needed information and make sure to use your github provided private email address. You can find that at https://github.com/settings/emails with the following pattern @users.noreply.github.com

Make sure that the checkbox Keep my email addresses private together with Block command line pushes that expose my email is checked.

Now that that is configured, time to export the generated keys so we can tell GitHub which keys proves who we are. First step is to get the key id, specifically the long keyid.

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

The long keyid is usually after pub ed25519/, copy the long keyid and execute the command below:

gpg --export --armor {long-keyid}

Copy the text in the terminal or use pbcopy to send exported data to clipboard

gpg --export --armor {long-keyid} | pbcopy

Github Setup 2

Now that the keys is copied to our clipboard, we must tell Github our GPG Public Key for it to be able verify commits we signed.

Open https://github.com/settings/keys on a browser and click New GPG key button. Paste the key.

Git Reconfiguration

Use the GPG Signing Key

Configure git to use a signingkey.

git config user.signingkey {long-keyid}

Protected Email

This is also a good time to re-configure your Git to no longer use your business email. Repositories can be scanned and is a good source of valid emails for spamming and phishing.

git config user.email {github_provided_username}@users.noreply.github.com 

Signing Application

Find the path of the gpg application using which

which gpg

Copy the return path and configure git to use that as the gpg.program. Assuming the value is /opt/homebrew/bin/gpg, execute the command below:

git config gpg.program /opt/homebrew/bin/gpg

or use backtick to use a command output as a command argument like:

git config gpg.program `which gpg`

Tell our Shell about GPG

There is no doubt that we use different shells so to cater to two commonly used shells while in terminal, execute the command below.

current_shell=`ps -p $$ | awk 'FNR == 2 {print}' | awk '{print $4}'`; if [[ $current_shell == '-bash' ]]; then echo 'export GPG_TTY=$(tty)' >> ~/.bashrc; elif [[ $current_shell == '/bin/zsh' ]]; then echo 'export GPG_TTY=$(tty)' >> ~/.zshrc; fi

What the above command does is check whether you are using bash or zsh in your current terminal. It then sets up an environment variable GPG_TTY, so it knows that it can invoke gpg.

Reload our environment/shell read command (rc)

With our read command file configured to utilize GPG, we need to reload it so the new variable will be available to us.

For those who use bash:

source ~/.bashrc

For those who use zsh:

source ~/.zshrc

The above will ensure that GPG_TTY variable is now an available environment variable.

Alternatively, closing the terminal and opening it will cause it to reload the rc file. This confuses other engineers, making them wonder why it suddenly worked.

Signing New Commits

To sign new commits, simply add -S to your git commit like so

git commit -S -m "This commit will be signed with the configured signing key"

Auto-Sign New Commits

Time to setup git to always sign commits.

git config commit.gpgsign true

With the commit.gpgsign configured to true, there will be no need to add -S to every commits made.

Multi-Project, Multi-Email, Multi-Keys/Machine

If you work with the above scenarios, you can use the --local option when executing git config for every local project repository you are working on.