Search code examples
c#grpcnamed-pipes

How to configure NamedPipes permissions when using gRPC ASP.NET Core over NamedPipes


I have a gRPC Server using ASP.Net Core running as a Windows Service. I also have a gRPC Client that is running as a limited user. If I run the gRPC Client as an admin they can communicate just fine. When I run it as a non admin I get the following error:

System.Net.Http.HttpRequestException: Access to the path is denied. (localhost:80)

This is a permissions issue. According to this stack overflow question Change Named Pipe Access Permissions I could change the permissions when creating the NamedPipeServerStream if I was using raw Named Pipes.

gRPCs use of named pipe is less direct.

builder.WebHost.ConfigureKestrel(serverOption =>
    {
        serverOption.ListenNamedPipe(HelloWorldInfo.gRpcPipeName,
            listenOptions =>
            {
                listenOptions.Protocols = HttpProtocols.Http2;
            });
    });
builder.Services.AddGrpc();

Is there a way to configure Kestrel to add the DACL to the named pipe, so that the limited user can communicate?

A second options would be to obtain the named pipe after the server starts, and add the DACL. But NamedPipes can handle this configuration already. It is just a matter of how.

I tried setting the PipeSecurity while configuring Kestrel like this.

var pipeSecurity = CreateSystemIOPipeSecurity();
builder.WebHost.UseNamedPipes(opts =>
{
    opts.PipeSecurity = pipeSecurity;
    opts.CurrentUserOnly = false;
});

But I get

System.IO.IOException: Failed to bind to address http://pipe:/HelloWorldPipe: address already in use.


Solution

  • It got me some trouble as well, the underlying error code is not nicely translated to the message that pipe is already in use.

    The trick is that the server process identity has to have not only readwrite permissions but also create pipe permission.

    When having only read write permission and the initial pipe creation succeeds but the subsequent pool connection creation fails due to the ACL restrictions.

    Add to your PipeSecurity creation method following

    pipeSecurity.AddAccessRule(
        new PipeAccessRule(
            WindowsIdentity.GetCurrent().Owner!,
            PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance,
            AccessControlType.Allow
        )
    );