Introduction
The Key Usage Extension is a component of x509 standard for Public Key Infrastructure. It's definition comes from RFC 5280:
The key usage extension defines the purpose (e.g., encipherment,
signature, certificate signing) of the key contained in the
certificate. The usage restriction might be employed when a key that
could be used for more than one operation is to be restricted.
In HashiCorp Vault's PKI secrets engine, by default, signed Intermediate CA certificates contain the following Key Usage assertions:
Certificate Sign, CRL Sign
If using exclusively Vault certs (via PKI secrets engine) behind a GCP load balancer, for instance, Google requires both the root and intermediate CAs have keyUsage
and extendedKeyUsage
values of keyCertSign
and clientAuth
respectively.
The following article describes how to accomplish this with HashiCorp Vault.
Expected Outcome
A Root CA imported into Vault with the desired key usage parameters
A signed Intermediate CA certificate with non-default Key Usage assertions.
Prerequisites (if applicable)
- A running Vault server
- openssl command line utility
- jq installed
- tested on openssl version 3.2.23
Procedure for Importing an external Root-CA into Vault
1. Enable PKI secrets engine and generate a private key within Vault to be used for signing
vault secrets enable pki vault write pki/keys/generate/exported -format=json | jq -r '.data.private_key' > root-key.pem
2. Create configuration file with necessary key usage parameters
cat << EOF >> root.cnf [req] prompt = no distinguished_name = dn [dn] C=US ST=State L=City O=Organization OU=Root CA CN=Root CA [v3_root_ca] keyUsage = critical, keyCertSign, cRLSign extendedKeyUsage = clientAuth basicConstraints = critical, CA:TRUE EOF
3. Using the configuration file and the generated private key from Vault, create a CSR for the root CA using the openssl utility
openssl req -new -key root-key.pem -out root.csr -config root.cnf -extensions v3_root_ca
4. Sign the CSR and output the root CA
openssl x509 -req -in root.csr -signkey root-key.pem -out root-ca.pem -extfile root.cnf -extensions v3_root_ca
5. Confirm key usage parameters using openssl
~ openssl x509 -in root-ca.pem -text -noout | grep 'Key Usage' -A 1
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Extended Key Usage:
TLS Web Client Authentication
5. Import the root into Vault
vault write pki/issuers/import/cert pem_bundle=@root-ca.pem
6. Confirm the cert is now the CA within Vault with desired key usage assertions
vault read pki/cert/ca -format=json \
| jq -r '.data.certificate' \
| openssl x509 -text -noout \
| grep X509v3 -A 1
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Extended Key Usage:
TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:TRUE
...
Procedure for Intermediate
1. Enable a second PKI secrets engine at an alternate path and generate a private key
vault secrets enable -path=pki_int pki
vault write pki_int/keys/generate/exported -format=json | jq -r '.data.private_key' > int-private-key.pem
2. Create a configuration file for openssl with the desired Key Usage Assertions defined:
cat << EOF >> int-csr.cnf
[req]
prompt = no
distinguished_name = dn
[dn]
C=US
ST=State
L=City
O=Organization
OU=Intermediate CA
CN=Intermediate CA
[ req_ext ]
basicConstraints = CA:TRUE
keyUsage = critical, digitalSignature, keyCertSign, cRLSign
extendedKeyUsage = clientAuth
EOF
3. Using the configuration file and the generated private key from Vault, create a CSR for the intermediate CA using the openssl utility:
openssl req -new -key int-private-key.pem -out int-ca.csr -config int-csr.cnf
4. If we inspect the generated CSR, we can see that the Key Usage assertions are defined:
~ openssl req -in int-ca.csr -text -noout | grep 'Key Usage' -A 1
X509v3 Key Usage: critical
Digital Signature, Key Encipherment, Certificate Sign, CRL Sign
X509v3 Extended Key Usage:
TLS Web Client Authentication
5. Next we'll sign the CSR using the root CA in Vault. Ensure on this request that the use_csr_values parameter is set to true:
vault write pki/root/sign-intermediate use_csr_values=true csr=@int-ca.csr -format=json | jq -r '.data.certificate' > signed-int-ca.pem
6. If we inspect the signed Intermediate CA, we can see that the Key Usage assertions are defined
~ openssl x509 -in signed-int-ca.pem -text -noout | grep 'Key Usage' -A 1
X509v3 Key Usage: critical
Digital Signature, Key Encipherment, Certificate Sign, CRL Sign
X509v3 Extended Key Usage:
TLS Web Client Authentication
7. We can now import the signed CA to the pki_int mount using the set-signed endpoint:
vault write pki_int/intermediate/set-signed certificate=@signed-int-ca.pem
Key Value
--- -----
existing_issuers <nil>
existing_keys <nil>
imported_issuers [eeb52eb8-20bb-79fe-fd82-68a0322624be d20beee4-ef26-5ae6-dbb5-e754128e819d]
imported_keys <nil>
mapping map[d20beee4-ef26-5ae6-dbb5-e754128e819d: eeb52eb8-20bb-79fe-fd82-68a0322624be:]
8. If we'd like further confirmation, we can list the uploaded intermediate, confirming the keys match the output of step 7
vault list pki_int/issuers
Keys
----
d20beee4-ef26-5ae6-dbb5-e754128e819d
eeb52eb8-20bb-79fe-fd82-68a0322624be
9. Finally, read the issuers cert, and pipe into openssl to inspect and verify our parameters
vault read -format=json pki_int/issuer/eeb52eb8-20bb-79fe-fd82-68a0322624be \
| jq -r '.data.certificate' \
| openssl x509 -text -noout | grep 'Key Usage' -A 1
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
X509v3 Extended Key Usage:
TLS Web Client Authentication