如何在 Windows Containers 安全的調整 IIS 站台設定 | The Will Will Web

The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何在 Windows Containers 安全的調整 IIS 站台設定

當你想要對 IIS 站台調整許多設定,又怕調整到一半突然出問題,這時候會殘留許多調整到一半的設定,如果想要做到 IaC (Infrastructure as code) 自動化,這個問題就必須被解決。還好 IISAdministration 模組中有提供「交易」相關的 Cmdlets 可用,本篇文章就來說說如何使用它。

建立容器

官方的 mcr.microsoft.com/dotnet/framework/aspnet:4.8 容器映象,已經預先安裝好 Web Server (IIS)ASP.NET 4.8 角色服務,我將會使用這個 image 為主要的執行環境。

docker run --name=mysite -d --isolation=process -p 80:80 -p 443:443 -v C:\Projects\WebApplication1:C:\Inetpub\wwwroot mcr.microsoft.com/dotnet/framework/aspnet:4.8

以下對上述參數進行說明:

  • --name=mysite 設定容器好記名稱為 mysite,方便後續命令說明。
  • -d 代表我們要將容器執行在 detach 模式(背景執行)。
  • --isolation=process 由於我們要複製現有的 PFX 憑證進容器,在 Windows 10 的 Windows Containers 必須要使用 proccess 隔離模式執行,才能執行 docker cp 命令複製檔案。
  • -p 80:80 -p 443:443 由於 Windows Containers 執行容器時,預設採用 nat 模式,所以需要將容器的 IP:Ports 對應到本機 Ports 比較方便測試。
  • -v C:\Projects\WebApplication1:C:\Inetpub\wwwroot 將一個現有的 ASP.NET MVC 5 專案對應到容器的 C:\Inetpub\wwwroot 路徑。
  • --entrypoint powershell 因為微軟官方的 aspnet 容器映象預設只能跑在 detach (-d) 模式,為了方便我們測試,我想改用 powershell 來當成預設進入程式。
  • mcr.microsoft.com/dotnet/framework/aspnet:4.8 已經預載 Web Server (IIS)ASP.NET 4.8 角色服務。這是微軟官方的「多架構」容器映象,詳見 Windows Container 版本相容性與多重架構容器映像介紹 文章。

接著透過 docker exec 進入容器中操作:

docker exec -it -w c:\inetpub\wwwroot mysite powershell

新增站台繫結

  1. 新增 HTTP 站台繫結

    綁定特定域名 ( 以 blog.miniasp.com 為例 )

    New-IISSiteBinding -Name "Default Web Site" -Protocol http -BindingInformation "*:80:blog.miniasp.com"
    

    綁定特定IP ( 以 192.168.9.100 為例 )

    New-IISSiteBinding -Name "Default Web Site" -Protocol http -BindingInformation "192.168.9.100:80:"
    

    綁定特定埠號 ( 以 8080 為例 )

    New-IISSiteBinding -Name "Default Web Site" -Protocol http -BindingInformation ":8080:"
    

    移除綁定

    Remove-IISSiteBinding -Name "Default Web Site" -Protocol http -BindingInformation "*:80:blog.miniasp.com" -Confirm:$false
    Remove-IISSiteBinding -Name "Default Web Site" -Protocol http -BindingInformation "192.168.9.100:80:" -Confirm:$false
    Remove-IISSiteBinding -Name "Default Web Site" -Protocol http -BindingInformation ":8080:" -Confirm:$false
    
  2. 新增 HTTPS 站台繫結

    綁定 IP-based SSL (不指定特定域名)

    $cert = New-SelfSignedCertificate -DnsName blog.miniasp.com -CertStoreLocation cert:\LocalMachine\My
    
    New-IISSiteBinding -Name "Default Web Site" -Protocol https -BindingInformation "*:443:" -CertificateThumbPrint $cert.Thumbprint -CertStoreLocation My
    

    綁定 SNI-based SSL (指定特定域名)

    $cert = New-SelfSignedCertificate -DnsName blog.miniasp.com -CertStoreLocation cert:\LocalMachine\My
    
    New-IISSiteBinding -Name "Default Web Site" -Protocol https -BindingInformation "*:443:blog.miniasp.com" -SslFlag Sni -CertificateThumbPrint $cert.Thumbprint -CertStoreLocation My
    

    移除綁定

    Remove-IISSiteBinding -Name "Default Web Site" -Protocol https -BindingInformation "*:443:" -Confirm:$false
    Remove-IISSiteBinding -Name "Default Web Site" -Protocol https -BindingInformation "*:443:blog.miniasp.com" -Confirm:$false
    

