Azure App Service Reverse Proxy works only on port 80 http - iis

I'm trying to configure Azure App Service Reverse Proxy to expose webserver in Azure Virtual Network to the internet and I had limited success - it's working when I'm not using encrypted connection between reverse proxy and target server.
Here is my currently working configuration:
web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<httpErrors errorMode="Detailed" />
<rewrite>
<rules>
<rule name="ForceSSL" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
<rule name="Proxy" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://example.com/{R:1}" />
<serverVariables>
<set name="HTTP_X_UNPROXIED_URL" value="http://example.com/{R:1}" />
<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
<set name="HTTP_X_ORIGINAL_HOST" value="{HTTP_HOST}" />
<set name="HTTP_ACCEPT_ENCODING" value="" />
</serverVariables>
</rule>
</rules>
<outboundRules>
<preConditions>
<preCondition name="CheckContentType">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^(text/html|text/plain|text/xml|application/rss\+xml)" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
</system.webServer>
</configuration>
applicationHost.xdt
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.webServer>
<proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="false" reverseRewriteHostInResponseHeaders="false"/>
<rewrite xdt:Transform="InsertIfMissing">
<allowedServerVariables xdt:Transform="InsertIfMissing">
<add name="HTTP_X_ORIGINAL_HOST" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/>
<add name="HTTP_X_UNPROXIED_URL" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/>
<add name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/>
<add name="HTTP_ACCEPT_ENCODING" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)"/>
</allowedServerVariables>
</rewrite>
</system.webServer>
</configuration>
IP Address of the server has been replaced by example.com
When I change web.config rewrite rule and HTTP_X_UNPROXIED_URL to https I get following IIS Error
Detailed Error Information:
Module ApplicationRequestRouting
Notification ExecuteRequestHandler
Handler ApplicationRequestRoutingHandler
Error Code 0x80072f8f
Requested URL https://example.com:80/
Physical Path D:\home\site\wwwroot
Logon Method Anonymous
Logon User Anonymous
Request Tracing Directory D:\home\LogFiles
This suggests, that for some reason it's trying to request https on port 80.
I tried to follow guide from here: https://www.patrickob.com/2018/11/10/adding-ca-certs-to-the-trusted-root-store-for-web-apps-hosted-in-an-ase/
I have added my organizations root cert to SSL certificated and added WEBSITE_LOAD_ROOT_CERTIFICATES setting.
Any help will be appreciated.

WEBSITE_LOAD_ROOT_CERTIFICATES is only supported in an App Service Environment, its not supported in multi-tenant app services. If the endpoint on-premises is signed by a certificate not using a public CA at this time there's no direct workaround to make this work outside of updating the certificate or possibly writing a simple proxy app that can ignore SSL cert validation (I typically wouldn't recommend this option unless you do the cert validation yourself in code).

Related

IIS ARR Reverse Proxy Works Until SSO Is Turned On

