Skip to content

[YARP Ingress Controller] TLS handshake missing private key: The server mode SSL must use a certificate with the associated private key #3051

Description

@Xulei-NL

Describe the bug

Hi there,

I implemented a HTTPS termination for YARP Ingress Controller this week. During my test, I found that TLS handshake would fail and error was The server mode SSL must use a certificate with the associated private key.

I checked the documentation. In summary, a C# X509Certificate2 instance by default has an ephemeral private key in memory linked by a memory pointer. ASP.NET Kestrel relies on OpenSSL on Linux for TLS handshake. However, the OpenSSL under the hood of Linux doesn't know how to get its private key by pointer so OpenSSL thinks the private key is missing.

I would like to make a PR fix for you to review and get your feedback if you regard it as a real bug.

My fix

We need to export the private key so that the PFX file itself includes the private key. The code has done it for Windows.

The following code would eliminate the TLS handshake error and my HTTPS termination would work:

if (OperatingSystem.IsLinux()) 
{
  var pfx = certificate.Export(X509ContentType.Pkcs12);
  certificate = X509CertificateLoader.LoadPkcs12(pfx, null); // a class in .NET9
}

I would say the current code would also work with slight modification based on .NET 8, even if I haven't tested:

  if (OperatingSystem.IsWindows() || OperatingSystem.IsLinux())
  {
    // Cert needs converting. Read https://github.com/dotnet/runtime/issues/23749#issuecomment-388231655
    using var convertedCertificate = X509Certificate2.CreateFromPem(certString, privateString);
    return new X509Certificate2(convertedCertificate.Export(X509ContentType.Pkcs12));
  }

To Reproduce

Reproduce

Use a certificate type secret in Kubernetes and use the generated certificate for TLS handshake by public X509Certificate2 ConvertCertificate(NamespacedName namespacedName, V1Secret secret).

Exceptions

[2026-09-03 16:05:36 DBG] [Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware] Failed to authenticate HTTPS connection.
System.Security.Authentication.AuthenticationException: The server mode SSL must use a certificate with the associated private key.
   at System.Net.Security.SslStream.AcquireServerCredentials(Byte[]& thumbPrint)
   at System.Net.Security.SslStream.GenerateToken(ReadOnlySpan`1 inputBuffer, Int32& consumed)
   at System.Net.Security.SslStream.NextMessage(ReadOnlySpan`1 incomingBuffer, Int32& consumed)
   at System.Net.Security.SslStream.ProcessTlsFrame(Int32 frameSize)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionMiddleware.OnConnectionAsync(ConnectionContext context)

Further technical details

Packages

<PackageReference Include="Yarp.Kubernetes.Controller" Version="3.0.0-preview.1.26370.1"/>
<PackageReference Include="Yarp.ReverseProxy" Version="3.0.0-preview.1.26370.1"/>

Platform

Docker image mcr.microsoft.com/dotnet/sdk:10.0-noble on Ubuntu host machine

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type: BugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions