Invalid or malformed certificate using caFingerprint

hi,

I generated a CA certificate using:
./elasticsearch-certutil ca --pem --out /certs/ca.zip

and then generated a cert using:

./bin/elasticsearch-certutil cert \
--out /var/snap/amazon-ssm-agent/7628/elasticsearch-8.11.2/config/certs/elastic.zip \
--name elastic \
--ca-cert /var/snap/amazon-ssm-agent/7628/elasticsearch-8.11.2/config/certs/ca/ca/ca.crt \
--ca-key /var/snap/amazon-ssm-agent/7628/elasticsearch-8.11.2/config/certs/ca/ca/ca.key \
--dns elastic-cluster.mydomain.com \
--pem

my current elasticsearch config is:

# Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents
xpack.security.http.ssl:
  enabled: true
  certificate: certs/elastic/elastic.crt
  key: certs/elastic/elastic.key
  certificate_authorities: certs/ca/ca/ca.crt
  #keystore.path: certs/http.p12

# Enable encryption and mutual authentication between cluster nodes
xpack.security.transport.ssl:
  enabled: true
  verification_mode: certificate
  keystore.path: certs/transport.p12
  truststore.path: certs/transport.p12
# Create a new cluster with the current node only
# Additional nodes can still join the cluster later
cluster.initial_master_nodes: ["ip-10-11-9-43"]

# Allow HTTP API connections from anywhere
# Connections are encrypted and require user authentication
http.host: 0.0.0.0

when I run:
curl -X GET -u user:password https://elastic-cluster.mydomain.com:9200/ --cacert /var/snap/amazon-ssm-agent/7628/elasticsearch-8.11.2/config/certs/ca/ca/ca.crt

it works, now I need to implemented with js code, then I generate caFingerprint using:
openssl x509 -fingerprint -sha256 -noout -in /var/snap/amazon-ssm-agent/7628/elasticsearch-8.11.2/config/certs/ca/ca/ca.crt

it returns:
"61:C2:4E:2B:5A:8A:F4:A5:DA:23:62:A8:E8:01:50:2B:9E:A6:31:61:2A:7B:BC:70:A3:1D:CF:45:89:81:37:31"

but when I implement my code as follow:

const client = new Client({
      node: "https://elastic-cluster.mydomain.com:9200",
      auth: {
        username: "user",
        password: "password",
      },
      // the fingerprint (SHA256) of the CA certificate that is used to sign
      // the certificate that the Elasticsearch node presents for TLS.
      caFingerprint: "61:C2:4E:2B:5A:8A:F4:A5:DA:23:62:A8:E8:01:50:2B:9E:A6:31:61:2A:7B:BC:70:A3:1D:CF:45:89:81:37:31",
      tls: {
        // might be required if it's a self-signed certificate
        rejectUnauthorized: false,
      },
    });

returns error:

(node:23052) UnhandledPromiseRejectionWarning: ConnectionError: Invalid or malformed certificate
    at SniffingTransport.request (/var/www/serverless/node_modules/@elastic/transport/lib/Transport.js:541:31)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async Cat.indices (/var/www/serverless/node_modules/@elastic/elasticsearch/lib/api/api/cat.js:221:16)
    at async /var/www/serverless/elastic.js:28:17

Condiser it worked with http_ca.crt caFingerPrint generated before I change the elasticsearch.yml using new ca and certs, but now that http_ca.crt fingerPrint doesnt work anymore

I tried using Fingerprint generated with http_ca.crt - ca.crt - elastic.crt. None works actually

Hi @joe_recra

Take out the colons... We should make that clearer

openssl x509 -fingerprint -sha256 -noout -in ./ca.crt | awk --field-separator="=" '{print $2}' | sed 's/://g'

Hi @stephenb thanks for your time.

I ran the command and it returned me a string without colons, but still giving me:

(node:21237) UnhandledPromiseRejectionWarning: ConnectionError: Invalid or malformed certificate

Interesting the example here shows with :s

Hmmm interesting... So with colons probably correct ... Sorry about that.. other clients/ Kibana use no colons

caFingerprint: '20:0D:...

Hmm not sure of the issue

But you need to use the CA you used to generate the cert you are using for the http endpoint.

Did you try leaving the default and then us the http_ca.crt to generate the the fingerprint.

Also I see where you generated your own cert for the http endpoint but you did NOT use the http option with the cert util so I am not exactly sure what state you are in and what you are trying to accomplish...

Well, http.p12 and http_ca.crt are automatically created with the instalation of elasticsearch.

I created a CA to generate elastic and kibana certs, I dind use http_ca.crt to sign them.

I also tried with http_ca.crt, ca/ca.crt and elastic/ca.crt. The connection to elasticsearch via curl only works with ca/ca.crt and elastic/ca.crt. But none of those three fingerprints generated works.

Can we try a few things?

First put this back into your elasticsearch.yml only comment out the other 3 lines and restart elasticsearch.

xpack.security.http.ssl:
  enabled: true
  keystore.path: certs/http.p12

Then

curl -v -u elastic:password --cacert /path/to/http_ca.crt "https://iptohost:9200"

