Tutorial: Hinzufügen eines HTTPS-Endpunkts für eine Service Fabric-Anwendung mithilfe von Kestrel
Dieses Tutorial ist der dritte Teil einer Reihe. Erfahren Sie, wie Sie einen HTTPS-Endpunkt in einem ASP.NET Core-Dienst hinzufügen, der in Azure Service Fabric ausgeführt wird. Am Ende des Tutorials verfügen Sie über eine Abstimmungsanwendung mit einem HTTPS-fähigen ASP.NET Core-Web-Front-End, das am Port 443 lauscht. Wenn Sie die Abstimmungsanwendung nicht manuell in Teil 1 der Tutorialreiheerstellen möchten, können Sie den Quellcode herunterladen, um die fertige Anwendung abzurufen.
In diesem Tutorial lernen Sie Folgendes:
- Definieren eines HTTPS-Endpunkts im Dienst
- Einrichten von Kestrel für die Verwendung von HTTPS
- Installieren des TLS-/SSL-Zertifikats auf den Remoteclusterknoten
- Gewähren von Zugriff auf den privaten Schlüssel des Zertifikats für „Network Service“
- Öffnen von Port 443 im Azure-Lastenausgleich
- Bereitstellen der Anwendung in einem Remotecluster
Die Tutorialreihe veranschaulicht folgende Vorgehensweisen:
- Erstellen einer .NET Service Fabric-Anwendung
- Bereitstellen der Anwendung in einem Remotecluster
- Hinzufügen eines HTTPS-Endpunkts zu einem ASP.NET Core-Front-End-Dienst (dieses Tutorial)
- Konfigurieren von CI/CD mit Azure Pipelines
- Einrichten der Überwachung und Diagnose für die Anwendung
Hinweis
Es wird empfohlen, das Azure Az PowerShell-Modul für die Interaktion mit Azure zu verwenden. Informationen zu den ersten Schritten finden Sie unter Installieren von Azure PowerShell. Informationen zum Migrieren zum Az PowerShell-Modul finden Sie unter Migrieren von Azure PowerShell von AzureRM zum Az-Modul.
Voraussetzungen
Bevor Sie mit diesem Tutorial beginnen können, müssen Sie Folgendes tun:
- Wenn Sie kein Azure-Abonnement besitzen, können Sie ein kostenloses Konto erstellen.
- Installieren Sie Visual Studio 2019 (Version 16.5 oder höher) mit den Workloads Azure-Entwicklung und ASP.NET und Webentwicklung.
- Installieren Sie das Service Fabric SDK.
Beziehen eines Zertifikats oder Erstellen eines selbstsignierten Entwicklungszertifikats
Verwenden Sie für Produktionsanwendungen ein Zertifikat einer Zertifizierungsstelle. Zu Entwicklungs- und Testzwecken können Sie auch ein selbstsigniertes Zertifikat erstellen und verwenden. Das Service Fabric SDK enthält das Skript CertSetup.ps1. Das Skript erstellt ein selbstsigniertes Zertifikat und importiert es in den Zertifikatspeicher:\LocalMachine\Mein Zertifikatspeicher. Öffnen Sie ein Eingabeaufforderungsfenster als Administrator, und führen Sie den folgenden Befehl aus, um ein Zertifikat mit dem Antragsteller „CN=mytestcert“ zu erstellen:
PS C:\program files\microsoft sdks\service fabric\clustersetup\secure> .\CertSetup.ps1 -Install -CertSubjectName CN=mytestcert
Wenn Sie bereits über eine PFX-Datei (Personal Information Exchange) verfügen, führen Sie Folgendes aus, um das Zertifikat in den Zertifikatspeicher Cert:\LocalMachine\My zu importieren:
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
Definieren eines HTTPS-Endpunkts im Dienstmanifest
Öffnen Sie Visual Studio, indem Sie die Option Als Administrator ausführen verwenden, und öffnen Sie dann die Abstimmungslösung. Öffnen Sie VotingWeb/PackageRoot/ServiceManifest.xml im Projektmappen-Explorer. Das Dienstmanifest definiert die Dienstendpunkte. Suchen Sie den Endpoints
Abschnitt, und bearbeiten Sie den Wert für ServiceEndpoint
Endpunkt. Ändern Sie den Namen in EndpointHttps
, legen Sie das Protokoll auf https
, den Typ auf Input
, und den Port auf 443
. Speichern Sie die Änderungen.
<?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>
Konfigurieren von Kestrel für die Verwendung von HTTPS
Öffnen Sie die Datei VotingWeb/VotingWeb.cs im Projektmappen-Explorer. Konfigurieren Sie Kestrel für die Verwendung von HTTPS und zum Nachschlagen des Zertifikats im Cert:\LocalMachine\My Speicher. Fügen Sie die folgenden using
-Anweisungen ein:
using System.Net;
using Microsoft.Extensions.Configuration;
using System.Security.Cryptography.X509Certificates;
Aktualisieren Sie den Wert für ServiceInstanceListener
, um den neuen EndpointHttps
Endpunkt zu nutzen und zum Überwachen von Port 443. Wenn Sie den Webhost für die Verwendung von Kestrel-Server konfigurieren, müssen Sie Kestrel so konfigurieren, dass an allen Netzwerkschnittstellen auf IPv6-Adressen gelauscht wird: 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();
}))
Fügen Sie als Nächstes außerdem die folgende Methode hinzu, damit Kestrel das Zertifikat im Speicher Cert:\LocalMachine\My anhand des Antragstellers findet.
Ersetzen Sie <your_CN_value>
mit mytestcert
, falls Sie mithilfe des vorherigen PowerShell-Befehls ein selbstsigniertes Zertifikat erstellt haben, oder verwenden Sie den allgemeinen Namen Ihres Zertifikats.
Wenn Sie eine lokale Bereitstellung an localhost
verwenden, empfiehlt es sich, CN=localhost
zu benutzen, um Authentifizierungsausnahmen zu vermeiden.
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];
}
}
Gewähren von Zugriff auf den privaten Schlüssel des Zertifikats für „Network Service“
In einem früheren Schritt haben Sie das Zertifikat im Cert:\LocalMachine\My Speicher auf dem Entwicklungscomputer importiert.
Gewähren Sie nun dem Konto, das den Dienst ausführt (standardmäßig „Network Service“), explizit Zugriff auf den privaten Schlüssel des Zertifikats. Dieser Schritt kann manuell über das Tool certlm.msc ausgeführt werden. Es empfiehlt sich jedoch, ein PowerShell-Skript auszuführen. Hierzu können Sie ein Startskript konfigurieren, im SetupEntryPoint
des Dienstmanifests.
Hinweis
Service Fabric unterstützt das Deklarieren von Endpunktzertifikaten nach Fingerabdruck oder allgemeinem Antragstellernamen. In diesem Fall richtet die Runtime die Bindung und eine Zugriffssteuerungsliste für den privaten Schlüssel des Zertifikats für die Identität ein, als die der Dienst ausgeführt wird. Die Laufzeit überwacht außerdem das Zertifikat auf Änderungen, Erneuerungen und Zuordnungsupdates für den entsprechenden privaten Schlüssel.
Konfigurieren des Setupeinstiegspunkts für Dienste
Öffnen Sie VotingWeb/PackageRoot/ServiceManifest.xml im Projektmappen-Explorer. Fügen Sie im CodePackage
Abschnitt den SetupEntryPoint
Knoten hinzu, und fügen Sie dann einen ExeHost
Knoten hinzu. In ExeHost
– Festlegen von Program
auf Setup.bat
und Festlegen von WorkingFolder
auf CodePackage
. Beim Start des VotingWeb-Diensts wird das Skript Setup.bat aus dem Ordner CodePackage vor dem Start von VotingWeb.exe ausgeführt.
<?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>
Hinzufügen des Batchskripts und des PowerShell-Setupskripts
Um PowerShell vom Wert für SetupEntryPoint
auszuführen, können Sie PowerShell.exe in einer Batchdatei ausführen, die auf eine PowerShell-Datei verweist.
Fügen Sie zunächst die Batchdatei dem Dienstprojekt hinzu. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf VotingWeb, und wählen Sie dann Hinzufügen>Neues Element aus. Fügen Sie eine neue Datei mit dem Namen Setup.bat hinzu. Bearbeiten Sie die Datei Setup.bat, und fügen Sie den folgenden Befehl hinzu:
powershell.exe -ExecutionPolicy Bypass -Command ".\SetCertAccess.ps1"
Legen Sie die Eigenschaften der Datei Setup.bat auf die Option In Ausgabeverzeichnis kopieren auf Kopieren, wenn neuer fest.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf VotingWeb. Wählen Sie dann Hinzufügen>Neues Element aus, und fügen Sie eine neue Datei namens SetCertAccess.ps1 hinzu. Bearbeiten Sie die Datei SetCertAccess.ps1, um das folgende Skript hinzufügen:
$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;
}
}
Legen Sie in den Dateieigenschaften von SetCertAccess.ps1 die Option In Ausgabeverzeichnis kopieren auf Kopieren, wenn neuer fest.
Ausführen des Setupskripts als Administrator
Standardmäßig wird die ausführbare Setupeinstiegspunkt-Datei des Diensts durch Nutzung der gleichen Anmeldeinformationen ausgeführt wie Service Fabric (in der Regel das NetworkService-Konto). Für SetCertAccess.ps1 sind Administratorberechtigungen erforderlich. Im Anwendungsmanifest können Sie die Sicherheitsberechtigungen zur Ausführung des Startskripts unter einem lokalen Administratorkonto ändern.
Öffnen Sie Voting/ApplicationPackageRoot/ApplicationManifest.xml im Projektmappen-Explorer. Erstellen Sie zunächst einen Principals
Abschnitt, und fügen Sie einen neuen Benutzer hinzu (z. B. SetupAdminUser
). Fügen Sie das Benutzerkonto „SetupAdminUser“ der Systemgruppe „Administratoren“ hinzu.
Konfigurieren Sie als Nächstes in „VotingWebPkg“ im Abschnitt ServiceManifestImport
eine Richtlinie vom Typ RunAsPolicy, um den Prinzipal „SetupAdminUser“ auf den Setupeinstiegspunkt anzuwenden. Diese Richtlinie teilt Service Fabric mit, dass die Datei Setup.bat als „SetupAdminUser“ (mit Administratorberechtigungen) ausgeführt wird.
<?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>
Lokales Ausführen der Anwendung
Klicken Sie im Projektmappen-Explorer auf die Anwendung Voting, und legen Sie die Eigenschaft Anwendungs-URL auf https://localhost:443
fest.
Speichern Sie alle Dateien, und wählen Sie F5, um die Anwendung lokal auszuführen. Nach der Bereitstellung der Anwendung wird https://localhost:443
in einem Browser geöffnet. Bei Verwendung eines selbstsignierten Zertifikats wird eine Warnung mit dem Hinweis angezeigt, dass Ihr PC der Sicherheit dieser Website nicht vertraut. Fahren Sie mit der Webseite fort.
Installieren des Zertifikats auf Clusterknoten
Bevor Sie die Anwendung in Azure bereitstellen, installieren Sie das Zertifikat im Cert:\LocalMachine\My Speicher aller Remoteclusterknoten. Dienste können in verschiedene Knoten im Cluster verschoben werden. Wenn der Front-End-Webdienst auf einem Clusterknoten gestartet wird, sucht das Startskript das Zertifikat und konfiguriert Zugriffsberechtigungen.
Um das Zertifikat auf Clusterknoten zu installieren, exportieren Sie zuerst das Zertifikat als PFX-Datei. Öffnen Sie die Anwendung certlm.msc, und navigieren Sie zu Eigene Zertifikate>Zertifikate. Klicken Sie mit der rechten Maustaste auf das Zertifikat mytestcert, und klicken Sie anschließend auf Alle Aufgaben>Exportieren.
Wählen Sie im Export-Assistenten Ja, privaten Schlüssel exportieren aus, und wählen Sie dann das PFX-Format aus. Exportieren Sie die Datei nach C:\Benutzer\sfuser\votingappcert.pfx.
Installieren Sie als Nächstes das Zertifikat im Remotecluster, indem Sie PowerShell-Skripts verwenden.
Warnung
Für Entwicklungs- und Testanwendungen reicht ein selbstsigniertes Zertifikat. Für Produktionsanwendungen muss dagegen ein Zertifikat von einer Zertifizierungsstelle verwendet werden.
Öffnen von Port 443 in Azure Load Balancer und im virtuellen Netzwerk
Öffnen Sie im Lastenausgleich den Port 443, sofern er nicht geöffnet ist:
$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
Führen Sie den gleichen Schritt für das zugehörige virtuelle Netzwerk aus:
$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
Bereitstellen der Anwendung in Azure
Speichern Sie alle Dateien, wechseln Sie vom Debug- in den Releasemodus, und wählen Sie F6, um das Projekt neu zu erstellen. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Voting, und klicken Sie auf Veröffentlichen. Wählen Sie den Verbindungsendpunkt des Clusters aus, den Sie im Tutorial Bereitstellen einer Anwendung in einem Service Fabric-Cluster in Azure erstellt haben, oder wählen Sie einen anderen Cluster aus. Wählen Sie Veröffentlichen, und veröffentlichen Sie die Anwendung für den Remotecluster.
Wenn die Anwendung bereitgestellt wurde, navigieren Sie in einem Webbrowser zu https://mycluster.region.cloudapp.azure.com:443
. (Aktualisieren Sie die URL mit dem Verbindungsendpunkt für Ihren Cluster.) Bei Verwendung eines selbstsignierten Zertifikats wird eine Warnung mit dem Hinweis angezeigt, dass Ihr PC der Sicherheit dieser Website nicht vertraut. Fahren Sie mit der Webseite fort.
Nächster Schritt
Fahren Sie mit dem nächsten Tutorial fort: