gRPC와 프로세스 간 통신

동일한 컴퓨터에서 실행되는 프로세스는 서로 통신하도록 설계할 수 있습니다. 운영 체제는 빠르고 효율적인 IPC(프로세스 간 통신)를 가능하게 하는 기술을 제공합니다. IPC 기술의 인기 있는 예는 Unix do기본 소켓 및 명명된 파이프입니다.

.NET은 gRPC를 사용하여 프로세스 간 통신을 지원합니다.

ASP.NET Core의 명명된 파이프에 대한 기본 제공 지원에는 .NET 8 이상이 필요합니다.

시작하기

IPC 호출은 클라이언트에서 서버로 전송됩니다. gRPC를 사용하여 머신의 앱 간에 통신하려면 적어도 하나 이상의 앱이 ASP.NET Core gRPC 서버를 호스팅해야 합니다.

ASP.NET Core gRPC 서버는 일반적으로 gRPC 템플릿에서 만들어집니다. 템플릿에서 만든 프로젝트 파일은 SDK로 사용합니다 Microsoft.NET.SDK.Web .

<Project Sdk="Microsoft.NET.Sdk.Web">

  <ItemGroup>
    <PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
    <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
  </ItemGroup>

</Project>

SDK 값은 Microsoft.NET.SDK.Web ASP.NET Core 프레임워크에 대한 참조를 자동으로 추가합니다. 이 참조를 통해 앱은 서버를 호스트하는 데 필요한 ASP.NET Core 형식을 사용할 수 있습니다.

Windows 서비스, WPF 앱 또는 WinForms 앱과 같은 기존 non-ASP.NET Core 프로젝트에 서버를 추가할 수도 있습니다. 자세한 내용은 non-ASP.NET Core 프로젝트의 호스트 gRPC를 참조하세요.

IPC(프로세스 간 통신) 전송

다른 머신의 클라이언트와 서버 간의 gRPC 호출은 일반적으로 TCP 소켓을 통해 전송됩니다. TCP는 네트워크 또는 인터넷을 통해 통신하는 데 적합합니다. 그러나 IPC 전송은 동일한 컴퓨터의 프로세스 간에 통신할 때 이점을 제공합니다.

  • 오버헤드가 적고 전송 속도가 빨라집니다.
  • OS 보안 기능과 통합
  • 제한된 리소스인 TCP 포트를 사용하지 않습니다.

.NET은 여러 IPC 전송을 지원합니다.

OS에 따라 플랫폼 간 앱은 다른 IPC 전송을 선택할 수 있습니다. 앱은 시작 시 OS를 검사 해당 플랫폼에 대해 원하는 전송을 선택할 수 있습니다.

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

보안 고려 사항

IPC 앱은 RPC 호출을 보내고 받습니다. 외부 통신은 IPC 앱에 대한 잠재적인 공격 벡터이며 제대로 보호되어야 합니다.

예기치 않은 호출자에서 IPC 서버 앱 보호

IPC 서버 앱은 호출할 다른 앱에 대한 RPC 서비스를 호스트합니다. 신뢰할 수 없는 클라이언트가 서버에 RPC를 호출하지 못하도록 수신 호출자를 인증해야 합니다.

전송 보안은 서버 보안을 위한 한 가지 옵션입니다. Unix do기본 소켓 및 명명된 파이프와 같은 IPC 전송은 운영 체제 권한에 따라 액세스 제한을 지원합니다.

  • 명명된 파이프는 Windows 액세스 제어 모델을 사용하여 파이프 보안을 지원합니다. 서버가 클래스를 사용하기 PipeSecurity 시작하면 .NET에서 액세스 권한을 구성할 수 있습니다.
  • Unix do기본 소켓은 파일 권한이 있는 소켓 보안을 지원합니다.

IPC 서버를 보호하기 위한 또 다른 옵션은 ASP.NET Core에 기본 제공된 인증 및 권한 부여를 사용하는 것입니다. 예를 들어 인증서 인증을 요구하도록 서버를 구성할 수 있습니다. 필요한 인증서 없이 클라이언트 앱에서 수행한 RPC 호출은 무단 응답으로 실패합니다.

IPC 클라이언트 앱에서 서버 유효성 검사

클라이언트 앱이 호출하는 서버의 ID의 유효성을 검사하는 것이 중요합니다. 악의적인 행위자가 신뢰할 수 있는 서버를 중지하고, 자체 서버를 실행하고, 클라이언트에서 들어오는 데이터를 수락하지 않도록 보호하려면 유효성 검사가 필요합니다.

명명된 파이프는 서버가 실행 중인 계정을 가져오기 위한 지원을 제공합니다. 클라이언트는 서버가 예상된 계정에서 시작되었는지 확인할 수 있습니다.

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

서버 의 유효성을 검사하는 또 다른 옵션은 ASP.NET Core 내에서 HTTPS 를 사용하여 엔드포인트를 보호하는 것입니다. 클라이언트는 연결이 설정될 때 서버가 예상 인증서를 사용하고 있는지 확인하도록 구성할 SocketsHttpHandler 수 있습니다.

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

명명된 파이프 권한 에스컬레이션으로부터 보호

명명된 파이프는 가장이라는 기능을 지원합니다. 명명된 파이프 서버는 가장을 사용하여 클라이언트 사용자의 권한으로 코드를 실행할 수 있습니다. 이 기능은 강력한 기능이지만 권한이 낮은 서버가 높은 권한의 호출자를 가장한 다음 악성 코드를 실행하도록 허용할 수 있습니다.

클라이언트는 서버에 연결할 때 가장을 허용하지 않음으로써 이 공격으로부터 보호할 수 있습니다. 서버 TokenImpersonationLevel 에서 필요하지 않은 경우 클라이언트 연결을 만들 때 값을 None 사용하거나 Anonymous 사용해야 합니다.

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

TokenImpersonationLevel.None 는 매개 변수가 없는 생성자의 기본값 NamedPipeClientStream 입니다 impersonationLevel .

클라이언트 및 서버 구성

IPC(프로세스 간 통신) 전송을 사용하도록 클라이언트와 서버를 구성해야 합니다. IPC 구성 Kestrel 및 SocketsHttpHandler 사용에 대한 자세한 내용은 다음을 수행합니다.

참고 항목

ASP.NET Core의 명명된 파이프에 대한 기본 제공 지원에는 .NET 8 이상이 필요합니다.

동일한 컴퓨터에서 실행되는 프로세스는 서로 통신하도록 설계할 수 있습니다. 운영 체제는 빠르고 효율적인 IPC(프로세스 간 통신)를 가능하게 하는 기술을 제공합니다. IPC 기술의 인기 있는 예는 Unix do기본 소켓 및 명명된 파이프입니다.

.NET은 gRPC를 사용하여 프로세스 간 통신을 지원합니다.

참고 항목

ASP.NET Core의 명명된 파이프에 대한 기본 제공 지원에는 .NET 8 이상이 필요합니다.
자세한 내용은 이 항목의 .NET 8 이상 버전을 참조 하세요.

시작하기

gRPC 호출은 클라이언트에서 서버로 전송됩니다. gRPC를 사용하여 머신의 앱 간에 통신하려면 적어도 하나 이상의 앱이 ASP.NET Core gRPC 서버를 호스팅해야 합니다.

ASP.NET Core 및 gRPC는 프로젝트에 Microsoft.AspNetCore.App 프레임워크를 추가하여 .NET Core 3.1 이상을 사용하는 모든 앱에서 호스팅할 수 있습니다.

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

이전 프로젝트 파일:

  • Microsoft.AspNetCore.App에 프레임워크 참조를 추가합니다. 프레임워크 참조를 사용하면 Windows 서비스, WPF 앱 또는 WinForms 앱과 같은 비 ASP.NET Core 앱이 ASP.NET Core를 사용하고 ASP.NET Core 서버를 호스팅할 수 있습니다.
  • Grpc.AspNetCore에 NuGet 패키지 참조를 추가합니다.
  • .proto 파일을 추가합니다.

Unix 도메인 소켓 구성

다른 머신의 클라이언트와 서버 간의 gRPC 호출은 일반적으로 TCP 소켓을 통해 전송됩니다. TCP는 네트워크를 통해 통신하도록 설계되었습니다. UDS(Unix 도메인 소켓)는 클라이언트와 서버가 동일한 머신에 있을 때 TCP보다 더 효율적으로 널리 지원되는 IPC 기술입니다. .NET은 클라이언트 및 서버 앱에서 UDS에 대한 기본 제공 지원을 제공합니다.

요구 사항:

서버 구성

UDS(Unix 도메인 소켓)는 Program.cs에서 구성된 Kestrel에 의해 지원됩니다.

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

위의 예제는 다음과 같습니다.

  • ConfigureKestrel에서 Kestrel의 엔드포인트를 구성합니다.
  • ListenUnixSocket을 호출하여 지정된 경로를 포함한 UDS를 수신 대기합니다.
  • HTTPS를 사용하도록 구성되지 않은 UDS 엔드포인트를 만듭니다. HTTPS를 사용하도록 설정하는 방법에 대한 자세한 내용은 Kestrel HTTPS 엔드포인트 구성을 참조하세요.

클라이언트 구성

GrpcChannel은 사용자 지정 전송을 통한 gRPC 호출을 지원합니다. 채널을 만들 때 사용자 지정 ConnectCallback가 포함된 SocketsHttpHandler로 구성할 수 있습니다. 콜백을 사용하면 클라이언트가 사용자 지정 전송을 통해 연결한 다음 해당 전송을 통해 HTTP 요청을 보낼 수 있습니다.

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

사용자 지정 연결 팩터리를 사용하여 채널을 만듭니다.

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

위의 코드를 사용하여 만든 채널은 Unix 도메인 소켓을 통해 gRPC 호출을 보냅니다. 다른 IPC 기술에 대한 지원은 Kestrel 및 SocketsHttpHandler의 확장성을 사용하여 구현할 수 있습니다.