Er is een moment waarop alles klikt. Je plugt je YubiKey in, typt je PIN één keer, en daarna werkt gewoon alles. SSH naar servers? Geen wachtwoord. Git commits signen? Automatisch. Wachtwoord uit pass halen? Touch de key en klaar.

Dat moment duurde bij mij ongeveer drie avonden van frustratie om te bereiken. Maar nu het werkt, wil ik nooit meer terug.

Waarom Deze Setup?

Ik had een probleem: te veel authenticatiemethoden.

  • SSH keys op disk (encrypted, maar toch)
  • GPG keys voor git signing (andere key, andere passphrase)
  • pass voor wachtwoorden (weer die GPG key, weer die passphrase)
  • 2FA codes in een authenticator app (telefoon pakken, code overtypen)

Elke keer dat ik iets wilde doen, moest ik een wachtwoord typen of mijn telefoon pakken. Dat is frictie. En frictie betekent dat ik security shortcuts ga nemen.

De oplossing: één YubiKey die alles doet.

Wat is de Stack?

Even de componenten:

ToolFunctie
YubiKeyHardware security key met smartcard functionaliteit
GPGEncryption en signing
passCLI password manager (gebruikt GPG)
gpg-agentAgent die GPG keys cached en SSH auth doet
SSHJe weet wat SSH is

De magie zit in gpg-agent. Die kan namelijk ook als SSH agent fungeren. Dus je GPG key op je YubiKey wordt ook je SSH key.

De Setup

1. GPG Key op YubiKey Zetten

Je hebt een GPG key nodig met drie subkeys:

  • Sign (voor git commits)
  • Encrypt (voor pass)
  • Authenticate (voor SSH)

Als je al een GPG key hebt, kun je subkeys toevoegen. Anders maak je een nieuwe.

# Nieuwe key genereren (of bestaande gebruiken)
gpg --full-generate-key

# Subkeys toevoegen
gpg --edit-key <KEY_ID>
gpg> addkey  # Sign
gpg> addkey  # Encrypt
gpg> addkey  # Authenticate (kies "set your own capabilities")
gpg> save

Nu de keys naar de YubiKey verplaatsen:

gpg --edit-key <KEY_ID>
gpg> key 1
gpg> keytocard  # Kies slot voor signing
gpg> key 1
gpg> key 2
gpg> keytocard  # Kies slot voor encryption
gpg> key 2
gpg> key 3
gpg> keytocard  # Kies slot voor authentication
gpg> save

Let op: keytocard verplaatst de key, niet kopieert. Maak eerst een backup van je .gnupg directory.

2. GPG-Agent Configureren

Dit is waar de magie gebeurt. Edit ~/.gnupg/gpg-agent.conf:

# Cache timeout (in seconden)
default-cache-ttl 600
max-cache-ttl 7200

# SSH support aanzetten
enable-ssh-support

# Pinentry programma (voor PIN invoer)
pinentry-program /usr/bin/pinentry-gnome3
# Of voor terminal: /usr/bin/pinentry-curses
# Of voor macOS: /usr/local/bin/pinentry-mac

En in je ~/.bashrc of ~/.zshrc:

# GPG agent als SSH agent gebruiken
export GPG_TTY=$(tty)
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)

# Agent herstarten als nodig
gpgconf --launch gpg-agent

Herstart je shell of source het bestand:

source ~/.zshrc

3. SSH Key Exporteren

Je GPG authentication key is nu ook je SSH key. Exporteer de public key:

# SSH public key van je GPG key
gpg --export-ssh-key <KEY_ID>

Voeg deze toe aan ~/.ssh/authorized_keys op je servers, of aan GitHub/GitLab.

Check of het werkt:

ssh-add -L
# Toont je GPG key als SSH key

4. Pass Configureren

pass is simpel - het encrypt wachtwoorden met GPG.

# Initialiseer pass met je GPG key
pass init <KEY_ID>

# Of met meerdere keys (handig voor backup)
pass init <KEY_ID_1> <KEY_ID_2>

Wachtwoorden toevoegen:

# Nieuw wachtwoord
pass insert servers/prod-db

# Genereer random wachtwoord
pass generate -n 32 servers/api-key

# Bekijk wachtwoord (vraagt om YubiKey touch)
pass servers/prod-db

5. Git Signing

Git commits signen met je GPG key:

git config --global user.signingkey <KEY_ID>
git config --global commit.gpgsign true
git config --global tag.gpgsign true

Elke commit vraagt nu om een YubiKey touch. Geen extra wachtwoord, gewoon een fysieke bevestiging.

De Dagelijkse Workflow

Dit is hoe mijn dag eruitziet:

# Ochtend: plug YubiKey in, typ PIN één keer
gpg --card-status  # Triggert PIN prompt

# SSH naar server - geen wachtwoord
ssh prod-server

