Last active 1729621908

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

matthew's Avatar matthew revised this gist 1729621908. Go to revision

No changes

matthew's Avatar matthew revised this gist 1729621888. 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