I am new to using IIS and the reverse proxy feature (ARR V3.0).
I have everything working correctly until a backend SSO authentication is enabled with the application.
The feature works from the IIS reverse proxy server if I go straight to the back end application but it fails when you try to authenticate thru the reverse proxy from the outside.
Flow is something like this when SSO is disabled:
Public User --> Public URL --> IIS/ARR --> Authentication --> Application Is Presented to user for login. Everything works. Again this is a single web server in the back end used for logon.
Flow is something like this when SSO is enabled:
Public User --> Public URL --> IIS/ARR --> Authentication --> Application Server --> SSO Application server --> IIS/ARR presents the back end (internal) SSO server name with DNS error. This is where the second server handling SSO is thrown into the mix.
The error displayed in a browser shows the internal server name in URL
(https://em004tcss066.xxxx.xxxx.xxx:8443/) with a DNS error (expected since the external DNS records do not contain the internal server names. I do see the redirectToSSO message above the address bar as it does that in the background but eventually times out with DNS error.
Current rules:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<clear />
<rule name="ReverseProxyInboundRule1" stopProcessing="false">
<match url="^(.*)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<serverVariables>
<set name="HTTP_REFERER" value="{HTTP_ACCEPT_ENCODING}" />
<set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
<set name="HTTP_ACCEPT_ENCODING" value="" />
</serverVariables>
<action type="Rewrite" url="https://em004tcweb062.xxx.xxxxxxxxx.xxx:3000/{R:1}" logRewrittenUrl="true" />
</rule>
</rules>
<outboundRules>
<rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
<match filterByTags="A, Base, Form, Img" pattern="^http(s)?://em004tcweb062.xxx.xxxxxxxxx.xxx:3000/(.*)" />
<action type="Rewrite" value="https{R:1}://xxxxxteamcentertraining.xxx.xxxxxxxxx.xxx/{R:2}" />
</rule>
<rule name="RestoreAcceptEncoding" preCondition="NeedsRestoringAcceptEncoding">
<match serverVariable="HTTP_ACCEPT_ENCODING" pattern="^(.*)" />
<action type="Rewrite" value="{HTTP_X_ORIGINAL_ACCEPT_ENCODING}" />
</rule>
<preConditions>
<preCondition name="ResponseIsHtml1">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
<preCondition name="NeedsRestoringAcceptEncoding">
<add input="{RESPONSE_CONTENT_TYPE}" pattern=".+" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
<defaultDocument enabled="true" />
</system.webServer>
</configuration>
I know this is an issue with ARR, but I am not sure what rule needs added/modified to resolve it?

DNN UrlRewrite ("DotNetNuke.HttpModules.UrlRewriteModule, DotNetNuke.HttpModules") does not run custom rewrite rule on web.config

On our DNN site hosted in an Azure app service, we have the following custom rule set on our web.config:
<rewrite>
<rules>
<rule name="Proxy" stopProcessing="true">
<match url="^base3/?(.*)" />
<action type="Rewrite" url="https://(a website hosted in aws s3)/tx/{R:1}" />
<serverVariables>
<set name="HTTP_ACCEPT_ENCODING" value="" />
<set name="HTTP_X_ORIGINAL_HOST" value="{HTTP_HOST}" />
<set name="HTTP_X_Blog" value="1" />
</serverVariables>
</rule>
</rules>
We have also setup the following in our applicationHost.xdt
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.webServer>
<proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="false" reverseRewriteHostInResponseHeaders="false" />
<rewrite>
<allowedServerVariables>
<add name="HTTP_X_ORIGINAL_HOST" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
<add name="HTTP_X_UNPROXIED_URL" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
<add name="HTTP_ACCEPT_ENCODING" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
<add name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
<add name="HTTP_X_Mischief" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
<add name="HTTP_X_Blog" xdt:Transform="Insert" xdt:Locator="Match(name)"/>
</allowedServerVariables>
</rewrite>
</system.webServer>
</configuration>
However, when trying to navigate to it (https://(our azure webapp.com)/base3/index.html) we constantly get the error The resource you are looking for has been removed, had its name changed, or is temporarily unavailable. which is confusing because this was the rewrite rule we have used on our other sites.
We even tried the same approach on a fresh app service and the rewrite rule above works just fine..
Trying to figure out what's wrong through heuristic analysis, on our web.config the rewrite rule now works if:
under <system.webServer>
<modules runAllManagedModulesForAllRequests="true">
then commenting <add name="UrlRewrite" type="DotNetNuke.HttpModules.UrlRewriteModule, DotNetNuke.HttpModules" preCondition="managedHandler" />
However, the main site breaks now..
How do we implement a rewrite rule that works properly with DotNetNuke.HttpModules.UrlRewriteModule, DotNetNuke.HttpModules??
UPDATE
<configSections>
<section name="RewriterConfig" type="URLRewriter.Config.RewriterConfigSerializerSectionHandler,URLRewriter" />
</configSections>
......
<RewriterConfig>
<Rules>
<RewriterRule>
<LookFor>^default/([0-9]+)/([_0-9a-z-]+)</LookFor>
<SendTo>11.aspx?id={R:1}</SendTo>
</RewriterRule>
</Rules>
</RewriterConfig>
PRIVIOUS
About the function of url rewrite, the reason is the Web Server integrated by App Service cannot have full control. You can refer my answer in another post .
You can use the Application Gateway to implement the url rewriting function.

HTTP 401 Error Only When Using IIS ARR Proxy

A application which contains a web interface is running on a Windows Server 2019 system with IIS 10 and ARR installed. When navigating to the webpage using IP:Port the webpage loads correctly. When navigating to the webpage using domain.com the website has some content that shows a 401 error in the console, and page does not load correctly.
When navigating to the domain the request passes through IIS and URL Rewrite. It would seem that there is some issue in regards to passing the information through the proxy.
This is the code for the rewrite rule in IIS:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://localhost:33337/{R:1}" />
<serverVariables>
<set name="HTTP_ACCEPT_ENCODING" value="" />
</serverVariables>
</rule>
</rules>
<outboundRules>
<rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
<match filterByTags="A, Form, Img" pattern="^http(s)?://localhost:33337\/?(.*)" />
<action type="Rewrite" value="http{R:1}://sub.domain.com/{R:2}" />
</rule>
<preConditions>
<preCondition name="ResponseIsHtml1">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
<urlCompression doStaticCompression="false" doDynamicCompression="true" dynamicCompressionBeforeCache="false" />
</system.webServer>
</configuration>
This is the GitHub Issue link for this specific issue:
https://github.com/qbittorrent/qBittorrent/issues/11207
I reproduced the issue.
Apparently qBittorrent expecting clients to send same-origin Referer headers. In your case it must be localhost:33337 but obviously sub.domain.com is being sent.
This security measure is activated by Enable Cross-Site Request Forgery (CSRF) protection setting that can be reached via qBitorrent > Options > Web UI > Security.
You have two options for the solution.
Disable the setting.
Rewrite the Referer header with an appropriate value.
If you want to rewrite the header, after allowing server variables HTTP_REFERER and HTTP_ORIGIN as you did for HTTP_ACCEPT_ENCODING, you should change your rules as follows.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://localhost:33337/{R:1}" />
<!-- New Optional Condition -->
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_REFERER}" pattern="^(?:https?://[^/]*/(.*))?$" />
</conditions>
<serverVariables>
<set name="HTTP_ACCEPT_ENCODING" value="" />
<!-- New Header Rewrite -->
<set name="HTTP_REFERER" value="http://localhost:33337/{C:1}" />
<!-- Remove Origin Header -->
<set name="HTTP_ORIGIN" value="" />
</serverVariables>
</rule>
</rules>
<outboundRules>
<rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
<match filterByTags="A, Form, Img" pattern="^http(s)?://localhost:33337\/?(.*)" />
<action type="Rewrite" value="http{R:1}://sub.domain.com/{R:2}" />
</rule>
<preConditions>
<preCondition name="ResponseIsHtml1">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
<urlCompression doStaticCompression="false" doDynamicCompression="true" dynamicCompressionBeforeCache="false" />
</system.webServer>
</configuration>
BTW bear in mind that, qBittorrent warns you about the issue. Remember to check Execution Log tab.

URL rewriting of subdirectory to diffent port using IIS

I'm trying to integrate ASP.net and Node.js on a single server.
ASP.net is at localhost:8080
NodeJs is at localhost:4000
My expectation is here.
client ----> IIS Server ----> ASP.NET (no rewriting except /api/* localhost:80)
(rev.0970.co.kr) |---> Node.js (matching with /api/* localhost:4000)
Node app is executed as a windows service, and serve localhost:4000/api/ locally. And should be accessed with http://rev.0970.co.kr/api/signin
All request excepting /api/ should be served normal IIS asp.net. (ex. http://rev.0970.co.kr/index.aspx)
My Setting Steps
- install ARR and UrlRewrite module
- enable proxy of ARR
- add rule to urlrewrite section as below.
<rule name="Proxy">
<match url="api/(.*)"/>
<conditions>
<add input="{HTTP_HOST}" pattern="rev.0970.co.kr" />
</conditions>
<action type="Rewrite" url="http://localhost:4000/api/{R:1}" />
</rule>
Result
- http://rev.0970.co.kr/api/signin : success
- http://rev.0970.co.kr/index.aspx : fail - 404 not found
I thought http://rev.0970.co.kr/index.aspx did not match api/(.*), so IIS might render index.aspx.
When I removed whole rule settings of urlrewrite, http://rev.0970.co.kr/index.aspx worked.
What did I do wrong?
edit
Here is my full web.config file.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<outboundRules>
<rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
<match filterByTags="A, Form, Img" pattern="^http(s)?://localhost:4000/(.*)" />
<action type="Rewrite" value="http{R:1}://rev.0970.co.kr/{R:2}" />
</rule>
<preConditions>
<preCondition name="ResponseIsHtml1">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
<rules>
<rule name="Proxy">
<match url="api/(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="rev.0970.co.kr" />
</conditions>
<action type="Rewrite" url="http://localhost:4000/api/{R:1}" />
</rule>
</rules>
</rewrite>
<tracing>
<traceFailedRequests>
<add path="*">
<traceAreas>
<add provider="ASP" verbosity="Verbose" />
<add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />
<add provider="ISAPI Extension" verbosity="Verbose" />
<add provider="WWW Server" areas="Security,CGI,RequestNotifications,Module,FastCGI" verbosity="General" />
</traceAreas>
<failureDefinitions timeTaken="00:00:00" statusCodes="404" />
</add>
</traceFailedRequests>
</tracing>
</system.webServer>
</configuration>

Is it possible to disable HTTP on an azure app service, not just redirect it to HTTPS

In azure app services you are able to redirect HTTP traffic to HTTPS either via the web.config file or through the custom domains blade in azure portal. Is it possible to disable HTTP completely without doing a redirect?
Here is a way to achieve this:
Go to Kudu console for the Web App
Go into the D:\home\site folder
Create a file called applicationhost.xdt in that folder, with the following content (you can drag/drop it from your local machine):
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<location path="%XDT_SITENAME%" xdt:Transform="InsertIfMissing" xdt:Locator="Match(path)">
<system.webServer xdt:Transform="InsertIfMissing">
<rewrite xdt:Transform="InsertIfMissing">
<rules xdt:Transform="InsertIfMissing">
<rule name="Disable HTTP" enabled="true" stopProcessing="true">
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="off" />
<add input="{WARMUP_REQUEST}" pattern="1" negate="true" />
</conditions>
<action type="CustomResponse" statusCode="401" />
</rule>
</rules>
</rewrite>
</system.webServer>
</location>
</configuration>
This will make http requests fail with 401 (you can customize the response in the <action> tag).

Resources