ARR as reverse-proxy authenticating itself to backend nodes with a Client Certificate

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 192.168.2.13, 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 192.168.2.14, 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.



Note:
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.



800x547?v=1.png IIS 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:



580x372?v=1.png Web 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.



800x745?v=1.png URL 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

640x335?v=1.png Edit 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:

640x609?v=1.png Client certificate settings for an ARR farm

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

clientCertFileName
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…

clientCertPassword
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.

clientCertHash
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.

clientCertHeaderName
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.



Notes


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:



340x476?v=1.png Read 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.



340x432?v=1.png Getting the certificate hash

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

641x677?v=1.png ARR 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.



641x610?v=1.png Configuration change at the ARR farm level

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



641x428?v=1.png Configuration change at the farm node level



To recap, now

  1. Clients are making requests to 192.168.2.13 (IP of ARR) having hostname ARR-Authentication (so http:// http://ARR-Authentication)
  2. ARR is re-routing requests to 192.168.2.14 (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:

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



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

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



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

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



All the best!

Continue reading...
 
Top Bottom