Note you cant try the hostname but most likely the FQDN will not work because it will not be in the cert... Yes I know you want to do this... but lets do 1 step at a time....

Please provide the command and the entire output for that. The -v is important.

Then, create the fingerprint from the http_ca.crt and leave the colons in

Then try in your node code... with the IP address or host that was shown in the output of the curl (in the IP, SANs etc)

Share all the results...

curl -v -u elastic:password --cacert /path/to/http_ca.crt "https://iptohost:9200"

returns:

*   Trying 10.11.9.43:9200...
* TCP_NODELAY set
* Connected to 10.11.9.43 (10.11.9.43) port 9200 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: ./config/certs/http_ca.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=ip-10-11-9-43
*  start date: Dec 11 07:31:09 2023 GMT
*  expire date: Dec 10 07:31:09 2025 GMT
*  subjectAltName: host "10.11.9.43" matched cert's IP address!
*  issuer: CN=Elasticsearch security auto-configuration HTTP CA
*  SSL certificate verify ok.
* Server auth using Basic with user 'elastic'
> GET / HTTP/1.1
> Host: 10.11.9.43:9200
> Authorization: Basic ZWxhc3RpYzpuaEgzLXVpQzUrdXNnR2t5ZVU4bg==
> User-Agent: curl/7.68.0
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-elastic-product: Elasticsearch
< content-type: application/json
< content-length: 537
<
{
  "name" : "ip-10-11-9-43",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "PHPt8H2LT-a7s-nKrtiTZA",
  "version" : {
    "number" : "8.11.2",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "76013fa76dcbf144c886990c6290715f5dc2ae20",
    "build_date" : "2023-12-05T10:03:47.729926671Z",
    "build_snapshot" : false,
    "lucene_version" : "9.8.0",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}
* Connection #0 to host 10.11.9.43 left intact

Then, create the fingerprint from the http_ca.crt and leave the colons in
Then try in your node code... with the IP address or host that was shown in the output of the curl (in the IP, SANs etc)

It works, but the configuration was restarted right ?

Unclear what you mean ... but yes you should have restarted elasticsearch after you made the changes to elasticsearch.yml

*  subject: CN=ip-10-11-9-43
*  start date: Dec 11 07:31:09 2023 GMT
*  expire date: Dec 10 07:31:09 2025 GMT
*  subjectAltName: host "10.11.9.43" matched cert's IP address!

so that default http.crt will only work with this is what the -v shows

hostname: ip-10-11-9-43
or 
IP: 10.11.9.43

If you want to use FQDN you will need to create the http cert correctly from a CA and then use the correct new http cert in the elasticsearch.yml with the fingerprint from the correct CA.

BTW you do not need this line in the elasticsearch.yml under the http section...

certificate_authorities: certs/ca/ca/ca.crt

If you want to use FQDN you will need to create the http cert correctly from a CA and then use the correct new http cert in the elasticsearch.yml with the fingerprint from the correct CA.

Sorry I didnt understand, you talking about to create a new http_ca.crt or http.p12 ?

I executed:

./bin/elasticsearch-certutil http

and it returned for me an http.p12 file, now what do I do with this ?

Sorry, sadly self-managed elastic is not too easy for newers

Set the path here to your new http.p12 cert you just created.

stop and start elasticsearch

Which CA did you use when that command asked? Did you use one you already had?

I ask because you need to use the fingerprint from the CA you used to create your new http.p12 cert.

Now try the curl command again and show the full output again let's see what you have.

True, but it also worked exactly as it was supposed to with the default automatic setup.

Now we're trying to change the SSL certs to meet your requirements and really this is no different than any other service that you would set up. SSL. SSL is a bit tricky the first time you go through. But again this is no different than if you're running a web server or other app that required SSL

You're almost there and you've learned so much :slight_smile:

Can you explain why you decided to do this?
The out of the box configuration is designed to make everything work simply and easily without all this messing around. What was your motivation for changing it?

I suspect the problem is here:

xpack.security.http.ssl.certificate_authorities doesn't do what you think it does. It is used to validate client certificates. Since you aren't using client certificates, this line achieves nothing.

What you seem to be trying to do is provide the issuing chain for the server certificate. In Elasticsearch you do that by concatating the issuing chain with the server certificate.

See the explanation and example commands here

As it is, it doesn't looks like you have configured Elasticsearch to send the CA certificate over the wire, so the client cannot verify the fingerprint.

Is there a particular reason you want to use the CA fingerprint rather than just trusting the CA cert itself?
The fingerprint is a simple option when you use security auto configuration because the CA fingerprint is included in the node's output when it is set up, but if you're using your own cert then there's no real benefit to a fingerprint

hi @TimV

Because I wanted to sign my domain. I mean that elasticsearch works with domain name, thats why applied this:

then you tell me it's not necessary I use this set up, correct ? with the custom keystore.path is necesarry ?

then If I wanna connect kibanna with elasticsearch, which certs I use ? http_ca.crt ?

btw, I followed this video to install elasticsearch and kibana with self sign certs: https://www.youtube.com/watch?v=OYS0hzPDgp4&t=986s

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.