0

I am trying to make a connection to my kubernetes api and cant seem to get SSL to work from C#.

When i run the following via curl, everything seems to work as expected:

enter image description here

And I have this for c# to do the same:

try
{
    // use the TLS protocol 
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;

    // create HTTP web request with proper content type
    HttpWebRequest request = WebRequest.Create(Constants.K8_API_RC_URI) as HttpWebRequest;
    request.ContentType = "application/json;charset=UTF8";
    request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + Constants.K8_TOKEN);
    // load the X.509 certificate and add to the web request
    X509Certificate cert = new X509Certificate(Constants.K8_CRT);
    request.ClientCertificates.Add(cert);

    // call the web service and get response
    WebResponse response = request.GetResponse();

    Stream responseStream = response.GetResponseStream();

    string jsonContents = new StreamReader(responseStream).ReadToEnd();
}
catch (Exception exc)
{
    // log and print out error
    log.Info(exc.Message);
}

Where

Constants.K8_CRT is the Path to ca.crt

and ca.crt contains the following:

-----BEGIN CERTIFICATE-----
MIIDMDCCAhigAwIBAgIIcwd9rrnaPcowDQYJKoZIhvcNAQELBQAwEzERMA8GA1UEAwwIYWNzazhz
and more letters.......
cwSfuIp7e49KC3HSqcU3Mz4oFNm5bw==
-----END CERTIFICATE-----

I get the following error:

Could not create SSL/TLS secure channel.

P.S. I know there are Kubernetes clients for .Net out there and I have tried just about all of them but since I am integrating this with Azure Functions most of the third party libraries do not work for various reasons.

scorpion5211
  • 1,020
  • 2
  • 13
  • 33
  • I can't say this is the problem, but `.SecurityProtocolType.Tls` enables just TLS 1.0 (which is enabled by default); Try with `.SecurityProtocolType.Tls12`. – Jimi Jan 08 '18 at 21:48
  • Tried it, same error. – scorpion5211 Jan 08 '18 at 21:55
  • A CookieContainer is also usually needed. – Jimi Jan 08 '18 at 22:01
  • Could you elaborate? What would CookieContainer be used for if there is no cookie involved? – scorpion5211 Jan 08 '18 at 22:03
  • Do you know that for sure? Trying it doesn't cost much. – Jimi Jan 08 '18 at 22:08
  • I definitely could give it a try but I'm not too sure what i would be inputting in the CookieContainer? – scorpion5211 Jan 08 '18 at 22:18
  • I don't input anything. Just add a CookieContainer to WebRequest so that Cookies can be exchanged if needed: `CookieContainer _CookieContainer = new CookieContainer();` assign it: `request.CookieContainer = _CookieContainer;` `request.Headers.Add(HttpRequestHeader.CacheControl, "no-cache");` – Jimi Jan 08 '18 at 22:22
  • ah! gotcha! I tried it and I can verify that unfortunately I am still getting the same error. – scorpion5211 Jan 08 '18 at 22:25
  • Check the StatusCode of the response, maybe it can give you some clues on what's failing. Also try `X509Certificate2` class. And get rid of that ";charset=UTF8" in the Content-Type header. Some links on the subject: [Authentication for Azure Functions](https://stackoverflow.com/questions/46757665/authentication-for-azure-functions), [Getting a 403 when calling Azure Resource Rate API using certificate auth](https://stackoverflow.com/questions/43963330/getting-a-403-when-calling-azure-resource-rate-api-using-certificate-auth). – Jimi Jan 08 '18 at 23:04
  • It came to mind that I didn't see you using a CertificationCallback: (`ServicePointManager.ServerCertificateValidationCallback += TlsValidationCallback;`). In the callback, just return `true`. – Jimi Jan 09 '18 at 16:20

2 Answers2

1

The CA cert should be used to validate server cert chain, not passed as an ClientCertificate.

Here is an example.

ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => {
    if (errors == SslPolicyErrors.None) return true;
    X509Certificate2 serverCert = new X509Certificate2(certificate);
    X509Certificate2 caCert = new X509Certificate2(@"./ca.cert");
    chain.ChainPolicy.ExtraStore.Add(caCert);
    chain.Build(serverCert);
    foreach (var chainStatus in chain.ChainStatus) {
        if (chainStatus.Status == X509ChainStatusFlags.UntrustedRoot) continue;
        if (chainStatus.Status != X509ChainStatusFlags.NoError) return false;
    }
    return true;
};

HttpWebRequest request = WebRequest.CreateHttp("https://master:6443/api/v1");
request.Headers[HttpRequestHeader.Authorization] = "Bearer " + "SOME_TOKEN";

HttpWebResponse response = (HttpWebResponse)request.GetResponse();
var content = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.WriteLine(content);
silverfox
  • 5,254
  • 1
  • 21
  • 26
0

Thanks for @Jimi's comments i was able to get this to work with adding the following:

System.Net.ServicePointManager.ServerCertificateValidationCallback +=
            delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                                    System.Security.Cryptography.X509Certificates.X509Chain chain,
                                    System.Net.Security.SslPolicyErrors sslPolicyErrors)
                {
                    return true; // **** Always accept
                };

NOTE: Im certain this just ignores the SSL validation and continues without it. In our case this may be acceptable.

scorpion5211
  • 1,020
  • 2
  • 13
  • 33