Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I trust dotnet's dev-cert, in Linux?

I'm working through an online course on building Microservices in .NET - https://www.dotnetmicroservices.com/.

But while the instructor is running on Windows, I'm working on Linux - Linux Mint 20.1 (Ulyssa).

.NET core and .NET 5.0 are supposed to be cross-platform, and I've had no real issues in getting things to work, until now.

At this point, I have two webapi services, one providing identity services and one providing a catalog service.

The identity service is configured to use IdentityServer4, IdentityServer4.AspNetIdentity, and Microsoft.AspNetCore.Identity.UI to provide OAuth 2.0 and OpenID services.

The catalog service is configured to use Microsoft.AspNetCore.Authentication.JwtBearer, and requires a valid JWT to access the endpoints.

So, in Postman, I have a Request configured to access a simple GET endpoint in the catalog service. In the Authorization tab for the Request I choose OAuth 2.0, and enter the necessary data to make the request, including the Auth URL and Access Token URL (https://localhost:5003/connect/authorize and https://localhost:5003/connect/token).

When I click on Postman's "Get New Access Token" button, I get the login page, I log in, and get the "MANAGE ACCESS TOKENS" dialog. I can copy the Access Token or the id_token from the dialog and paste them into https://jwt.ms/ and they both look fine.

So that much is working.

But when I click on Postman's "Use Token" button, and then do a "Send" on the Request, I get an exception in the catalog service:

fail: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[3]
      Exception occurred while processing message.
      System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String'.
       ---> System.IO.IOException: IDX20804: Unable to retrieve document from: 'System.String'.
       ---> 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: PartialChain
         at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception)
         at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
         at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
         --- End of inner exception stack trace ---
         at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
         at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
         at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
         at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
         at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
         at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
         at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
         at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
         at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
         --- End of inner exception stack trace ---
         at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
         at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String address, IDocumentRetriever retriever, CancellationToken cancel)
         at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
         --- End of inner exception stack trace ---
         at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
         at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()

It looks like the problem is that dotnet's developer certificate isn't trusted.

The usual method for doing this is to use the dotnet cli:

dotnet dev-certs https --trust

But on Linux, this returns:

Trusting the HTTPS development certificate was requested. Trusting the certificate on Linux distributions automatically is not supported. For instructions on how to manually trust the certificate on your Linux distribution, go to https://aka.ms/dev-certs-trust

So I went to https://aka.ms/dev-certs-trust, and it contains a lot of stuff, most of which clearly isn't relevant. The section on "Ubuntu trust the certificate for service-to-service communication" seemed apropos:

sudo dotnet dev-certs https -ep /usr/local/share/ca-certificates/aspnet/https.crt --format PEM
sudo update-ca-certificates

And while that ran without issue, it didn't not fix the problem.

As for the rest, the page says "Establishing trust is browser specific. The following sections provide instructions for the Chromium browsers Edge and Chrome and for Firefox."

And I don't see how either is relevant to the problem at hand.

What is dotnet core doing, when it is verifying certificates? What do I need to do to mark the dotnet developer's certificate as trusted?

like image 971
Jeff Dege Avatar asked Jul 06 '26 08:07

Jeff Dege


1 Answers

The following works on Linux:

  • Generate a local CA.

    mkcert -install

  • Generate the certificate to be used in your service

    mkcert -pkcs12 -p12-file myservice.local.pfx myservice.local

  • Add an entry for myservice.local in /etc/hosts

    127.0.0.1 myservice.local

  • Use the p12 certificate in your dotnet service

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Hosting;
    
    namespace myservice
    {
      public class Program
      {
        public static void Main(string[] args)
        {
          CreateHostBuilder(args).Build().Run();
        }
    
        public static IHostBuilder CreateHostBuilder(string[] args) =>
          Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
    
    #if DEBUG
              webBuilder.UseStartup<Startup>().UseKestrel(options =>
              {
                options.Listen(IPAddress.Loopback, 5001, listenOptions =>
                {
                  listenOptions.UseHttps("./myservice.local.pfx", "changeit");
                });
              }).UseUrls("https://myservice.local:5001");
    
    #else
                        webBuilder.UseStartup<Startup>();
    #endif
            });
      }
    }

like image 71
qed Avatar answered Jul 08 '26 14:07

qed