Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WebToolsE2E][Aspire] With the dev cert not trusted, when running Aspire app with https, the dashboard page fails to load with the browser dev tools showing: Error starting gRPC call. HttpRequestException: The SSL connection could not be established, see inner exception. AuthenticationException #2914

Closed
v-sherryfan opened this issue Mar 15, 2024 · 28 comments · Fixed by #3212
Assignees

Comments

@v-sherryfan
Copy link

v-sherryfan commented Mar 15, 2024

REGRESSION INFO: https is a new feature on Aspire 8.0 P5

INSTALL STEPS

  1. Clean machine: Win11 x64 23h2 ENU
  2. Install the SDK 8.0.300-preview.24164.23
  3. Install Aspire.ProjectTemplates.8.0.0-preview.5.24164.9
  4. Apply nuget dotnet8 feed

REPRO STEPS

  1. Open cmd, run following code to create an aspire / aspire-starter app and run with https
    dotnet new aspire-starter -o AspireSta
    cd AspireSta/AspireSta.AppHost
    dotnet run -lp https
    
  2. Go to https://localhost:xxxx

Note

  1. Running with http works fine.

Workaround

  1. Run dotnet dev-certs https --trust (Windows and macOS only ) to trust the certificate, then run it again with https, it works fine.
  2. But this workaround only supports windows/mac, not linux.

ACTUAL
The exception only shows up in the browser F12 tool and not in the console output.

image

image
Error: Grpc.Core.RpcException: Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: The SSL connection could not be established, see inner exception. AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot", DebugException="System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.")
---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions)
at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken)
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.AddHttp2ConnectionAsync(QueueItem queueItem)
at System.Threading.Tasks.TaskCompletionSourceWithCancellation1.WaitWithCancellationAsync(CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken) at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at Grpc.Net.Client.Balancer.Internal.BalancerHttpHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at Grpc.Net.Client.Internal.GrpcCall2.RunCall(HttpRequestMessage request, Nullable1 timeout) --- End of inner exception stack trace --- at Grpc.Net.Client.Internal.Retry.RetryCall2.StartRetry(Action1 startCallFunc) at Grpc.Net.Client.Internal.Retry.RetryCallBase2.GetResponseCoreAsync()
at Aspire.Dashboard.Model.DashboardClient.<>c__DisplayClass25_0.<g__ConnectAsync|2>d.MoveNext() in //src/Aspire.Dashboard/Model/DashboardClient.cs:line 164
--- End of stack trace from previous location ---
at Aspire.Dashboard.Components.ApplicationName.OnInitializedAsync() in /
/src/Aspire.Dashboard/Components/Controls/ApplicationName.razor.cs:line 32
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

EXPECTED
image

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-integrations Issues pertaining to Aspire Integrations packages label Mar 15, 2024
@DamianEdwards
Copy link
Member

DamianEdwards commented Mar 15, 2024

This is by design and the same experience as that when creating and launching ASP.NET Core projects using the CLI. Visual Studio will auto-select the "https" launch profile and prompt to install and trust the dev certificate, but the CLI has no equivalent experience and requires the user to manually trust the certificate so that the browser and OS trusts it. See dotnet/aspnetcore#32842 for details on trusting the cert on Linux.

@balachir
Copy link

@DamianEdwards to get a comparison with running ASP.NET Core web apps (without Aspire) using https launch profile, I tried the following steps.

STEPS

  1. Clean Win11 x64 ENU machine
  2. Install latest-released .NET SDK 8.0.203
  3. Open command prompt and run dotnet --info and dotnet workload list
    • When I run dotnet workload list (or any dotnet command for the first-time), it installs the ASP.NET Core HTTPS dev cert and displays the command that I need to run in order to trust the cert.
      image

Note: For this repro, I intentionally ignored the recommendation in screenshot above and did not run the command to trust the cert. I did not install the Aspire workload either.

  1. Create new MVC app dotnet new mvc -o MvcApp1
  2. Cd to MvcApp1 folder and run the app with the https launch profile dotnet run -lp https

ACTUAL
We get a clear warning saying that the ASP.NET Core developer certificate is not trusted and an aka.ms link pointing to the steps needed to trust the cert.

image
image

@DamianEdwards
Copy link
Member

Yeah that's because the logs from Kestrel are suppressed in the AppHost project today, even warnings and errors. I think we should let warnings and errors through as it will help debugging issues with dashboard to AppHost connectivity too. I logged #2936 to track that.

@balachir balachir added this to the preview 5 (Apr) milestone Mar 18, 2024
@balachir
Copy link

Marking this for preview 5 because the dashboard remains in 'Loading' state with F12 tools showing the exception when the app is run with https since the dev cert hasn't been trusted yet.

@eerhardt eerhardt added area-tooling and removed area-integrations Issues pertaining to Aspire Integrations packages labels Mar 18, 2024
@davidfowl
Copy link
Member

davidfowl commented Mar 27, 2024

@mitchdenny I am giving this one to you. We need to make sure we show the warning from kestrel when the dev cert isn't trusted when running the app host. Right now we suppress all logs from kestrel in the apphost.

@mitchdenny
Copy link
Member

Hrm we suppress that whole category right now.

@davidfowl
Copy link
Member

I think it might be as simple as changing this

@mitchdenny
Copy link
Member

We suppressed that because we wanted to tightly control what was being output to the console. For example if you raise it to warning you get this in the output:

image

@mitchdenny
Copy link
Member

OK so I think we got lucky in this case because this particular warning is from a deeper category.

@eerhardt
Copy link
Member

We suppressed that because we wanted to tightly control what was being output to the console. For example if you raise it to warning you get this in the output:

image

@adityamandaleeka @amcasey @halter73 - would it make sense to have a setting in Kestrel that told it "I did this override intentionally, please don't emit a warning for this?" That way Aspire wouldn't need to suppress all warnings, and then opt back in case-by-case to the warnings it wants to bubble out.

@amcasey
Copy link
Member

amcasey commented Mar 27, 2024

@eerhardt I'm not 100% sure what you're asking, but after skimming the thread, I think your concern is that you want to suppress the warning about address overriding but let other errors and warnings through.

For this particular warning, do you know where that URL is coming from? Is it from launchSettings.json? Or an env var set by the docker tooling? Do you have a way to just remove the address that's being overridden?

For the more general question, it sounds like you want message-id level filtering of log messages. Sadly, we don't have a recommended way to do that, but here's the code I use:

internal sealed class FilteringLoggerProvider : ILoggerProvider 
{ 
    public static readonly ILoggerProvider Instance = new FilteringLoggerProvider(); 
    private FilteringLoggerProvider() { } 
    public ILogger CreateLogger(string _categoryName) => FilteringLogger.Instance; 
    public void Dispose() { } 
 
    private class FilteringLogger : ILogger 
    { 
        public static readonly ILogger Instance = new FilteringLogger(); 
        private FilteringLogger() { } 
        public IDisposable BeginScope<TState>(TState _state) => DummyDisposable.Instance; 
        public bool IsEnabled(LogLevel logLevel) => logLevel >= LogLevel.Debug; 
 
        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) 
        { 
            switch (eventId.Name) 
            { 
                case "Http2FlowControlQueueOperationsExceeded": 
                case "Http2TooManyEnhanceYourCalms": 
                    Console.Error.WriteLine($"[{eventId.Id}] {formatter(state, exception)}"); 
                    break; 
            } 
        } 
 
        private sealed class DummyDisposable : IDisposable 
        { 
            public static readonly IDisposable Instance = new DummyDisposable(); 
            private DummyDisposable() { } 
            public void Dispose() { } 
        } 
    } 
} 

@DamianEdwards
Copy link
Member

It's because of how the URL is flowing into the first process (AppHost) as the standard ASPNETCORE_URLS environment variable being passed by VS after it reads the launch profile. The AppHost doesn't want to bind to that address though, it's going to forward it to another process (the Dashboard process) for it to listen on, and AppHost reads another environment variable and uses that to set its own address. Kestrel in the AppHost process sees both the ASPNETCORE_URLS environment variable and manual bindings added via code and emit the warning. @eerhardt is asking for a way to tell Kestrel "Hey just ignore the ASPNETCORE_URLS environment variable, I know it's there and has a value and I don't want you to warn me that you ignored it".

