Sdílet prostřednictvím


Komunikace mezi procesy pomocí služby gRPC

Procesy spuštěné na stejném počítači je možné navrhnout tak, aby vzájemně komunikují. Operační systémy poskytují technologie pro zajištění rychlé a efektivní komunikace mezi procesy (IPC). Mezi oblíbené příklady technologií IPC patří sokety domény unixu a pojmenované kanály.

.NET poskytuje podporu komunikace mezi procesy pomocí gRPC.

Integrovaná podpora pojmenovaných kanálů v ASP.NET Core vyžaduje .NET 8 nebo novější.

Začínáme

Volání IPC se odesílají z klienta na server. Aby bylo možné komunikovat mezi aplikacemi na počítači s gRPC, musí alespoň jedna aplikace hostovat server ASP.NET Core gRPC.

Server ASP.NET Core gRPC se obvykle vytváří ze šablony gRPC. Soubor projektu vytvořený šablonou se používá Microsoft.NET.SDK.Web jako sada 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>

Microsoft.NET.SDK.Web Hodnota sady SDK automaticky přidá odkaz na architekturu ASP.NET Core. Odkaz umožňuje aplikaci používat typy ASP.NET Core vyžadované k hostování serveru.

Je také možné přidat server do existujících projektů non-ASP.NET Core, jako jsou služby Windows, aplikace WPF nebo aplikace WinForms. Další informace najdete v tématu Host gRPC v projektech non-ASP.NET Core.

Přenosy komunikace mezi procesy (IPC)

Volání gRPC mezi klientem a serverem na různých počítačích se obvykle posílají přes sokety TCP. Tcp je dobrou volbou pro komunikaci přes síť nebo internet. Přenosy IPC však nabízejí výhody při komunikaci mezi procesy na stejném počítači:

  • Menší režijní a rychlejší přenosová rychlost.
  • Integrace s funkcemi zabezpečení operačního systému
  • Nepoužívá porty TCP, což jsou omezené prostředky.

.NET podporuje více přenosů IPC:

V závislosti na operačním systému můžou multiplatformní aplikace zvolit různé přenosy IPC. Aplikace může zkontrolovat operační systém při spuštění a zvolit požadovaný přenos pro danou platformu:

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;
    });
});

Bezpečnostní aspekty

Aplikace IPC odesílají a přijímají volání RPC. Externí komunikace je potenciální vektor útoku pro aplikace IPC a musí být správně zabezpečený.

Zabezpečení serverové aplikace IPC proti neočekávaným volajícím

Serverová aplikace IPC hostuje služby RPC pro volání jiných aplikací. Příchozí volající by měli být ověřeni, aby se zabránilo nedůvěryhodným klientům v volání RPC na server.

Zabezpečení přenosu je jednou z možností zabezpečení serveru. Přenosy IPC, jako jsou sokety domény Unix a pojmenované kanály, podporují omezení přístupu na základě oprávnění operačního systému:

  • Pojmenované kanály podporují zabezpečení kanálu pomocí modelu řízení přístupu systému Windows. Přístupová práva je možné nakonfigurovat v .NET při spuštění serveru pomocí PipeSecurity třídy.
  • Unixové doménové sokety podporují zabezpečení soketu s oprávněními k souborům.

Další možností zabezpečení serveru IPC je použití ověřování a autorizace integrované do ASP.NET Core. Server může být například nakonfigurovaný tak, aby vyžadoval ověření certifikátu. Volání RPC provedená klientskými aplikacemi bez požadovaného certifikátu selžou s neoprávněnou odpovědí.

Ověření serveru v klientské aplikaci IPC

Je důležité, aby klientská aplikace ověřila identitu serveru, který volá. Ověření je nezbytné k ochraně před škodlivým aktérem před zastavením důvěryhodného serveru, spuštěním vlastního serveru a přijetím příchozích dat z klientů.

Pojmenované kanály podporují získání účtu, pod kterým běží server. Klient může ověřit, jestli byl server spuštěn očekávaným účtem:

internal static bool CheckPipeConnectionOwnership(
    NamedPipeClientStream pipeStream, SecurityIdentifier expectedOwner)
{
    var remotePipeSecurity = pipeStream.GetAccessControl();
    var remoteOwner = remotePipeSecurity.GetOwner(typeof(SecurityIdentifier));
    return expectedOwner.Equals(remoteOwner);
}

Další možností ověření serveru je zabezpečení koncových bodů pomocí HTTPS uvnitř ASP.NET Core. Klient může nakonfigurovat SocketsHttpHandler , aby ověřil, že server používá očekávaný certifikát při navázání připojení.

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.
        }
    }
};

Ochrana před eskalací oprávnění pojmenovaného kanálu

