Esercitazione: Aggiungere un endpoint HTTPS per un'applicazione di Service Fabric usando Kestrel
Questa esercitazione è la terza parte di una serie. Informazioni su come aggiungere un endpoint HTTPS in un servizio ASP.NET Core in esecuzione in Azure Service Fabric. Al termine, si dispone di un'applicazione di voto con un front-end Web di ASP.NET Core abilitato per HTTPS in ascolto sulla porta 443. Se non si vuole creare manualmente l'applicazione di voto nella prima parte della serie di esercitazioni, è possibile scaricare il codice sorgente per ottenere l'applicazione completata.
In questa esercitazione apprenderai a:
- Definire un endpoint HTTPS nel servizio
- Configurare Kestrel per l'uso di HTTPS
- Installare il certificato TLS/SSL nei nodi del cluster remoto
- Concedere a NetworkService l'accesso alla chiave privata del certificato
- Aprire la porta 443 nel servizio di bilanciamento del carico di Azure
- Distribuire l'applicazione in un cluster remoto
La serie di esercitazioni mostra come:
- Creare un'applicazione di Service Fabric .NET
- Distribuire l'applicazione in un cluster remoto
- Aggiungere un endpoint HTTPS a un servizio front-end ASP.NET Core (questa esercitazione)
- Configurare l'integrazione continua e il recapito continuo con Azure Pipelines
- Configurare il monitoraggio e la diagnostica per l'applicazione
Nota
È consigliabile usare il modulo Azure Az PowerShell per interagire con Azure. Per iniziare, vedere Installare Azure PowerShell. Per informazioni su come eseguire la migrazione al modulo AZ PowerShell, vedere Eseguire la migrazione di Azure PowerShell da AzureRM ad Az.
Prerequisiti
Prima di iniziare questa esercitazione:
- Se non hai una sottoscrizione di Azure, crea un account gratuito.
- Installare Visual Studio 2019 versione 16.5 o successiva, inclusi il carico di lavoro Sviluppo di Azure e il carico di lavoro ASP.NET e sviluppo Web.
- Installare Service Fabric SDK.
Ottenere un certificato o creare un certificato di sviluppo autofirmato
Per le applicazioni di produzione, usare un certificato di un'autorità di certificazione (CA). Per finalità di sviluppo e test, è possibile creare e usare un certificato autofirmato. Service Fabric SDK include lo script CertSetup.ps1 . Lo script crea un certificato autofirmato e lo importa nell'archivio certificati Cert:\LocalMachine\My . Aprire una finestra del prompt dei comandi come amministratore ed eseguire il comando seguente per creare un certificato con l'oggetto "CN=mytestcert":
PS C:\program files\microsoft sdks\service fabric\clustersetup\secure> .\CertSetup.ps1 -Install -CertSubjectName CN=mytestcert
Se si dispone già di un file PFX (Personal Information Exchange), eseguire quanto segue per importare il certificato nell'archivio certificati 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
Definire un endpoint HTTPS nel manifesto del servizio
Aprire Visual Studio usando l'opzione Esegui come amministratore e quindi aprire la soluzione Voting. In Esplora soluzioni aprire VotingWeb/PackageRoot/ServiceManifest.xml. Il manifesto del servizio definisce gli endpoint di servizio. Trovare la Endpoints
sezione e modificare il valore per ServiceEndpoint
l'endpoint. Modificare il nome in EndpointHttps
, impostare il protocollo su https
, il tipo su Input
e la porta su 443
. Salva le modifiche.
<?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>
Configurare Kestrel per l'uso di HTTPS
In Esplora soluzioni aprire il file VotingWeb/VotingWeb.cs. Configurare Kestrel per l'uso di HTTPS e per cercare il certificato nell'archivio Cert:\LocalMachine\My . Aggiungere le istruzioni using
seguenti:
using System.Net;
using Microsoft.Extensions.Configuration;
using System.Security.Cryptography.X509Certificates;
Aggiornare il valore per per ServiceInstanceListener
l'uso del nuovo EndpointHttps
endpoint e per l'ascolto sulla porta 443. Quando si configura l'host Web per l'uso del server Kestrel, è necessario configurare Kestrel per l'ascolto degli indirizzi IPv6 in tutte le interfacce di rete: 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();
}))
Aggiungere quindi il metodo seguente in modo che Kestrel possa trovare il certificato nell'archivio Cert:\LocalMachine\My usando l'oggetto .
Sostituire <your_CN_value>
con mytestcert
se è stato creato un certificato autofirmato usando il comando di PowerShell precedente o usare il nome comune del certificato.
Se si usa una distribuzione locale in localhost
, è consigliabile usare CN=localhost
per evitare eccezioni di autenticazione.
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];
}
}
Concedere al servizio di rete l'accesso alla chiave privata del certificato
In un passaggio precedente il certificato è stato importato nell'archivio Cert:\LocalMachine\My nel computer di sviluppo.
A questo punto, assegnare in modo esplicito all'account che esegue il servizio (servizio di rete, per impostazione predefinita) l'accesso alla chiave privata del certificato. È possibile eseguire questo passaggio manualmente (usando lo strumento certlm.msc ), ma è preferibile eseguire uno script di PowerShell configurando uno script di avvio nel SetupEntryPoint
manifesto del servizio.
Nota
Service Fabric supporta la dichiarazione di certificati endpoint tramite identificazione personale o nome comune del soggetto. In tal caso, il runtime configura l'associazione e l'allocazione per la chiave privata del certificato sull'identità in cui è in esecuzione il servizio. Il runtime monitora anche il certificato per le modifiche, i rinnovi e gli aggiornamenti di allocazione per la chiave privata corrispondente.
Configurare il punto di ingresso dell'installazione del servizio
In Esplora soluzioni aprire VotingWeb/PackageRoot/ServiceManifest.xml. CodePackage
Nella sezione aggiungere il SetupEntryPoint
nodo e quindi aggiungere un ExeHost
nodo. In ExeHost
impostare su Program
Setup.bat
e su WorkingFolder
CodePackage
. All'avvio del servizio VotingWeb, lo script Setup.bat viene eseguito nella cartella CodePackage prima dell'avvio 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>
Aggiungere gli script batch e di configurazione di PowerShell
Per eseguire PowerShell dal valore per SetupEntryPoint
, è possibile eseguire PowerShell.exe in un file batch che punta a un file di PowerShell.
Per prima cosa, aggiungere il file batch al progetto del servizio. In Esplora soluzioni fare clic con il pulsante destro del mouse su VotingWeb e quindi scegliere Aggiungi>nuovo elemento. Aggiungere un nuovo file denominato Setup.bat. Modificare il file Setup.bat e aggiungere il comando seguente:
powershell.exe -ExecutionPolicy Bypass -Command ".\SetCertAccess.ps1"
Modificare le proprietà per il file Setup.bat per impostare Copia nella directory di output su Copia se più recente.
In Esplora soluzioni fare clic con il pulsante destro del mouse su VotingWeb. Selezionare quindi Aggiungi>nuovo elemento e aggiungere un nuovo file denominato SetCertAccess.ps1. Modificare il file SetCertAccess.ps1 per aggiungere lo script seguente:
$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;
}
}
Modificare le proprietà per il file SetCertAccess.ps1 per impostare Copia nella directory di output su Copia se più recente.
Eseguire lo script di installazione come amministratore
Per impostazione predefinita, l'eseguibile del punto di ingresso dell'installazione del servizio viene eseguito usando le stesse credenziali di Service Fabric(in genere, l'account del servizio di rete). SetCertAccess.ps1 richiede autorizzazioni di amministratore. Nel manifesto dell'applicazione, è possibile modificare le autorizzazioni di sicurezza per eseguire lo script di avvio con un account amministratore locale.
In Esplora soluzioni aprire Voting/ApplicationPackageRoot/ApplicationManifest.xml. Creare prima di tutto una Principals
sezione e aggiungere un nuovo utente , ad esempio SetupAdminUser
. Aggiungere l'account utente SetupAdminUser al gruppo di sistema Administrators.
Successivamente, nella ServiceManifestImport
sezione VotingWebPkg configurare runAsPolicy per applicare l'entità SetupAdminUser al punto di ingresso dell'installazione. Questo criterio indica a Service Fabric che il file Setup.bat viene eseguito come SetupAdminUser (con autorizzazioni di amministratore).
<?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>
Eseguire l'applicazione in locale
In Esplora soluzioni selezionare l'applicazione Voting e impostare la proprietà APPLICATION URL su https://localhost:443
.
Salvare tutti i file e quindi selezionare F5 per eseguire l'applicazione in locale. Dopo la distribuzione dell'applicazione, viene aperto un browser su https://localhost:443
. Se si usa un certificato autofirmato, viene visualizzato un avviso che indica che il PC non considera attendibile la sicurezza di questo sito Web. Continuare con la pagina Web.
Installare il certificato nei nodi del cluster
Prima di distribuire l'applicazione in Azure, installare il certificato nell'archivio Cert:\LocalMachine\My di tutti i nodi del cluster remoto. I servizi possono essere spostati in nodi diversi del cluster. Quando il servizio Web front-end viene avviato in un nodo del cluster, lo script di avvio cerca il certificato e configura le autorizzazioni di accesso.
Per installare il certificato nei nodi del cluster, esportare prima di tutto il certificato come file PFX. Aprire il file dell'applicazione certlm.msc e passare a Certificati personali>. Fare clic con il pulsante destro del mouse sul certificato mytestcert e quindi scegliere Tutte le attività>esportate.
Nella procedura guidata di esportazione selezionare Sì, esportare la chiave privata e quindi selezionare il formato PFX. Esportare il file in C:\Users\sfuser\votingappcert.pfx.
Installare quindi il certificato nel cluster remoto usando gli script di PowerShell.
Avviso
Per le applicazioni di sviluppo e test è sufficiente un certificato autofirmato. Per le applicazioni di produzione, usare un certificato di un'autorità di certificazione (CA) anziché usare un certificato autofirmato.
Aprire la porta 443 nel servizio di bilanciamento del carico di Azure e nella rete virtuale
Aprire la porta 443 nel servizio di bilanciamento del carico se non è aperta:
$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
Eseguire la stessa operazione per la rete virtuale associata:
$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
Distribuire l'applicazione in Azure
Salvare tutti i file, passare da Debug a Rilascio e selezionare F6 per ricompilare. In Esplora soluzioni fare clic con il pulsante destro del mouse su Voto e scegliere Pubblica. Selezionare l'endpoint di connessione del cluster creato in Distribuire un'applicazione in un cluster oppure selezionare un altro cluster. Selezionare Pubblica per pubblicare l'applicazione nel cluster remoto.
Quando l'applicazione viene distribuita, aprire un Web browser e passare a https://mycluster.region.cloudapp.azure.com:443
(aggiornare l'URL con l'endpoint di connessione per il cluster). Se si usa un certificato autofirmato, viene visualizzato un avviso che indica che il PC non considera attendibile la sicurezza di questo sito Web. Continuare con la pagina Web.
Passaggio successivo
Passare all'esercitazione successiva: