Comunicação entre processos com gRPC
Observação
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.
Advertência
Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.
Importante
Estas informações referem-se a um produto de pré-lançamento que pode ser substancialmente modificado antes de ser lançado comercialmente. A Microsoft não oferece garantias, expressas ou implícitas, em relação às informações fornecidas aqui.
Para a versão atual, consulte a versão .NET 9 deste artigo.
Os processos executados na mesma máquina podem ser projetados para se comunicarem entre si. Os sistemas operativos fornecem tecnologias que permitem uma comunicação entre processos (IPC) rápida e eficiente. Exemplos populares de tecnologias IPC são soquetes de domínio Unix e pipes nomeados.
O .NET fornece suporte para comunicação entre processos usando gRPC.
O suporte interno para pipes nomeados no ASP.NET Core requer o .NET 8 ou posterior.
Começar
As chamadas IPC são enviadas de um cliente para um servidor. Para se comunicar entre aplicativos em uma máquina com gRPC, pelo menos um aplicativo deve hospedar um servidor gRPC ASP.NET Core.
Um servidor gRPC ASP.NET Core geralmente é criado a partir do modelo gRPC. O arquivo de projeto criado pelo modelo usa Microsoft.NET.SDK.Web
como o SDK:
<Project Sdk="Microsoft.NET.Sdk.Web">
<ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
</Project>
O valor Microsoft.NET.SDK.Web
SDK adiciona automaticamente uma referência à estrutura ASP.NET Core. A referência permite que o aplicativo use ASP.NET tipos Core necessários para hospedar um servidor.
Também é possível adicionar um servidor a projetos non-ASP.NET Core existentes, como Serviços do Windows, aplicativos WPF ou aplicativos WinForms. Consulte Host gRPC em projetos que não usam ASP.NET Core para obter mais informações.
Transportes de comunicação entre processos (IPC)
As chamadas gRPC entre um cliente e um servidor em máquinas diferentes geralmente são enviadas por soquetes TCP. O TCP é uma boa opção para comunicar através de uma rede ou da Internet. No entanto, os transportes IPC oferecem vantagens na comunicação entre processos na mesma máquina.
- Menos sobrecarga e velocidades de transferência mais rápidas.
- Integração com funcionalidades de segurança do SO.
- Não usa portas TCP, que são um recurso limitado.
O .NET suporta vários transportes IPC:
- de soquetes de domínio Unix (UDS) é uma tecnologia IPC amplamente suportada. O UDS é a melhor opção para criar aplicativos multiplataforma e pode ser usado no Linux, macOS e Windows 10/Windows Server 2019 ou posterior.
- Tubos nomeados são suportados por todas as versões do Windows. Os tubos nomeados integram-se bem com a segurançado Windows, que pode controlar o acesso dos clientes ao tubo.
- Transportes IPC adicionais implementando IConnectionListenerFactory e registando a implementação na inicialização da aplicação.
Dependendo do sistema operativo, as aplicações multiplataforma podem escolher diferentes transportes IPC. Um aplicativo pode verificar o sistema operacional na inicialização e escolher o transporte desejado para essa plataforma:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
if (OperatingSystem.IsWindows())
{
serverOptions.ListenNamedPipe("MyPipeName");
}
else
{
var socketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");
serverOptions.ListenUnixSocket(socketPath);
}
serverOptions.ConfigureEndpointDefaults(listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
});
Considerações de segurança
Os aplicativos IPC enviam e recebem chamadas RPC. A comunicação externa é um vetor de ataque potencial para aplicativos IPC e deve ser protegida corretamente.
Proteja o aplicativo do servidor IPC contra chamadores inesperados
A aplicação servidor IPC aloja serviços RPC para serem chamados por outras aplicações. Os chamadores de entrada devem ser autenticados para impedir que clientes não confiáveis façam chamadas RPC para o servidor.
A segurança de transporte é uma opção para proteger um servidor. Os transportes IPC, como soquetes de domínio Unix e pipes nomeados, suportam limitar o acesso com base nas permissões do sistema operacional:
- Os pipes nomeados suportam a proteção de um pipe com o modelo de controle de acesso do Windows . Os direitos de acesso podem ser configurados no .NET quando um servidor é iniciado usando a classe PipeSecurity.
- Os soquetes de domínio Unix suportam a proteção de um soquete com permissões de arquivo.
Outra opção para proteger um servidor IPC é usar autenticação e autorização incorporadas ao ASP.NET Core. Por exemplo, o servidor pode ser configurado para exigir autenticação por certificado. As chamadas RPC feitas por aplicativos cliente sem o certificado necessário falham com uma resposta não autorizada.
Validar o servidor no aplicativo cliente IPC
É importante que o aplicativo cliente valide a identidade do servidor que está chamando. A validação é necessária para proteger contra um agente mal-intencionado, evitando que pare o servidor confiável, execute o seu próprio e aceite dados de entrada dos clientes.
Os pipes nomeados fornecem suporte para obter a conta na qual um servidor está sendo executado. Um cliente pode validar que o servidor foi iniciado pela conta esperada:
internal static bool CheckPipeConnectionOwnership(
NamedPipeClientStream pipeStream, SecurityIdentifier expectedOwner)
{
var remotePipeSecurity = pipeStream.GetAccessControl();
var remoteOwner = remotePipeSecurity.GetOwner(typeof(SecurityIdentifier));
return expectedOwner.Equals(remoteOwner);
}
Outra opção para validar o servidor é proteger seus pontos de extremidade com HTTPS dentro ASP.NET Core. O cliente pode configurar SocketsHttpHandler
para validar que o servidor está usando o certificado esperado quando a conexão é estabelecida.
var socketsHttpHandler = new SocketsHttpHandler()
{
SslOptions = new SslOptions()
{
RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
if (sslPolicyErrors != SslPolicyErrors.None)
{
return false;
}
// Validate server cert thumbprint matches the expected thumbprint.
}
}
};
Proteja-se contra a elevação de privilégios de tubulação nomeada
Os pipes nomeados suportam um recurso chamado representação. Usando a representação, o servidor de pipes nomeado pode executar código com os privilégios do usuário cliente. Este é um recurso poderoso, mas pode permitir que um servidor de baixo privilégio se faça passar por um chamador de alto privilégio e, em seguida, execute código mal-intencionado.
O cliente pode proteger-se contra este ataque, não permitindo a imitação ao ligar-se a um servidor. A menos que exigido por um servidor, um valor TokenImpersonationLevel de None
ou Anonymous
deve ser usado ao criar uma conexão de cliente:
using var pipeClient = new NamedPipeClientStream(
serverName: ".", pipeName: "testpipe", PipeDirection.In, PipeOptions.None, TokenImpersonationLevel.None);
await pipeClient.ConnectAsync();
TokenImpersonationLevel.None
é o valor padrão nos construtores NamedPipeClientStream
que não têm o parâmetro impersonationLevel
.
Configurar cliente e servidor
O cliente e o servidor devem ser configurados para usar um transporte de comunicação entre processos (IPC). Para obter mais informações sobre como configurar Kestrel e SocketsHttpHandler para usar o IPC:
- Comunicação entre processos com soquetes de domínio gRPC e Unix
- Comunicação entre processos com gRPC e pipes nomeados
Observação
O suporte interno para pipes nomeados no ASP.NET Core requer o .NET 8 ou posterior.
Os processos executados na mesma máquina podem ser projetados para se comunicarem entre si. Os sistemas operativos fornecem tecnologias que permitem uma comunicação entre processos (IPC) rápida e eficiente. Exemplos populares de tecnologias IPC são soquetes de domínio Unix e pipes nomeados.
O .NET fornece suporte para comunicação entre processos usando gRPC.
Observação
O suporte interno para pipes nomeados no ASP.NET Core requer o .NET 8 ou posterior.
Para obter mais informações, consulte .NET 8 ou uma versão posterior deste tópico
Começar
As chamadas gRPC são enviadas de um cliente para um servidor. Para se comunicar entre aplicativos em uma máquina com gRPC, pelo menos um aplicativo deve hospedar um servidor gRPC ASP.NET Core.
ASP.NET Core e gRPC podem ser hospedados em qualquer aplicativo usando o .NET Core 3.1 ou posterior, adicionando a estrutura Microsoft.AspNetCore.App
ao projeto.
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
</Project>
O arquivo de projeto anterior:
- Adiciona uma referência de estrutura a
Microsoft.AspNetCore.App
. A referência de estrutura permite que aplicativos non-ASP.NET Core, como Serviços do Windows, aplicativos WPF ou aplicativos WinForms, usem o ASP.NET Core e hospedem um servidor ASP.NET Core. - Adiciona uma referência de pacote NuGet a
Grpc.AspNetCore
. - Adiciona um arquivo
.proto
.
Configurar soquetes de domínio Unix
As chamadas gRPC entre um cliente e um servidor em máquinas diferentes geralmente são enviadas por soquetes TCP. O TCP foi concebido para comunicar através de uma rede. Os soquetes de domínio Unix (UDS) são uma das tecnologias de comunicação entre processos (IPC) mais amplamente suportadas e são mais eficientes do que o TCP quando o cliente e o servidor estão na mesma máquina. O .NET fornece suporte interno para UDS em aplicativos cliente e servidor.
Prescrições:
- .NET 5 ou posterior
- Linux, macOS ou Windows 10/Windows Server 2019 ou posterior
Configuração do servidor
Soquetes de domínio Unix (UDS) são suportados pelo Kestrel, que é configurado em Program.cs
:
public static readonly string SocketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureKestrel(options =>
{
if (File.Exists(SocketPath))
{
File.Delete(SocketPath);
}
options.ListenUnixSocket(SocketPath, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
});
});
O exemplo anterior:
- Configura os pontos de extremidade do Kestrelno
ConfigureKestrel
. - Chama ListenUnixSocket para ouvir um UDS com o caminho especificado.
- Cria um ponto de extremidade UDS que não está configurado para usar HTTPS. Para obter informações sobre como habilitar HTTPS, consulte Kestrel Configuração de Ponto de Extremidade HTTPS.
Configuração do cliente
GrpcChannel
suporta que se possa fazer chamadas gRPC em transportes personalizados. Quando um canal é criado, ele pode ser configurado com um SocketsHttpHandler
que tenha um ConnectCallback
personalizado. A função de callback permite que o cliente faça conexões em transportes personalizados e, em seguida, envie solicitações HTTP através desse transporte.
Exemplo de fábrica de ligações de soquetes de domínio Unix.
public class UnixDomainSocketConnectionFactory
{
private readonly EndPoint _endPoint;
public UnixDomainSocketConnectionFactory(EndPoint endPoint)
{
_endPoint = endPoint;
}
public async ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext _,
CancellationToken cancellationToken = default)
{
var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
try
{
await socket.ConnectAsync(_endPoint, cancellationToken).ConfigureAwait(false);
return new NetworkStream(socket, true);
}
catch
{
socket.Dispose();
throw;
}
}
}
Usando a fábrica de conexões personalizadas para criar um canal:
public static readonly string SocketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");
public static GrpcChannel CreateChannel()
{
var udsEndPoint = new UnixDomainSocketEndPoint(SocketPath);
var connectionFactory = new UnixDomainSocketConnectionFactory(udsEndPoint);
var socketsHttpHandler = new SocketsHttpHandler
{
ConnectCallback = connectionFactory.ConnectAsync
};
return GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions
{
HttpHandler = socketsHttpHandler
});
}
Os canais criados usando o código anterior enviam chamadas gRPC através de soquetes de domínio Unix. O suporte para outras tecnologias de comunicação entre processos (IPC) pode ser implementado usando a extensibilidade em Kestrel e SocketsHttpHandler
.