Vault Authentication with YubiKey

This guide provides step-by-step instructions on how to use Yubikey NEO or any other pkcs11 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