ARR authenticating itself to backend with client certificate on re-routing requests
Published Apr 28 2020 03:35 AM 6,146 Views

We want ARR to act as a reverse-proxy in front of an IIS machine. In fact, we could have several back-end machines, making ARR a load-balancer reverse-proxy. Requests arriving to ARR’s IP address, bearing host name header ARR-Authentication, should be re-routed to the IP address of IIS back-end node, with the host-name changed to Client-Cert-Mapping-IIS. In this setup, we have:

  • An IIS machine with ARR installed, Application Request Routing:
    Machine name is ARR, with IP address, endpoint http://ARR-Authentication.
  • A backend application node, where the app is using IIS Client Certificate Mapping Authentication:
    Machine name is IIS-A, with IP address, endpoint http://Client-Cert-Mapping-IIS.

While re-routing the request to IIS-A, the ARR should present a client certificate, to authenticate itself to the backend node.


Let’s avoid a potential confusion. IIS is not authenticating the user from the certificate. It does not determine the request user from the certificate properties. Instead, IIS is looking into its mappings, and it maps the client certificate of the request to a user account; if the account is determined from the mappings, then the corresponding user will be considered the HTTP request user. That user account may be locally defined, on the IIS machine, or it may be a domain account, in the Active Directory where the IIS may be a member.


Of course, on the backend node, the site should be using HTTPS, because only via TLS could IIS-A ask the client – in our case ARR node – to present its certificate. So we would have ARR re-routing requests to https://Client-Cert-Mapping-IIS.




Client Certificate Mapping


I am not going to cover the setup required for Client Certificate Mapping. It is already documented widely on the Internet. You may look at the official documentation or in my article about sub-applications using IIS Client Certificate Mapping Authentication.

Suffice to say that, on IIS-A, I have mapped the SSL client certificate, that would be presented by ARR, to a local user account defined on IIS-A. Like this: using IIS Manager, selecting the site then opening Configuration Editor, on Section drop-down selecting system.webServer > security > authentication > clientCertificateMappingAuthentication and iisClientCertificateMappingAuthentication.


IIS client certificate mappings to user accounts on server machineIIS client certificate mappings to user accounts on server machine




ARR configuration to present client certificate


First, my IIS-A node is added in a regular ARR server farm, with its FQDN; it could as well be added with its IP address:


Web farm node on ARRWeb farm node on ARR

And then the farm also has a corresponding URL Rewrite global rule (at the server level). Notice that we’re re-routing over HTTPS, to allow for certificate exchange during TLS handshake negotiation. Also notice that for the moment we’re re-routing to https://ARR-Authentication; we’ll soon cover how to make sure that requests are going to point to https://Client-Cert-Mapping-IIS.


URL Rewrite rule corresponding to ARR farmURL Rewrite rule corresponding to ARR farm

But how do you let ARR know that is has to present a client certificate to back-end farm nodes when it re-routes requests?

Well, that configuration is hidden, like many others in IIS. One would have to use the Configuration Editor in IIS Manager. So, on ARR node with IIS Manager:

  1. Select the server node, then open the Configuration Editor
  2. In the Section drop-down, we select webFarms
  3. Choose to edit the farms collection

Edit the collection of ARR web farmsEdit the collection of ARR web farms

  1. Select the server farm we’re interested in, namely ARR-Authentication.
  2. Then, expanding the applicationRequestRouting > protocol for the said farm:

Client certificate settings for an ARR farmClient certificate settings for an ARR farm

We have a couple of fields here related to client certificates:

I’m pointing to a PFX file, because PFX is a container format – it can hold several items: the certificate, its entire trust root and, most importantly, the corresponding private key. Since the private key is serious sensitive information, PFX files are regularly protected with a password. Hence…

This is the password allowing IIS/ARR to open the PFX file and retrieve from there the client certificate and its private key. So, we place here the password we used when saving/exporting the client certificate as PFX file.

Instead of placing the client certificate in a PFX file, we could have it retrieved by ARR from the machine’s certificate store. In this case, the certificate would be referenced or identified by its hash, or thumbprint. See details immediately below.

