我有個需要中介伺服器轉接 WebAPI 請求的情境,ApWeb 主機與 ApiWeb 主機間網路不互通,故需要在中間網段架設 Proxy 串接,之前玩過 IIS ARR ,打算找台 IIS 設成 Reverse Proxy 負責轉送 ApWeb 主機發出的 WebAPI 請求。ARR 之前已設過幾次,但全憑 GUI 手工,操作步驟有點繁瑣怕有人為失誤,同時也不利自動化標準化,故我研究了以 PowerShell 及檔案部署為主的簡化安裝方法,特筆記備忘。

  1. 下載取得Application Request Routing 3.0 Stand-alone package (IExpress) x64 四合一安裝包,一次裝好 Web Farm Framework module、External cache module、URL Rewrite module 以及 ARR。加上 /Q 參數 ARRv3_setup_amd64_en-us.EXE /Q 可以批次方式安裝。
  2. 使用以下 PowerShell 指令啟用 ARR Proxy 功能
    Set-WebConfigurationProperty -filter /system.webServer/proxy -name enabled -value True  
    
    註:執行後會在 C:\Windows\System32\inetsrv\config\applicationHost.config 加入 <system.webServer><proxy enabled="true"/>
  3. 如果轉送時要加入自訂 HTTP Header,則要宣告名稱以 HTTP_* 起首 Server Variables。我希望直接寫在 web.config,但 allowedServerVariables 預設只能在 appicationHost.config 宣告。applicationHost.config configSections/sectionGroup name="rewrite"/section name="allowedServerVariables" 有個的 overrideModeDefault 設定為 Deny,改為 Allow 即可從 web.config 直接定義 allowedServerVariables。這裡依舊招喚 PowerShell 為我們搞定:
    Set-WebConfigurationProperty -filter /system.webServer/rewrite -name 'sections["allowedServerVariables"].overrideModeDefault' -value Allow 
    
  4. 在 web.config 加入以下設定
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <system.webServer>
            <rewrite>
                <allowedServerVariables>
                    <add name="HTTP_X_Orig_ClientIP" />
                </allowedServerVariables>
                <rules>
                    <rule name="TestReverseProxy" stopProcessing="true">
                        <match url="Test/(.*)" />
                        <conditions>
                            <add input="{CACHE_URL}" pattern="^(https?)://" />
                        </conditions>
                        <action type="Rewrite" url="http://172.28.1.1/Test/{R:1}" />
                        <serverVariables>
                            <set name="HTTP_X_Orig_ClientIP" value="{REMOTE_ADDR}" />
                        </serverVariables>
                    </rule>
                </rules>
            </rewrite>
        </system.webServer>
    </configuration>
    
    以上設定定義將連上 Reverse Proxy IIS 的 httq://rev-proxy/Test/* 一律導向 httq://172.28.1.1/Test/*,並在 HTTP Header 加入一條 X-Orig-ClientIP 傳入原始來源 IP。allowedServerVariables 中以 HTTP_* 為首的伺服器變數名稱,將會對應成 HTTP Header,而變數名稱中的 _ 會轉成 -。

就醬,連 IIS 管理員都不用打開,我們已完成所有設定。

我寫了一個測試網頁觀察轉換效果:ShowHeaders.aspx

<%@ Page Language="C#" %>

<script runat="server">
    void Page_Load(object sender, EventArgs e)
    {
        Response.ContentType = "text/plain";
        Response.Write("[Headers]\n");
        foreach (string key in Request.Headers.Keys)
        {
            Response.Write(key + ": " + Request.Headers[key] + "\n");
        }
        Response.Write("\n[Variables]");
        Response.Write("\nUserHostAddress = " + Request.UserHostAddress);
        Response.End();
    }
</script>

在 Reverse Proxy 主機 (在本例為 172.28.1.11) 開 IE 直接連 172.28.1.1/Test/ShowHeaders.aspx 長這樣:

若改呼叫 localhost/Test/ShowHeaders.aspx 由 Reverse Proxy 轉接時長這樣:

紅色部分是我們加入的自訂 Header,黃色部分則是 ARR 自動加上的。

最後補充,如果要從 Header 取出原始 IP,不管是自訂 Header 或是 X-Forwarded-For 都有被偽造的可能,不可盡信。一個稍微提升安全度的做法是 - 以白名單列舉 Reverse Proxy 或 Proxy 的 IP,只有來自這些 IP 的 Request 才改由 Header 取 IP,否則以 Request.UserHostAddress 為準。

【延伸閱讀】

A script-based IIS reverse proxy setup procedures.


Comments

Be the first to post a comment

Post a comment