# Wachtwoord pakken - touch de key
pass show infra/grafana | head -1

# Git commit - touch de key
git commit -m "Fix critical bug"

# Alles werkt, YubiKey blijft in USB

Na die eerste PIN blijft alles werken tot de cache timeout (600 seconden standaard voor PIN, onbeperkt voor touch).

Handige Aliassen

# Snelle pass lookup met fzf
alias p='pass show $(find ~/.password-store -name "*.gpg" | sed "s|$HOME/.password-store/||;s|\.gpg$||" | fzf)'

# Kopieer wachtwoord naar clipboard
alias pc='pass show -c $(find ~/.password-store -name "*.gpg" | sed "s|$HOME/.password-store/||;s|\.gpg$||" | fzf)'

# YubiKey status
alias yk='gpg --card-status'

# SSH keys tonen
alias sshkeys='ssh-add -L'

Touch Policy

YubiKey heeft verschillende touch policies:

PolicyBetekenis
OffGeen touch nodig
OnTouch voor elke operatie
FixedTouch nodig, niet te wijzigen
CachedTouch geldig voor X seconden

Ik gebruik “On” voor signing en authentication. Elke git commit en SSH login vereist een fysieke touch. Dat is bewust - ik wil weten wanneer mijn key gebruikt wordt.

# Touch policy instellen via ykman
ykman openpgp keys set-touch sig on
ykman openpgp keys set-touch aut on
ykman openpgp keys set-touch enc on

Backup Strategie

Je YubiKey kan kapot gaan of kwijtraken. Plan daarvoor:

  1. Backup YubiKey: Zet dezelfde keys op een tweede YubiKey, bewaar die veilig
  2. Paper backup: Print je master key en bewaar die offline
  3. Revocation certificate: Genereer en bewaar dit apart
# Revocation certificate genereren
gpg --gen-revoke <KEY_ID> > revoke.asc
# Bewaar dit veilig, apart van je key backup

Voor pass kun je de hele store syncen met git:

cd ~/.password-store
git init
git remote add origin git@github.com:user/pass-store-private.git
git push -u origin main

De wachtwoorden zijn encrypted, dus zelfs als de repo lekt zijn ze nutteloos zonder je GPG key.

Troubleshooting

“No secret key”

# Check of YubiKey zichtbaar is
gpg --card-status

# Niet zichtbaar? Check USB
lsusb | grep -i yubi

# GPG weet niet waar de key is? Refresh
gpg-connect-agent "scd serialno" "learn --force" /bye

SSH werkt niet

# Check of gpg-agent als SSH agent draait
echo $SSH_AUTH_SOCK
# Moet iets zijn als: /run/user/1000/gnupg/S.gpg-agent.ssh

# Keys laden
ssh-add -L
# Moet je GPG key tonen

# Niet? Agent herstarten
gpgconf --kill gpg-agent
gpgconf --launch gpg-agent

PIN geblokkeerd

Na drie foute PIN pogingen blokkeert de YubiKey. Reset met de Admin PIN:

gpg --edit-card
gpg/card> admin
gpg/card> passwd
# Kies optie 2: unblock PIN

Admin PIN vergeten? Dan is je YubiKey onbruikbaar voor die keys. Daarom: backup YubiKey.

Waarom Dit Werkt voor Mij

Security en gemak staan normaal op gespannen voet. Meer security = meer frictie. Maar deze setup draait dat om:

  • Minder wachtwoorden typen: PIN eenmaal per sessie, daarna alleen touch
  • Onmogelijk te phishen: Fysieke key vereist, geen wachtwoord dat gestolen kan worden
  • Unified workflow: Eén key voor alles, geen context switching tussen tools
  • Offline bruikbaar: Geen internet nodig, geen cloud dependency

Het belangrijkste: ik gebruik het daadwerkelijk. Een security setup die irritant is, ga je omzeilen. Deze niet.

Minimale Viable Setup

Als je dit wilt proberen maar niet meteen alles wilt configureren:

  1. Koop een YubiKey 5 (de NFC variant is handig voor telefoon)
  2. Genereer een GPG key met authentication subkey
  3. Zet de keys op de YubiKey
  4. Configureer gpg-agent voor SSH
  5. Test met ssh-add -L

Daarna kun je pass toevoegen, git signing configureren, en de fijnere details tweaken.

Conclusie

De initiële setup is niet triviaal. Je moet GPG begrijpen, gpg-agent configureren, en snappen hoe de pieces samenwerken. Dat kost tijd.

Maar als het eenmaal werkt? Dan heb je een setup waarbij je YubiKey echt het centrum van je authenticatie wordt. Eén fysieke key, één PIN, en alles werkt.

Plug in, PIN, en go.

# Check of alles werkt
gpg --card-status && ssh-add -L && pass show test/dummy

Als dat allemaal werkt zonder errors: je bent klaar.