Two different services are exposed, call them 'cat service' and 'dog service'. "Cats" and "dogs" authenticate to the services via client certificates. The client certificates have cat and dog identities in the Subject (or SAN) field.
The PKI hierarchy is as follows:
root CA / \ cat CA dog CA / \ cat client certs dog client certs
I want to prevent cat service CA operator issuing dog client certificates (and the other way around).
It appears there are two options for this:
use the name constraint certificate extension on the intermediate CAs. In this case, the server is configured to trust the root CA. Now, if a client sends a dog certificate signed by the cat CA (+cat CA as a part of the cert. chain), the server sees a contradiction and rejects even before validating against the root CA.
Have the 'cat service' listener pin the intermediate 'cat CA' and dog service pin the 'dog CA'. In this case, the server doesn't trust the root CA.
As pointed out in the comments by garethTheRed, there's also the third option: >> Use Certificate Policies to constrain each CA path to an OID. Have the Root CA issue each Sub CA cert with it's own OID and have the server check this during path verification of the client certificate.
What are the upsides/downside/comparison of the three approaches?
Note: this is question different than Will two intermediate CAs signed by the same root CA trust each other's signed client certs? as it asks if there's any particular down/upsides for any of two listed approaches.