@amcasey
Copy link
Member

amcasey commented Mar 28, 2024

Do you have an opportunity to clear the env var before the app starts? Maybe in the same place you were going to set the flag to ignore it?

@davidfowl
Copy link
Member

davidfowl commented Mar 28, 2024

That's a good workaround actually.

@DamianEdwards
Copy link
Member

I don't think you can remove it completely, but you can clear its value. As long as that results in the same outcome, then yeah that should work.

@eerhardt
Copy link
Member

Thanks @amcasey! I opened #3262 to track doing this work.

@balachir balachir changed the title [WebToolsE2E][Aspire] After running with https, the dashboard page shows loading: "The SSL connection could not be established..." [WebToolsE2E][Aspire] With the dev cert not trusted, when running Aspire app with https, the dashboard page fails to load with the browser dev tools showing: Error starting gRPC call. HttpRequestException: The SSL connection could not be established, see inner exception. AuthenticationException Apr 5, 2024
@balachir
Copy link

balachir commented Apr 5, 2024

Updated title so that this issue is easier to find. With https profile now being the default for Aspire Apps in Aspire 8.0 Preview 5, we now get this warning when we do dotnet run. This is expected.

Workaround: As described in the warning, you can trust the dev certificate by running the command dotnet dev-certs https --trust to fix this problem.

image

@tmds
Copy link
Member

tmds commented Apr 18, 2024

If you run into this issue on a Linux system (where dev-certs https --trust is not supported), you can use http instead of https:

export ASPIRE_ALLOW_UNSECURED_TRANSPORT=true
dotnet run --launch-profile http

The security impact of this is limited because the services bind to localhost, and only someone with sufficient privileges on the system to capture interface packets will now be able to see unencrypted packages instead of encrypted ones.

@davidfowl
Copy link
Member

and only someone with sufficient privileges on the system to capture interface packets will now be able to see unencrypted packages instead of encrypted ones.

Can you say more about the "sufficient privileges" part? If I install tcp dump can't I sniff the packets of any user on the system? Or are more permissions required to do so?

@tmds
Copy link
Member

tmds commented Apr 18, 2024

No, you can't unless you have permissions to do so.

$ tcpdump -i lo
tcpdump: lo: You don't have permission to perform this capture on that device
(socket: Operation not permitted)

@DamianEdwards
Copy link
Member

DamianEdwards commented Apr 18, 2024

I could still attempt to connect to all ports on localhost using HTTP to find running dashboards though couldn't I? If I can scrape the dashboard I can get privileged information about the running apps, e.g. credentials used to secure communications between resources. Enabling unsecured dashboard also disables the dashboard authentication.

@tmds
Copy link
Member

tmds commented Apr 19, 2024

Enabling unsecured dashboard also disabled the dashboard authentication.

I wasn't aware the dashboard has authentication in the https case.

Does authentication need to be disabled in the localhost http case?

@davidfowl
Copy link
Member

Does authentication need to be disabled in the localhost http case?

It doesn't. Those are separate flags.

@JamesNK do we document the apphost config as well?

@JamesNK
Copy link
Member

JamesNK commented Apr 19, 2024

I have only documented the dashboard config. I don't know about app host docs.

@tmds
Copy link
Member

tmds commented Apr 19, 2024

Long, long ago I was prototyping some code to create and install a developer certificate on Linux. I just did some work to package it as a global tool and support Debian based distro (except for a Ubuntu browser issue). You can find it here: https://github.com/tmds/linux-dev-certs.

@davidfowl
Copy link
Member

@adityamandaleeka 👀

@adityamandaleeka
Copy link
Member

@amcasey 👀

@raix
Copy link

raix commented May 4, 2024

@tmds Works like a charm, thanks!

Reference: The linux/WSL setup guide on PlatformPlatform platformplatform/PlatformPlatform#446 (Still some manual trust steps on WSL)

@github-actions github-actions bot locked and limited conversation to collaborators Jun 3, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.