ARR could relay to backend node the certificates presented by clients connecting to it. It would relay these certificates by adding a new HTTP request header. However, this is not the certificate that ARR presents to backend during its own TLS negotiation with IIS-A. So, this setting is not relevant to what we’re pursuing in this article.



When storing the client certificate as a PFX file, we need to make sure that ARR, the IIS worker process w3wp.exe executing the ARR module, has read access to the location where the PFX file is placed. In my case, I have added the built-in Windows group used by IIS – IIS_IUSRS – with read-access to E:\Certificates\. So:


Read rights for IIS on certificateRead rights for IIS on certificate

If, instead of a PFX container file, you’re going to place the client certificate in the dedicated Windows store, then:

  1. Make sure you’re placing the certificate in the machine’s store, meaning Computer Certificates (not User Certificates).
  2. Get the certificate hash: open the certificate, locate the Thumbprint field in the Details tab.


Getting the certificate hashGetting the certificate hash

  1. Then simply use the thumbprint value, or hash, in the ARR configuration for client certificate:

ARR reads client certificate from machine's repositoryARR reads client certificate from machine's repository




Change the hostname of the farm


As we said in the beginning, the hostname must be changed during re-routing of the requests.

So how do we “convince” ARR to change the host header from ARR-Authentication to Client-Cert-Mapping-IIS when it re-routes requests from clients?

Well, I’m covering this in a separate article, but in short there are 2 settings that we need to change using Configuration Manager:

Firstly, change the applicationRequestRouting > protocol settings for the server farm, setting the preserveHostHeader to False.


Configuration change at the ARR farm levelConfiguration change at the ARR farm level

Secondly, change the hostName of the farm node(s) that are placed in the ARR server farm:


Configuration change at the farm node levelConfiguration change at the farm node level


To recap, now

  1. Clients are making requests to (IP of ARR) having hostname ARR-Authentication (so http:// http://ARR-Authentication)
  2. ARR is re-routing requests to (IP of IIS-A backend), changing the hostname to Client-Cert-Mapping-IIS (so ARR becomes a client requesting https://Client-Cert-Mapping-IIS).
  3. While re-routing, ARR is authenticating itself to IIS-A by presenting its own client certificate, that is stored in PFX file. The gateway/reverse-proxy/load-balancer is authenticated.

ARR could also relay the client certificates of the actual clients. But these are relayed as HTTP request headers, so custom code would be needed on the backend to inspect those, possibly doing a second authentication, of the actual user.

For reference, the applicationHost.config code that we end-up with is:

The URL Rewrite rule for the farm, because ARR acts as reverse-proxy:

                <rule name="ARR-Authentication_farm" patternSyntax="Wildcard" stopProcessing="true">
                    <match url="*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                        <add input="{HTTP_HOST}" pattern="ARR-Authentication" />
                    <action type="Rewrite" url="https://ARR-Authentication/{R:0}" />
        <proxy enabled="true" arrResponseHeader="true" />


ARR presenting a client certificate from a PFX container on disk:

    <webFarms onDemandHealthCheck="true">
        <webFarm name="ARR-Authentication" enabled="true">
            <server address="IIS-A.PinguLab.local" enabled="true">
                <applicationRequestRouting hostName="Client-Cert-Mapping-IIS" />
                <protocol preserveHostHeader="false"
                          clientCertPassword="[enc:AesProvider:Ac2...ZvG:enc]" />


ARR presenting a client certificate from the machine’s certificate store:

    <webFarms onDemandHealthCheck="true">
        <webFarm name="ARR-Authentication" enabled="true">
            <server address="IIS-A.PinguLab.local" enabled="true">
                <applicationRequestRouting hostName="Client-Cert-Mapping-IIS" />
                <protocol preserveHostHeader="false"
                          clientCertHash="e62fc3a1381f69fc17602e25d9e233014cd74b7c" />


All the best!

1 Comment
Version history
Last update:
‎May 03 2020 05:05 AM
Updated by: