1

I am trying to use Elasticsearch NEST with .NET Core and our Elasticsearch instance. We are connecting via SSL and it has a wildcard certificate which we need to accept programmatically. I am trying to figure out how to hook the HttpClientHandler to NEST to accept it. There doesn't appear to be good documentation on how, it just says to do it on their instructions https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/connecting.html#configuring-ssl.

I am looking for an example if possible. Thanks in advance!

Mike Moser
  • 21
  • 3

2 Answers2

0

I figured this out. I needed to create an HttpConnection and override the CreateHttpClientHandler method. Here is an example that returns true regardless of what the certificate is.

public class ConnectionWithCert : HttpConnection
{
    protected override HttpClientHandler CreateHttpClientHandler(RequestData requestData)
    {
        var handler = base.CreateHttpClientHandler(requestData);
        handler.ServerCertificateCustomValidationCallback = ValidateCertificate;
        return handler;
    }

    private bool ValidateCertificate(HttpRequestMessage message, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors errors)
    {
        return true;
    }
}

A person would want to check the cert to ensure that it is one they expect.

Then, I added this connection in the ConnectionSettings

var connectionSettings = new ConnectionSettings(connnectionPool, new ConnectionWithCert());

Probably want to do some Dependency Injection, but figured I would share the solution just in case anyone else wonders what they need to do.

Mike Moser
  • 21
  • 3
  • 1
    We added some helpers in 5.3.0 to help with setting client certificates. The documentation will be updated soon with this:https://github.com/elastic/elasticsearch-net/blob/5.x/docs/client-concepts/certificates/working-with-certificates.asciidoc it's based on https://github.com/elastic/elasticsearch-net/blob/5.x/src/Tests/ClientConcepts/Certificates/WorkingWithCertificates.doc.cs – Russ Cam Mar 30 '17 at 21:47
  • @RussCam That documentation is still missing how to do it with .NET Core. It has a blurb in there about "sadly this is not available in .NET Core...", but it really doesn't explain how to do it in .NET Core. Examples would be great in your documentation. – Mike Moser Mar 31 '17 at 15:43
0

This took me some head scratching to figure out, so I thought I would post it here. We are using a reverse proxy where we send the request to 443 SSL port (load balanced in azure to three client nodes) using a cert to authenticate, then forward that to the local client node to scatter to the data nodes. The cert is self signed, and is in the local store (Current User > Personal) on the server housing our api. The thumbprint is in our web.config.

public class ConnectionWithCert : Elasticsearch.Net.HttpConnection
{
    protected override HttpWebRequest CreateHttpWebRequest(RequestData requestData)
    {
        var handler = base.CreateHttpWebRequest(requestData);

        string certThumbprint = System.Configuration.ConfigurationManager.AppSettings["ElasticsearchCertificateThumbprint"];
        X509Certificate2 certificate =
            GetCertificateByThumbprint(certThumbprint);

        handler.ClientCertificates.Add(certificate);
        return handler;
    }

    /// <summary>
    /// Get the certificate using the certificate thumbprint
    /// </summary>
    /// <param name="certificateThumbprint">Thumbprint of certificate</param>
    /// <returns>Certificate object</returns>
    public static X509Certificate2 GetCertificateByThumbprint(string certificateThumbprint)
    {
        Ensure.ArgumentNotEmpty(certificateThumbprint, nameof(certificateThumbprint));

        // Open the certificate store
        X509Store certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        certificateStore.Open(OpenFlags.ReadOnly);

        // Get the certificates
        var matchingCertificates = certificateStore.Certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false);
        if (matchingCertificates.Count == 0)
        {
            // No certificate found
            return null;
        }
        else
        {
            // Return first certificate
            return matchingCertificates[0];
        }
    }
}

Once I have this, I can set that on my connectionSettings in my helper class:

    public ElasticSearchHelper(string elasticSearchUrl, OcvElasticSearchDataProvider dataProvider, int elasticSearchConflictRetryCount)
    {
        // Parameters
        this.elasticSearchConflictRetryCount = elasticSearchConflictRetryCount;
        this.dataProvider = dataProvider;

        // Create the ElasticSearch client and configure
        var node = new Uri(elasticSearchUrl);

        var pool = new SingleNodeConnectionPool(node);
        var settings = new ConnectionSettings(pool, new ConnectionWithCert());

        this.client = new ElasticClient(settings);
    }

Now all operations carried out through my helper have the client cert attached, and is granted access through my reverse proxy.

John
  • 239
  • 4
  • 12