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?
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.