Tutorial: agregar un punto de conexión HTTPS para una aplicación de Service Fabric mediante Kestrel
Este tutorial es la tercera parte de una serie. Más información sobre cómo agregar un punto de conexión HTTPS en un servicio de ASP.NET Core que se ejecuta en Azure Service Fabric. Cuando haya terminado tendrá una aplicación de votación con un front-end web de ASP.NET Core habilitado para HTTPS que escucha en el puerto 443. Si no desea crear manualmente la aplicación de votación de la primera parte de la serie de tutoriales, puede descargar el código fuente para obtener la aplicación terminada.
En este tutorial, aprenderá a:
- Definir un punto de conexión HTTPS en el servicio
- Configurar Kestrel para usar HTTPS
- Instalar el certificado TLS/SSL en los nodos del clúster remoto
- Conceder a NetworkService acceso a la clave privada del certificado
- Abrir el puerto 443 en Azure Load Balancer
- Implementar la aplicación en un clúster remoto
En esta serie de tutoriales se muestra cómo realizar las siguientes acciones:
- Crear una aplicación de .NET Service Fabric
- Implementar la aplicación en un clúster remoto
- Agregar un punto de conexión HTTPS a un servicio de front-end de ASP.NET Core (este tutorial)
- Configuración de CI/CD con Azure Pipelines
- Configurar la supervisión y el diagnóstico para la aplicación
Nota:
Se recomienda usar el módulo Azure Az de PowerShell para interactuar con Azure. Para comenzar, consulte Instalación de Azure PowerShell. Para más información sobre cómo migrar al módulo Az de PowerShell, consulte Migración de Azure PowerShell de AzureRM a Az.
Prerrequisitos
Antes de empezar este tutorial:
- Si no tiene una suscripción a Azure, cree una cuenta gratuita.
- Instale la versión 16.5 o posterior de Visual Studio 2019, incluidas las cargas de trabajo de desarrollo de Azure y la carga de trabajo de desarrollo de ASP.NET y web.
- Instale el SDK de Service Fabric.
Obtener un certificado o crear de un certificado de desarrollo autofirmado
Para aplicaciones de producción, use un certificado de una entidad de certificación (CA). Con fines de desarrollo y pruebas, puede crear y usar un certificado autofirmado. El SDK de Service Fabric incluye el script CertSetup.ps1. El script crea un certificado autofirmado y lo importa al almacén de certificados Cert:\LocalMachine\My. Abra una ventana del símbolo del sistema como administrador y ejecute el siguiente comando para crear un certificado con el asunto "CN=mytestcert":
PS C:\program files\microsoft sdks\service fabric\clustersetup\secure> .\CertSetup.ps1 -Install -CertSubjectName CN=mytestcert
Si ya tiene un archivo de intercambio de información personal (PFX) certificado, ejecute lo siguiente para importar el certificado en el almacén de certificados 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
Definición de un punto de conexión HTTPS en el manifiesto de servicio
Abra Visual Studio mediante la opción Ejecutar como administrador y, a continuación, abra la solución Voting. En el Explorador de soluciones, abra VotingWeb/PackageRoot/ServiceManifest.xml. El manifiesto del servicio define los puntos de conexión del servicio. Busque la sección Endpoints
y edite el valor del punto de conexión ServiceEndpoint
. Cambie el nombre a EndpointHttps
, establezca el protocolo en https
, el tipo en Input
y el puerto en 443
. Guarde los cambios.
<?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>
Configurar Kestrel para que use HTTPS
En el Explorador de soluciones, abra el archivo VotingWeb/VotingWeb.cs. Configure Kestrel para usar HTTPS y buscar el certificado en el almacén Cert:\LocalMachine\My. Agregue las instrucciones siguientes using
:
using System.Net;
using Microsoft.Extensions.Configuration;
using System.Security.Cryptography.X509Certificates;
Actualice el valor de ServiceInstanceListener
para que use el nuevo punto de conexión EndpointHttps
y escuche en el puerto 443. Al configurar el host de web para usar el servidor Kestrel, debe configurar Kestrel para escuchar las direcciones IPv6 en todas las interfaces de red: 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();
}))
Luego, agregue el método siguiente para que Kestrel pueda encontrar el certificado en el almacén Cert:\LocalMachine\My mediante el asunto.
Reemplace <your_CN_value>
por mytestcert
si ha creado un certificado autofirmado usando el comando de PowerShell anterior o use el nombre CN del certificado.
Si usa una implementación local para localhost
, se recomienda usar CN=localhost
para evitar excepciones de autenticación.
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];
}
}
Conceder acceso al Servicio de red a la clave privada del certificado
En un paso anterior, importó el certificado al almacén Cert:\LocalMachine\My en el equipo de desarrollo.
Ahora, proporcione explícitamente a la cuenta que ejecuta el servicio (servicio de red, de forma predeterminada) acceso a la clave privada del certificado. Puede hacerlo manualmente (mediante la herramienta certlm.msc), pero es mejor ejecutar un script de PowerShell realizando la configuración de un script de inicio en el SetupEntryPoint
del manifiesto de servicio.
Nota:
Service Fabric admite la declaración de certificados de punto de conexión por huella digital o nombre común del firmante. En ese caso, el runtime configura el enlace y la asignación de la clave privada del certificado para la identidad en la que se ejecuta el servicio. El runtime también supervisa el certificado en busca de cambios y renovaciones y actualizaciones de asignación de la clave privada correspondiente.
Configuración del punto de entrada de instalación del servicio
En el Explorador de soluciones, abra VotingWeb/PackageRoot/ServiceManifest.xml. En la sección CodePackage
, agregue el nodo SetupEntryPoint
y, a continuación, agregue un nodo ExeHost
. En ExeHost
, establezca Program
en Setup.bat
y establezca WorkingFolder
en CodePackage
. Cuando se inicia el servicio VotingWeb, el script Setup.bat se ejecuta en la carpeta CodePackage antes de que se inicie 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>
Incorporación del lote y de los scripts de configuración de PowerShell
Para ejecutar PowerShell desde el valor de SetupEntryPoint
, puede ejecutar PowerShell.exe en un archivo por lotes que apunte al archivo de PowerShell.
En primer lugar, agregue el archivo por lotes al proyecto de servicio. En el Explorador de soluciones, haga clic con el botón derecho en VotingWeb y seleccione Agregar>Nuevo elemento. Agregue un nuevo archivo denominado Setup.bat. Edite el archivo Setup.bat y agregue el siguiente comando:
powershell.exe -ExecutionPolicy Bypass -Command ".\SetCertAccess.ps1"
Modifique las propiedades del archivo Setup.bat para establecer la opción Copiar en el directorio de salida en Copiar si es posterior.
En el Explorador de soluciones, haga clic con el botón derecho en VotingWeb. Luego, seleccione Agregar>Nuevo elemento y agregue un nuevo archivo denominado SetCertAccess.ps1. Edite el archivo SetCertAccess.ps1 para agregar el siguiente script:
$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;
}
}
Modifique las propiedades del archivo SetCertAccess.ps1 para establecer Copiar en el directorio de salida en Copiar si es posterior.
Ejecutar el script de instalación como administrador
De forma predeterminada, el ejecutable de punto de entrada del programa de instalación del servicio se ejecuta usando las mismas credenciales que Service Fabric (normalmente la cuenta de servicio de red). El archivo SetCertAccess.ps1 requiere permisos de administrador. En el manifiesto de aplicación, puede cambiar los permisos de seguridad para ejecutar el script de inicio con una cuenta de administrador local.
En el Explorador de soluciones, abra Voting/ApplicationPackageRoot/ApplicationManifest.xml. En primer lugar, cree una sección Principals
y agregue un nuevo usuario (por ejemplo, SetupAdminUser
). Agregue la cuenta de usuario SetupAdminUser al grupo de administradores del sistema.
A continuación, en la sección ServiceManifestImport
de VotingWebPkg, configure una directiva RunAsPolicy para aplicar la entidad de seguridad SetupAdminUser al punto de entrada de la instalación. Esta directiva indica a Service Fabric que el archivo Setup.bat se debe ejecutar como SetupAdminUser (con permisos de administrador).
<?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>
Ejecutar la aplicación localmente
En el Explorador de soluciones, seleccione la aplicación Voting y establezca la propiedad Application URL en https://localhost:443
.
Guarde todos los archivos y presione la tecla F5 para ejecutar la aplicación localmente. Después de que se implementa la aplicación, se abre un explorador en https://localhost:443
. Si va a usar un certificado autofirmado, aparecerá una advertencia que le indica que el PC no confía en la seguridad de este sitio web. Continúe con la página web.
Instalación del certificado en los nodos de clúster
Antes de implementar la aplicación en Azure, instale el certificado en el almacén Cert:\LocalMachine\My de todos los nodos de clúster remotos. Los servicios se pueden mover a diferentes nodos del clúster. Cuando se inicia el servicio web de front-end en un nodo de clúster, el script de inicio busca el certificado y configura los permisos de acceso.
Para instalar el certificado en los nodos del clúster, primero exporte el certificado como un archivo PFX. Abra el archivo de aplicación certlm.msc y vaya a Personal>Certificados. Haga clic con el botón derecho en el certificado mytestcert y seleccione Todas las tareas>Exportar.
En el Asistente para exportar, seleccione Sí, exportar la clave privada y, a continuación, seleccione el formato PFX. Exporte el archivo a C:\Users\sfuser\votingappcert.pfx.
A continuación, instale el certificado en el clúster remoto mediante scripts de PowerShell.
Advertencia
Un certificado autofirmado es suficiente para desarrollar y probar aplicaciones. Para aplicaciones de producción, use un certificado de una entidad de certificación (CA) en vez de usar un certificado autofirmado.
Apertura del puerto 443 en Azure Load Balancer y la red virtual
Abra el puerto 443 en el equilibrador de carga si no está abierto:
$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
Haga lo mismo para la red virtual asociada:
$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
Implementar la aplicación en Azure
Guarde todos los archivos, cambie de depurar a liberar y seleccione F6 para recompilar. En el Explorador de soluciones, haga clic con el botón derecho en Voting y seleccione Publicar. Seleccione el punto de conexión del clúster creado en Implementar una aplicación en un clúster., o seleccione otro clúster. Seleccione Publicar para publicar la aplicación en el clúster remoto.
Cuando se implemente la aplicación, abra un explorador web y vaya a https://mycluster.region.cloudapp.azure.com:443
(actualice la dirección URL con el punto de conexión del clúster). Si va a usar un certificado autofirmado, aparecerá una advertencia que le indica que el PC no confía en la seguridad de este sitio web. Continúe con la página web.
Paso siguiente
Avance hasta el siguiente tutorial: