Tutorial: Adicionar um ponto de extremidade HTTPS para um aplicativo do Service Fabric usando o Kestrel
Este tutorial é a terceira parte de uma série. Saiba como adicionar um ponto de extremidade HTTPS em um serviço ASP.NET Core em execução no Azure Service Fabric. Quando terminar, você terá um aplicativo de votação que tem um front-end da Web ASP.NET Core habilitado para HTTPS que escuta na porta 443. Se você não quiser criar manualmente o aplicativo de votação na primeira parte da série de tutoriais, você pode baixar o código-fonte para obter o aplicativo completo.
Neste tutorial, irá aprender a:
- Definir um ponto final de HTTPS no serviço
- Configurar o Kestrel para usar HTTPS
- Instalar o certificado TLS/SSL nos nós de cluster remoto
- Conceder acesso NetworkService à chave privada do certificado
- Abrir a porta 443 no Balanceador de Carga do Azure
- Implementar a aplicação num cluster remoto
A série de tutoriais mostra como:
- Criar uma aplicação .NET do Service Fabric
- Implementar a aplicação num cluster remoto
- Adicionar um ponto de extremidade HTTPS a um serviço front-end ASP.NET Core (este tutorial)
- Configurar CI/CD usando o Azure Pipelines
- Configurar a monitorização e os diagnósticos da aplicação
Nota
Recomendamos que utilize o módulo Azure Az do PowerShell para interagir com o Azure. Para começar, consulte Instalar o Azure PowerShell. Para saber como migrar para o módulo do Az PowerShell, veja Migrar o Azure PowerShell do AzureRM para o Az.
Pré-requisitos
Antes de começar este tutorial:
- Se não tiver uma subscrição do Azure, crie uma conta gratuita.
- Instale o Visual Studio 2019 versão 16.5 ou posterior, incluindo a carga de trabalho de desenvolvimento do Azure e a carga de trabalho de desenvolvimento ASP.NET e Web.
- Instale o SDK do Service Fabric.
Obter um certificado ou criar um certificado de desenvolvimento autoassinado
Para aplicações de produção, utilize um certificado de uma autoridade de certificação (AC). Para fins de desenvolvimento e teste, pode criar e utilizar um certificado autoassinado. O SDK do Service Fabric inclui o script CertSetup.ps1 . O script cria um certificado autoassinado e o importa para o armazenamento de certificados Cert:\LocalMachine\My . Abra uma janela de prompt de comando como administrador e execute o seguinte comando para criar um certificado que tenha o assunto "CN=mytestcert":
PS C:\program files\microsoft sdks\service fabric\clustersetup\secure> .\CertSetup.ps1 -Install -CertSubjectName CN=mytestcert
Se você já tiver um arquivo PFX (Personal Information Exchange) de certificado, execute o seguinte para importar o certificado para o armazenamento 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
Definir um ponto final de HTTPS no manifesto de serviço
Abra o Visual Studio usando a opção Executar como administrador e, em seguida, abra a solução de votação. No Explorador de Soluções, abra VotingWeb/PackageRoot/ServiceManifest.xml. O manifesto do serviço declara os pontos finais do serviço. Encontre a Endpoints
seção e edite o valor do ponto de ServiceEndpoint
extremidade. Altere o nome para EndpointHttps
, defina o protocolo como https
, o tipo para Input
e a porta para 443
. Guardar as suas alterações.
<?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 o Kestrel para utilizar HTTPS
No Explorador de Soluções, abra o ficheiro VotingWeb/VotingWeb.cs. Configure o Kestrel para usar HTTPS e procurar o certificado no repositório Cert:\LocalMachine\My . Adicione as seguintes instruções using
:
using System.Net;
using Microsoft.Extensions.Configuration;
using System.Security.Cryptography.X509Certificates;
Atualize o valor para ServiceInstanceListener
usar o novo EndpointHttps
ponto de extremidade e escutar na porta 443. Quando você configura o host para usar o servidor Kestrel, você deve configurar o Kestrel para ouvir endereços IPv6 em todas as interfaces de rede: 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();
}))
Em seguida, adicione o seguinte método para que Kestrel possa encontrar o certificado no repositório Cert:\LocalMachine\My usando o assunto.
Substitua <your_CN_value>
por mytestcert
se você criou um certificado autoassinado usando o comando anterior do PowerShell ou use o CN do seu certificado.
Se você usar uma implantação local para localhost
, recomendamos que você use CN=localhost
para evitar exceções de autenticação.
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 acesso do Serviço de Rede à chave privada do certificado
Em uma etapa anterior, você importou o certificado para o armazenamento Cert:\LocalMachine\My no computador de desenvolvimento.
Agora, dê explicitamente à conta que está executando o serviço (Serviço de Rede, por padrão) acesso à chave privada do certificado. Você pode fazer essa etapa manualmente (usando a ferramenta certlm.msc ), mas é melhor executar um script do PowerShell configurando um script de inicialização no SetupEntryPoint
manifesto do serviço.
Nota
O Service Fabric oferece suporte à declaração de certificados de ponto de extremidade por impressão digital ou por nome comum do assunto. Nesse caso, o tempo de execução configura a associação e a alocação da chave privada do certificado para a identidade como a qual o serviço está sendo executado. O tempo de execução também monitora o certificado em busca de alterações, renovações e atualizações de alocação para a chave privada correspondente.
Configurar o ponto de entrada da configuração do serviço
No Explorador de Soluções, abra VotingWeb/PackageRoot/ServiceManifest.xml. CodePackage
Na seção, adicione o SetupEntryPoint
nó e, em seguida, adicione um ExeHost
nó. Em ExeHost
, defina Program
como Setup.bat
, e defina WorkingFolder
como CodePackage
. Quando o serviço VotingWeb é iniciado, o script Setup.bat é executado na pasta CodePackage antes VotingWeb.exe é iniciado.
<?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>
Adicionar os scripts de batch e do PowerShell
Para executar o PowerShell a partir do valor do SetupEntryPoint
, você pode executar PowerShell.exe em um arquivo em lotes que aponte para um arquivo do PowerShell.
Primeiro, adicione o ficheiro de batch ao projeto do serviço. No Gerenciador de Soluções, clique com o botão direito do mouse em VotingWeb e selecione Adicionar>Novo Item. Adicione um novo arquivo chamado Setup.bat. Edite o ficheiro Setup.bat e adicione o seguinte comando:
powershell.exe -ExecutionPolicy Bypass -Command ".\SetCertAccess.ps1"
Modifique as propriedades do arquivo Setup.bat para definir Copy to Output Directory como Copy se for mais recente.
No Gerenciador de Soluções, clique com o botão direito do mouse em VotingWeb. Em seguida, selecione Adicionar>Novo Item e adicione um novo arquivo chamado SetCertAccess.ps1. Edite o arquivo SetCertAccess.ps1 para adicionar o seguinte 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 as propriedades do arquivo SetCertAccess.ps1 para definir Copy to Output Directory como Copy se for mais recente.
Execute o script de instalação como administrador
Por padrão, o executável do ponto de entrada da configuração do serviço é executado usando as mesmas credenciais do Service Fabric (normalmente, a conta do Serviço de Rede). O SetCertAccess.ps1 requer permissões de administrador. No manifesto da aplicação, pode alterar as permissões de segurança para executar o script de arranque com uma conta de administrador local.
No Explorador de Soluções, abra Voting/ApplicationPackageRoot/ApplicationManifest.xml. Primeiro, crie uma Principals
seção e adicione um novo usuário (por exemplo, SetupAdminUser
). Adicione a conta de utilizador SetupAdminUser ao grupo Administradores do sistema.
Em seguida, em VotingWebPkg, na ServiceManifestImport
seção , configure um RunAsPolicy para aplicar o principal SetupAdminUser ao ponto de entrada de instalação. Esta política informa ao Service Fabric que o arquivo Setup.bat é executado como SetupAdminUser (com permissões 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>
Executar a aplicação localmente
No Gerenciador de Soluções, selecione o aplicativo de votação e defina a propriedade URL do aplicativo como https://localhost:443
.
Salve todos os arquivos e selecione F5 para executar o aplicativo localmente. Depois que o aplicativo é implantado, um navegador é aberto para https://localhost:443
. Se estiver a utilizar um certificado autoassinado, verá um aviso de que o seu PC não confia na segurança deste Web site. Continue para a página web.
Instalar o certificado em nós de cluster
Antes de implantar o aplicativo no Azure, instale o certificado no repositório Cert:\LocalMachine\My de todos os nós de cluster remoto. Os serviços podem ser movidos para diferentes nós do cluster. Quando o serviço Web front-end é iniciado em um nó de cluster, o script de inicialização procura o certificado e configura as permissões de acesso.
Para instalar o certificado em nós de cluster, primeiro exporte o certificado como um arquivo PFX. Abra o arquivo de aplicativo certlm.msc e vá para Certificados Pessoais>. Clique com o botão direito do mouse no certificado mytestcert e selecione Todas as tarefas>de exportação.
No assistente de exportação, selecione Sim, exportar a chave privada e, em seguida, selecione o formato PFX. Exporte o ficheiro para C:\Users\sfuser\votingappcert.pfx.
Em seguida, instale o certificado no cluster remoto usando scripts do PowerShell.
Aviso
Para as aplicações de desenvolvimento e teste, basta um certificado autoassinado. Para aplicativos de produção, use um certificado de uma autoridade de certificação (CA) em vez de usar um certificado autoassinado.
Abra a porta 443 no balanceador de carga do Azure e na rede virtual
Abra a porta 443 no balanceador de carga se ela não estiver aberta:
$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
Faça o mesmo para a rede virtual associada:
$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 a aplicação no Azure
Salve todos os arquivos, alterne de Debug para Release e selecione F6 para reconstruir. No Gerenciador de Soluções, clique com o botão direito do mouse em Votação e selecione Publicar. Selecione o ponto final da ligação do cluster criado em Implementar uma aplicação num cluster ou selecione outro cluster. Selecione Publicar para publicar o aplicativo no cluster remoto.
Quando o aplicativo for implantado, abra um navegador da Web e vá para https://mycluster.region.cloudapp.azure.com:443
(atualize a URL com o ponto de extremidade de conexão para seu cluster). Se estiver a utilizar um certificado autoassinado, verá um aviso de que o seu PC não confia na segurança deste Web site. Continue para a página web.
Próximo passo
Avance para o tutorial seguinte: