"unable to verify the first certificate" when connecting to elasticsearch from nodejs using self-generated certificates

Issue

How do I connect to my elasticsearch cluster (TLS secured) when there are certificates generated by myself with the elasticsearch-certutil?

According to the ES documentation this code snippet should do it:

const client = new Client({
  node: config.elastic.node,
  auth: {
    username: "elastic",
    password: config.elastic.password
  },
  tls: {
    ca: fs.readFileSync( "./share/es/certs/ca.crt" ),
    rejectUnauthorized: false
  }
})

Unfortunately, this gives me this famous error:

ConnectionError: unable to verify the first certificate

I’ve setup ES via docker-compose. To wrap up, I did the following:

  1. Generating the certs using the elasticsearch-certutil using cert command via: bin/elasticsearch-certutil cert --silent --pem --in config/instances.yml -out /certs/bundle.zip. instances.yml contains all of my nodes as well as kibana. bundle.zip contains all certs and keys as well as the certificate for CA.

  2. Configuring my nodes in docker-compose.yml so that they can read the generated certificates. For instance,

       ...
       - xpack.security.http.ssl.key=${ES_CERTS_DIR}/es01/es01.key
       - xpack.security.http.ssl.certificate_authorities=${ES_CERTS_DIR}/ca/ca.crt
       - xpack.security.http.ssl.certificate=${ES_CERTS_DIR}/es01/es01.crt
       - xpack.security.transport.ssl.certificate_authorities=${ES_CERTS_DIR}/ca/ca.crt
       - xpack.security.transport.ssl.certificate=${ES_CERTS_DIR}/es01/es01.crt
       - xpack.security.transport.ssl.key=${ES_CERTS_DIR}/es01/es01.key
       ...
    
  3. Validating the connection with curl with this command

    $ curl -X GET "https://elastic:[email protected]:9201" -H "Content-type: application/json" --cacert $CACERT --key $KEY --cert $CERT
    

    where $CACERT, $KEY, $CERT are pointing to the CA cert, the key and certificate for the node that I am connecting to. This results in:

    {
      "name" : "es01",
      "cluster_name" : "es-docker-cluster",
      ...
      "tagline" : "You Know, for Search"
    }
    

    which is fine I suppose.

But why can’t I connect to my cluster from my expressjs application? I read something about creating a the certificate chain and letting ES know that. But, I this necessary? I mean, I can connect via curl and also using elasticdump. What gives my an error is when I access the cluster via browser https://my-cluster-domain.com:9201. The browser warns me that, although the certificate is valid, the connection is not secure.

Any ideas? Thank you.

Solution

Well, after a lot of googling it turned out that adding the CA file to the ES client config is not enough, as indicated in my example configuration above.

  ...
  tls: {
    ca: fs.readFileSync( "./share/es/certs/ca.crt" ),
    rejectUnauthorized: false  # don't do this in production
  }

Instead, one has to announce the CA certificate to the Node process itself, before configuring your connecting to ES. You can do this, as described in this and in this post (solution 2a, with the NODE_EXTRA_CA_CERTS environment variable. I now start my process like this and it worked out:

$ NODE_EXTRA_CA_CERTS="./share/es/certs/ca.crt" NODE_ENV=prod ...

One last remark, you don’t have to set rejectUnauthorized: false, as some workarounds do, in case you have the current version of the elasticsearch client.

My final configuration looks like this:

  const client = new Client({
    node: config.elastic.node,
    auth: {
      username: "elastic",
      password: config.elastic.password
    }
  })

Answered By – matthaeus

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published