Delve into the significance of Git signed commits and their role in ensuring code integrity.
This article offers invaluable insights and guidance for mastering this crucial aspect of software development.
Introduction #
With the increased focus on Common Vulnerabilities and Exposures (CVEs) and Supply Chain Security in the DevOps world, Git-signed commits are an invaluable mechanism to safeguard against unauthorized code modifications that could introduce vulnerabilities.
Git signed commits use private/public key signing (either via SSH or GPG keys) to track the provenance of code changes, ensuring code integrity.
If a commit has a GPG or an SSH signature that is cryptographically verifiable, GitHub marks it “Verified” or “Partially verified.”
I recently discovered this new feature and wanted to share what I’ve learned with you in this article.
Most of the content in this article can be easily found in the official GitHub documentation. So why should you read it?
There are a few reasons:
- The official documentation is lengthy, so having a brief article explaining only the necessary steps provides a quicker understanding.
- I still provide links to the official documentation just in case you want to delve deeper or encounter any issues.
- Some interesting discoveries I made (and share with you here) are not fully documented in the official documentation.
By reading this article, you’ll save time and acquire a valuable skill.
This article will focus on using GitHub, the most used version control tool. However, the same commands will work in other version control tools. How to share the SSH or GPG keys with the version control tool of choice changes.
Git signed commits #
To sign a single Git commit, you can use the following command.
git commit -S -m "YOUR_COMMIT_MESSAGE"
Alternatively, you can automatically sign all your subsequent commits without the -S
parameter by applying the Git repository config:
git config commit.gpgsign true
If you want to sign all your commits in all your repositories on your machine instead of changing this config for a single repository, you must add the parameter --global
to the previous command to apply this config globally.
If, later on, you want to disable signing all your commits, you can run (with or without --global
):
git config commit.gpgsign false
Signing a Git commit requires configuring the key and algorithm for the signing.
You have two main alternatives.
- a GPG key requires generating a GPG key and a passphrase.
- an SSH key an easier solution since you can reuse an existing SSH key, and there is no need for a passphrase.
More information on this topic is available at signing commits.
Sign Git commits with SSH key #
If you want to sign all your Git commits with an SSH key, you can run the following commands:
git config gpg.format ssh
git config user.signingkey ~/.ssh/id_ed25519.pub
As already discussed with the previous Git configs, these commands are valid for the current repo only. To set them globally (for all repositories on your machine), you must add the parameter --global
to both two commands.
Those commands assume that you have already enabled signing all Git commits, as described in the previous section.
If you are not using the default SSH algorithm Ed25519, you might need to adapt the previous command to point to a different SSH public key.
The same public key you used here needs to be added to your GitHub account. To learn how to add your public SSH key to GitHub, head to tell Git about your SSH key.
IMPORTANT: What GitHub fails to say in their documentation is that even if you have already added the SSH key to your GitHub account (probably as an “Authentication key” since that is the default option), you need to add that same key as a “Signing key” as well; otherwise, your signed commit will be “unverified”, and you won’t really achieve much.
Sign Git commits with a GPG key #
First, you need to create a new GPG key
gpg --full-generate-key
You can use the default encryption algorithm but must provide your full name, a valid email, and a passphrase. For more information on the topic, see generating a new GPG key.
Once your GPG key has been created, you can list it with the following command:
gpg --list-secret-keys --keyid-format=long
You can configure Git to sign all your commits with your GPG key (assuming that you only have one) with the following commands:
git config gpg.format openpgp
KEY_ID=$(gpg --list-secret-keys --keyid-format LONG | awk '/^sec/ {split($2, a, "/"); print a[2]}')
git config user.signingkey ${KEY_ID}
The previous commands assume you only have a single GPG key. Otherwise, you might need to adjust them to select the appropriate key.
They are valid for the current repo only. To set them globally (for all repositories), you must add the following parameter --global
to all three commands.
Those commands assume that you have already enabled signing all Git commits as described in the first section.
Finally, similarly to what we described in the previous section, you must export your public GPG key to GitHub. Assuming you only have one GPG key, you can use the following commands:
KEY_ID=$(gpg --list-secret-keys --keyid-format LONG | awk '/^sec/ {split($2, a, "/"); print a[2]}')
gpg --armor --export ${KEY_ID}
If you have more than one GPG key, you might need to adapt the previous commands to select the desired key.
For more info, head to adding a GPG key to your GitHub account
As mentioned in the first section, when we compared the two options, if you want to use a GPG key after each signed commit, you must provide the passphrase you used to create the GPG key.
To store your GPG key passphrase so you don’t have to enter it at every commit, we recommend using the following tools:
- GPG Suite allows Mac users to store GPG key passphrases in the macOS Keychain.
- For Windows users, Gpg4win integrates with other Windows tools.
Conclusion #
As this article shows, signing your Git commits is not complex, and its benefits go a long way.
Furthermore, once you have configured either a single repo or your entire laptop, you don’t have to do anything else at each commit. Unless you chose GPG signing and haven’t yet configured one of those suggested tools above, that allows avoiding prompting for the passphrase at every commit.