Freigeben über


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:

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:

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.

Screenshot, der das Einrichten der Dateieigenschaften zeigt.

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.

Screenshot der Service Fabric Voting-Beispiel-App, die in einem Browser und der URL Localhost ausgeführt wird.

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.

Screenshot, der den Export des Zertifikats zeigt.

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.

Screenshot der Service Fabric Voting-Beispiel-App, die in einem Browserfenster ausgeführt wird.

Nächster Schritt

Fahren Sie mit dem nächsten Tutorial fort: