Last active 1 year ago

Notes from my journey to getting Yubikey to authenticate everything on my system.

matthew's Avatar matthew revised this gist 1 year ago. Go to revision

No changes

matthew's Avatar matthew revised this gist 1 year ago. Go to revision

1 file changed, 323 insertions

yubikey-all-the-things.md(file created)

@@ -0,0 +1,323 @@
1 + ## U2F for login and sudo access
2 +
3 + I followed this guide: https://support.yubico.com/hc/en-us/articles/360016649099-Ubuntu-Linux-Login-Guide-U2F
4 +
5 + For step 3, I only did the user-specific pamu2fcfg setup; I did not put it at the system level.
6 + This makes the `$HOME` partition portable, and allows different users on the system to require U2F and/or use different keys.
7 +
8 + > ## Challenge-Response auth with YubiKey
9 + >
10 + > When I originally purchased my key, and for four years thereafter, I used the challenge-response feature for restricting user authentication and sudo access.
11 + > I found with the update to Ubuntu 20.10, however, that challenge-respose no longer worked; even with a known, valid key, I could no longer login.
12 + > I'm retaining this information here for posterity, but will also note that there's a more up-to-date article covering this now maintained by Yubico: https://support.yubico.com/hc/en-us/articles/360016649079-Ubuntu-Linux-Login-Guide-Challenge-Response
13 + >
14 + > Started with https://developers.yubico.com/yubico-pam/Authentication_Using_Challenge-Response.html
15 + >
16 + > - Install yubikey-personalization
17 + > - Install libpam-yubico
18 + > - The instructions indicated that I'd get a question about the PAM
19 + > configuration line. I did not. As such, I had to run `dpkg-reconfigure
20 + > libpam-yubico` to do so. When I did, I used the value
21 + > `mode=challenge-response`. Additionally, this then gives the dialog
22 + > associated with `pam-auth-update`, and initially has `Yubico` selected. The
23 + > instructions are unclear at this point, and make it seem like you should
24 + > deselect everything; DO NOT DO THIS! Just deselect the Yubico entry.
25 + > - Set the appropriate yubikey mode: `sudo ykpersonalize -m86`.
26 + > - Mode 6 allows the yubikey 4 to act as each of OTP, U2F, and CCID.
27 + > - OTP allows it to be used as a one-time-password device with the yubicloud
28 + > as a replacement for things like google authenticator.
29 + > - U2F allows it to be used as a universal 2 factor auth device, which we
30 + > will be using with the challenge-response settings for PAM.
31 + > - CCID allows it to be used as a smartcard for usage with GPG.
32 + > - Mode 80 sets the `MODE_FLAG_EJECT` mode, which allows it to "eject" itself
33 + > and then "re-insert" itself when touched for an OTP. Combine it with the
34 + > above modes.
35 + > - Set slot 2 as a challenge-response slot:
36 + > `ykpersonalize -2 -ochal-resp -ochal-hmac -ohmac-lt64 -oserial-api-visible`
37 + > (This is also required for usage as a GPG smartcard)
38 + > - Create the challenge/response for your user:
39 + > - `mkdir $HOME/.yubico`
40 + > - `ykpamcfg -2 -v`
41 + > - Note: if you have an encrypted home directory, you MUST do this differently!
42 + > In that case:
43 + > - `sudo mkdir /var/yubico`
44 + > - `sudo chmod +t /var/yubico`
45 + > - `sudo chmod 777 /var/yubico`
46 + > - `ykpamcfg -2 -v -p /var/yubico`
47 + > - Update the PAM configuration.
48 + > - Edit `/etc/pam.d/common-auth`
49 + > - Check for the line: `auth required pam_yubico.so mode=challenge-response`;
50 + > if not present, create it.
51 + > - IF YOU HAVE AN ENCRYPTED HOME DIRECTORY, add the verbiage
52 + > `chalresp_path=/var/yubico` to the end of the line.
53 + > - Open a root terminal in your shell: `sudo -s` (This is a fail-safe, to
54 + > ensure that if any configuration is wrong, you can disable the yubico PAM
55 + > requirements.)
56 + > - In a separate terminal, run `sudo pam-auth-update`, and enable the Yubico
57 + > module.
58 + > - Test it. `Ctrl-Alt-F1` to get to the TTY.
59 + > - Remove your yubikey
60 + > - Attempt to login. It should fail.
61 + > - Insert your yubikey.
62 + > - Attempt to login. It should succeed.
63 + > - exit.
64 + > - `Alt-F7` to get back to your GUI. In fact, at this point, your GUI should
65 + > likely be at the lock screen, and you should find that you'll be unable to
66 + > unlock it without the yubikey inserted!
67 + >
68 + > ## Adding Yubikey as a sudo authentication mechanism
69 + >
70 + > I followed this guide: https://defensiveinfosec.wordpress.com/2013/07/09/adding-otp-wyubikey-to-ubuntu-13-04-to-sudo-or-login/
71 +
72 + ## PGP on Yubikey
73 +
74 + I tried three different approaches:
75 +
76 + - Upgrading my existing 1024bit DSA key to a 2048bit RSA key (see below)
77 + - https://www.esev.com/blog/post/2015-01-pgp-ssh-key-on-yubikey-neo/
78 + - https://www.preining.info/blog/2016/04/gnupg-subkeys-yubikey/
79 +
80 + None worked out-of-the-box.
81 +
82 + In the first case, I never successfully got the key updated. On further reading,
83 + I discovered (a) the instructions are out-of-date, and (b) using subkeys
84 + effectively solves the problem anyways. The latter two use that latter approach.
85 +
86 + With the latter two, I ran into issues with each.
87 +
88 + For the blog post from Eric Severance (www.esev.com), I ran into an issue only
89 + at the very end, when I'd do my `gpg --card-status`: there was no "general key
90 + info" listed, which meant I did not have a valid keychain.
91 +
92 + For the blog post from Norbert Preining (www.preining.info), I'd run into issues
93 + as soon as I issued `keytocard`, due to missing a secret key.
94 +
95 + What I discovered was this: the instructions from Norber Preining *did* work, if
96 + I generated the subkeys *using gpg2, and not gpg1*. Once I did that, everything
97 + fell into place.
98 +
99 + This means, of course, that I cannot use these for embedded systems, or when
100 + using GPG v1. I'm okay with that.
101 +
102 + ### Updating GIT
103 +
104 + Once you've got everything setup, it's time to tell Git to use your new signing
105 + key from your yubikey.
106 +
107 + If you run `gpg -K`, look for your signing key (it'll have `[S]` at the end of
108 + the key's listing, just prior to the expiration date). Grab the key ID, and now
109 + run:
110 +
111 + ```bash
112 + $ git config --global user.signingkey <key id>
113 + ```
114 +
115 + Also, since *I must use gpg2*, I had to update one other configuration, to tell
116 + git to use gpg2 when signing commits:
117 +
118 + ```bash
119 + $ git config --global gpg.program gpg2
120 + ```
121 +
122 + ### Using touch for authentication
123 +
124 + Instead of entering a GPG passphrase and/or the PIN associated with the yubikey,
125 + I wanted to be able to just *touch* the key instead. Why?
126 +
127 + - Simpler. I have enough passwords running through my head, and I don't want to
128 + have to remember them all.
129 + - More secure. The yubikey acts as an input device by default, which means that,
130 + technically, a keylogger could potentially sniff it. On top of that, a
131 + keylogger could sniff the PIN associated with it. While I may still need to
132 + enter the PIN for the first signing or encryption operation I performed, I can
133 + reduce the number of opportunities.
134 +
135 + I followed the [directions on the yubico site for enabling touch
136 + operations](https://developers.yubico.com/PGP/Card_edit.html). It worked
137 + flawlessly immediately; I ran it using:
138 +
139 + ```bash
140 + $ yubitouch.sh sig on
141 + $ yubitouch.sh aut on
142 + $ yubitouch.sh dec on
143 + ```
144 +
145 + I've put the script in `$HOME/bin/yubitouch.sh`, and kept it around.
146 +
147 + ### Updating the private (master) key and/or subkeys
148 +
149 + You may need to update the private (master) key and/or its subkeys from time to
150 + time:
151 +
152 + - to reset expiration
153 + - to update the user identity
154 +
155 + This turned out to be somewhate complicated, and, again, no one source I read
156 + worked for me, though this one [by Abel Luck and forked from Kenny
157 + MacDermid](https://gist.github.com/abeluck/3383449) came quite close.
158 +
159 + Essentially, you do the following:
160 +
161 + - Pull the data from your USB into a new folder locally, setting the folder
162 + permissions to 0700. Export a variable, GPGHOME, pointing to this directory.
163 + - `killall gpg-agent` (just to be on the safe side)
164 + - Edit the key, using `gpg --homedir $GPGHOME --edit-key <key>`
165 + - Make whatever changes you need. For example, to reset expiry:
166 + - Type `key <index>` to select a key.
167 + - Type `expire` and follow the prompts.
168 + - Type `key <index>` to deselect the key.
169 + - Repeat the previous steps for each expired key.
170 + - Type `save` to save the changes.
171 + - Export the secret key: `gpg --homedir $GPGHOME -a --export-secret-keys > $GPGHOME/master-secret-key.gpg`
172 + - Export the secret keys for the subkeys: `gpg --homedir $GPGHOME -a --export-secret-subkeys > $GPGHOME/sub-secret-keys.gpg`
173 + - Export the public key: `gpg --homedir $GPGHOME -a --export <key> > $GPGHOME/pub-key.gpg`
174 +
175 + If you follow along with the above link, you'll notice I'm not exporting the key
176 + *stubs*. I don't do this, because *it did not work for me*. When I would import
177 + them, they'd be imported as keys *missing their secrets*, but not as keys
178 + *on a device*.
179 +
180 + At this point, you have one of two options:
181 +
182 + - Import the public key into a new, empty `$HOME/.gnupg/` directory
183 + - Import the public key into the existing `$HOME/.gnupg/` directory
184 +
185 + I chose the first. To do this, I also had to first save my keyring, which can
186 + be in `$HOME/.gnupg/pubring.gpg`, but, starting in GPG 2.1, is in
187 + `$HOME/.gnupg/pubring.kbx`; I'll import that later.
188 +
189 + - `killall gpg-agent` (just to be on the safe side)
190 + - `mv $HOME/.gnupg $HOME/.gnupg.$(date +%Y%m%d)`
191 + - `mkdir -p $HOME/.gnupg`
192 + - `chmod 700 $HOME/.gnupg`
193 + - `gpg --import $GPGHOME/pub-key.gpg`
194 + - `gpg --import $GPGHOME/master-secret-key.gpg`
195 + - `gpg --import $GPGHOME/sub-secret-keys.gpg`
196 + - Import the keyring:
197 + - If you have a non-zero byte `pubring.gpg`: `gpg --import $HOME/.gnupg.$(date +%Y%m%d)/pubring.gpg`
198 + - For `pubring.kbx`: `gpg --keyring=$HOME/.gnupg.$(date +%Y%m%d)/pubring.kbx --export | gpg --import`
199 +
200 + At this point, we also need to mark the root key as trusted. Run
201 + `gpg --edit-key <key>`, type `trust`, and mark the key as "ultimately trusted".
202 + You should also do this for any UIDs present: `uid <num>` + `trust`, and mark as
203 + "ultimately trusted".
204 +
205 + Check to see if the yubikey has the keys properly marked, using `gpg --card-status`.
206 + You should see each of your keys with a "card-no: ..." entry; validate that the expiry is correct.
207 +
208 + If not, or if card-status doesn't show any keys, you will need to move the keys onto the yubikey again.
209 +
210 + - Kill any running gpg-agents (`killall gpg-agent`)
211 + - Run `gpg --edit-key <key>`
212 + - `toggle`
213 + - Select the first subkey to move
214 + - `keytocard`; select the appopriate key type, agree to overwrite, and go from
215 + there.
216 + - Deselect the key, and select the next one; wash, rinse, repeat.
217 + - `save`
218 +
219 + At this point, if you do `gpg --list-secret-keys`, you should see it correctly.
220 +
221 + Finally: whenever you re-add keys to the card, *you have to re-enable touch
222 + capabilities*. ~~Run the `$HOME/bin/yubitouch.sh` script to do this, running it
223 + once for each of the key types (sig, aut, dec).~~ Remove your card, and re-insert it;
224 + run `dmesg` to ensure you see it, and then run `ykman openpgp info` to verify that
225 + the `ykman` tool can see it. Then run `ykman openpgp keys set-touch dec on` and `ykman openpgp keys set-touch sig on`
226 + (which enables touch for de/encryption and signature, but keeps it off for authentication;
227 + this allows you to enter your admin PIN once per SSH agent session, instead of requiring
228 + a touch each time you connect).
229 +
230 + ### GitHub and signing keys
231 +
232 + So, now it's time to update GitHub. I had already associated my GPG key with the
233 + service, but found that new releases I signed with my *signing key* were not
234 + showing up as verified. This bothered me.
235 +
236 + So, I tried to export the signing key and upload it as an additional key on
237 + github. That failed; github complained that the key was already present.
238 +
239 + Deleting the existing key indicated that I'd lose all verification on other
240 + releases I'd made.
241 +
242 + In the end, I bit the bullet, and:
243 +
244 + - Deleted my existing key
245 + - Uploaded the contents of my pub-key.pgp
246 +
247 + Lo and behold, all my previous verified releases were still verified, and new
248 + releases were as well! Additionally, the GPG key listing showed all my subkeys,
249 + and all email addresses associated with the primary key.
250 +
251 + ### Using gpg-agent as an ssh-agent
252 +
253 + I did the following:
254 +
255 + - First, remove `ssh-agent` from any oh-my-zsh plugin lists you're using.
256 + - Second, `echo "enable-ssh-support" >> $HOME/.gnupg/gpg-agent.conf`
257 + - Third, add a `$HOME/.zsh/gpg-ssh-agent.zsh` script with the following contents:
258 + ```bash
259 + #!/usr/bin/zsh
260 + gpg-connect-agent /bye
261 + export SSH_AUTH_SOCK=$HOME/.gnupg/S.gpg-agent.ssh
262 + ```
263 + and, when done, `source` it in your `.zshrc`.
264 +
265 + Open a new terminal, `killall ssh-agent`, and run `ssh-add -l -E md5`; you
266 + should see your GPG authentication key now listed as a key. You can add your
267 + default SSH keys as well, using `ssh-add`; they'll be added to
268 + `$HOME/.gnupg/sshcontrol`; I chose not to, and instead used the results of `gpg
269 + --export-ssh-key <key>` to seed `authorized_keys` entries everywhere.
270 +
271 + The one issue I ran into was on AWS. I found I needed to ssh ANYWHERE else
272 + first, and, once I had, SSH to AWS worked fine.
273 +
274 + ### Convert DSA 1024 GPG key to RSA 2048
275 +
276 + I never got this to work; these are just my notes on what I tried.
277 +
278 + Followed instructions at: http://atom.smasher.org/gpg/gpg-migrate.txt
279 +
280 + First thing to remember: make sure you're using GPG v1 releases, and not v2, as
281 + it manipulates the secring.gpg and pubring.gpg. (I tried originally after first
282 + aliasing gpg to gpg2, which led me down an incorrect path.)
283 +
284 + My second try didn't work, either; in the end, I had the new key, but the
285 + original key was not attached as a subkey properly.
286 +
287 + Trying a third time... All goes well until I get to the step where the author
288 + notes "this last part makes no sense to me (but it doesn't seem to work
289 + otherwise)". When I get to this step, after removing the new key from the
290 + keyring, the *original* key disappears as well. Importing the exported secret
291 + and key imports the new key, but the *original* key is no longer listed as a
292 + subkey at that point; it's just completely gone.
293 +
294 + I tried creating and verifying signatures *before* that step, and this worked
295 + for the *new* key, but not the *original*; at that point, the original is not
296 + considered a valid secret signing key.
297 +
298 + One thing to note: when I listed the keys under the new key, the original, as a
299 + subkey, does not have any modes associated with it. I wonder if I need to toggle
300 + the capabilities somehow first?
301 +
302 + > ## Encrypted Disk Yubikey Challenge
303 + >
304 + > > I enabled disk encryption on two of my laptops, from 2017-2019.
305 + > > However, I found this was quite a bit of effort, and highly risky in the case where you have no backup key.
306 + > > I keep the instructions for posterity only.
307 + >
308 + > I have enabled disk encryption on two of my laptops. On Linux, the encryption
309 + > system is called luks, and there's a tool that will essentially allow you to
310 + > use the yubikey as the primary authentication mechanism.
311 + >
312 + > I followed the instructions in the blog post https://www.howtoforge.com/ubuntu-two-factor-authentication-with-yubikey-for-harddisk-encryption-with-luks
313 + > The first key difference, is that you no longer need a PPA in order to
314 + > install the yubikey-luks package; on 17.10, at least, it's "just there".
315 + > The second difference is that it does _not_ assume that `/dev/sda5` is the
316 + > encrypted partition, but instead `/dev/sda3`. You do not need to set any
317 + > environment variables, however; the `yubikey-luks-enroll` script now also accepts
318 + > a `-d` (for "device partition") argument, allowing you to specify it during
319 + > invocation:
320 + >
321 + > ```bash
322 + > $ sudo yubikey-luks-enroll -d /dev/sda5
323 + > ```
Newer Older