I have configured an Azure website (with one ApiController) to use client-certificate authentication using the instructions provided here. Summarizing: you set the clientCertEnabled
flag to true
and from then on your website starts asking for a client-authentication-certificate.
Works great, however, now I want to access the client certificate that is sent to the server. According to the MSDN article, it should be available in the X-ARR-ClientCert
request header, except that it isn't!!
This means that anyone with a client-authentication-certificate can access my API, which is undesirable in my case.
So how do I retrieve the client-authentication-certificate that a client sends to my Web API?
UPDATE 1: I'm actually calling my API through Azure API Management. I configured APIM with my client-authentication-certificate and APIM calls my API without issues. However, when the API is called from APIM, no X-ARR-ClientCert header is set. When called directly via Fiddler, I do see the header. So APIM is calling my API in some different way?!?
UPDATE 2: I went through everything again and produced some logging. First the relevant part of the DelegatingHandler
class I'm logging from:
protected override async Task<HttpResponseMessage>
SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Trace.TraceInformation("Going to validate client certificate.");
var x509Certificate2 = request.GetClientCertificate();
Trace.TraceInformation("Client cert: {0}", x509Certificate2 == null
? "<null>"
: x509Certificate2.Subject);
try
{
var headerKeys = string.Join("|", request.Headers.Select(h => h.Key));
Trace.TraceInformation("Header keys: {0}", headerKeys);
...
And the resulting log output:
2015-12-07T08:08:24 PID[8464] Information Going to validate client certificate.
2015-12-07T08:08:24 PID[8464] Information Client cert: <null>
2015-12-07T08:08:24 PID[8464] Information Header keys:
Connection|Host|Max-Forwards|Conf-Organisation-Key|Ocp-Apim-Subscription-Key|
X-Forwarded-For|X-LiveUpgrade|X-ARR-LOG-ID|DISGUISED-HOST|X-SITE-DEPLOYMENT-ID|
X-Original-URL
So there's no client certificate and also no X-ARR-ClientCert
header.
UPDATE 3: And here's the log that results when I go to my actual API directly with a client-authentication-certificate:
2015-12-07T09:16:45 PID[8464] Information Going to validate client certificate.
2015-12-07T09:16:45 PID[8464] Information Client cert: [email protected]
2015-12-07T09:16:45 PID[8464] Information Header keys:
Connection|Accept|Accept-Encoding|Accept-Language|Cookie|Host|Max-Forwards|
User-Agent|Upgrade-Insecure-Requests|DNT|X-LiveUpgrade|X-ARR-LOG-ID|DISGUISED-HOST|
X-SITE-DEPLOYMENT-ID|X-Original-URL|X-Forwarded-For|X-ARR-SSL|X-ARR-ClientCert
Both a client certificate directly from the request and the expected X-ARR-ClientCert
header.
UPDATE 4: In the end this happened to be my own mistake (of course). I was convinced that the url for the backend was https
while in fact it was http
. Client certificate authentication only works over https so in hindsight it made perfect sense no certificate was found in the backend...
You also need to enable client certificate authentication for the Azure hosted API - this step will ensure Azure carries over any X-ARR-ClientCert headers coming on the incoming request.
Otherwise Azure removes the X-ARR-ClientCert header from Request.Headers before it reaches your API.
Note: this setup is only available for paid subscriptions
"properties": { "name": "my-site", "state": "Running", "hostNames": [ "my-site.azurewebsites.net", "(string)" ], ... "clientCertEnabled": true, ... }
Documentation: https://learn.microsoft.com/en-us/azure/app-service-web/app-service-web-configure-tls-mutual-auth
Do you really want to manage client certificates for all users of the API? I understand using a client-cert to ensure only APIM can talk directly to your backend API. Usually developers who expose APIs via API Management use API keys to control access to the API. Using this approach enables policies to be applied based on different configured "products".
If you have the infrastructure in place to manage cert creation and revocation then this might be the right choice, it is just an uncommon approach. Having said that I will investigate what options are available in API Management to be able to extract the certificate thumbprint on the APIM gateway.
I am contacting the engineers in APIM to figure out how this is intended to work and will get back to you. When you have APIM in front of your actual API (web app), my guess is that APIM is the proxy that will take care of all the authN / authZ for you. So requests would go to your API only when this succeeds. I am guessing that is why they probably just drop the client certificate instead of forwarding it onward. But I can definitely see why the client cert would still be useful in the web app.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With