批次新增站台繫結

如果你一次需要新增好幾個站台繫結,或是一口氣要用 PowerShell 調整多項 IIS 設定的話,透過一行一行執行其實是不太好的。因為這些 PowerShell Cmdlets 每次執行時,都會確實寫入到 applicationHost.config 設定檔中,若你有其中一段設定掛掉的話,就可能會有設定不一致的問題!

IISAdministration 有兩個 Cmdlets 可以讓你的批次作業擁有「交易特性」(Transaction)。

以下是使用範例:

Start-IISCommitDelay

New-IISSite -Name "Test" -PhysicalPath "c:\Inetpub\wwwroot" -BindingInformation ":80:www.example.com" -Protocol http
New-IISSiteBinding -Name "Test" -Protocol http -BindingInformation "*:80:i1.example.com"
New-IISSiteBinding -Name "Test" -Protocol http -BindingInformation "*:80:i2.example.com"
New-IISSiteBinding -Name "Test" -Protocol http -BindingInformation "*:80:i3.example.com"
New-IISSiteBinding -Name "Test" -Protocol http -BindingInformation "*:80:i4.example.com"
New-IISSiteBinding -Name "Test" -Protocol http -BindingInformation "*:80:i5.example.com"

Stop-IISCommitDelay -Commit $True

如果你發現設定的過程有問題發生,就可以用 Stop-IISCommitDelay -Commit $False 來取消取消之前所有的變更!

以下是完整的使用範例:

$ErrorActionPreference = "Stop"

Get-IISSite

try
{
  Write-Host "開始建立站台"
  Start-IISCommitDelay

  New-IISSite -Name "Test" -PhysicalPath "c:\Inetpub\wwwroot" -BindingInformation ":80:www.example.com" -Protocol http
  New-IISSiteBinding -Name "Test" -Protocol http -BindingInformation "*:80:i1.example.com"
  New-IISSiteBinding -Name "Test" -Protocol http -BindingInformation "*:80:i2.example.com"
  New-IISSiteBinding -Name "Test" -Protocol http -BindingInformation "*:80:i2.example.com" # 重複的域名
  New-IISSiteBinding -Name "Test" -Protocol http -BindingInformation "*:80:i4.example.com"
  New-IISSiteBinding -Name "Test" -Protocol http -BindingInformation "*:80:i5.example.com"

  Write-Host "站台建立成功!"
  Stop-IISCommitDelay -Commit $True
}
catch
{
  Write-Host "建立站台發生錯誤,復原所有設定"
  Stop-IISCommitDelay -Commit $False
}

Get-IISSite

使用 Get-IISServerManager 批次設定

透過 IISAdministration 模組下的 Get-IISServerManager 也可以讓你的批次作業擁有「交易特性」(Transaction)。

透過 Get-IISServerManager 可以取回 .NET 的 Microsoft.Web.Administration 物件,讓你直接透過 .NET 物件來操作 IIS 內的各項設定。以下是使用範例:

$sm = Get-IISServerManager

$sm.Sites["Default Web Site"].Bindings.Add("*:80:www.example.com", "http")
$sm.Sites["Default Web Site"].Bindings.Add("*:80:a.example.com", "http")
$sm.Sites["Default Web Site"].Bindings.Add("*:80:b.example.com", "http")
$sm.Sites["Default Web Site"].Bindings.Add("*:80:c.example.com", "http")
$sm.Sites["Default Web Site"].Bindings.Add("*:80:d.example.com", "http")
$sm.Sites["Default Web Site"].Bindings.Add("*:80:e.example.com", "http")

$sm.CommitChanges();

我個人還是比較喜歡用 IISAdministration 模組下標準的 Cmdlets 來調整 IIS 設定,一來比較簡單,二來就算沒有 .NET 經驗也可以使用。

不過,透過 .NET 物件操作的彈性,會比用 PowerShell 來的強大很多,至於你想用哪種方式調整設定,就全看你個人喜好囉! 🙂

相關連結