OS: Debian Stretch
In my previous post here, I went through the process of creating 2048 bit LUKS keys with
openssl and keeping them encrypted with a symmetric GPG key. While this process works, it creates another threat vector for the security of the private GPG key and could be even better designed. So, let's change that.
I have an extra Yubikey 3 Neo so I'm going to use that here, however, with a Yubikey 4 you'd be able to generate a 4096 bit GPG key instead of the 2048 bit key I use below. Perhaps one day I'll upgrade it, but for now, let's proceed.
- Insert Yubikey into server with the LUKS keys/drives.
server1# lsusb ... Bus 001 Device 005: ID 1050:0114 Yubico.com Yubikey NEO(-N) OTP+U2F ...
- Install the
ykpersonalizetool and GPG dependancies
server1# aptitude install yubikey-personalization gnupg2 pcscd scdaemon
- Configure the Yubikey for
HID & CCID (OTP and OpenPGP) EJECT Flag set – allows SmartCard and OTP concurrently.See https://www.yubico.com/2012/12/yubikey-neo-composite-device/ for more information on the various modes. This is the mode I use, as having the OTP enabled is still useful. You can chose your own mode that works for your setup. Just ensure that the OpenPGP applet is enabled for that mode.
Server1# ykpersonalize -m86 Firmware version 3.4.3 Touch level 1285 Program sequence 1 The USB mode will be set to: 0x86 Commit? (y/n) [n]: y
- Unplug and plug back in the Yubikey. This is required because, we connected it prior to the
ykpersonalizetool being installed leading to the proper
udevrule not being configured. You should see the following:
server1% gpg --card-status gpg: detected reader Yubico Yubikey NEO OTP+U2F+CCID 00 00' # Followed by information about the Yubikey
Nuke all the datas! Just in case there's anything left over (I had some cruft) follow https://developers.yubico.com/ykneo-openpgp/ResetApplet.html to wipe the OpenGPG app on the Yubikey completely.
Confirm the version of the OpenGPG applet on the the card.
server1# gpg-connect-agent --hex "scd apdu 00 f1 00 00" /bye D 01 00 10 90 00 ..... OK
This means that applet is v1.0.10. Yay not affected by https://developers.yubico.com/ykneo-openpgp/SecurityAdvisory 2015-04-14.html so, continuing on.
- Setup gpg config at
~/.gnupg/gpg.conf. All of these settings are not required but, are what I use as defaults and seem to make sense to me. Feel free to modify to suit your needs.
use-agent personal-cipher-preferences AES256 AES192 AES CAST5 personal-digest-preferences SHA512 SHA384 SHA256 SHA224 default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed cert-digest-algo SHA512 s2k-digest-algo SHA512 charset utf-8 fixed-list-mode no-comments no-emit-version keyid-format 0xlong list-options show-uid-validity verify-options show-uid-validity with-fingerprint
- Reset the Yubikey's admin and user pins
server1# gpg2 --card-edit gpg/card> admin Admin commands are allowed gpg/card> passwd gpg: OpenPGP card no. D2760001240102000006037107190000 detected 1 - change PIN 2 - unblock PIN 3 - change Admin PIN 4 - set the Reset Code Q - quit Your selection? 3 # Default Admin Password: 12345678 PIN changed. 1 - change PIN 2 - unblock PIN 3 - change Admin PIN 4 - set the Reset Code Q - quit Your selection? 1 # Default User Password: 123456 PIN changed. # Optionally set a Reset Code
- Let's generate the master GPG key.
This key will simply be for creating sub-GPG keys which will be the ones actually used for encryption. Notice here, that we are generating the key directly on the Yubikey device. This isn't required, as you could generate the keys offline on a secure device, and then copy only the subkeys to the Yubikey. This way, you could also backup and recover your GPG keys if you lost the Yubikey. Personally, I do not want these keys anywhere but stored physically on this device.
gpg/card> generate Make off-card backup of encryption key? (Y/n) n Please specify how long the key should be valid. 0 = key does not expire <n> = key expires in n days <n>w = key expires in n weeks <n>m = key expires in n months <n>y = key expires in n years Key is valid for? (0) 1y Key expires at Mon 19 Jun 2017 08:17:51 AM CDT Is this correct? (y/N) y GnuPG needs to construct a user ID to identify your key. Real name: Server1 Email address: email@example.com Comment: You selected this USER-ID: "Server1 <firstname.lastname@example.org>" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O gpg: /root/.gnupg/trustdb.gpg: trustdb created gpg: key 0x1234567891011 marked as ultimately trusted gpg: directory '/root/.gnupg/openpgp-revocs.d' created gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/1234567891011ABCDEFGHIJKLMNOP.rev' public and secret key created and signed. gpg: checking the trustdb gpg: marginals needed: 3 completes needed: 1 trust model: PGP gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u gpg: next trustdb check due at 2017-06-19
- Now, let's verify the master GPG key was created on the card, and take a look at it's setup.
gpg/card> list Reader ...........: 1234:1234:X:0 Application ID ...: D1231234567892000006037101230000 Version ..........: 2.0 Manufacturer .....: Yubico Serial number ....: <snip> Name of cardholder: Server1 TechsMix Networks Language prefs ...: [not set] Sex ..............: unspecified URL of public key : [not set] Login data .......: [not set] Signature PIN ....: forced Key attributes ...: rsa2048 rsa2048 rsa2048 Max. PIN lengths .: 127 127 127 PIN retry counter : 3 3 3 Signature counter : 4 Signature key ....: 03B3 1234 1234 3F2E 1511 9FA7 1234 E96B 1234 BC92 created ....: 2016-06-19 13:18:46 Encryption key....: 7B2F 1234 9DFD 4567 9A1D D717 5432 75DB 1234 7129 created ....: 2016-06-19 13:18:46 Authentication key: 1234 C817 945C EADF F0F1 ABCD FA33 98F7 1234 86BA created ....: 2016-06-19 13:18:46 General key info..: pub rsa2048/0xABE7E96123456789 2016-06-19 Server1 < email@example.com> sec> rsa2048/0xA3EABCDEF7123456 created: 2016-06-19 expires: 2017-06-19 card-no: 0006 12312312 ssb> rsa2048/0xABCDEFCD1F86196A created: 2016-06-19 expires: 2017-06-19 card-no: 0006 12312312 ssb> rsa2048/0x2283ABC654327129 created: 2016-06-19 expires: 2017-06-19 card-no: 0006 12312312
root@Balerion:~# gpg2 --list-keys /root/.gnupg/pubring.gpg ------------------------ pub rsa2048/0xABE7E96123456789 2016-06-19 [SC] [expires: 2017-06-19] Key fingerprint = 7B2F 1234 9DFD 4567 9A1D D717 5432 75DB 1234 7129 uid [ultimate] Server1 < firstname.lastname@example.org> sub rsa2048/0xA3EABCDEF7123456 2016-06-19 [A] [expires: 2017-06-19] sub rsa2048/0xABCDEFCD1F86196A 2016-06-19 [E] [expires: 2017-06-19] sub rsa2048/0x2283ABC654327129 2016-06-19 [S] [expires: 2017-06-19]
- As we confirmed above, the Yubikey now has the Master GPG key and that GPG key is ultimately trusted locally. Now, this next part is optional but, let's create 3 unique sub-keys off this master key and set them to be used for Authentication, Encryption, and Signing individually.
It's been a long time since I've had to do this. I will edit this section once I've re-tested and confirmed the command sequence. https://github.com/drduh/YubiKey-Guide#create-subkeys looks like be nearly exactly what I remember following.
- Whew, alright, that was most of the hard work. At this point, all that's left is to convert the existing, GPG encrypted, 2048 bit LUKS encryption keys to be encrypted with the Encryption sub-key and while we're at it, signed each key with the Signing Subkey.
I wrote and use https://github.com/jaredledvina/array-scripts/blob/master/array-key-rotate.sh to do the magic.
- Finally, we can test the process by rebooting the server (or unmounting and manually closing the LUKS volumes for each drive) and run the following:
https://github.com/jaredledvina/array-scripts/blob/master/array-unlock.sh is great and handles looking up the keys by drive UUID and decrypted the keyfile and finally tries to open the LUKS device.
There we have it, unique 2048 bit LUKS keys, now encrypted and signed with GPG sub-keys that have and only exist physically on the Yubikey 3. The Yubikey from here on out, will need to be physically attached to the server, and when accessed, unlocked with the User pin. This allows us to have much greater confidence that the private GPG key is secured on a physical medium which could be destroyed with a small script like the following if need be:
#!/bin/bash echo "Performing emergency wipe of Yubikey" /usr/bin/gpg-connect-agent -r /root/kill-yubikey for drive in $(lsblk -dlnp --output NAME) do echo "Performing emergency wipe of drive: $drive" /sbin/cryptsetup luksErase $drive done echo "Forcing emergency shutdown procedure now" /sbin/shutdown --no-wall now
kill-yubikey file is:
/hex scd serialno scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40 scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40 scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40 scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40 scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40 scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40 scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40 scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40 scd apdu 00 e6 00 00 scd apdu 00 44 00 00 /echo Yubikey has been successfully wiped.