Root CA rotation, cross-sign, chains, per-issuers url

Hello,

I have to prepare for a Root CA rotation and I am struggling to understand the different points in the documentation. I have read several github issues, Discuss topics, Vault tutorials and APIs but some uncertainties remain.

  1. Root rotation :

In my scenario, we have three PKI layer in their respective mount point : pki_root, pki_int and pki_iss in the descending order of the hierarchy. All of these have internal CA inside Vault.

pki_root CAs ---- signs----> pki_int CAs ----signs----> pki_iss CAs

For compliance issues, I have to create CA successors at half the liftime of the old CAs :

|____________ oldCA____________|
                |____________newCa____________|

The pki_int and pki_iss cases are good as they stem from the same Root, and the root is installed on clients.

When it comes to the Root CA, things are confusing for me. The documentations and tutorials tell to create a new root issuer in pki_root. So i have oldRoot and newRoot issuers. Then, the new root should be cross-signed by the old root inside pki_root as pki_root/intermediate.

The resulting chain for newRoot is said to be the following :

|oldRoot|  ->  |cross-signed newRoot|  ->  |newRoot|
                                               

so in a time format as I used before :

|__________________oldRoot____________________|
                     |____________________newRoot____________________|
                     |__cross-signed newRoot__|                                          

Won’t this cause problems once oldRoot is expired ?
I mean we shouldn’t have signing CAs lasting shorter that leaf CAs. So won’t the chain cause problem at this moment or simply by using the timeframe allowed by the cross-signed newRoot to update Root CA to newRoot on clients will be sufficient ?
Should I edit the ca_chain of newRoot to “self” only once the oldRoot is expired ?

Also in this cross-signing scenario, should the pki_int CAs be directly signed by pki_root/newRoot or pki_root/cross-signed_newRoot in order to have valid automatic chains ?

pkit_root/oldRoot   ___________signs_____________
                                                |
                                                |
                                                v
newRoot <--- same key materials ---> cross-signed newRoot
   |                                            |
   |                                            |
   |____signs or not ?                          |____signs or not ?
               |                                           |
               |                                           |
               v                                           v
          pki_int/CA                                   pki_int/CA
               
  1. per-issuer urls embedded in cert :

As all of this heavily relies on the multi-issuer ability of pki mounts, how can I make sure to have per-issuer ressources (url/uri) embedded in the CA cert for CRL,CA and OCSP ? We used to do with pki/config/urls before. The documentation states that we can update the issuer but it won’t update the certificate. Maybe i could create the issuer once, set issuer ressources and rotate the issuer to make these fields appear in the certificate ?

Thank your for your time, I know I have a lot questions as all of this is confusing me :sweat_smile:

This part does not make sense. You have three certificates, it is true:

Issuer=oldRoot
Subject=oldRoot
Issuer=oldRoot
Subject=newRoot
Issuer=newRoot
Subject=newRoot

but it doesn’t make sense to consider them all part of a single chain. You have two chains:

oldRoot --certifies--> newRoot (cross-signed)
newRoot (self-signed)

I believe there is a certain amount of inconsistency between various TLS libraries - there are some interesting articles out there about how Let’s Encrypt discovered various issues navigating their own transition from being a cross-signed CA to their own standalone root.

Certainly once the cross-certificate expires, there is no longer any point serving it in certificate chains.

To be purely correct, yes, but it probably doesn’t matter much since the root CA won’t be issuing certificates direct to clients. It’s more important to ensure a sensible chain is being served from your issuing CA.

It literally doesn’t have any effect on the produced certificate - as you’ve noted below, they have the same key material. They also have the same Distinguished Name.

I’m not sure what Vault will do regarding automatic chain building… last time I did major PKI work, I was still using an earlier Vault version before that was a thing. But in any case, you always have the option of reconfiguring the chain after the CA has been signed.

The CA/CRL/OCSP URLs can now be set on a per-issuer basis too - https://developer.hashicorp.com/vault/api-docs/secret/pki#update-issuer

Set them correctly before issuing any certificates from the relevant issuer.

2 Likes

Yes PKI-wise, I agree. I was talking about the tutorial step 8. Vault sets the newRoot ca_chain to oldRoot -> crossSigned -> newRoot. I guess it got twisted in my words. The question would rather be how such a chain is validated ?

Old clients would go all the way to oldRoot because they trust only oldRoot CA cert and new ones stop at newRoot because newRoot CA cert has been installed. So it would rather be a trick to form a chain that both client would be able to verify than a “correct” chain.

Interesting ressources, i will check that once work is bit less busy.
Well this one step to add to internal procedure about Vault PKI lifecycle.

You are right, I am actually testing the automatic chain building to make sure no loose ends breaks TLS depending on how the PKI is created and maintained in Vault. I’ll try to compute the results and try a PR to enhance documentation if needed.

I agree too but when it comes to chain building I think it may differ depending on the pki structure : mounts, issuer types inside, etc…

Yes, I am actually testing this. It is great and I was not using it correctly before.

Overall thank you for your answers and your time.