Nebula VPN med Yubikey
Nebula är en öppen VPN-mjukvara från Defined Networking som erbjuder möjligheten att skapa så kallade overlay networks. Defined beskriver själva sin lösning enligt följande:
”Nebula is a mutually authenticated peer-to-peer software defined network based on the Noise Protocol Framework. Nebula uses certificates to assert a node’s IP address, name, and membership within user-defined groups. Nebula’s user-defined groups allow for provider-agnostic traffic filtering between nodes.” – https://nebula.defined.net/docs/#technical-details
Då Nebula nyligen accepterade en pull request för PKCS#11-stöd är det möjligt att generera x509-certifikat på en Yubikey och använda den för autentisering. Det här blogginlägget kommer att introducera Nebula och demonstrera hur man kan använda en Yubikey för att lagra klientcertifikatet.
De kommandon och handgrepp som visas i denna artikel utgår ifrån virtuella testmaskiner baserade på Fedora Server 42. Om du är nyfiken på hur Nebula fungerar på andra plattformar noterades att författaren till ovan pull request har använt MacOS.
Huruvida PKCS#11-stödet fungerar på Windows är en övning som lämnas till läsaren.
Förbereda klienter
I denna demonstration befinner sig klienterna som ska kopplas ihop via Nebula på samma lokala nätverk, 192.168.100.0/24, men det enda som har någon betydelse är att ”lighthouse-noden” är nåbar från övriga system på port 4242 via UDP.

Artikeln kommer fortsatt att visa hur host1 kan konfigureras att använda sig av nebula-certifikat på Yubikey, och övriga noder kommer att konfigureras med konventionellt lokalt nyckelmaterial.
Notera att om du följer denna instruktion på Debian Bookworm så är den version av Go som finns i officiella pakethanteraren i skrivande stund version 1.19.8, vilken är för gammal för att kunna bygga Nebula. Installera Go manuellt innan du går vidare.
I denna artikel användes Go 1.24.4 för att bygga commit 442a528 från master branch i Nebulas kodvalv.
Utöver Go behövs pkcs11-tool för generell administration av smarta kort. Vi behöver också libykcs11 vilket finns inkluderat i yubico-piv-tool. Tänk på att paketnamnen kan ha andra namn beroende på vilken Linux-distribution du använder.
sudo dnf install golang ykman pkcs11-tool yubico-piv-tool
Du kan behöva starta om systemet innan din Yubikey detekteras. Notera också att om du testar PKCS#11-funktionaliteten med en virtualiserad klient och USB passthrough för din Yubikey can du mötas av intermittenta fel, beroende på hypervisor och övriga omständigheter.
Att bygga Nebula
PKCS#11-stödet kommer att ingå i version 2.0-releasen som ännu inte har något fastslaget datum. För att få tillgång till stödet måste Nebula därför byggas manuellt från källkoden, som är skriven i Go.
Det generella tillvägagångssättet är dokumenterat i Nebulas kodvalv:

I den pull request som referereades till ovan framgår det att målet ”bin-pkcs11” har lagts till i projektets Makefile.

De kommandon som behövs för att klona valvet och för att bygga Nebula med PKCS#11-stöd är alltså:
git clone https://github.com/slackhq/nebula.git
cd nebula
make bin-pkcs11
När bygget är klart finns två binärer i nebula-mappen: nebula och nebula-cert.

För över nebula-binären till lighthouse, host1 och host2.
Skapa CA-certifikat
Om du inte redan har ett CA-certifikat för Nebula genererar du det med nebula-cert. Om du redan har ett Nebula CA-cert sedan tidigare kan du gå vidare till nästa steg, men tänk på att om PKCS#11-stödet ska fungera behöver det använda Curve P-256.
Notera även att giltighetstiden för CA-certifikatet är ett år om du inte använder flaggan ”-duration”.
./nebula/nebula-cert ca -ips '10.104.0.0/24' -name 'CA för bloggartikel' -curve P256
För över ca.crt-filen till alla noderna, men behåll ca.key (den privata nyckeln) på en säker plats.
Konfigurera lighthouse-nod
För att hålla demonstrationen så kortfattad som möjligt genereras nycklarna centralt och kopieras ut till respektive klient. I produktionsmiljöer bör detta undvikas, se vidare instruktion här.
Skapa ett certifikat för lighthouse-noden:
./nebula/nebula-cert sign -ip '10.104.0.1/24' -name lighthouse
Kopiera därefter över nyckelmaterialet till lighthouse-noden, och konfigurera den med en minimal konfiguration. Eftersom det är en lighthouse-nod skall static_host_map samt hosts-blocket under lighthouse normalt sett vara blanka.

