本教學課程是系列的 第三部分 。 瞭解如何在 Azure Service Fabric 中執行的 ASP.NET Core 服務中新增 HTTPS 端點。 當您完成時,您會有一個投票應用程式,其啟用 HTTPS 的 ASP.NET Core 網路前端會在連接埠 443 上接聽。 如果您不想在 教學課程系列的第一部分中手動建立投票應用程式,您可以 下載原始程式碼 以取得完整的應用程式。
在本教學課程中,您將瞭解如何:
- 在服務中定義 HTTPS 端點
- 設定 Kestrel 以使用 HTTPS
- 在遠端叢集節點上安裝TLS/SSL憑證
- 授與 NetworkService 憑證私密金鑰的存取權
- 在 Azure 負載平衡器中開啟連接埠 443
- 將應用程式部署至遠端叢集
教學課程系列說明如何:
- 建置 .NET Service Fabric 應用程式
- 將應用程式部署到遠端叢集
- 將 HTTPS 端點新增至 ASP.NET Core 前端服務 (本教學課程)
- 使用 Azure Pipelines 設定 CI/CD
- 設定應用程式的監視和診斷
備註
建議您使用 Azure Az PowerShell 模組來與 Azure 互動。 開始使用前,請參閱安裝 Azure PowerShell。 若要了解如何移轉至 Az PowerShell 模組,請參閱將 Azure PowerShell 從 AzureRM 移轉至 Az。
先決條件
開始進行本教學課程之前:
- 如果您沒有 Azure 訂閱,請建立免費帳戶。
- 安裝 Visual Studio 2019 16.5 版或更新版本,包括 Azure 開發工作負載以及 ASP.NET 和 Web 開發工作負載。
- 安裝 Service Fabric SDK。
取得憑證或建立自我簽署的開發憑證
對於正式作業應用程式,請使用 憑證授權單位 (CA) 的憑證。 出於開發和測試目的,您可以建立和使用自我簽署憑證。 Service Fabric SDK 包含 CertSetup.ps1 指令碼。 指令碼會建立自我簽署憑證,並將它匯入 Cert:\LocalMachine\My 憑證存放區。 以系統管理員身分開啟命令提示字元視窗,然後執行下列命令來建立主體為 “CN=mytestcert” 的憑證:
PS C:\program files\microsoft sdks\service fabric\clustersetup\secure> .\CertSetup.ps1 -Install -CertSubjectName CN=mytestcert
如果您已經有憑證個人資訊交換 (PFX) 檔案,請執行下列命令,將憑證匯入 Cert:\LocalMachine\My 憑證存放區:
PS C:\mycertificates> Import-PfxCertificate -FilePath .\mysslcertificate.pfx -CertStoreLocation Cert:\LocalMachine\My -Password (ConvertTo-SecureString "!Passw0rd321" -AsPlainText -Force)
PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\My
Thumbprint Subject
---------- -------
3B138D84C077C292579BA35E4410634E164075CD CN=zwin7fh14scd.westus.cloudapp.azure.com
在服務資訊清單中定義 HTTPS 端點
使用 [以系統管理員身分執行] 選項開啟 Visual Studio,然後開啟 [投票] 解決方案。 在 [方案總管] 中,開啟 VotingWeb/PackageRoot/ServiceManifest.xml。 服務資訊清單會定義服務端點。 尋找Endpoints章節並編輯ServiceEndpoint端點的值。 將名稱變更為 EndpointHttps,將通訊協定設定為 https,將型別設定為 Input,並將連接埠變更為 443。 儲存您的變更。
<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="VotingWebPkg"
Version="1.0.0"
xmlns="http://schemas.microsoft.com/2011/01/fabric"
xmlns:xsd="https://www.w3.org/2001/XMLSchema"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<ServiceTypes>
<StatelessServiceType ServiceTypeName="VotingWebType" />
</ServiceTypes>
<CodePackage Name="Code" Version="1.0.0">
<EntryPoint>
<ExeHost>
<Program>VotingWeb.exe</Program>
<WorkingFolder>CodePackage</WorkingFolder>
</ExeHost>
</EntryPoint>
</CodePackage>
<ConfigPackage Name="Config" Version="1.0.0" />
<Resources>
<Endpoints>
<Endpoint Protocol="https" Name="EndpointHttps" Type="Input" Port="443" />
</Endpoints>
</Resources>
</ServiceManifest>
設定 Kestrel 以使用 HTTPS
在 [方案總管] 中,開啟 VotingWeb/VotingWeb.cs 檔案。 將 Kestrel 設定為使用 HTTPS,並在 Cert:\LocalMachine\My store 中查閱憑證。 新增下列 using 陳述式:
using System.Net;
using Microsoft.Extensions.Configuration;
using System.Security.Cryptography.X509Certificates;
更新值 ServiceInstanceListener 以使用新的 EndpointHttps 端點,並在埠 443 上接聽。 當您將 Web 主機設定為使用 Kestrel 伺服器時,您必須將 Kestrel 配置為接聽所有網路介面上的 IPv6 位址: opt.Listen(IPAddress.IPv6Any, port, listenOptions => {...}。
new ServiceInstanceListener(
serviceContext =>
new KestrelCommunicationListener(
serviceContext,
"EndpointHttps",
(url, listener) =>
{
ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");
return new WebHostBuilder()
.UseKestrel(opt =>
{
int port = serviceContext.CodePackageActivationContext.GetEndpoint("EndpointHttps").Port;
opt.Listen(IPAddress.IPv6Any, port, listenOptions =>
{
listenOptions.UseHttps(FindMatchingCertificateBySubject());
listenOptions.NoDelay = true;
});
})
.ConfigureAppConfiguration((builderContext, config) =>
{
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
})
.ConfigureServices(
services => services
.AddSingleton<HttpClient>(new HttpClient())
.AddSingleton<FabricClient>(new FabricClient())
.AddSingleton<StatelessServiceContext>(serviceContext))
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
.UseUrls(url)
.Build();
}))
此外,新增下列方法,以便 Kestrel 在 Cert:\LocalMachine\My 存放區中使用主體來尋找憑證。
如果您使用先前的 PowerShell 命令建立自我簽署憑證,或使用憑證的 CN,請取代 <your_CN_value> 為 mytestcert 。
如果您使用本機部署來 localhost,建議您使用 CN=localhost 來避免驗證例外狀況。
private X509Certificate2 FindMatchingCertificateBySubject(string subjectCommonName)
{
using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
var certCollection = store.Certificates;
var matchingCerts = new X509Certificate2Collection();
foreach (var enumeratedCert in certCollection)
{
if (StringComparer.OrdinalIgnoreCase.Equals(subjectCommonName, enumeratedCert.GetNameInfo(X509NameType.SimpleName, forIssuer: false))
&& DateTime.Now < enumeratedCert.NotAfter
&& DateTime.Now >= enumeratedCert.NotBefore)
{
matchingCerts.Add(enumeratedCert);
}
}
if (matchingCerts.Count == 0)
{
throw new Exception($"Could not find a match for a certificate with subject 'CN={subjectCommonName}'.");
}
return matchingCerts[0];
}
}
授與網路服務對憑證私密金鑰的存取權
在先前的步驟中,您將憑證匯入開發電腦上的 Cert:\LocalMachine\My 存放區。
現在,明確授與執行服務的帳戶 (預設為網路服務) 憑證私密金鑰的存取權。 您可以使用 certlm.msc 工具手動執行此步驟,但最好在服務資訊清單的 中SetupEntryPoint來執行 PowerShell 指令碼。
備註
Service Fabric 支援依指紋或主體一般名稱宣告端點憑證。 在這種情況下,執行階段會將憑證的私密金鑰的繫結和配置設定給服務正在執行的身分。 執行階段也會監視憑證的變更、續約和配置更新,以更新對應的私密金鑰。
設定服務安裝入口
在 [方案總管] 中,開啟 VotingWeb/PackageRoot/ServiceManifest.xml。 在區 CodePackage 段中,新增 SetupEntryPoint 節點,然後新增節點 ExeHost 。 在 中 ExeHost,將設定 Program 為 Setup.bat,然後設定 WorkingFolder 為 CodePackage。 當 VotingWeb 服務啟動時, Setup.bat 指令碼會在 CodePackage 資料夾中執行,然後再 VotingWeb.exe 啟動。
<?xml version="1.0" encoding="utf-8"?>
<ServiceManifest Name="VotingWebPkg"
Version="1.0.0"
xmlns="http://schemas.microsoft.com/2011/01/fabric"
xmlns:xsd="https://www.w3.org/2001/XMLSchema"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
<ServiceTypes>
<StatelessServiceType ServiceTypeName="VotingWebType" />
</ServiceTypes>
<CodePackage Name="Code" Version="1.0.0">
<SetupEntryPoint>
<ExeHost>
<Program>Setup.bat</Program>
<WorkingFolder>CodePackage</WorkingFolder>
</ExeHost>
</SetupEntryPoint>
<EntryPoint>
<ExeHost>
<Program>VotingWeb.exe</Program>
<WorkingFolder>CodePackage</WorkingFolder>
</ExeHost>
</EntryPoint>
</CodePackage>
<ConfigPackage Name="Config" Version="1.0.0" />
<Resources>
<Endpoints>
<Endpoint Protocol="https" Name="EndpointHttps" Type="Input" Port="443" />
</Endpoints>
</Resources>
</ServiceManifest>
新增批次檔和 PowerShell 設置腳本
若要從SetupEntryPoint的值執行 PowerShell,可以在指向 PowerShell 檔案的批次檔中執行 PowerShell.exe。
首先,將批次檔案加入服務專案。 在 [方案總管] 中,右鍵按一下 VotingWeb,然後選取 新增>項目。 新增名為 Setup.bat的新檔案。 編輯 Setup.bat 檔案並新增下列命令:
powershell.exe -ExecutionPolicy Bypass -Command ".\SetCertAccess.ps1"
修改 Setup.bat 檔案的內容,將「複製到輸出目錄」設定為「複製」(如果較新)。
在 [方案總管] 中,以滑鼠右鍵按一下 VotingWeb。 然後選取新增>新專案,並新增一個名為SetCertAccess.ps1的新檔案。 編輯 SetCertAccess.ps1 檔案以新增下列指令碼:
$subject="mytestcert"
$userGroup="Network Service"
Write-Host "Checking permissions to certificate $subject.." -ForegroundColor DarkCyan
$cert = (gci Cert:\LocalMachine\My\ | where { $_.Subject.Contains($subject) })[-1]
if ($cert -eq $null)
{
$message="Certificate with subject:"+$subject+" does not exist at Cert:\LocalMachine\My\"
Write-Host $message -ForegroundColor Red
exit 1;
}elseif($cert.HasPrivateKey -eq $false){
$message="Certificate with subject:"+$subject+" does not have a private key"
Write-Host $message -ForegroundColor Red
exit 1;
}else
{
$keyName=$cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
$keyPath = "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\"
if ($keyName -eq $null){
$privateKey = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
$keyName = $privateKey.Key.UniqueName
$keyPath = "C:\ProgramData\Microsoft\Crypto\Keys"
}
$fullPath=$keyPath+$keyName
$acl=(Get-Item $fullPath).GetAccessControl('Access')
$hasPermissionsAlready = ($acl.Access | where {$_.IdentityReference.Value.Contains($userGroup.ToUpperInvariant()) -and $_.FileSystemRights -eq [System.Security.AccessControl.FileSystemRights]::FullControl}).Count -eq 1
if ($hasPermissionsAlready){
Write-Host "Account $userGroup already has permissions to certificate '$subject'." -ForegroundColor Green
return $false;
} else {
Write-Host "Need add permissions to '$subject' certificate..." -ForegroundColor DarkYellow
$permission=$userGroup,"Full","Allow"
$accessRule=new-object System.Security.AccessControl.FileSystemAccessRule $permission
$acl.AddAccessRule($accessRule)
Set-Acl $fullPath $acl
Write-Output "Permissions were added"
return $true;
}
}
修改 SetCertAccess.ps1 檔案的內容,將 [複製到輸出目錄] 設定為 [複製] (如果較新)。
以管理員身分執行安裝指令碼
根據預設,服務安裝進入點可執行檔會使用與 Service Fabric 相同的認證 (通常是網路服務帳戶) 來執行。 SetCertAccess.ps1 需要管理員權限。 在應用程式資訊清單中,您可以變更安全性許可權,以在本機系統管理員帳戶下執行啟動指令碼。
在 [方案總管] 中,開啟 Voting/ApplicationPackageRoot/ApplicationManifest.xml。 首先,建立區 Principals 段並新增使用者 (例如 SetupAdminUser)。 將 SetupAdminUser 使用者帳戶新增至 Administrators 系統群組。
接下來,在 VotingWebPkg 套件的 ServiceManifestImport 區段中,設定一個 RunAsPolicy,將 SetupAdminUser 主體應用於設定進入點。 此原則會告知 Service Fabric Setup.bat 檔案會以 SetupAdminUser (具有系統管理員權限) 執行。
<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="VotingType" ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Parameters>
<Parameter Name="VotingData_MinReplicaSetSize" DefaultValue="3" />
<Parameter Name="VotingData_PartitionCount" DefaultValue="1" />
<Parameter Name="VotingData_TargetReplicaSetSize" DefaultValue="3" />
<Parameter Name="VotingWeb_InstanceCount" DefaultValue="-1" />
</Parameters>
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="VotingDataPkg" ServiceManifestVersion="1.0.0" />
<ConfigOverrides />
</ServiceManifestImport>
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="VotingWebPkg" ServiceManifestVersion="1.0.0" />
<ConfigOverrides />
<Policies>
<RunAsPolicy CodePackageRef="Code" UserRef="SetupAdminUser" EntryPointType="Setup" />
</Policies>
</ServiceManifestImport>
<DefaultServices>
<Service Name="VotingData">
<StatefulService ServiceTypeName="VotingDataType" TargetReplicaSetSize="[VotingData_TargetReplicaSetSize]" MinReplicaSetSize="[VotingData_MinReplicaSetSize]">
<UniformInt64Partition PartitionCount="[VotingData_PartitionCount]" LowKey="0" HighKey="25" />
</StatefulService>
</Service>
<Service Name="VotingWeb" ServicePackageActivationMode="ExclusiveProcess">
<StatelessService ServiceTypeName="VotingWebType" InstanceCount="[VotingWeb_InstanceCount]">
<SingletonPartition />
</StatelessService>
</Service>
</DefaultServices>
<Principals>
<Users>
<User Name="SetupAdminUser">
<MemberOf>
<SystemGroup Name="Administrators" />
</MemberOf>
</User>
</Users>
</Principals>
</ApplicationManifest>
在本機執行應用程式
在 [方案總管] 中,選取 [ 投票 ] 應用程式,並將 [ 應用程式 URL ] 屬性設定為 https://localhost:443。
儲存所有檔案,然後選取 F5 以在本機執行應用程式。 在應用程式部署後,瀏覽器會開啟至 https://localhost:443。 如果您使用自我簽署憑證,您會看到一則警告,指出您的電腦不信任此網站的安全性。 繼續瀏覽網頁。
在叢集節點上安裝憑證
將應用程式部署至 Azure 之前,請在所有遠端叢集節點的 Cert:\LocalMachine\My 存放區中安裝憑證。 服務可以移至叢集的不同節點。 當前端 Web 服務在叢集節點上啟動時,啟動指令碼會查閱憑證並設定存取權限。
若要在叢集節點上安裝憑證,請先將憑證匯出為 PFX 檔案。 開啟 certlm.msc 應用程式檔案,然後移至 個人>憑證。 以滑鼠右鍵按一下 mytestcert 憑證,然後選取 [ 所有工作>匯出]。
在匯出精靈中,選取 [ 是,匯出私密金鑰],然後選取 PFX 格式。 將檔案匯出至 C:\Users\sfuser\votingappcert.pfx。
接下來,使用 PowerShell 腳本在遠端叢集上安裝憑證。
警告
自我簽署憑證足以用於開發和測試應用程式。 對於正式作業應用程式,請使用 憑證管理中心 (CA) 的憑證,而不是使用自我簽署憑證。
在 Azure 負載平衡器和虛擬網路中開啟連接埠 443
如果負載平衡器未開啟,請在負載平衡器中開啟連接埠 443:
$probename = "AppPortProbe6"
$rulename="AppPortLBRule6"
$RGname="voting_RG"
$port=443
# Get the load balancer resource
$resource = Get-AzResource | Where {$_.ResourceGroupName –eq $RGname -and $_.ResourceType -eq "Microsoft.Network/loadBalancers"}
$slb = Get-AzLoadBalancer -Name $resource.Name -ResourceGroupName $RGname
# Add a new probe configuration to the load balancer
$slb | Add-AzLoadBalancerProbeConfig -Name $probename -Protocol Tcp -Port $port -IntervalInSeconds 15 -ProbeCount 2
# Add rule configuration to the load balancer
$probe = Get-AzLoadBalancerProbeConfig -Name $probename -LoadBalancer $slb
$slb | Add-AzLoadBalancerRuleConfig -Name $rulename -BackendAddressPool $slb.BackendAddressPools[0] -FrontendIpConfiguration $slb.FrontendIpConfigurations[0] -Probe $probe -Protocol Tcp -FrontendPort $port -BackendPort $port
# Set the goal state for the load balancer
$slb | Set-AzLoadBalancer
對相關聯的虛擬網路執行相同的動作:
$rulename="allowAppPort$port"
$nsgname="voting-vnet-security"
$RGname="voting_RG"
$port=443
# Get the network security group resource
$nsg = Get-AzNetworkSecurityGroup -Name $nsgname -ResourceGroupName $RGname
# Add the inbound security rule.
$nsg | Add-AzNetworkSecurityRuleConfig -Name $rulename -Description "Allow app port" -Access Allow `
-Protocol * -Direction Inbound -Priority 3891 -SourceAddressPrefix "*" -SourcePortRange * `
-DestinationAddressPrefix * -DestinationPortRange $port
# Update the network security group
$nsg | Set-AzNetworkSecurityGroup
將應用程式部署至 Azure
儲存所有檔案,從偵錯切換至發行,然後選取 F6 進行重建。 在 [方案總管] 中,以滑鼠右鍵按一下 [投票],然後選取 [發佈]。 選取在將 應用程式部署至叢集中建立之叢集的連線端點,或選取另一個叢集。 選取 [發佈] 以將應用程式發佈至遠端叢集。
當應用程式部署時,請開啟網頁瀏覽器,然後前往 https://mycluster.region.cloudapp.azure.com:443 (請使用您叢集的連線端點來更新該 URL)。 如果您使用自我簽署憑證,您會看到一則警告,指出您的電腦不信任此網站的安全性。 繼續瀏覽網頁。
後續步驟
前進到下一個教學課程: