Setting up a PKI using Vault — EXPLAINED

PKI Diagram

I’ve spent a good chunk of time setting up a PKI (Public Key Infrastructure) lately. Having little to no experience or prior knowledge regarding PKIs or PKI setup/management in Hashicorp Vault, I thought it would be a good idea to write a small guide on how to achieve this, including some resources that link to more in depth explanations.

For this guide we’ll be using Hashicorp Vault as previously mentioned to set up our PKI. Setting up Vault in a Cluster or even locally is easy. These are some links to get you started.

I’ve also uploaded some files and scripts to start your local Consul and Vault using Minikube you can find them in my GitLab HERE

I’ll be using the fictional company called Gengar. For a full bash script please visit my GitLab HERE

We will be creating at 2 layer PKI, which consist of a Root CA and an Intermediate CA which will be issuing End Entity certificates through a role. This is how the Issuer and Subject will appear in each corresponding certificate.

The Root CA will be signed by itself and hence the Issuer and the Subject are Root CA. The intermediate will be signed by the Root CA and therefore the Isser is the Root CA. Lastly the actual certificates being issued by the Intermediate CA will have Issuing CA in the Issuer and the CN specified in the Subject.

Once you have your Vault launched, running, and logged in you can run the following commands to issue a root ca.

Creating the Root CA

Breaking down the commands

Enabling the PKI path

We are merely creating a PKI engine under the path pki_gnr_ca

Tuning the Time To Live

Here we are tuning the max-lease-ttl of pki_gnr_ca to 10 years (87600h) .

Configuring the Root CA

This will generate a new self-signed CA certificate and private key. If the path ends with exported, (e.g. pki_gnr_ca/root/generate/exported) the private key will be returned in the response; if it is internal the private key will not be returned and cannot be retrieved later. We will continue with internal and save the private key as a file called CA_cert.crt. If you are planning to use this in production make sure you have a copy if the private key.

Max Path Length

max_path_length is set to 1 because we only have a 2 layer PKI and the last layer in our PKI setup, the Intermediates CA, will be 0. The image below illustrates this very well with a 3 layer PKI, a Root CA and 2 Intermediates CA with the layer 3 issuing EE (End Entity) certificates and layer 4 being the EE certificate it self.

In our 2 layer PKI the public root ca certificate, once decrypted will state this information like this:

Key Usage

The key_usage extension of an X.509 V3 digital certificate defines how the public key contained within the certificate may be used. For example, a key usage extension of dataEncipherment indicates that the certificate may be used to encrypt user data. You can find a list of options HERE

Extended key usage

ext_key_usage further refines key usage extensions. An extended key is either critical or non-critical. If the extension is critical, the certificate must be used only for the indicated purpose or purposes. If the certificate is used for another purpose, it is in violation of the CA’s policy. You can find a list of options HERE

For this example they will be empty key_usage=’’ ext_key_usage=’’

Common Name, Organization Unit, Organization, Country, Time To Live (ttl) and Key Bits

common_name, ou, organization, country, ttl and key_bits

  • common_name: this specifies the requested CN for the certificate. We will use Gengar Root CA to be explicit that this CN is the Root CA
  • ou: This field is the name of the department or organization unit. We will go with GNR PKI
  • organization: We will just state the overall organization. Gengar Corp
  • country: We will just put the country code GB
  • ttl: Is the Time To Live which is 10 years(87600h), this is the average time for a root CA.
  • key_bits: This will be the level of encryption. Vault default for PKI is 2048 but we will change this to be higher: 4096

In the public root ca certificate it will look like this:

Configuring the URLs

The endpoint pki_gnr_ca/config/urls is used, like the name suggests, to configure the urls of this CA. It is here where you will define the urls for downloading issuing certificates for the root ca and the CRL which is the certificate revocation list.

These two commands will configure the CRL expiry and rotate them. CRLs should be short in length around a week or 168h, in this example we are setting up the expiry of the CRL for 6 months.

The public certificate of the root CA (Root CA)

To download a public root CA certificate you can visit : http://vault.gengar.com/v1/pki_gnr_ca/ca or http://127.0.0.1:8200//v1/pki_gnr_ca/ca

The file will be download will be in DER format to decrypt it you can use openssl
openssl x509 -in root_ca -text -noout -inform der

Once decrypted the public root CA will look like this:

Creating the Intermediate CA

Breaking down the commands

Enabling the PKI path

Just like before we will be creating an additional pki engine this time in the path pki_int_gnr_ca

Tuning the Time To Live

We will set the max time to live for 43800h which is 5 years.

We’ll be generating a certificate signing request (CSR) for our root to sign.

Max Path Length

This will be equal to 0. This is to signal that this is the last level in our PKI and no more intermediates will follow. Meaning that the certificates this Ca generates will be for End Entity (EE) users.

In the certificate it will appear like this:

Common Name, Organization Unit, Organization, Country, Time To Live (ttl) and Key Bits

common_name, ou, organization, country, and key_bits

The information here will be slightly different to the one on our root ca.

  • common_name will be set to Gengar Issuing CA This is to establish this will be the level in the PKI that will be issuing certificates to EE users
  • ou will remain the same as in the root ca: GNR PKI
  • organization will remain the same as in the root ca:Gengar Corp
  • country will remain the same as in the root ca: GB
  • key_bits will remain the same as the root ca: 4096

the last bit of the command will output the CSR into a file called pki_int_gnr_ca.csr

Signing the Intermediate CA

This command will sign the CSR that we just created and output a pem file

You should note that we are providing the same values common_name, ou, organization, country, and key_bits . This is just as a precaution if you trust the entity that will be sending you the CSR you can remove all of those values and replace them with use_csr_values=true This will use the values provided in the CSR:

