diff --git a/Kudu.Core/Kube/KubernetesClientUtil.cs b/Kudu.Core/Kube/KubernetesClientUtil.cs index 4eb5614b..425e9de7 100644 --- a/Kudu.Core/Kube/KubernetesClientUtil.cs +++ b/Kudu.Core/Kube/KubernetesClientUtil.cs @@ -1,7 +1,11 @@ using System; +using System.Diagnostics; +using System.IO; using System.Net.Http; using System.Net.Security; +using System.Security.Claims; using System.Security.Cryptography.X509Certificates; +using System.Xml.Linq; using Microsoft.Rest.TransientFaultHandling; namespace Kudu.Core.Kube @@ -11,6 +15,7 @@ public class KubernetesClientUtil public const int ClientRetryCount = 3; public const int ClientRetryIntervalInSeconds = 5; private const string caPath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"; + private const string serviceCAPath = "/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt"; public static void ExecuteWithRetry(Action action) { @@ -21,12 +26,23 @@ public static void ExecuteWithRetry(Action action) retryPolicy.ExecuteAction(action); } - public static bool ServerCertificateValidationCallback( + public static bool ServerCertificateValidationCallback2( HttpRequestMessage request, X509Certificate2 certificate, X509Chain certChain, SslPolicyErrors sslPolicyErrors) { + Console.WriteLine("ServerCertificateValidationCallback2 : false"); + return false; + } + + public static bool ServerCertificateValidationCallback( + HttpRequestMessage request, + X509Certificate2 certificate, + X509Chain certChain, + SslPolicyErrors sslPolicyErrors) + { + Console.WriteLine($"sslPolicyErrors: {sslPolicyErrors}"); if (sslPolicyErrors == SslPolicyErrors.None) { // certificate is already valid @@ -36,6 +52,7 @@ public static bool ServerCertificateValidationCallback( { // only remaining error state is RemoteCertificateChainErrors // check custom CA + bool caresult = true; var privateChain = new X509Chain(); privateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; @@ -46,17 +63,72 @@ public static bool ServerCertificateValidationCallback( // Build the chain for `certificate` which should be the self-signed kubernetes api-server cert. privateChain.Build(certificate); + foreach (X509ChainElement element in privateChain.ChainElements) + { + Console.WriteLine(); + Console.WriteLine(element.Certificate.Subject); + Console.WriteLine(element.ChainElementStatus.Length); + foreach (X509ChainStatus status in element.ChainElementStatus) + { + Console.WriteLine($"Status: {status.Status}: {status.StatusInformation}"); + } + } + foreach (X509ChainStatus chainStatus in privateChain.ChainStatus) { if (chainStatus.Status != X509ChainStatusFlags.NoError && // root CA cert is not always trusted. chainStatus.Status != X509ChainStatusFlags.UntrustedRoot) { - return false; + Console.WriteLine($"ca crt: {chainStatus.Status}"); + caresult = false; + break; } } - return true; + if (caresult) + { + return true; + } + + if (File.Exists(serviceCAPath)) + { + var serviceCAprivateChain = new X509Chain(); + serviceCAprivateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + + var serviceCA = new X509Certificate2(serviceCAPath); + // https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509chainpolicy?view=netcore-2.2 + // Add CA cert to the chain store to include it in the chain check. + serviceCAprivateChain.ChainPolicy.ExtraStore.Add(serviceCA); + // Build the chain for `certificate` which should be the self-signed kubernetes api-server cert. + serviceCAprivateChain.Build(certificate); + + foreach (X509ChainElement element in serviceCAprivateChain.ChainElements) + { + Console.WriteLine(); + Console.WriteLine(element.Certificate.Subject); + Console.WriteLine(element.ChainElementStatus.Length); + foreach (X509ChainStatus status in element.ChainElementStatus) + { + Console.WriteLine($"Status: {status.Status}: {status.StatusInformation}"); + } + } + + foreach (X509ChainStatus chainStatus in serviceCAprivateChain.ChainStatus) + { + if (chainStatus.Status != X509ChainStatusFlags.NoError && + // root CA cert is not always trusted. + chainStatus.Status != X509ChainStatusFlags.UntrustedRoot) + { + Console.WriteLine($"service crt: {chainStatus.Status} "); + return false; + } + } + + return true; + } + + return false; } else { diff --git a/Kudu.Services.Web/Services/ServiceExtensions.cs b/Kudu.Services.Web/Services/ServiceExtensions.cs index fe698a1f..50028e6d 100644 --- a/Kudu.Services.Web/Services/ServiceExtensions.cs +++ b/Kudu.Services.Web/Services/ServiceExtensions.cs @@ -138,7 +138,7 @@ internal static void AddKubernetesClientFactory(this IServiceCollection services }) .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { - ServerCertificateCustomValidationCallback = KubernetesClientUtil.ServerCertificateValidationCallback, + ServerCertificateCustomValidationCallback = KubernetesClientUtil.ServerCertificateValidationCallback2, }); } }