-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.qmd
176 lines (125 loc) · 9.06 KB
/
index.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
---
title: How to sign your commits
subtitle: Setting up gpg authentication while keeping separate work and personal projects
date: 2022-07-23
categories: [hacks, tutorial, security, github]
image: images/cover.png
toc: true
draft: false
github: <a href="https://github.com/SebastianoF/GeoDsBlog/blob/master/posts/bp-2022-07-23-gpg/index.qmd" target="_blank"> <img src="images/github.svg"> </a>
twitter-card:
image: images/cover.png
include-in-header: meta.html
---
![](images/cover.png)
This short blog post introduces the reader to the PGP key signatures, and suggests a way of signing commits with different accounts - e.g. personal and work settings - and to swap between them with a single CLI command.
### PGP minimal intro
A PGP key signature (Pretty Good Privacy) is a generic protocol that associates a *signature* to an encryption protocol, such as RSA, DSA or ElGamal. In this intro we will use RSA for git, but the method is generalisable for any protocol and remote git repository.
A *signature* consists of a *fingerprint* alongside with a username and user email that becomes part of the encription protocol to uniquely authenticate the author's encryption. The *fingerprint* is a "mini" public key that authenticates the author of an exchange of keys.
The owner of the signature will be able to sign files, documents, and in particular to sign commits via PGP protocol. In the normal workflow each time you are signing a document or git commit, the CLI will ask you for your *passphrase* to authenticate the author. As usual the passphrase can also be cached.
## Requirements
- You are familiar with git command line and gitlab / github interface.
- You installed the gpg[^1] command line interface ([Mac](https://formulae.brew.sh/formula/gnupg), [Linux](https://www.poftut.com/install-use-gpg-encrytion-linux-order-encrypt-decrypt-files-folder/) or [PowerShell - Windows](https://gwood.dev/blog/2021/10/gpg-tutorial-command-line/)).
[^1]: Note that `gpg` stands for Gnu Privacy Guard and implements the OpenPGP standard as defined by RFC4880. It is not the PGP protocol.
## Create and add a PGP key signature to github or gitlab
The procedure of creating and adding a PGP key signature is similar to the one to add an RSA key to your [github](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) or [gitlab](https://docs.gitlab.com/ee/ssh/) account. The difference is that instead of using the ssh-agent you will be using the gpg CLI, and you will be asked to pair the configurations of your PGP key with the RSA key.
1. Create a new RSA (read only) key-pair with fingerprint (PGP key signature) via gpg the CLI command
```bash
gpg --full-generate-key
```
The command above will bring you to a prompt asking you to input the kind of key that you want and its expiry period, followed by your email, username, and a passphrase. Recommended settings for a key to sign commits is `RSA (sign only)` followed by `4096` for the keysize (in the appendix of this article you can find some instructions to undo the key creation).
2. If you are using gitlab, please add the pgp public key to the page [https://gitlab.com/-/profile/gpg_keys](https://gitlab.com/-/profile/gpg_keys). If you are using github, go instead to use the page [https://github.com/settings/keys](https://github.com/settings/keys).
You can see the list of created key pairs with `pgp -k`, and you can export the public key to a file with `gpg --export -a "email@address.com" > public.key`, then copy the content of `public.key` to clipboard to export it to github/gitlab.
3. Now you have created your RSA key pair, and the pgp public key. The missing step is to tell git that it has to start using the created key to sign the commits. To achive this goal, change the user setting on the local machine with
```
git config --global user.email <same email used when creating the key-pair>
git config --global user.name <same username used when creating the key-pair>
git config --global user.signingkey <your fingerprint - copy paste from git(lab-hub) gpg page>
git config --global commit.gpgSign true
```
## Swap between work and personal profile
At this point you may also have the problem that I had: swapping between multiple gitub/gitlab profiles, for work, personal project, etc.
With the commands above I can create as many gpg keys with as many username and emails. To quickly tell git to swap between them, the solution that I suggest here is to create a bash script for each profile in the sub-folder `~/.git-accounts-settings/`:
```bash
# ~/.git-accounts-settings/company_A.sh
git config --global user.email <same email used when creating the key-pair>
git config --global user.name <same username used when creating the key-pair>
git config --global user.signingkey <your fingerprint - copy paste from gitlab gpg page>
git config --global commit.gpgSign true
```
```bash
# ~/.git-accounts-settings/company_B.sh
git config --global user.email <another email, same used when creating the key-pair>
git config --global user.name <another username used when creating the key-pair>
git config --global user.signingkey <your fingerprint - copy paste from gitlab gpg page>
git config --global commit.gpgSign true
```
```bash
# ~/.git-accounts-settings/personal.sh
git config --global user.email <personal email>
git config --global user.name <personal user>
git config --global commit.gpgSign false
```
Each time you want to swap across profiles, you can simply call the script with `bash ~/.git-accounts-settings/<my profile>.sh`.
And to quickly swap between them, the commands can be aliased with shorter variable names:
```bash
# in the .bashrc
alias set_git_config_company_A="bash ~/.git-accounts-settings/company_A.sh"
alias set_git_config_company_B="bash ~/.git-accounts-settings/company_B.sh"
alias set_git_config_personal="bash ~/.git-accounts-settings/personal.sh"
```
## Cache the passphrases
To avoid typing the passphrase each time a commit requires to be signed, it is possible to specify a caching duration the gpp agent config file, under `~/.gnupg/gpg-agent.conf`.
For caching the passphrase for 400 days, create the config file with these two lines, where 34560000 is 400 times the number of seconds in a day.
```bash
default-cache-ttl 34560000
maximum-cache-ttl 34560000
```
![key-and-nib](images/key_and_nib.png)
## Appendix 0: List created keys and delete some
To undo the key creation of step 1 you can retrieve the list of existing keys with `gpg -k`, hen copy the key public id to clipboard, that is a string like this dummy `43525435HJJH5K2H3KJHK3452KJH65NBMBV` in the output
```
pub ed25519 2022-02-18 [SC] [expires: 2024-02-18]
43525435HJJH5K2H3KJHK3452KJH65NBMBV
uid [ultimate] Sebastiano Ferraris <seb@email.com>
sub cv25519 2022-02-18 [E] [expires: 2024-02-18]
```
Finally delete public and private key with:
```
gpg --delete-secret-key 43525435HJJH5K2H3KJHK3452KJH65NBMBV
gpg --delete-key 43525435HJJH5K2H3KJHK3452KJH65NBMBV
```
## Appendix 1: Troubleshooting on mac
If git commit fails to authenticate the git commit, with the following error message
Then you have to redirect the `GPG_TTY` key to the local `tty` with:
```
export GPG_TTY=$(tty)
```
If this solves the problem, you will have to append it to your `.bashrc`.
## Appendix 2: Export public and private keys
How do I know my public key?
This command will export an ascii armored version of the public key:
```
gpg --output public.pgp --armor --export username@email
```
Also to export the secret key, there is a similar command:
```
gpg --output private.pgp --armor --export-secret-key username@email
```
## Appendix 3: Trigger gpg passphrase on linux
On some linux distributions, the prompt to insert the gpg passphrase [does not pop up](https://stackoverflow.com/questions/37763170/git-signed-commits-how-to-suppress-you-need-a-passphrase-to-unlock-the-secret) when you create a new commit. Git simply refuses to add a new non-signed commit.
So you will be in the situation where you have some code to commit, you know your passphrase, you have the gpg-agent on so you not need to retype the passphrase each time, but nobody is asking you for your passphrase when you are committing a message.
A workaround is to trigger gpg to ask you for your passphrase for another reason (e.g. signing a file), after which your passphrase is stored in the gpg-agent and you will be free to create signed commits, as the passphrase is automatically retrieved from cache. The list of commands would be:
```
git commit -am "new stuff" # this commit is not added and does not trigger the passphrase prompt
cd
touch z_tmp.txt # creating a dummy file to authenticate
gpg -s z_tmp.txt # this trigger the passphrase (and a y/n question to confirm your choice)
cd <repo you were working>
git commit -am "new stuff"
```
To turn this workaround into a oneliner, you can create the dummy file `z_tmp.txt` in the root directory (as above), and then add the following line to your bash profile:
```
alias gpg_trigger='gpg -s ~/z_tmp.txt'
```
So the next time, instead of running all the commands of the previous block, you can simply call the newly created alias `gpg_trigger`.