- Assuming you are on a mac and set up your SSH key as described in detail below:
ssh-keygen -o -a 100 -t ed25519 -f ~/.ssh/id_ed25519 -C gears@umich.edu -N ''
- Then you won't be prompted for a passphrase. However, if you did have a passphrase:
ssh-keygen -o -a 100 -t ed25519 -f ~/.ssh/id_ed25519 -C gears@umich.edu -N 'Really do not use this passphrase'
-
Then you will be prompted to type your passphrase every time you interact with git remote (pull, push, fetch, etc.) This is intolerable.
-
You can avoid typing your passphrase millions of times a day if you use the ssh-agent. ssh-agent is a helper program that keeps track of user's identity keys and their passphrases. The agent can then use the keys to log into other servers without having the user type in a password or passphrase again.
-
But you will need to add it to your keychain:
eval "$(ssh-agent -s)"
ssh-add -K ~/.ssh/id_ed25519
NOTE: I'm not totally clear on why adding a passphrase you never type is more secure then not having a passphrase if you're only using it for github. I guess so the private key cannot be stolen off of your encrypted hard disk and used on another machine? Seems unlikely, but whatevs.
.ssh/config
:
# later rules override earlier ones if they are more specific
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
# IdentityFile ~/.ssh/id_rsa # Keep any old insecure key files if you want?
Host github.com
User StevenACoffman
HostName github.com
IdentityFile ~/.ssh/id_ed25519
# IdentityFile ~/.ssh/id_rsa
StrictHostKeyChecking no
UseKeychain yes
AddKeysToAgent yes
UserKnownHostsFile=/dev/null
# NOTE:The IdentitiesOnly yes is required to prevent the SSH default behavior
# of sending the identity file matching the default filename for each protocol. If you have a file named
# ~/.ssh/id_rsa that will get tried BEFORE your ~/.ssh/id_rsa.github without this option.
The difference between signoff and gpg-sign are significant but subtle. Signoff doesn’t require the GPG key and is just the line: "Signed-off by" which will make the Developer Certificate of Origin bots stop bothering you.
Signing Git commits is important because in this age of malicious code and back doors, it helps protect you from an attacker who might otherwise inject malicious code into your codebase. It also helps discourage untrustworthy developers from adding their own back doors to the code, because once it's discovered, the bad code will be traced to them.
First thing to do is to install gpg + gpg2 and gpg-agent + pinentry-mac. The first two are for the main GPG actions (we need both for compatibility reasons) and the last two will be used for storing the GPG key passphrase in OS X’s keychain.
brew install gpg2 pinentry-mac
mkdir -p ~/.gnupg/
echo "pinentry-program $(brew --prefix pinentry-mac)/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
alias pinentry='pinentry-mac'
Test it with echo GETPIN | pinentry
and verify that it asks you for the PIN (really passphrase).
You may also want to install pinentry-touchid:
brew tap jorgelbg/tap
brew install pinentry-touchid
and then modify the ~/.gnupg/gpg-agent.conf
to point to `"$(brew --prefix pinentry-mac)/bin/pinentry-touchid"
Second, we have to generate a new GPG key if you don’t already have one. Make sure you have gpg2 version >= 2.1.21. You can start the wizard to generate a new key with the following command:
gpg2 --full-gen-key --expert
The wizard is going to ask you a few questions, here’s what I’d recommend:
- Select (10) ECC (sign only)
- Select (1) Curve 25519
- Answer remaining options with any response, but use a strong passphrase
- After the key is created record its fingerprint
- Copy the newly created key from GPG keychain: gpg --armor --export
- Go to github account > settings > GPG keys > paste the Ed25519 PGP public key from the previous step
- click "add key"
Now to configuring gpg-agent. This will prevents us from having to enter our key every time we want to encrypt, decrypt or sign something.
Note: Prior to GPG 2.1 where autostart became the norm (see https://www.gnupg.org/faq/whats-new-in-2.1.html#autostart) you would need to add to the shell.
In order to do so, add to following to your ~/.bash_profile file (or any other location that will be executed during shell startup)
[ -f ~/.gnupg/gpg-agent.env ] && source ~/.gnupg/gpg-agent.env
if [ -S "${GPG_AGENT_INFO%%:*}" ]; then
export GPG_AGENT_INFO
else
eval $(gpg-agent --daemon --log-file /tmp/gpg.log --write-env-file ~/.gnupg/gpg-agent.env --pinentry-program $(brew --prefix pinentry-mac))
fi
This will ensure that the gpg-agent is running when you open a shell, and will also configure your current shell to find it.
Next, open the file ~/.gnupg/gpg.conf
and uncomment the line where it says use-agent.
Now, everything on the GPG side is setup and we can test it with the following command. It will encrypt "hello world" for <recipient>
and then immediately decrypt it again.
$ echo hello world | gpg2 -e -r <identifier> | gpg2 -d
Replace <identifier>
with yourself - it will fuzzy match it against the name and email you have specified earlier when we’ve created the key. This will also open the pinentry program again: Enter your key, mark the checkbox Save in Keychain and confirm with OK
References:
find ./* $HOME -type d | xargs grep some_random_string > /dev/null
gpg2 --list-secret-keys --keyid-format LONG
gpg2 --armor --export YOUR_KEY_ID
YOUR_KEY_ID is the hash in front of sec
in previous command.
(for example sec 4096R/234FAA343232333 => key id is: 234FAA343232333)
git config --global user.signingkey your_key_id
git config --global commit.gpgsign true
git config --global gpg.program gpg2
git commit -S -s -a -m "Test a signed commit"
-s
,--signoff
: Add Signed-off-by line by the committer at the end of the commit log message. The meaning of a signoff depends on the project, but it typically certifies that committer has the rights to submit this work under the same license and agrees to a Developer Certificate of Origin (see http://developercertificate.org/ for more information).-S[<keyid>]
,--gpg-sign[=<keyid>]
: GPG-sign commits. The keyid argument is optional and defaults to the committer identity; if specified, it must be stuck to the option without a space.-a
,--all
: Tell the command to automatically stage files that have been modified and deleted, but new files you have not told Git about are not affected.-m <msg>
,--message=<msg>
: Use the given as the commit message. If multiple -m options are given, their values are concatenated as separate paragraphs. The -m option is mutually exclusive with -c, -C, and -F.
If you don't specify a message explicitly git -m "Something"
then the editor will get preloaded with a git template:
printf "\nSigned-off-by: Steven A Coffman <gears@umich.edu>\n" > ~/.gitmessage.txt
git config --global commit.template ~/.gitmessage.txt
This might still be useful for resolving merge conflicts, but git -s -m "Something" seems pretty easy to alias.