dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.37k stars 9.99k forks source link

Enable health check only management port #6677

Open tillig opened 5 years ago

tillig commented 5 years ago

Issue #2579 added the ability to bind health checks to a specific port so they're only visible to internal components. Good stuff.

However, it turns out you can't dedicate the port to management/health check purposes. That is, if there's a "main port" for handling other requests and a "management port" for handling health requests... you can still make all requests over that management port that you would over the main port. Setting a port on health checks means the health checks only listen on that port... but the rest of the app (e.g., the MVC middleware) is still listening on all ports.

It would be nice if you could specify the health check port and have that be an exclusive handler on that port - only health checks would respond on that port.

Granted, this is easy enough middleware to write oneself, which is what I'll end up doing to work around it, but it'd be helpful if this was supported out of the box.

My general use case here is Kubernetes and Istio using mTLS authentication. I want Kubernetes to be able to do readiness/liveness checks on a specific port that bypasses the mTLS because you can't make Kubernetes use the specified certs for those checks but I don't want to leave the "back door" open for all the other services in the cluster to bypass the mTLS auth by making calls on the port I leave open for the health checks.

rynowak commented 5 years ago

Hi @tillig - we agree that this is a good idea to have a recipe for. We will need to do some more server and configuration work to make this easy.

I think you could do this today by placing the health checks middleware before the http redirect. If you register the health checks middleware with a port and an empty path it will respond to all requests for that port.

https://github.com/aspnet/AspNetCore/blob/master/src/Middleware/HealthChecks/src/Builder/HealthCheckApplicationBuilderExtensions.cs

tillig commented 5 years ago

Circling back on this, a concrete example of something that works:

app.UseHealthChecks("/healthz", 49331)
   .MapWhen(
     ctx => ctx.Connection.LocalPort == 49331,
     b => b.Run(ctx => { ctx.Response.StatusCode = 400; return Task.CompletedTask; }))

In this case, if the management port is set up and it's not a health request, everything else will be 400. However, on the main port for the app, the rest of the app will kick in correctly.

This would also allow you to add other checks, like a separate readiness check or something, on the same port as long as the middleware was registered before the MapWhen.