Pojmenované kanály podporují funkci označovanou jako zosobnění. Pomocí zosobnění může server pojmenovaných kanálů spouštět kód s oprávněními uživatele klienta. Jedná se o výkonnou funkci, ale může umožnit serveru s nízkými oprávněními zosobnit volajícího s vysokou úrovní oprávnění a pak spustit škodlivý kód.

Klient může chránit před tímto útokem tím, že při připojování k serveru nepovoluje zosobnění. Pokud server nevyžaduje, TokenImpersonationLevelNone hodnota nebo Anonymous by se měla použít při vytváření připojení klienta:

using var pipeClient = new NamedPipeClientStream(
    serverName: ".", pipeName: "testpipe", PipeDirection.In, PipeOptions.None, TokenImpersonationLevel.None);
await pipeClient.ConnectAsync();

TokenImpersonationLevel.None je výchozí hodnota v NamedPipeClientStream konstruktorech, které nemají impersonationLevel parametr.

Konfigurace klienta a serveru

Klient a server musí být nakonfigurované tak, aby používaly přenos komunikace mezi procesy (IPC). Další informace o konfiguraci Kestrel a SocketsHttpHandler použití IPC:

Poznámka:

Integrovaná podpora pojmenovaných kanálů v ASP.NET Core vyžaduje .NET 8 nebo novější.

Procesy spuštěné na stejném počítači je možné navrhnout tak, aby vzájemně komunikují. Operační systémy poskytují technologie pro zajištění rychlé a efektivní komunikace mezi procesy (IPC). Mezi oblíbené příklady technologií IPC patří sokety domény unixu a pojmenované kanály.

.NET poskytuje podporu komunikace mezi procesy pomocí gRPC.

Poznámka:

Integrovaná podpora pojmenovaných kanálů v ASP.NET Core vyžaduje .NET 8 nebo novější.
Další informace najdete v .NET 8 nebo novější verzi tohoto tématu.

Začínáme

Volání gRPC se odesílají z klienta na server. Aby bylo možné komunikovat mezi aplikacemi na počítači s gRPC, musí alespoň jedna aplikace hostovat server ASP.NET Core gRPC.

ASP.NET Core a gRPC je možné hostovat v libovolné aplikaci pomocí .NET Core 3.1 nebo novějšího přidáním Microsoft.AspNetCore.App architektury do projektu.

<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>

Předchozí soubor projektu:

  • Přidá odkaz na architekturu do Microsoft.AspNetCore.App. Referenční informace k architektuře umožňují non-ASP.NET aplikacím Core, jako jsou služby Windows, aplikace WPF nebo aplikace WinForms, používat ASP.NET Core a hostovat server ASP.NET Core.
  • Přidá odkaz na balíček NuGet do Grpc.AspNetCoresouboru .
  • .proto Přidá soubor.

Konfigurace soketů domény se systémem Unix

Volání gRPC mezi klientem a serverem na různých počítačích se obvykle posílají přes sokety TCP. Protokol TCP byl navržen pro komunikaci přes síť. Unixové sokety domény (UDS) jsou široce podporovaná technologie IPC, která je efektivnější než TCP, když jsou klient a server na stejném počítači. .NET poskytuje integrovanou podporu UDS v klientských a serverových aplikacích.

Požadavky:

Konfigurace serveru

Systémy Unix domain sockets (UDS) jsou podporovány rozhraním Kestrel, které je nakonfigurováno v 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;
                });
            });
        });

Předchozí příklad:

  • Konfiguruje Kestrelkoncové body v ConfigureKestrel.
  • Volání ListenUnixSocket pro naslouchání UDS se zadanou cestou
  • Vytvoří koncový bod UDS, který není nakonfigurovaný tak, aby používal PROTOKOL HTTPS. Informace o povolení PROTOKOLU HTTPS najdete v tématu Kestrel Konfigurace koncového bodu HTTPS.

Konfigurace klienta

GrpcChannel podporuje volání gRPC přes vlastní přenosy. Po vytvoření kanálu je možné ho nakonfigurovat pomocí SocketsHttpHandler vlastního ConnectCallbackkanálu . Zpětné volání umožňuje klientovi vytvářet připojení přes vlastní přenosy a poté odesílat požadavky HTTP přes tento přenos.

Příklad připojení k doméně unixových soketů:

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;
        }
    }
}

Vytvoření kanálu pomocí vlastní továrny pro připojení:

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
    });
}

Kanály vytvořené pomocí předchozího kódu odesílají volání gRPC přes sokety domény Unix. Podporu pro další technologie IPC lze implementovat pomocí rozšiřitelnosti v Kestrel a SocketsHttpHandler.