Konfigurera host2
Skapa ett klientcertifikat för host2, kopiera över nyckelfilerna och etablera kontakt med lighthouse-noden.
./nebula/nebula-cert sign -ip '10.104.0.11/24' -name host2

Starta Nebula på lighthouse och host2
Starta nu Nebula på lighthouse-noden och host2, antingen manuellt eller genom att använda service-skripten som finns i Nebula-projektet under examples/service-scripts. Om allt går som det ska bör du kunna nå lighthouse-noden över Nebula-nätverket med ping.

Konfigurera host1
Förbereda Yubikey
I demonstrationssyfte används här en Yubikey som är dedikerad för teständamål. Använd inte en Yubikey som innehåller data du är rädd om innan du är helt säker på att du vet vad du gör, reset-kommandot kommer att radera all PIV-data på nyckeln.
Anslut Yubikeyn till klienten och använd ykman för att rensa Yubikeyn från eventuellt redan existerande PIV-data. I denna demonstration får Yubikeyn behålla standard PIN-koden 123456 men detta är givetvis inte rekommenderat för en skarp driftsättning.
Skapa därefter ett certifikat med Curpe P-256 (det är än så länge den enda algoritmen som stöds).
ykman piv reset
ykman piv keys generate --algorithm ECCP256 9a nebula_yubikey.pem
Notera att nebula_yubikey.pem inte behövs, vi kommer att generera en ny publik nyckel senare.
Lista PIV-informationen på Yubikey men pkcs11-tool. Notera att du behöver ange sökvägen till rätt PKCS#11-modul annars tolkas inte informationen korrekt. Med standard-modulen ser det ut så här:

Om du anger sökvägen till libykcs11s biblioteksfil ser informationen ut så här:
pkcs11-tool --module /usr/lib64/libykcs11.so.2 --list-slots

Skapa klientcertifikat för host1
Nu kan vi använda nebula-cert för att generera klient-certifikatet, baserat på den publika nyckel vi genererade på Yubikeyn.
För att konstruera kommandot behöver vi uri-fältet från pkcs11-tool, till vilket vi lägger till ”id=%01?module-path=/usr/lib64/libykcs11.so.2&pin-value=123456
”. Beroende på vilket OS eller vilken distribution du använder kan du behöva justera module-path, och om du har satt en annan PIN-kod på din Yubikey får du uppdatera pin-value med korrekt värde.
./nebula-cert keygen -curve P256 -pkcs11 "pkcs11:model=YubiKey%20YK5;manufacturer=Yubico%20%28www.yubico.com%29;serial=19777900;token=YubiKey%20PIV%20%2319777900;id=%01?module-path=/usr/lib64/libykcs11.so.2&pin-value=123456" -out-pub host1.pub
Den fortsatta processen för att skapa klientcertifikat ser nästan identisk ut för Yubikey-genererade certifikat som för de ordinarie, med skillnaden att -in-pub används för att utgå ifrån den publika nyckel vi skapade med nebula-cert.
nebula-cert sign -in-pub host1.pub -ip '10.104.0.100/24' -name host1
Om allt har gått som det ska har du nu host1.crt i din arbetskatalog. Vi kan nu skapa en konfigurationsfil för Nebula. Key-fältet ska innehålla samma sträng som du använde i nebula-cert-kommandot för att generera din nyckel, men konfigurationsfilen ser i övrigt identisk ut med den vi skapade för host2.

Starta Nebula och verifiera att du kan nå lighthouse-noden och host2 via ping.


Avslutning
Vi har nu lyckats generera nycklar på en Yubikey och har framgångsrikt autentiserat oss mot Nebula! Funktionen är dock inte helt utan brister och det är förhoppningsvis en funktion som kommer att poleras vidare framöver. I skrivande stund tycks Nebula behålla nyckelmaterialet i datorns arbetsminne när tunneln väl är etablerad. Att koppla ifrån Yubikeyn leder inte till att tunneln går ned, vilket kanske inte är önskvärt och är något som borde gå att konfigurera.
Det noterades också att Nebula kraschar om den försöker starta när Yubikeyn är urkopplad från host1 eftersom den privata nyckeln inte är tillgänglig.

Förhoppningsvis kommer Nebulas felhantering förbättras för att undvika en okontrollerad krasch och hantera situationen mer elegant, men det är spännande att se att Nebula nu får officiellt stöd för att använda Yubikeys och smart cards vid autentisering.