Within github, there are two things you can do to make your commits more secure both for you and for others you work with: signing your commits, and ensuring that your personal email remains private in your commits. In this piece, We'll go over each of these methods, why they are important, and how to accomplish them smoothly on Mac OSX.
Anyone who has access to a repository can push a commit to that repo under your name, and nobody will be able to tell the difference. All they have to do is change their git settings to use your name and email address for commits. Let that sink in for a minute, or if it helps more, read this piece explaining how it can turn into a serious problem. The way you can solve this problem is through signing your commits with a GPG key - when you do this, github will display a "verified" badge next to each commit. You can even set up repos so that only signed commits can be pushed, which is probably something we should do, at least for internal projects.
The way this works is fairly simple. You generate a public/private keypair on your machine, and put your public key under github's settings. Then you set up git such that it uses the private key to encrypt a message which the public key can decrypt, and git sends the encrypted message along with your commit. If github is able to decrypt it using your public key, github can be assured that it was only you who could have encrypted it, since nobody else has access to your private key, and they mark the commit as verified, because regardless of how you have configured your name and email address, they know for sure that it was you who made the commit due to the signature. If this is confusing or you feel like it doesn't make total sense, reviewing how public key cryptography works might help.
So, let's talk about how to actually get this working. Github has an excellent guide you can follow to get started. I am also including a shorter, more focused version below that automates more of the setup and is specific to OSX.
-
Make sure you have homebrew installed and it's up to date with
brew update
-
Install the latest version of the
gpg
tool usingbrew install gpg
-
Run
gpg --full-generate-key
to enter the key generation interface. Use the default answers for each step except for the key size, for which you should use4096
. -
When asked for your user information, enter in
<YOUR_GITHUB_HANDLE>@users.noreply.github.com
- so for me it would be[email protected]
. You'll see why this is in the next section. Use any password that you will remember. -
Your key should now be created. You can run
gpg --list-secret-keys --keyid-format LONG
to list out your keys. You'll see some output like this:/Users/USER/.gnupg/pubring.kbx *** sec rsa4096/32E23F61AB5451DB 2019-08-01 [SC] A58D24148508Q690C60A0BD839D23C61HB5450AB uid [ultimate] YOUR NAME <[email protected]> ssb rsa4096/25112294A022DH52 2019-08-01 [E]
-
Copy the part on the
sec
line afterrsa4096/
-- in the above example it would be32E23F61AB5451DB
-
Now to get your public key, run
gpg --armor --export ID
, withID
being the string you copied above -
Head over to your github keys gettings and click the "new GPG key" button - paste in the public key output you just got.
At this point, you have a key and github has the key. Now, you need to ensure that git is using the key to sign your commits. You also don't want to have to enter the password to access your private key every time you run a commit. So we'll install some tooling to ensure your password is stored in the keychain, then make sure git signs all of your commits automatically with it.
- First we install the
pinentry
tool, which will give us a UI modal to enter our password and let us save it for future use. Use thebrew install pinentry-mac
to do so. - Now run
echo "pinentry-program /usr/local/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
to ensure that GPG uses this as our password entry program, then restart the GPG agent withkillall gpg-agent
. - To ensure that git is using GPG as the signing program, run
git config --global gpg.program gpg
- Now we'll add our signing key to git with the command
git config --global user.signingkey <YOUR_SIGNING_KEY>
- the key is the one you copied out above to generate your public key - in our example it was32E23F61AB5451DB
. - Finally, let's tell git to sign all your commits with it by running
git config --global commit.gpgsign true
- Now you can make a commit, and you should see a UI modal pop up prompting you for the password to your key. Enter it, and make sure to check the "save to keychain" box, so you won't have to do it every time (unless you're on a public or shared machine, I guess)
- You can verify that your commit was properly signed using the command
git log --show-signature -1
That's it! Once this is done, all of your commits should also include a "verified" tag next to them in github. If you see a commit from yourself that does not have a verified tag, you will know to be very suspicious of it.
Another unfortunate reality of github's default settings is that while you can hide your personal email in the github interface, it remains public as part of the data for any commit that you make. This means that any contribution to an open source project exposes your email to anyone who wants it, including recruiters, spammers, even people who have something against you, or your organization. Unfortunately, this did happen recently to HashiCorp, where many employees were subscribed to a variety of mailing lists with their names listed as offensive racial slurs, using their personal emails.
There is a way to hide your personal email from commits, and enforce this for all commits going forward, and I do recommend setting this up. Steps will be listed out below:
- Head over to github's email settings
- Make sure you have checked the "Keep my email address private" and "Block command line pushes that expose my email" options
- Now if you try to commit, it will be denied by github, so you need to change your github email. You can do this with the command
git config --global user.email "<GITHUB_HANDLE>@users.noreply.github.com"
- That's all! If you have commits that you have not yet pushed, you will need to change the author so that it does not expose your private email. You can do this with the command
git commit --amend --reset-author
. After running this, you should be able to push without issue.
I should note that none of the instructions above go through all of your commits to all of your projects in the past and correct them. This is a bit more involved and invasive, and may not be a step that you want to take. If you do though, github has a guide on how to do it. Your email will not be entirely private to github scrapers unless you do this.
Heads-up for those enabling the email privacy option for the first time, from GitHub:
"Note: If you created your GitHub account after July 18, 2017, your GitHub-provided no-reply email address is a seven-digit ID number and your username in the form of
[email protected]
. If you created your GitHub account prior to July 18, 2017, your GitHub-provided no-reply email address is your username in the form of[email protected]
. You can get an ID-based GitHub-provided no-reply email address by selecting (or deselecting and reselecting)Keep my email address private
in your email settings."Before you generate your key, if you've never checked the email privacy box I'd recommend doing that so you can generate an email address in the new format. I tried following the guide before realizing this and my signatures were considered unverified after I pushed my next commit 😱
Here's a guide by GitHub to add that new format email to your existing GPG key: https://help.github.com/en/articles/associating-an-email-with-your-gpg-key
Near the end of that guide you'll need to delete your existing key from GitHub before uploading the edited one.