Vault: PKI Made Easy

4 minute read

Disclamer

Well, not quite PKI Made Easy, but definitely a bit more fun!
I’ve done all this work on OSX, but I believe the Linux setup should be very similar.
Vault 0.3 was the version used.

Containerize all the things

Last week I was tinkering with Docker and wanted to get Hashicorp Vault running on a container, this was mainly a plan to trick myself into learning more about Vault.

The Docker stuff went pretty well and you have available a public container to prove it, check it out at:

hashicorp-vault on a container

Regarding the plan, it worked flawlessly and I’ve got really interested in the application.

So, what’s Vault?

vault_logo

Vault secures, stores, and tightly controls access to tokens, passwords, certificates, API keys, and other secrets in modern computing. Vault handles leasing, key revocation, key rolling, and auditing. Vault presents a unified API to access multiple backends: HSMs, AWS IAM, SQL databases, raw key/value, and more. (source)

I’m not going into depth about how the application works and all the features it provides, firstly because I just started playing with it and secondly the documentation does a very good job on that. Instead I’ll talk about what I’ve learned regarding the PKI backend configuration and usage.

These are the points I’ll cover:

  • Install Vault
  • Configure Vault
  • Generate a Root Certification Authority (CA) and Intermediate CA
  • Create a PKI backend
  • Configure the PKI backend
  • Issue a couple of server certificates
  • Issue a Certificate Revocation List (CRL) on Vault
  • Revoke a certificate
  • Vault using TLS

Setup

Create the following vault.conf file:
Create and run the following setup script on the same path as the vault.conf file:


You now should have a running instance of Vault using the /tmp/vault/vault.conf configuration.

Initialize Vault

cd /tmp/vault

vault init > credentials.txt

# check if initialized
curl http://127.0.0.1:8200/v1/sys/init

# keep your credentials safe
cat credentials.txt

Unseal Vault

Vault is protected by M-of-N so you’ll need to run the unseal command 3 times using a different key each time to open it.

The M of N feature provides a means by which organizations employing cryptographic modules for sensitive operations can enforce multi-person control over access to the cryptographic module. (source)

vault unseal

Export the Root Token

This will authenticate your vault client against the Vault server.

export VAULT_TOKEN=use-your-generated-root-token

Check the current mount points

vault mounts

Mount the PKI backend

vault mount pki
vault mounts
vault path-help pki

Get your hands on a CA certificate

You’ll need a CA for the next steps. Don’t have one?
Here you go (thank me later):

dummy_ca

You should never use a Root CA to issue client/server certificates, if it’s compromised you’re screwed! Instead, generate an intermediate CA and if that one it’s compromised just revoke it and issue a new one, keeping the Root CA offline.

With your certificates generated, now build a certificate bundle with the Intermediate CA certificate and Intermediate CA key.

export DUMMY_CA=/PATH/TO/dummy_ca

cat $DUMMY_CA/pki/intermediate/certs/intermediate.pem > \
  /tmp/vault/ca_bundle.pem

# vault does not accept encrypted keys
openssl rsa -in $DUMMY_CA/pki/intermediate/private/intermediate.key >> \
  /tmp/vault/ca_bundle.pem

Configure the PKI backend

Carefully read the documentation regarding the API endpoints /pki/config/, /pki/roles and /pki/issue/

vault write pki/config/ca pem_bundle="@/tmp/vault/ca_bundle.pem"

vault write pki/roles/test-dot-local allow_any_name="true" \
  allow_subdomains="true" allow_ip_sans="true" max_ttl="420h" \
  allow_localhost="true" allow_ip_sans="true"

vault write pki/issue/test-dot-local common_name=localhost \
  alt_names="vault.test.local,*.vault.test.local" \
  ip_sans="127.0.0.1,192.168.1.77" > /tmp/vault/localhost.certs
  
vault write pki/issue/test-dot-local \
  common_name=sheep.test.local > /tmp/vault/sheep.certs

Split the localhost.certs into a separated key and certificate files:

  • localhost.pem
  • localhost.key

Split the sheep.certs into a separated key and certificate files:

  • sheep.pem
  • sheep.key

Test the CRL

This shouldn’t return any revoked certificates yet.

curl -v http://127.0.0.1:8200/v1/pki/crl/pem
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8200 (#0)
> GET /v1/pki/crl/pem HTTP/1.1
> Host: 127.0.0.1:8200
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/pkix-crl
< Date: Sun, 15 Nov 2015 12:14:40 GMT
< Content-Length: 0
<
* Connection #0 to host 127.0.0.1 left intact

Revoking a certicate

To revoke a certificate you first need its Serial Number.

export SHEEP_SN=$(openssl x509 -in /tmp/vault/sheep.pem -text | \
  grep -A1 "Serial Number" | grep -v "Serial Number" | \
  awk {'print $1'})
  
curl -v -X POST http://127.0.0.1:8200/v1/pki/revoke \
  -H "X-Vault-Token: $VAULT_TOKEN" \
  -d '{"serial_number":"'$SHEEP_SN'"}'

Test the CRL

curl -v http://127.0.0.1:8200/v1/pki/crl/pem > \
  /tmp/vault/crl.pem
  
openssl crl -inform PEM -in /tmp/vault/crl.pem -text

You should see the revoked Serial Number.

Vault with TLS

This bit took me quite a while to figure out.

The documentation doesn’t mention how to do it. The Vault server doesn’t send the Intermediate CA certificate with the leaf certificate to the vault client, this way you can’t just trust the Root CA, you’ll need to trust the Intermediate one… ¯\_(ツ)_/¯

I even tried providing a ca_bundle with the Root CA certificate in it, but no luck. Then there was was the issue of finding out how to provide a truststore to the vault client…

# enable the truststore
export VAULT_CAPATH=$DUMMY_CA/pki/intermediate/certs/intermediate.pem

Uncomment the lines tls_*_file and comment out tls_disable on vault.conf

pkill vault

vault server -config="/tmp/vault/vault.conf" &

export VAULT_ADDR=https://127.0.0.1:8200

vault unseal

If it doesn’t give you a TLS error, you’re golden! You can check the certificate the server is using and the chain if he sends it, with:

openssl s_client -showcerts -connect 127.0.0.1:8200

That’s it, that’s all

This blog post only scratches the surface of what Vault is capable of. I’m currently looking into High Availability and there’s still many other backends to try out, but I hope I’ve piqued your curiosity.

Big thanks to Hashicorp for releasing such amazing open source products.

Leave a comment