441 lines
14 KiB
Markdown
441 lines
14 KiB
Markdown
---
|
|
title: Yubikey for personal use
|
|
date: 2024-08-07T07:45:00+02:00
|
|
categories:
|
|
- yubikey
|
|
---
|
|
|
|
At work, we use SSH to connect to our infrastructure using
|
|
[PIV](https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html)
|
|
and a [Yubikey](https://www.yubico.com/) to comply with the PCI DSS standard.
|
|
I've seen a post from [Christian
|
|
Stankowic](https://chaos.social/@stdevel/112490125694988342) (aka "stdevel") on
|
|
Mastodon showing a Yubikey for personal use, so I decided to give it a try.
|
|
This blog post is the result of how I use a Yubikey outside of work.
|
|
|
|
![](/yubikey/picture.jpg)
|
|
|
|
Parts:
|
|
- [YubiKey 5 NFC (USB-A)](https://www.yubico.com/be/product/yubikey-5-nfc/)
|
|
- [Lanyard](https://www.yubico.com/be/product/yubico-keyport-parapull-lanyard/)
|
|
- [Double Rainbow Cover](https://www.yubico.com/be/product/yubistyle-covers-usb-a-c-nfc/)
|
|
|
|
|
|
I'm not paid to promote these products.
|
|
|
|
# Disclaimer
|
|
|
|
Modifying security keys may be dangerous. I cannot be responsible of any data
|
|
loss that may have been caused. Use the commands with caution.
|
|
|
|
# Requirements
|
|
|
|
I'm running on Ubuntu 24.04 (Noble Numbat) at the time of writing. The easiest
|
|
way to install Yubikey Manager to set up the Yubikey is to use the PPA.
|
|
|
|
```
|
|
sudo add-apt-repository ppa:yubico/stable
|
|
sudo apt-get update
|
|
sudo apt-get install yubikey-manager
|
|
ykman --version
|
|
```
|
|
|
|
If you have another system, please [follow the official
|
|
documentation](https://docs.yubico.com/software/yubikey/tools/ykman/).
|
|
|
|
# SSH with FIDO2
|
|
|
|
At home, I self-host multiple services from a [distributed file
|
|
storage](/socallinuxexpo2024.handout.html),
|
|
[finances](https://www.firefly-iii.org/) to my home lab. They run on various
|
|
hosts accessible via SSH. But instead of relying on PIV, like at work, I wanted
|
|
to try something more secure and supposed to be easy to use:
|
|
[FIDO2](https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html).
|
|
|
|
The components:
|
|
|
|
![](/yubikey/yubikey-ssh.png)
|
|
|
|
In short, it's a regular public and private key system, using [eliptic-curve
|
|
cryptography](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography)
|
|
("ECC"), but instead of storing the private key on on your client, an _access_
|
|
key (with "sk" suffix for "Security Key") is used to access the private key on
|
|
the Yubikey.
|
|
|
|
Like regular SSH keys, a **password** can protect the private key itself.
|
|
|
|
With FIDO2 on the Yubikey, there are two more security mechanisms to be aware
|
|
of:
|
|
- **PIN**: alphanumeric password, special chars allowed, that must be **at
|
|
least** 4 chars long
|
|
- **Touch**: security that requires you to touch the "Y" area of the Yubikey
|
|
with your finger to validate your physical presence
|
|
|
|
Note that the minimum version of OpenSSH with FIDO2 support is 8.2, which means
|
|
at least Debian 11. If you have older versions around, it's time to upgrade!
|
|
|
|
## PIN
|
|
|
|
By default, the FIDO PIN is not defined. You should generate a strong PIN from
|
|
a password manager like [KeepPassXC](https://keepassxc.org/).
|
|
|
|
```
|
|
read -s PIN
|
|
echo -ne $PIN | wc -c
|
|
ykman fido access change-pin --new-pin "${PIN}"
|
|
```
|
|
|
|
## SSH keys
|
|
|
|
The next step is to create a pair of SSH keys. This operation has to be
|
|
repeated for each client. The Yubikey is able to store multiple private keys.
|
|
One private key should not be re-used by multiple clients because that would
|
|
mean the _access_ key, which must stay private, on the client
|
|
(`~/.ssh/id_ed25519_sk`) used to unlock the private key on the Yubikey, has to
|
|
be moved around, which is a bad practice.
|
|
|
|
I've chosen the [Ed25519](https://en.wikipedia.org/wiki/EdDSA) algorithm
|
|
instead of
|
|
[ECSDA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)
|
|
because interoperability is not an issue for me, all my systems are up-to-date
|
|
and compatible. Both are strong options. Both are not
|
|
[RSA](https://en.wikipedia.org/wiki/RSA_(cryptosystem)).
|
|
|
|
```
|
|
ssh-keygen -t ed25519-sk -O resident -O verify-required \
|
|
-O "application=ssh:$(hostname -f)" \
|
|
-C "$(hostname -f)"
|
|
```
|
|
|
|
Enter the **PIN**, **touch** the Yubikey then set a **password** to protect the
|
|
SSH key.
|
|
|
|
Finally copy the public key to the remote hosts (file
|
|
`~/.ssh/id_ed25519_sk.pub`).
|
|
|
|
## SSH agent
|
|
|
|
The main problem is that we need to pass 3 security tests for every single SSH
|
|
connection:
|
|
|
|
1. Enter the password of the SSH key
|
|
1. Enter the FIDO2 PIN of the Yubikey
|
|
1. Touch the Yubikey
|
|
|
|
I know this is security but it's not very user-friendly. So I've tried to use
|
|
an SSH agent to "cache" the private key for a limited amount of time, like I do
|
|
for regular keys and even with PIV.
|
|
|
|
Let's try to add the identities to the agent:
|
|
|
|
```
|
|
$ ssh-add -K
|
|
Enter PIN for authenticator:
|
|
Resident identity added: ED25519-SK SHA256:***
|
|
$ ssh-add -l
|
|
256 SHA256:*** (ED25519-SK)
|
|
```
|
|
|
|
Then connect:
|
|
|
|
```
|
|
$ pilote
|
|
sign_and_send_pubkey: signing failed for ED25519-SK "/home/jriou/.ssh/id_ed25519_sk" from agent: agent refused operation
|
|
```
|
|
|
|
Unfortunately, the SSH agent doesn't seem to load the FIDO keys properly. To
|
|
fix this issue, you can disable the agent in file `~/.ssh/config`:
|
|
|
|
```
|
|
Host *
|
|
IdentityAgent none
|
|
```
|
|
|
|
You still need to pass the 3 security checks but, at least, you can connect.
|
|
|
|
I use [Ansible](https://github.com/ansible/ansible) to manage most of my
|
|
personal infrastructure. With FIDO2, you can multiply the number of security
|
|
checks by the number of managed host. This is a nightmare. Unfortunately, I've
|
|
chosen to create a regular ed25519 key pair and use it only for Ansible from
|
|
one host that will never leave my secure house.
|
|
|
|
# FIDO U2F to replace OTPs
|
|
|
|
This [open authentication
|
|
standard](https://www.yubico.com/authentication-standards/fido-u2f-standard/)
|
|
enables you add an additional security check based on a hardware key, to log on
|
|
a website for example. Traditionally, you have to enter your user name and your
|
|
password. You can add [two-factor
|
|
authentication](https://en.wikipedia.org/wiki/Multi-factor_authentication) with
|
|
an application generating one-time passwords ("OTP"). They are generated for a
|
|
limited amount of time. I have way too many OTPs registered in my
|
|
[FreeOTP](https://freeotp.github.io/) application. FIDO U2F is a way to replace
|
|
your OTP by touching your Yubikey. As simple as that.
|
|
|
|
It's supported by plenty of platforms including (but not limited) Mastodon,
|
|
Github and Linkedin. The workflow to setup a hardware key goes often like this:
|
|
|
|
1. Go to Settings / Security or Account
|
|
1. Look for 2FA or MFA
|
|
1. Setup OTP (even if you won't use it)
|
|
1. Search for hardware key
|
|
1. Enter the FIDO PIN
|
|
1. Touch the Yubikey
|
|
|
|
The interface will be different for each platform but the workflow should be
|
|
the same.
|
|
|
|
# PGP
|
|
|
|
Nowadays, communication systems provide transparent [end-to-end
|
|
encryption](https://en.wikipedia.org/wiki/End-to-end_encryption). But it's not
|
|
always enabled by default (I see you [Telegram](https://telegram.org/)). Do you
|
|
trust those providers claiming they are not able to decrypt your messages?
|
|
Where are my keys? Can I bring my own? _It's encrypted, trust me bro_.
|
|
|
|
Technically, Pretty Good Privacy ("PGP") solves this issue. I can generate my
|
|
own set of keys to encrypt or authenticate data using public key cryptography.
|
|
[ECC](https://www.rfc-editor.org/rfc/rfc6637) is supported. The **private key**
|
|
can be protected by the **Yubikey**.
|
|
|
|
The only problem is to find people like me, believing in privacy, able to use
|
|
PGP to encrypt communications. In our daily lives, we talk mostly to
|
|
non-technical people that don't know a word about how cryptography works or
|
|
even how computers work. E-mails are less and less used. Which means I don't
|
|
use PGP to encrypt my messages very often, except at work.
|
|
|
|
Another usage of PGP is to encrypt **sensible files**. In that case, storing
|
|
the private key on a Yubikey is a good way to make it more secure. But at the
|
|
same time, if you loose the key, you will never be able to decrypt the original
|
|
files. You can still export the private key and store it somewhere secure. But
|
|
how secure is it? Here it comes the endless loop of paranoia to encrypt the key
|
|
of the key of the key of the... You get it. I've chosen to protect the exported
|
|
private key by a password stored on my password manager which has its own
|
|
password that I know in my head. The security stops if I forget the password
|
|
manager's password, and it's ok.
|
|
|
|
I also use PGP to **sign my git commits**.
|
|
|
|
## Access
|
|
|
|
There are two differents PINs for the PGP application on the Yubikey:
|
|
- **Admin PIN**: to unlock PGP administration commands
|
|
- **PIN**: to unlock the PGP private key
|
|
|
|
The PIN is specific to the PGP application. If you have already set up a FIDO
|
|
PIN, please chose a different one for PGP.
|
|
|
|
Unlike FIDO, default PINs are set from factory. Run the "reset" operation only
|
|
if you don't know the current PIN. Be careful, this is a **destructive**
|
|
operation. Any existing PGP key will be removed.
|
|
|
|
```
|
|
ykman openpgp reset
|
|
```
|
|
|
|
Change the Admin PIN:
|
|
|
|
```
|
|
ykman openpgp access change-admin-pin --admin-pin 12345678
|
|
```
|
|
|
|
Change the PIN:
|
|
|
|
```
|
|
ykman openpgp access change-pin --pin 123456
|
|
```
|
|
|
|
## Generate key
|
|
|
|
Let's generate the key pair locally, then move the private key to the Yubikey
|
|
afterwards.
|
|
|
|
```
|
|
gpg --expert --full-gen-key
|
|
Please select what kind of key you want:
|
|
(9) ECC (sign and encrypt) *default*
|
|
Your selection? 9
|
|
Please select which elliptic curve you want:
|
|
(1) Curve 25519 *default*
|
|
Your selection? 1
|
|
Please specify how long the key should be valid.
|
|
Key is valid for? (0) 1y
|
|
Is this correct? (y/N) y
|
|
```
|
|
|
|
Enter real name, e-mail address and eventually a comment.
|
|
|
|
Validate:
|
|
```
|
|
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
|
|
```
|
|
|
|
Then move key to the Yubikey:
|
|
|
|
```
|
|
gpg --edit-key 0x1234
|
|
gpg> keytocard
|
|
```
|
|
|
|
Enter the **PGP password**, the one to protect the private key itself, then the
|
|
**Admin PIN** to store it on the Yubikey.
|
|
|
|
## Publish to keyserver
|
|
|
|
How to discover public keys from other people?
|
|
|
|
1. Participate to a [key signing
|
|
party](https://en.wikipedia.org/wiki/Key_signing_party) (at
|
|
[FOSDEM](https://fosdem.org) for example)
|
|
1. Use a **keyserver**, because we cannot meet everybody in person
|
|
|
|
The [keys.openpgp.org](https://keys.openpgp.org/) server seems to be a popular
|
|
option to publish your public key. It verifies your identity by sending an
|
|
e-mail to every PGP identity (= e-mail) included in the published key.
|
|
|
|
```
|
|
gpg --export 0x1234 | curl -T - https://keys.openpgp.org
|
|
```
|
|
|
|
## Info on the card
|
|
|
|
The gpg binary enables you to store more information like your full name and
|
|
the URL of your public key, directly on the Yubikey. Feel free to set them up
|
|
or not. Anyone grabbing your Yubikey will be able to retreive such information.
|
|
|
|
```
|
|
gpg --card-edit
|
|
gpg/card> admin
|
|
gpg/card> name
|
|
```
|
|
|
|
Enter your **last** name, **first** name, then the Admin PIN to save the
|
|
modification.
|
|
|
|
For the URL:
|
|
```
|
|
gpg/card> url
|
|
```
|
|
|
|
Enter the public key URL (ex:
|
|
`https://keys.openpgp.org/vks/v1/by-fingerprint/1234`), then the Admin PIN to
|
|
save the modification.
|
|
|
|
Verify:
|
|
|
|
```
|
|
gpg --card-status
|
|
```
|
|
|
|
This commands tells you if your Yubikey has been detected by the gpg
|
|
application by showing the card details. Sometimes, you could have the
|
|
following error:
|
|
|
|
```
|
|
gpg: OpenPGP card not available: General error
|
|
```
|
|
|
|
In that case, you should unplug then plug your Yubikey.
|
|
|
|
<p style="text-align: center">
|
|
<img
|
|
src="/yubikey/the-it-crowd-meme.jpg"
|
|
alt="The IT Crowd (TV show) meme saying 'Have you tried to turning it off and on again?'"
|
|
/>
|
|
</p>
|
|
|
|
## Renew an expired key
|
|
|
|
It's important to set an expiration duration because if you lose control over
|
|
your key, it will expire automatically. I've performed this
|
|
[operation](https://superuser.com/questions/813421/can-you-extend-the-expiration-date-of-an-already-expired-gpg-key/1141251#1141251)
|
|
a couple of times over the years.
|
|
|
|
Edit the main key:
|
|
|
|
```
|
|
gpg --edit-key 0x1234
|
|
gpg> expire
|
|
Key is valid for? (0) 1y
|
|
Is this correct? (y/N) y
|
|
```
|
|
|
|
Enter the PIN to unlock the Yubikey.
|
|
|
|
Then edit the sub key:
|
|
|
|
```
|
|
gpg> key 1
|
|
gpg> expire
|
|
Key is valid for? (0) 1y
|
|
Is this correct? (y/N) y
|
|
```
|
|
|
|
Enter the PIN to unlock the Yubikey.
|
|
|
|
Save and publish:
|
|
|
|
```
|
|
gpg> save
|
|
gpg --keyserver keys.openpgp.org --send-keys 0x1234
|
|
```
|
|
|
|
This doesn't prevent from compromision. In that case, you should [revoke the
|
|
key](https://superuser.com/questions/1526283/how-to-revoke-a-gpg-key-and-upload-in-gpg-server).
|
|
|
|
## Sign git commits
|
|
|
|
[Git](https://git-scm.com/) is a very popular [version
|
|
control](https://en.wikipedia.org/wiki/Version_control) software used by
|
|
open-source projects to distribute code and accept contributions. Show the
|
|
world that you own your git commits! With PGP, you can sign your commits so
|
|
everybody can verify that you are effectively the one and true author of the
|
|
commit, or your private key has been compromised but that's another topic.
|
|
|
|
File `~/.gitconfig`:
|
|
|
|
```
|
|
[user]
|
|
email = first@name.email
|
|
name = First Name
|
|
signingkey = 0x1234
|
|
```
|
|
|
|
Every time you will try to commit a change using git, you will have to unlock
|
|
your PGP private key on the Yubikey by entering the PIN.
|
|
|
|
Finally, add your public key to your [Github
|
|
account](https://docs.github.com/en/authentication/managing-commit-signature-verification/adding-a-gpg-key-to-your-github-account)
|
|
so everyone will see the check mark on your commits.
|
|
|
|
<p style="text-align: center">
|
|
<img
|
|
src="/yubikey/github-signed-commit.png"
|
|
alt="Screenshot from Github with 'jouir committed 2 weeks ago' + 'Verified'"
|
|
/>
|
|
</p>
|
|
|
|
# Sudo
|
|
|
|
The Yubikey can be used to secure [sudo](https://en.wikipedia.org/wiki/Sudo),
|
|
the software used to execute commands with root privileges. You can decide to
|
|
**replace** your password by a touch on the Yubikey ("passwordless"), or
|
|
**add** a touch on the Yubikey after the password ("2FA"). [This blog
|
|
post](https://dev.to/bashbunni/set-up-yubikey-for-passwordless-sudo-authentication-4h5o)
|
|
describes the procedure to do both.
|
|
|
|
I've tried to setup a **passwordless** authentication for sudo but I'm still
|
|
asked for my password from time to time. And when the Yubikey requires to be
|
|
touched, sudo doesn't print any instruction on the terminal, the Yubikey starts
|
|
to blink. The sudo command is not stuck, you just have to touch the Yubikey.
|
|
|
|
# Conclusion
|
|
|
|
Is my digital life more secure now? Yes, probably. But security comes at a
|
|
cost. The cost of entering two passwords and touch the Yubikey for **every
|
|
single SSH connection** (maybe using SSH with PIV is easier after all). The
|
|
cost of encrypting messages with PGP to non tech-savvy people. The cost of
|
|
monitoring the expiration date of your PGP keys. The cost of the Yubikey
|
|
itself. On the bright side, replacing vicious OTPs that regenerate too quickly
|
|
by a simple touch is very nice! Same for sudo. In the end, it was a fun project
|
|
and that's what matters.
|