I am having problems with the PKI backend from vault, especially importing existing CAs and certificates.
vault version: 1.12.3
I have successfully created:
- root ca (k3s-ca)
- intermediate ca (k3s-client-ca)
- intermediate ca (k3s-server-ca)
I used the type exported
when creating each of those.
I can now issue certificates with a role with the k3s-client-ca with the python library like so:
c = hvac.Client(url="http://localhost:8200", token="123456"
c.secrets.pki.generate_certificate(
name="k3s-client",
mount_point="k3s-client-ca",
common_name="sustem:admin",
extra_params={"ip_sans": f"192.168.168.2"},
)
I can also fetch the certificate via this library:
c.secrtes.pki.read_certificate(
...: serial="MY_SERIAL",
...: mount_point="k3s-ca")
Everything works fine for now.
Setup process from scratch for reference
Setup k3s-ca
Enable the mount point:
vault secrets enable -path=k3s-ca pki
Create a CA and retrieve the certifacte and private key.
vault write -format=json k3s-ca/root/generate/exported common_name="Root, k3s CA" issuer_name="k3s-ca" ttl=87600h key_name="k3s-ca" > k3s-ca-root.json
Create the root k3s-bundle:
jq -r .data.private_key k3s-ca-root.json > k3s-ca-root.pem
jq -r .data.certificate k3s-ca-root.json >> k3s-ca-root.pem
Setup k3s-client-ca
Enable mount point for k3s-client-ca
vault secrets enable -path=k3s-client-ca pki
adjust default lease time to 5 years
vault secrets tune -max-lease-ttl=43800h k3s-client-ca
Create intermediate certifcate signing request (CSR) and retrieve the response from vault as a json file.
vault write -format=json k3s-client-ca/intermediate/generate/exported common_name="k3s-client-ca" > k3s-client-ca-intermediate.csr.json
Export the CSR from the json and store as a file
jq -r .data.csr k3s-client-ca-intermediate.csr.json > k3s-client-ca-intermediate.csr
Export the private key from the json and store as a file
jq -r .data.private_key k3s-client-ca-intermediate.csr.json > k3s-client-ca-intermediate.pem
Take the intermediate certificate CSR and sign it with another Certifcate authority (our root/k3s-ca).
Also store the response as a json file.
The response contains the signed certificate.
vault write -format=json k3s-ca/root/sign-intermediate csr=@k3s-client-ca-intermediate.csr format=pem_bundle ttl=43800h > k3s-client-ca-intermediate.json
Export the signed certificate from json
jq -r .data.certificate k3s-client-ca-intermediate.json > k3s-client-ca-signed-certificate.pem
Import the intermediate certificate k3s-client-ca into vault.
For some reason creating all this with vault does not store this in vault.
Also store the response as a json file which contains the issuer id.
Each certificate has an issuer id.
vault write -format=json k3s-client-ca/intermediate/set-signed certificate=@k3s-client-ca-signed-certificate.pem > k3s-client-ca-import.json
We need the issuer id from k3s-client-ca-import.json later for the role.
I checked and each certificate in the chain will get an id.
I think it depends on the order in the file.
So in this process:
-
The first issuer [0] is the intermediate CA
-
the second issuer [1] is the root CA
That mean we can get the issuer id for our intermediate CA like this:
jq -r '.data.imported_issuers[0]' k3s-client-ca-import.json
set some configs (maybe not needed?)
vault write k3s-client-ca/config/urls issuing_certificates="http://127.0.0.1:8200/v1/pki_int/ca" crl_distribution_points="http://127.0.0.1:8200/v1/pki_int/crl"
Create roles to allow issuing client certificates.
Here we have to reference the correct issuer id otherwise we will not get a certificate from our intermediate CA.
vault write k3s-client-ca/roles/k3s-client allowed_domains=system:admin organization=system:masters key_usage=DigitalSignature,KeyAgreement,KeyEncipherment issuer_ref=$(jq -r '.data.imported_issuers[0]' k3s-client-ca-import.json) allow_any_name=true allow_bare_domains=false allow_glob_domains=false enforce_hostnames=false max_ttl=86400
Now I clear my vault instance and create an empty one and want to import everything I just created.
For the local testing I just run a local vault with docker:
docker run -it -p 8200:8200 --rm --name vault vault:1.12.3 server -dev -dev-root-token-id=123456
I can import the root ca k3s-ca and the intermediate CA k3s-client-ca and issue certificates just fine.
Working part with importing the k3s-ca and the k3s-client-ca:
Importing root CA with certifcate and key (bundle)
Create the pki mountpoint for the root CA
vault secrets enable -path=k3s-ca pki
Import the root CA bundle:
vault write -format=json k3s-ca/config/ca pem_bundle=@k3s-ca-root.pem > k3s-ca-root-bundle.json
Set the issue name for the root CA.
Not really needed but it is nice to have.
vault write k3s-ca/issuer/$(jq -r '.data.imported_issuers[0]' k3s-ca-root-bundle.json) issuer_name="k3s-root-ca"
Set configurations:
vault write k3s-ca/config/urls issuing_certificates="http://vault.example.com:8200/v1/pki/ca" crl_distribution_points="http://vault.example.com:8200/v1/pki/crl"
Import the intermediate CA bundle k3s-client-ca
Create the pki mountpoint for the intermediate k3s-client-ca
vault secrets enable -path=k3s-client-ca pki
Set the lifetime of the certificates to 5 years.
Needs to be less than the lifetime of the root CA.
vault secrets tune -max-lease-ttl=43800h k3s-client-ca
Import the intermediate CA bundle for k3s-client-ca and save the response to a file:
vault write -format=json k3s-client-ca/issuers/import/bundle pem_bundle=@k3s-client-ca-bundle > k3s-ca-client-bundle-respone.json
Set some configs:
vault write k3s-client-ca/config/urls issuing_certificates="http://127.0.0.1:8200/v1/pki_int/ca" crl_distribution_points="http://127.0.0.1:8200/v1/pki_int/crl"
Create a role to allow issuing client certificates with the respective issuer.
The issuer id is taken from the response of the import.
vault write k3s-client-ca/roles/k3s-client allowed_domains=system:admin organization=system:masters key_usage=DigitalSignature,KeyAgreement,KeyEncipherment issuer_ref=$(jq -r '.data.imported_issuers[0]' k3s-ca-client-bundle-respone.json) allow_any_name=true allow_bare_domains=false allow_glob_domains=false enforce_hostnames=false max_ttl=86400
Now the part that does not work as expected:
Import the intermediate CA bundle k3s-server-ca.
I can not fetch the k3-server-ca certificate after importing it with c.secrtes.pki.read_certificate(serial="MY_SERIAL", mount_point="k3s-ca")
since I do not see any serial.
In the initial setup, I also could see the certificate created on the k3s-ca certificate list in the vault web UI.
I now can not see that anymore in the imported version of this scenario.
vault secrets enable -path=k3s-server-ca pki
vault secrets tune -max-lease-ttl=43800h k3s-server-ca
vault write -format=json k3s-server-ca/config/ca pem_bundle=@k3s-server-ca-bundle > k3s-ca-server-bundle-respone.json
vault write k3s-server-ca/config/urls issuing_certificates="http://127.0.0.1:8200/v1/pki_int/ca" crl_distribution_points="http://127.0.0.1:8200/v1/pki_int/crl"
Either I am missing something or this is not possible.