If set to true, then: 1) Subject information, including names and alternate names, will be preserved from the CSR rather than using the values provided in the other parameters to this path; 2) Any key usages (for instance, non-repudiation) requested in the CSR will be added to the basic set of key usages used for CA certs signed by this path; 3) Extensions requested in the CSR will be copied into the issued certificate. — https://www.vaultproject.io/api/secret/pki#use_csr_values

csr=@pki_int_gnr_ca.csr format=pem_bundle ttl=”43800h”

when using the @ through command line you are stating to Vault the location of the file you are providing is local, since the path of the CSR is the same as where we saved it we’ll just give it the name of the file.

format=pem_bundle is just the format of output

ttl is the time to live set to 5 years (43800h)

Installing the Signed Certificate

Here we’re providing the pem file we obtained from the root ca from the command above.

Configuring the URLs

Like we defined in the root ca we are defining the urls for downloading issuing certificates for the issuing ca and the CRL.

These two commands will configure the CRL expiry and rotate them. CRLs should be short in length around a week or 168h, in this example we are setting up the expiry of the CRL for 6 months. If you use this for production remember to keep this short like a week or two.

The public certificate from the intermediate CA (Issuing CA)

If you decrypt the public intermediate CA you will get the following

The Role

Up until this point we have created the Root and Intermediate Certificate Authorities. Now we need to create a role which will utilise the Intermediate CA to issue EE certificates.

This is a very long command so let’s break it down in parts like we did the others and show what each part is responsible for in an EE (End Entity) certificate.

Setting up the role

Here we tell Vault we’ll create a role called Issuer which will issue certificates using the pki_int_gnr_ca level. This can be called what ever you want, for this example it’s called Issuer. It should be noted creating this role doesn’t add an additional level in the PKI it is merely a role which will use the intermediate PKI.

Allow Any Name

Specifies if clients can request any CN. Useful in some circumstances, but make sure you understand whether it is appropriate for your installation before enabling it. — Vault Docs

If you are using it for production you will want to have this to False and provide a specific value.

Server Flag and Client Flag

Specifies if certificates are flagged for server use. — Vault Docs

Specifies if certificates are flagged for client use. — Vault Docs

When server_flag and client_flag are not defined as false, -the default is true for both, you get TLS Web Server Authentication in Extended Key Usage detail in the EE certificate:

Allow Subdomains

This would allow hunter.example.com to be allowed, that is if example.com is in the allowed list. Which because of allow_any_name=True this is allowed.

Ou, Organization and Country

In this example we are only specifying the ou and the organization

Key Usage

Key usage extensions define the purpose of the public key contained in a certificate. You can use them to restrict the public key to as few or as many operations as needed. For example, if you have a key used only for signing or verifying a signature, enable the digital signature and/or non-repudiation extensions. Alternatively, if a key is used only for key management, enable key encipherment. — https://help.hcltechsw.com/domino/11.0.0/conf_keyusageextensionsandextendedkeyusage_r.html

Using the config: key_usage=”DigitalSignature, KeyEncipherment” will output the following in the EE certificate:

If you wish to remove all together this option from the certificate you need to set the to be empty key_usage=””

Use CSR Common Name

This will use the CSR common name when you are signing a CSR.

Ext Key Usage and Ext Key Usage OID

Extended Key Usage extensions (EKUs) are newer and are generally used to restrict usage while the Key Usage Extensions (KUEs) are considered less flexible. KUEs is defined in terms of “operations whereas EKUs are defined in terms of “operations”. Generally EKUs are checked offensively (ie. This certificate must contain this EKU OID) whereas KUEs are generally checked defensively (ie. This certificate must contain this but may contain this or that). — https://knowledge.digicert.com/quovadis/ssl-certificates/extended-key-usage-and-key-usage-extensions.htm

TTL (Time To Live) and Max TTL

This will define how long the certificates that this role generates will last. For testing 4380h (6 months) will be more than enough. Note that the role values default to system values if not explicitly set. Set both for more control

Enforce Hostnames

Specifies if only valid host names are allowed for CNs, DNS SANs, and the host part of email addresses. — Vault Docs

Allow Bare Domains

Specifies if clients can request certificates matching the value of the actual domains themselves; e.g. if a configured domain set with allowed_domains is example.com, this allows clients to actually request a certificate containing the name example.com as one of the DNS values on the final certificate. In some scenarios, this can be considered a security risk. — Vault Docs

Issuing a certificate

You can issue an EE certificate using the UI, by going to your browser or you can do this by terminal. If you want to issue a certificate using terminal you can use a command like this one:

The output will be a Certificate, Issuing CA, and a CA chain all encrypted.

if you want the output decrypted you can use a command like this:

If you generate a certificate using this PKI and role setup it will generate a Certificate, Issuing CA, and a CA chain. The certificate will be the End Entity (EE) certificate that the End Entity will use. Depending on the usage of the certificate you might also require a Chain Certificate. Vault doesn’t provide a true Chain Certificate without some configuration. For that you will need to generate a public certificate from the Root CA and concat it along with the Issuing CA which in this case is the Intermediate CA and the EE certificate in the following order:

You can download the the Public Issuing Root CA and the Public Issuing Intermediate CA by visiting the URL you set up the both of these up

“http://vault.gengar.com/v1/pki_gnr_ca/ca"
and
“http://vault.gengar.com/v1/pki_int_gnr_ca/ca"

If you are using local host then you will need to change the URL to the bellow when creating the Root CA and the Intermediate CA:

“http://http://127.0.0.1:8200//v1/pki_gnr_ca/ca"
and
“http://http://127.0.0.1:8200//v1/pki_int_gnr_ca/ca"

The end result

When finally issued and decrypted the certificate will look something like this:

If you have any questions feel free to leave a comment and I will respond as soon as I can.

Platform Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store