I find myself needing to set up SSH and GPG keys for use with GitHub, Bitbucket, GitLab and other similar services rather frequently. Here are the steps I use to set this up.
SSH Keys
Create SSH keys
Use the below command to create SSH keys. It might be wise to "silo" your keys such that you dedicate a separate key for each computer you use and per repository, service or some other logical way. For instance, have one key for GitHub and another for Bitbucket.
$ ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_$(whoami)_$(date -f %Y-%m-%d) -C "Macbook Pro SSH Key for GitHub"
Make sure to set a passphrase! If you don't, and your key is compromised, it's a free pass for the attacker.
Get public key
Copy the public key from the .pub
file created in the last command to your clipboard. From our previous example, it would be something like this:
$ clip < ~/.ssh/id_ed25519_jdoe_2020-12-29.pub
You can also open the file in your favorite editor (*cough vim) and simply copy it that way (assuming you can quit out of vim :p ).
Add to GitHub (or whatever service you are using)
In GitHub, or whichever service you happen to be using, go to your settings and then to SSH Keys. Many services combine SSH key and GPG key management into the same page, so don't leave the page once you find it.
Select "Add new key", and paste the key in. If you copied the whole key, it should automagically populate the key name. I personally only copy the type and the base64 encoded key leaving out the username, hostname and comment, if any, e.g. ssh-ed25519 aAbBcCdD...
(see https://coolaj86.com/articles/the-ssh-public-key-format/ for a breakdown of the key format).
You will receive an email stating that a new key has been added. Likewise, if you delete a key you will also receive an email alerting you to the activity.
Set git config
This step isn't entirely necessary, however, it does help if you plan to use multiple keys.
Open ~/.ssh/config
in your favorite vim, I mean editor. Add the following, making changes where you see text surrounded by '<>'.
Host <slug>
Hostname <github.com or your services FQDN>
Username git
IdentityFile <path to private key>
IdentitiesOnly yes
Here's a breakdown:
- Host: If you are only planning to have one key (to rule them all), you can put the FQDN of the service here, like
github.com
, but if you are going to silo, you might choose something more descriptive, like mycoolwidget. Then when you set up your git remote in your local repository, you should use that slug instead ofgithub.com
.
This configuration will essentially alias the FQDN for the slug. The main benefit here is that you can use multiple keys with the same service. Just make different slugs that point to each key, add the keys to your service and then make sure to use the slug when you set up the git remote locally. See the example below for context. - Hostname: This is the FQDN that will be aliased using the "Host" slug in the line above. For instance, if your github.com repository SSH URI is
git@github.com:jdoe/mycoolwidget.git
you would simply usegithub.com
here. - Username: This is the SSH username that will be used. Virtually all git implementations will use "git" here, but if you have some weird setup, you can change this.
- IdentityFile: Defines the key pair to use. The private key is the file generated by
ssh-keygen
in step 1 above that has no extension. Keep it secret, keep it safe. But refer to it here. In our above example, it would be~/.ssh/id_ed25519_jdoe_2020-12-29
. You can use the~
here, thats fine. - IdentitiesOnly: This line simply means that the host configuration should only be used with SSH keys.
You need to make sure that the config file has chmod 600, meaning that the owner of the file has read and write permissions (6), and then group and everyone have no permissions(0). You can always hit it with a quick chmod 600 ~/.ssh/config
to make sure.\
As an example of "siloing" your keys, assuming your project mycoolwidget is hosted on github:
# ~/.ssh/config
Host mycoolwidget
Hostname github.com
Username git
IdentityFile ~/.ssh/id_ed25519_jdoe_2020-12-29_mycoolwidget
IdentitiesOnly yes
Host mycoolapp
Hostname github.com
Username git
IdentityFile ~/.ssh/id_ed25519_jdoe_2020-12-29_mycoolapp
IdentitiesOnly yes
# set up local git repositories
# the alias would be the equivalent to 'git@github.com:jdoe/mycoolwidget.git',
# but since we are using the slug we defined in the SSH config, our identity file will automatically be used
/home/jdoe/projects/mycoolwidget $ git remote add origin mycoolwidget:jdoe/mycoolwidget.git
/home/jdoe/projects/mycoolwidget $ cd ../mycoolapp
/home/jdoe/projects/mycoolwidget $ git remote add origin mycoolapp:jdoe/mycoolapp.git
Lastly, verify that your config works.
ssh -T <slug>
You should get a message back saying something along the lines of you've connected successfully, but shells aren't allowed.
Thats it for the SSH key peice. Now for the hard part...GPG keys.
GPG Keys
You will need the GPG command line tool for this. Make sure you install the correct version for your OS. Most linux and Mac (including Windows Subsystem for Linux) will already have gpg ready for you.
Create a new key
-
If you don't already have keys set up for your e-mail, or if like me, you've failed to store your passphrase in your password vault and have now forgotten it, then you need to generate a new key.
gpg --full-generate-key
You will be prompted for several things:
- Key algorithm: You can accept the default of
RSA and RSA
unless you are feeling frisky - Key Size: Anything greater than 4096 should be adequate (multiples of 1024, and not a bakers kilobyte)
- Expiration: If you enter nothing, it will never expire. You should probably think twice before doing that. Values can be in days, weeks, years...e.g. 30d, 52w, 3y, etc.
- Verify: If your selections so far are valid, type
y
, else bail out and start over. - Your email address: Enter your email address. This needs to match a verified email address on your GitHub (or whatever) account AND the email you use in your local git configuration. You can also use the privatized email address provided by GitHub, like
12345678+jdoe@users.no-reply.github.com
which can be found in your email settings, but just make sure that it matches your local git config as well. - Enter a passphrase: As annoying as it may seem, this is crucial. If you don't set a passphrase, ANYONE can use the gpg key to sign things as though it was from you. This is all about chain of trust and if you can't establish non-repudiation, then there is no trust AND EVERYTHING WILL FALL INTO CHAOS! Seriously though, it's not THAT bad...just set a passphrase.
- Key algorithm: You can accept the default of
-
Congratulations, you have a gpg key. Now we need to get the keyid and the ASCII armored key so we can tell our provider du jour about it.
You need to copy the key ID from the output of the following, which in this example would be3XE290DWFIXQ8L1J
.$ gpg --list-secret-keys --keyid-format LONG /Users/jdoe/.gnupg/secring.gpg ---------------------------------------------- sec 4096R/3XE290DWFIXQ8L1J 2020-12-29 [expires: 2021-12-29] uid jdoe ssb 4096R/CTRNZTHH95IG5CSB 2020-12-29
-
Using the key ID that we just got, we need to export the key in ASCII armor format:
$ gpg --armor --export 3XE290DWFIXQ8L1J -----BEGIN PGP PUBLIC KEY BLOCK----- gibberish -----END PGP PUBLIC KEY BLOCK-----
Copy the key output, including the
-----BEGIN PGP PUBLIC KEY BLOCK-----
and-----END PGP PUBLIC KEY BLOCK-----
-
Paste the key output into your providers Add GPG Key interface
Hold your horses, we aren't done yet. Now, let's tell our local git repository to use the key
Configure git to use the key
You can do this globally for all repositories if you will use only one GPG key (i.e. only one email/git account/persona), or by repository. If you are doing this globally, you can skip step 1.
- In command line,
cd
into your git repository - Get your Key ID again, just like before. Again the Key ID in the example below would be
3XE290DWFIXQ8L1J
$ gpg --list-secret-keys --keyid-format LONG /Users/jdoe/.gnupg/secring.gpg ---------------------------------------------- sec 4096R/3XE290DWFIXQ8L1J 2020-12-29 [expires: 2021-12-29] uid jdoe ssb 4096R/CTRNZTHH95IG5CSB 2020-12-29
- Set your GPG signing key.
# For only the repository in the current directory $ git config user.signingkey 3XE290DWFIXQ8L1J # OR globally for all repositories. Can be overriden by repository specific config $ git config --global user.signingkey 3XE290DWFIXQ8L1J
- (OPTIONAL) If you want to sign all commits by default, you can configure it by repository or globally as well:
# Repository specific $ git config commit.gpgsign true # Global $ git config --global commit.gpgsign true
- Sometimes on windows, you may get a "gpg failed to sign data" message. Add the following to the end of your
~/.bashrc
file:$ export GPG_TTY=$(tty)
Now run your commit again, and it should prompt you for your GPG passphrase.
Conclusion
This should be it. Your workflow should look something like this:
- Make changes in local branch
- Stage changes using
git add
- Commit changes using
git commit -m 'message'
- Enter your GPG passphrase to sign the commits
- Push changes using
git push origin <branch>
- Enter your SSH key passphrase to push the commit
Once pushed, you should see that your commit is now reflected in the remote via the git web interface. You should also note that your commit features a verified committer a la pretty green checkmark or similar icon.
Hope you found this useful. Please let me know in the comments if you have any questions, or if this doesn't yield promised results. I wrote it from memory, not doing an actual walkthrough so cut me a bit of slack.
Dylan Jacob
Excepteur sint occaecat cupidatat non proident, sunt in cul deserunt mollitest dolor sit amet, consectetur adipi sed do eiusmod temp labore...
Related Posts You May Also Like
Upping your SSH game
Here is how I create my SSH keys, and why I do it the way I do. For a much more in depth and lengthy explanation, go to https://infosec.mozilla.org/guidelines/openssh.
Continue Reading