Certificate is not reaching the API in Apigee X

We're trying to do the certificate authentication POC but we see that the certificate is not reaching the API Proxy in Apigee X. As per checking, the client.cn variable is null whenever we send an API request with a certificate. 

In Apigee Edge, the Client Authorization is enabled in the property of the Virtual Host that is being used by API Proxies with certificate validation. Please refer to the below configuration:

 

{...

    "sSLInfo": {

        "clientAuthEnabled": "true",

...}

 

With regard to this, we would like to confirm how this configuration can be done in Apigee X.
@dchiesa1 

Solved Solved
2 6 158
1 ACCEPTED SOLUTION

And, this sample shows you how to set up mTLS on the "northbound", ingress side of Apigee X. 

https://github.com/GoogleCloudPlatform/apigee-samples/tree/main/mtls-northbound

It specifically describes  how you can get the fingerprint, serial number, subject DN, etc, into HTTP headers that can be handled by your proxy. 

eg

Screenshot 2024-04-22 at 1.48.55 PM.png

View solution in original post

6 REPLIES 6

In X you do not configure the mTLS on the virtualhost (since virtualhost does not exist). 

In Apigee X, you will use the load balancer. If you configure mTLS there, then you can get additional headers automatically. This takes the place of PropagateTLSInformation in the Edge virtualhost.

Relevant information: 

https://cloud.google.com/load-balancing/docs/https/custom-headers-global#mtls-variables

And, this sample shows you how to set up mTLS on the "northbound", ingress side of Apigee X. 

https://github.com/GoogleCloudPlatform/apigee-samples/tree/main/mtls-northbound

It specifically describes  how you can get the fingerprint, serial number, subject DN, etc, into HTTP headers that can be handled by your proxy. 

eg

Screenshot 2024-04-22 at 1.48.55 PM.png

Thanks,  @dchiesa1. We already followed and tried the mTLS configuration on the northbound. As of now, we were able to capture the following certificate information in the request headers:

--custom-request-header="X-Client-Cert-Present:{client_cert_present}" \
  --custom-request-header="X-Client-Cert-Chain-Verified:{client_cert_chain_verified}" \
  --custom-request-header="X-Client-Cert-Error:{client_cert_error}" \
  --custom-request-header="X-Client-Cert-Hash:{client_cert_sha256_fingerprint}" \
  --custom-request-header="X-Client-Cert-Serial-Number:{client_cert_serial_number}" \
  --custom-request-header="X-Client-Cert-SPIFFE:{client_cert_spiffe_id}" \
  --custom-request-header="X-Client-Cert-URI-SANs:{client_cert_uri_sans}" \
  --custom-request-header="X-Client-Cert-DNSName-SANs:{client_cert_dnsname_sans}" \
  --custom-request-header="X-Client-Cert-Valid-Not-Before:{client_cert_valid_not_before}" \
  --custom-request-header="X-Client-Cert-Valid-Not-After:{client_cert_valid_not_after}", \
  --custom-request-header='X-Client-Cert-Issuer-DN:{client_cert_issuer_dn}' \
  --custom-request-header='X-Client-Cert-Subject-DN:{client_cert_subject_dn}' \
  --custom-request-header='X-Client-Cert-Leaf:{client_cert_leaf}' \
  --custom-request-header='X-Client-Cert-Chain:{client_cert_chain}'


Would you be able to share any documentations related to the other available custom request header that we can add? We are trying to look for the certificate common name value to be present in the request headers as well.

Thanks again! 

Thanks, @dchiesa1.

Sure thing, glad to help.

Would you be able to share any documentations related to the other available custom request header that we can add?

All of the relevant documentation for custom headers related to mTLS, is here:
https://cloud.google.com/load-balancing/docs/https/custom-headers-global#mtls-variables

As of now, we were able to capture the following certificate information in the request headers:

I suppose you probably do not need ALL of those headers. For example if you are not examining the serial number or the fingerprint (or are not using these for pinning purposes) then you don't need to include that as a custom request header!

We are trying to look for the certificate common name value to be present in the request headers as well.

As for the Common Name (aka CN) I suppose you can extract that pretty easily from the subject DN. (X-Client-Cert-Subject-DN).

a DN (Distinguished name) is a comma-separated list of key-value pairs, looking like this

 

C=US, ST=Washington, L=Kirkland, O=MyCompany LLC, OU=Apim team, CN=api.mydomain.net, emailAddress=owner@mycompany.com

 

The client-provided certificate will have an ISSUER and a SUBJECT. This is analogous to your driver's license in the USA; in which the issuer is the government of the state where you live, and the subject is YOU. Both the issuer and the subject are expressed as a DN. You saw in the documentation how to get headers than contain the DNs for these things.

The common Name, or CN, is one of the key/value pairs in a DN. In the example above, the common name is api.mydomain.net. For a server-side entity, like a website or an API endpoint, the CN is usually a fully-qualified domain name (FQDN). For a client, where there is no "domain name" associated to the client, the CN can take some other form. Like an email address, or a uuid, or some other less structured value.

But you can get your CN by just parsing the DN header.

To parse it, and extract just the CN=whatever value, you could use ExtractVariables, or a JavaScript policy.

I do not believe the Load Balancer has a way to send you JUST the CN for the Subject. It sends the entire DN, and it's up the the receiver, in this case the Apigee proxy, to extract the CN from that DN.

This is very helpful @dchiesa1. We manage to configure this now successfully. One last thing, we are getting below error when trying to import certificates with Basic Constraints set fo CA:false.

As per checking, most of the certificates that are being used are currently set to CA:false. Is there a way to bypass this validation or any workaround to import certificates with Basic Constraints set to CA:false?Config validation failed.png

I'm not an expert in the network load balancer and  cert manager, but I know some things about TLS. 

In general, when you provision a TLS endpoint, you populate the TRUST STORE with root certificates that you want to trust.  In the x509 chain-of-trust model, you do not configure endpoints to trust every certificate of every system that will connect with that endpoint.  Instead there is a hierarchy, and you configure the endpoint to trust... a trusted authority, and then any certificate that authority produces, will be indirectly trusted.   

The authority is a "CA", a Certificate Authority, that can sign certificates for other parties (like client apps, or servers, etc).  Some examples here are Cybertrust, Entrust, GoDaddy, Google, Internet Security Research Group (Let's Encrypt), and so on. 

The idea is, you add these "root certificates" to the trust store, and then your endpoint can trust any certificate signed by that CA. As a concrete example, I can add GoDaddy's root CA into my truststore, and then any certificate that GoDaddy produces, my endpoint will also trust. 

I suspect the reason you are seeing the error message you shared above is that you're trying to add a non-root certificate to the truststore. That's not the right way.  You need to add the certificate of the root - the root signer - to the trust store.

Who is the root CA?  

That depends. If you have a cert that your clients will be using, then you can interrogate them using the openssl tool like this: 

openssl x509 -in certfile.pem -noout -text

That will show you the Issuer of the certificate. That issuer is the one you want to trust. Actually it's not that simple, because the issuer might not be a root ca.  So you need to check the cert of the first issuer, and see if it is a root CA.  If it is, then THAT is the cert you want to trust (add to the trust store).  If it is not a root CA, then you need to get the cert of the issuer of THAT cert, and check it.  And keep going until you reach the root.  And add THAT cert to the trust store. 

Then when the client connects it will send in its certificate chain, and the load balancer will look at the chain and decide whether to trust the client's cert, based on the contents of the truststore.