Vault Authentication with YubiKey
Posted
This guide provides step-by-step instructions on how to use Yubikey NEO or any other PKCS#11 enabled hardware token to authenticate with HashiCorp Vault’s TLS Certificates Auth backend.
Steps in a nutshell:
- Setup Vault server with self-signed TLS certificate
- Create certification authority and issue a certificate for authentication
- Enable TLS certificates authentication method
- Import private key and certificate to YubiKey
- Find out pkcs11 URI and authenticate
Vault server with self-signed TLS certificate
Let’s setup Vault instance with self-signed certificate. We need to have TLS enabled, so we can use curl
certificate authentication functions later. You can skip this part if you already have running Vault server.
Generate self-signed certificate
$ openssl req \
-x509 -newkey rsa:2048 -nodes -keyout server.key \
-subj "/C=SK/O=Example s.r.o./CN=localhost" \
-sha256 -days 1825 -out server.crt
Write Vault configuration to disk
$ cat <<EOT >> config.hcl
backend "inmem" {
}
listener "tcp" {
tls_cert_file = "server.crt"
tls_key_file = "server.key"
}
disable_mlock = true
default_lease_ttl = "768h"
max_lease_ttl = "768h"
api_addr = "https://127.0.0.1:8200"
EOT
Start the Vault instance with our configuration file
$ vault server -config=config.hcl
** The Vault is not initialized, so let’s initialize and unseal it in other console window**
# set the environment variables for the next steps
export VAULT_SKIP_VERIFY=True
export VAULT_ADDR='https://127.0.0.1:8200'
# initialize Vault
$ vault operator init -key-shares=1 -key-threshold=1
Unseal Key 1: JGpSgUGI9R4jqH/3JErxM++tDvxaJh25U1hr51wSfFU=
Initial Root Token: s.f4UtQFTyPAk9oZ7xpEbQXxB1
# unseal
$ vault operator unseal JGpSgUGI9R4jqH/3JErxM++tDvxaJh25U1hr51wSfFU=
# export root token for further setup
export VAULT_TOKEN='s.f4UtQFTyPAk9oZ7xpEbQXxB1'
Create certification authority and issue a certificate for authentication
In this step, we will generate certification authority, then we will generate a key pair for YubiKey and sign it with our authority. I will use openssl
as I am used to it, but you can use also Vault PKI backend or any other software for certificate management.
You can also generate private key directly on the YubiKey, but I will import it instead.
# create certification authority
$ openssl req \
-x509 -newkey rsa:2048 -nodes -keyout rootca.key \
-subj "/C=SK/O=Example s.r.o./CN=Certification Authority" \
-sha256 -days 1825 -out rootca.crt
# generate a private key and certificate for our hardware token
$ openssl req \
-newkey rsa:2048 -nodes -keyout hwtoken.key \
-subj "/C=SK/O=Example s.r.o./CN=Vault Auth key pair" \
-out hwtoken.csr
# issue certificate using previously generated certification authority and CSR file
$ openssl x509 -req \
-in hwtoken.csr -CA rootca.crt -CAkey rootca.key -CAcreateserial -out hwtoken.crt -days 365 -sha256
Enable TLS certificates authentication method
Now let’s enable TLS certificates authentication method in Vault and configure our certification authority as a verification mechanism. I will also set a hwtoken_policy
policy as a policy that will be assigned to a token after successful authentication.
# enable auth backend
$ vault auth enable cert
Success! Enabled cert auth method at: cert/
# set CA certificate as an auth mechanism
$ vault write auth/cert/certs/hwtoken \
display_name=hwtoken \
policies=hwtoken_policy \
certificate=@rootca.crt \
ttl=360
Success! Data written to: auth/cert/certs/hwtoken
Import private key and certificate to YubiKey
Let’s install dependencies on Ubuntu 19.10, and setup our YubiKey.
We are using YubiKey PIV 9a
slot which should authenticate the cardholder and require PIN for any private key operations.
# install YubiKey related libraries
$ sudo apt install yubikey-manager yubico-piv-tool
# install pkcs11 SSL Engine and p11tool
$ sudo apt install libengine-pkcs11-openssl gnutls-bin
Now, we will reset YubiKey PIV slot and import the private key and certificate. I will use default values of PIN and management key, but you definitely want to set your own management key, pin and puk according to a Yubico manual.
# reset yubikey PIV slot
$ ykman piv reset
WARNING! This will delete all stored PIV data and restore factory settings. Proceed? [y/N]: y
Resetting PIV data...
Success! All PIV data have been cleared from your YubiKey.
Your YubiKey now has the default PIN, PUK and Management Key:
PIN: 123456
PUK: 12345678
Management Key: 010203040506070801020304050607080102030405060708
# export the management key
$ export key=010203040506070801020304050607080102030405060708
# import authentication key and certificate to a PIV slot of the YubiKey token
$ yubico-piv-tool --key=$key -a import-key -s 9a < hwtoken.key
Successfully imported a new private key.
$ yubico-piv-tool --key=$key -a import-certificate -s 9a < hwtoken.crt
Successfully imported a new certificate.
# show information about the PIV slot
$ ykman piv info
PIV version: 1.0.4
PIN tries remaining: 3
CHUID: No data available.
CCC: No data available.
Slot 9a:
Algorithm: RSA2048
Subject DN: C=SK,O=Example s.r.o.,CN=Vault Auth key pair
Issuer DN: C=SK,O=Example s.r.o.,CN=Certification Authority
Serial: 366488651603630184900744804202490464178266778093
Fingerprint: c833125e86db447cb566ced42bde33a76dfeeb51dfb0a32a6a63676a0bcfc73f
Not before: 2020-03-19 19:08:41
Not after: 2021-03-19 19:08:41
Finally, let’s authenticate
Before calling Vault authentication we have to find out pkcs11 URI. We can use p11tool
which we have installed.
To make the curl
command less ugly, you can create a bash alias.
$ p11tool --list-tokens
Token 0:
URL: pkcs11:model=p11-kit-trust;manufacturer=PKCS%2311%20Kit;serial=1;token=System%20Trust
Label: System Trust
Type: Trust module
Flags: uPIN uninitialized
Manufacturer: PKCS#11 Kit
Model: p11-kit-trust
Serial: 1
Module: p11-kit-trust.so
Token 1:
URL: pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=00000000;token=Vault%20Auth%20key%20pair
Label: Vault Auth key pair
Type: Hardware token
Flags: RNG, Requires login
Manufacturer: piv_II
Model: PKCS#15 emulated
Serial: 00000000
Module: opensc-pkcs11.so
Let’s log in to Vault using certificate stored in YubiKey:
$ curl \
-E 'pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=00000000;token=Vault%20Auth%20key%20pair' \
--request POST \
--insecure \
--data '{"name": "hwtoken"}' \
https://127.0.0.1:8200/v1/auth/cert/login
Enter PKCS#11 token PIN for Vault Auth key pair:
{
"request_id": "fa7077ac-7f0a-7446-c31b-a541b8ac599e",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": null,
"wrap_info": null,
"warnings": null,
"auth": {
"client_token": "s.6xu4yB6qVWakZGk4zLW6C4T4",
"accessor": "IKxMB4zoJdoKwIB1EGNRoOQC",
"policies": ["default", "hwtoken_policy"],
"token_policies": ["default", "hwtoken_policy"],
"metadata": {
"authority_key_id": "",
"cert_name": "hwtoken",
"common_name": "Vault Auth key pair",
"serial_number": "366488651603630184900744804202490464178266778093",
"subject_key_id": ""
},
"lease_duration": 360,
"renewable": true,
"entity_id": "e639e6fe-d5c4-92eb-f757-785276d01866",
"token_type": "service",
"orphan": true
}
}
Software, hardware used:
- Ubuntu 19.10
- OpenSSL 1.1.1c 28 May 2019
- Vault v1.1.5 (‘f08b88029d959e1318746b188fecaad54468230b’)
- YubiKey NEO, Firmware version: 3.4.9, OTP+FIDO+CCID enabled