Elastic Agent ca_trusted_fingerprint does not working, but the certificate works

Hello,

I've built a simple docker compose that will spin up a single node cluster with Elasticsearch, Kibana and a Fleet server and I'm facing an issue where the ca_trusted_fingerprint is not working as expected.

The compose will create a CA and a certificate using openssl and in a further step it will create a default elasticsearch output in fleet with the sha256 fingerprint of the ca as the value for ca_trusted_fingerprint.

The issue is that it even with the ca_trusted_fingerprint configured, the Agent on the fleet container cannot connect to the Elasticsearch container and keeps throwing the unknown authority error.

Error dialing x509: certificate signed by unknown authority

But if I get the certificate and configure in the advanced yml with ssl.certificate_authorities, it will work.

For example, considering the CA file as ca-siem.pem, I can get the fingerprint with the following command:

sudo openssl x509 -fingerprint -sha256 -in ca-siem.pem

And the result will be something like this:

sha256 Fingerprint=2F:96:88:4D:A6:20:0B:ED:CA:CE:E9:92:85:99:1E:31:E8:78:75:CD:67:68:4A:82:CD:D3:20:8C:C2:D5:EC:55
-----BEGIN CERTIFICATE-----
MIIDkTCCAnmgAwIBAgIUcElxHmR8/QJQRmpQ1OXMdmQsFbkwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCQlIxCzAJBgNVBAgMAlJKMRcwFQYDVQQHDA5SSU8gREUg
SkFORUlSTzEUMBIGA1UECgwLU0lFTSBET0NLRVIxDTALBgNVBAsMBFNJRU0wHhcN
MjQwNjI5MDQ0NjAyWhcNMjkwNzAzMDQ0NjAyWjBYMQswCQYDVQQGEwJCUjELMAkG
A1UECAwCUkoxFzAVBgNVBAcMDlJJTyBERSBKQU5FSVJPMRQwEgYDVQQKDAtTSUVN
IERPQ0tFUjENMAsGA1UECwwEU0lFTTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBANIyUorRCtZRcH2JMEbT3xInlCakNHu5fUCigx3IA5IgegpJOgXghO2B
25QQ21FJXsvLBEklde+f9BC2AwfST2g8fvqDjCHvnX3MygibfWDXKAvrkTSDqGPR
z07i1DQEyTkkJcuud8d7fuUNZ8LS40n+IPdRBFI0qeHFNoYudIf9e09aqICRO/wZ
EkjR4uV2UjoBXYHNLsn8uDqCd1Zx70deQDuXMYP+9jJ0oWaXfKlt92qGg6TGsthF
9rMX0b2VM22Tw7YvVhYHoH0Pk6f5fphFF0LeSXQEITEP9yCuHHTNGhf5lpkzg5UV
HgKbTx24EmFm48zGeEuhKMjtUfu+tdUCAwEAAaNTMFEwHQYDVR0OBBYEFKSw10ms
wAMXgIlrD2Ns1BjVB2LeMB8GA1UdIwQYMBaAFKSw10mswAMXgIlrD2Ns1BjVB2Le
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAOwTRBloKxr8EGG
Mge2pMpxb5pK6zUwsFe4nhJq/5gxxpNoEALvLRMWA7fGF9UNB6pHEmZzSRyJeDnC
L3sYwgwmcExqfKkDWlDCuvnVcFi3drgDUp86iDuaUs7LrGZYBlbJdk4SaVuSfmd5
mfgrmoqzqeHwZnnJsft6CVlTr2J76EC5tiWsiAvlTPPYq3swugckXLI4IhGV9HHy
cbaA9EHZ0qFi6rkUfGX8NuByPxtUbH6clmxT1LzvQzx9evaMUE+ZIaN2I9n48yFU
0DGCk/bjNG3PLnD/iZwvE29RSMvTW1OwNjWCPMBgwGttXIAcB7DjnBwcqdhkRfj8
kl+ZnaI=
-----END CERTIFICATE-----

The ca_trusted_fingerprint would then be configured to use 2F96884DA6200BEDCACEE99285991E31E87875CD67684A82CDD3208CC2D5EC55 as the value.

But this will lead to errors regarding the fingerprint and the unkown authority:

{"log.level":"info","@timestamp":"2024-06-29T04:56:58.691Z","message":"'ca_trusted_fingerprint' set, looking for matching fingerprints","component":{"binary":"metricbeat","dataset":"elastic_agent.metricbeat","id":"beat/metrics-monitoring","type":"beat/metrics"},"log":{"source":"beat/metrics-monitoring"},"log.origin":{"file.line":179,"file.name":"tlscommon/tls_config.go","function":"github.com/elastic/elastic-agent-libs/transport/tlscommon.trustRootCA"},"service.name":"metricbeat","ecs.version":"1.6.0","log.logger":"tls","ecs.version":"1.6.0"}
{"log.level":"warn","@timestamp":"2024-06-29T04:56:58.691Z","message":"no CA certificate matching the fingerprint","component":{"binary":"metricbeat","dataset":"elastic_agent.metricbeat","id":"beat/metrics-monitoring","type":"beat/metrics"},"log":{"source":"beat/metrics-monitoring"},"log.logger":"tls","log.origin":{"file.line":208,"file.name":"tlscommon/tls_config.go","function":"github.com/elastic/elastic-agent-libs/transport/tlscommon.trustRootCA"},"service.name":"metricbeat","ecs.version":"1.6.0","ecs.version":"1.6.0"}
{"log.level":"error","@timestamp":"2024-06-29T04:56:58.691Z","message":"Error dialing x509: certificate signed by unknown authority","component":{"binary":"metricbeat","dataset":"elastic_agent.metricbeat","id":"beat/metrics-monitoring","type":"beat/metrics"},"log":{"source":"beat/metrics-monitoring"},"log.origin":{"file.line":38,"file.name":"transport/logging.go","function":"github.com/elastic/elastic-agent-libs/transport/httpcommon.(*HTTPTransportSettings).RoundTripper.LoggingDialer.func2"},"service.name":"metricbeat","address":"elasticsearch:9200","log.logger":"esclientleg","network":"tcp","ecs.version":"1.6.0","ecs.version":"1.6.0"}

But if I use the certificate in the advanced yaml configuration it will work.

ssl.certificate_authorities:
  - |
    -----BEGIN CERTIFICATE-----
    MIIDkTCCAnmgAwIBAgIUcElxHmR8/QJQRmpQ1OXMdmQsFbkwDQYJKoZIhvcNAQEL
    BQAwWDELMAkGA1UEBhMCQlIxCzAJBgNVBAgMAlJKMRcwFQYDVQQHDA5SSU8gREUg
    SkFORUlSTzEUMBIGA1UECgwLU0lFTSBET0NLRVIxDTALBgNVBAsMBFNJRU0wHhcN
    MjQwNjI5MDQ0NjAyWhcNMjkwNzAzMDQ0NjAyWjBYMQswCQYDVQQGEwJCUjELMAkG
    A1UECAwCUkoxFzAVBgNVBAcMDlJJTyBERSBKQU5FSVJPMRQwEgYDVQQKDAtTSUVN
    IERPQ0tFUjENMAsGA1UECwwEU0lFTTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
    AQoCggEBANIyUorRCtZRcH2JMEbT3xInlCakNHu5fUCigx3IA5IgegpJOgXghO2B
    25QQ21FJXsvLBEklde+f9BC2AwfST2g8fvqDjCHvnX3MygibfWDXKAvrkTSDqGPR
    z07i1DQEyTkkJcuud8d7fuUNZ8LS40n+IPdRBFI0qeHFNoYudIf9e09aqICRO/wZ
    EkjR4uV2UjoBXYHNLsn8uDqCd1Zx70deQDuXMYP+9jJ0oWaXfKlt92qGg6TGsthF
    9rMX0b2VM22Tw7YvVhYHoH0Pk6f5fphFF0LeSXQEITEP9yCuHHTNGhf5lpkzg5UV
    HgKbTx24EmFm48zGeEuhKMjtUfu+tdUCAwEAAaNTMFEwHQYDVR0OBBYEFKSw10ms
    wAMXgIlrD2Ns1BjVB2LeMB8GA1UdIwQYMBaAFKSw10mswAMXgIlrD2Ns1BjVB2Le
    MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAOwTRBloKxr8EGG
    Mge2pMpxb5pK6zUwsFe4nhJq/5gxxpNoEALvLRMWA7fGF9UNB6pHEmZzSRyJeDnC
    L3sYwgwmcExqfKkDWlDCuvnVcFi3drgDUp86iDuaUs7LrGZYBlbJdk4SaVuSfmd5
    mfgrmoqzqeHwZnnJsft6CVlTr2J76EC5tiWsiAvlTPPYq3swugckXLI4IhGV9HHy
    cbaA9EHZ0qFi6rkUfGX8NuByPxtUbH6clmxT1LzvQzx9evaMUE+ZIaN2I9n48yFU
    0DGCk/bjNG3PLnD/iZwvE29RSMvTW1OwNjWCPMBgwGttXIAcB7DjnBwcqdhkRfj8
    kl+ZnaI=
    -----END CERTIFICATE-----

The certificate works, but the fingerprint does not work, what am I missing?

Hi @leandrojmp !!

Can you share your compose?

Perhaps I can take a look later today

Quicktest would be does the fingerprint work with a beat?

Sure, it is in this repository: GitHub - leandrojmp/docker-elastic

The README is in portuguese, but you just need to create the .env.

It will then create the certificates, configure the kibana user and fleet output.

The only issue I'm having is that the fingerprint does not work, but the certificate works.

It was based on this another project GitHub - peasead/elastic-container: Stand up a simple Elastic container with Kibana, Fleet, and the Detection Engine, but way simpler.

The main difference Is that I'm creating my CA and certificates using openssl, not elasticsearch-certutil, and to make it even more simpler I'm using the same certificate for elasticsearch, kibana and fleet.

Didn't test this, but will try something like this later.

@leandrojmp

So what is in the repo is the working version without using the fingerprint confirm?

Can you share the version where you tried to use the fingerprint?

One quick look ... I don't see any of these under fleet
I would expect to see 1st or 2nd or 3 and 4
I believe These are what are forwarded down to the agents (and used with the outputs) I would need to take a closer look...

[--fleet-server-es-ca <string>]
[--fleet-server-es-ca-trusted-fingerprint <string>] 
^^^This is the one you are trying to set? 
[--fleet-server-es-cert <string>]
[--fleet-server-es-cert-key <string>]

--fleet-server-es-ca-trusted-fingerprint <string>
The SHA-256 fingerprint (hash) of the certificate authority used to self-sign Elasticsearch certificates. This fingerprint will be used to verify self-signed certificates presented by Fleet Server and any inputs started by Elastic Agent for communication. This flag is required when using self-signed certificates with Elasticsearch.

When I get a chance I will look

If you generate the command from Kibana you will see (yes I know you need more ... just double checking)

sudo ./elastic-agent install \
  --fleet-server-es=https://192.168.2.107:9200 \
  --fleet-server-service-token=AAEAAWVsYXN0aWMvZmxlZXQtc2VydmVyL3Rva2VuLTE3MTk2ODUxMjIxNjI6SWt1c1NFdFRUWC1DNnB2T0xOd0w0UQ \
  --fleet-server-policy=fleet-server-policy \
  --fleet-server-es-ca-trusted-fingerprint=1f5fd789732ce83a08778ca577502769f8159beecc1a8d5f1edc95422321e528 \
  --fleet-server-port=8220

BTW I did a quick metricbeat test using the trusted fingerprint and it worked... using mine I will try with yours...

No, there is no working version using the fingerprint, this is what I'm trying to troubleshoot.

The docker compose in the repository will perform the following steps:

  • Spin-up a one-time container using the ubuntu image to create a custom CA and a certificate, this certificate will be used by the elasticsearch, kibana and fleet containers.
    The certificates is stored on a persistent path that is shared with the other containers.

  • After that, a Elasticsearch single-node container will be started and use the certificate generate in the previous step for both the transport and http endpoints.

  • When the Elasticsearch container is healthy, a one-time container will run to setup the password for the kibana_system user as we cannot use the internal elastic user anymore.

  • The next step is to spin-up a Kibana container and when it is healthy another one-time container will be executed to setup two fleet settings, the fleet host and the default output.

  • This setup_fleet container is required to avoid the need to manually create a fleet host and to change the default output to point to the elasticsearch container, the default value is https://localhost:9200 which of course will not work, it is in this step that the ca_trusted_fingerprint is used.

  • The last step is to start a container running the Elastic Agent with the Fleet Server integration.

The only issue I'm facing is that the container running the Fleet Server cannot send data to the cluster because it is not recognizing the ca_trusted_fingerprint.

After running the compose, this is how the output configuration looks like:

If I use openssl to check the generate certificate, I will have this:

sha256 Fingerprint=8F:08:33:C6:AC:54:B9:8C:95:67:AC:57:62:14:1A:05:11:EE:63:30:B0:5E:3D:E7:7E:06:6E:2D:38:E6:FE:E4
-----BEGIN CERTIFICATE-----
MIIDlzCCAn+gAwIBAgIUKnZdiBZHMD7lz90tGQBgnbG8HQEwDQYJKoZIhvcNAQEL
BQAwWzELMAkGA1UEBhMCQlIxCzAJBgNVBAgMAlJKMRcwFQYDVQQHDA5SSU8gREUg
SkFORUlSTzEXMBUGA1UECgwORE9DS0VSIEVMQVNUSUMxDTALBgNVBAsMBFNJRU0w
HhcNMjQwNjI5MTkzMjQ4WhcNMjkwNzAzMTkzMjQ4WjBbMQswCQYDVQQGEwJCUjEL
MAkGA1UECAwCUkoxFzAVBgNVBAcMDlJJTyBERSBKQU5FSVJPMRcwFQYDVQQKDA5E
T0NLRVIgRUxBU1RJQzENMAsGA1UECwwEU0lFTTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAKX/Wj0JnJUoxzBpxyRJoCzbaT/Wf6DauwJVoKenyf7m3vba
Q/Uysb7sOIQZ4im1IHTgFdFc9ITQtT1o7yjBmGhUxCU2VH6RxBPgLpPs8O3Hxaxi
er0kBhB7vW9xYw9vlPGUBp5x4LtpTsCK7Qkl6im+ZCy/We5n1nvr81p0YpJFm5gG
zUfAsG3MWHL+SFOQTN1J9vnSiL8U16gxu6/2k6KkkY8Cx49JKhH6vAWTJNYs9Jlw
zj6LgLoBwIy2ML/AuoZ1InA/AfArGl+bbWaDIbke3JpPvbd+fjQWLpb0IJrHVC5g
Qm/yONfX+q15Z4CYp1wiTNmo6SMfmMJiCa7RrvcCAwEAAaNTMFEwHQYDVR0OBBYE
FCG/Y+8BqUdc7xN3bKw8oNQvvl4fMB8GA1UdIwQYMBaAFCG/Y+8BqUdc7xN3bKw8
oNQvvl4fMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAF+wJb0x
sEW1S/jNphRTkfNmSRS4vrrbG2Fe6uHBs1uBhyB4uDEdmY785lnXgoohtQTMV9Ux
JW8+ydUucZ0VIpqc+w4TZo+e6/P0sJklujvQxwTaoRWeKjNTptkfYxnHp2D0T0nW
GPPDA//GgAgNfLoYh5aAF8w4ofCIGRm+IkvCN2tF5MARxjP/ogylvwqyHBQ+KtN9
J+1tz4BxsaB1oW3NnrI7MigJSFNAuDlraTY8cyp7mLJLeJUNFx4M+HuUQaRvyUNK
DxCFgP3bW6MrljJj3rMNaUlKq7HoSlYv73NdMoRPz62mpp8D7eLyhq8+r+wr46Tq
6SokdUdWcoNEIT0=
-----END CERTIFICATE-----

As you can see, the fingerprint comes from the certificate, but I got these errors messages in the fleet container:

'ca_trusted_fingerprint' set, looking for matching fingerprints"

Followed by

no CA certificate matching the fingerprint

But now, if I change the output in the fleet settings to this:

Everything will work fine and I will get the logs inside the cluster, which I can confirm looking at the container logs:

Connection to backoff(elasticsearch(https://elasticsearch:9200)) established

So, to resume, I have a CA certificate, the agent cannot send data if I use just the fingerprint of this certificate, but it can send data if I use the certificate in the advanced yaml configuration.

Of course I've could change my docker-compose to set the entire certificate in the setup_fleet step, but I'm trying to understand what is the issue here.

I've tested with both 8.13.4 and 8.14.1, same behaviour in both.

No, these are used when enrolling the agent, I have no issues enrolling the agent that will work as the Fleet Server, I'm using the ca file in the enroll process.

Also, the default output created in Fleet does not use none of these settings, it creates a dummy default output pointing to https://localhost:9200 that you have to manually change.

What I'm doing is using the Fleet API to change this during the setup process, and to make it easier I'm trying to use the fingerprint of the CA.

Ok I am caught all the way up....
(I got hung up along the way on the kibana_user.exist you have to manually clean that up)

I am in the same state as you ... let me poke... weird...

@leandrojmp Found something ... and you are more of a cert expert than I.

So setup with your exact compose...

Then I put the CA fingerprint in metricbeat and test the output

Same error BUT if I set this with my other script that uses all the normal gen certs with our tool it works... (not saying you have to, but there must be some difference)

So seems to me ... something is wrong with a cert chain or the fingerprint
(or something wrong with the way we validate etc)

Last line seems to indicate
ERROR x509: “SIEM” certificate is not standards compliant

If you look at the 2 last logs... same as you are getting with the fleet...

./metricbeat -e test output
...
elasticsearch: https://localhost:9200...
  parse url... OK
  connection...
    parse host... OK
    dns lookup... OK
    addresses: ::1, 127.0.0.1
    dial up... OK
  TLS...
    security: server's certificate chain verification is enabled
{"log.level":"info","@timestamp":"2024-06-29T14:02:28.165-0700","log.logger":"tls","log.origin":{"function":"github.com/elastic/elastic-agent-libs/transport/tlscommon.trustRootCA","file.name":"tlscommon/tls_config.go","file.line":179},"message":"'ca_trusted_fingerprint' set, looking for matching fingerprints","service.name":"metricbeat","ecs.version":"1.6.0"}
{"log.level":"warn","@timestamp":"2024-06-29T14:02:28.165-0700","log.logger":"tls","log.origin":{"function":"github.com/elastic/elastic-agent-libs/transport/tlscommon.trustRootCA","file.name":"tlscommon/tls_config.go","file.line":208},"message":"no CA certificate matching the fingerprint","service.name":"metricbeat","ecs.version":"1.6.0"}
    handshake... ERROR x509: “SIEM” certificate is not standards compliant
hyperion:metricbeat-8.14.1-darwin-x86_64 sbrown$

Looks like the code here

And here is what it looks like when it matches this is just an elasticsearch doing the default setup.

elasticsearch: https://localhost:9200...
  parse url... OK
  connection...
    parse host... OK
    dns lookup... OK
    addresses: ::1, 127.0.0.1
    dial up... OK
  TLS...
    security: server's certificate chain verification is enabled
{"log.level":"info","@timestamp":"2024-06-29T14:12:16.403-0700","log.logger":"tls","log.origin":{"function":"github.com/elastic/elastic-agent-libs/transport/tlscommon.trustRootCA","file.name":"tlscommon/tls_config.go","file.line":179},"message":"'ca_trusted_fingerprint' set, looking for matching fingerprints","service.name":"metricbeat","ecs.version":"1.6.0"}
{"log.level":"info","@timestamp":"2024-06-29T14:12:16.403-0700","log.logger":"tls","log.origin":{"function":"github.com/elastic/elastic-agent-libs/transport/tlscommon.trustRootCA","file.name":"tlscommon/tls_config.go","file.line":199},"message":"CA certificate matching 'ca_trusted_fingerprint' found, adding it to 'certificate_authorities'","service.name":"metricbeat","ecs.version":"1.6.0"}
    handshake... OK
    TLS version: TLSv1.3
    dial up... OK

Oh Thanks!

This doesn't show up in the elastic agent logs, but this gives some direction on what to troubleshoot.

Maybe the way I'm creating the CA and certificates with openssl is not the correct way, I will look into it.

Hard to debug... argh!

So when I get stuck like this...

I use Elastic tar.gz and metricbeat

Generate the certs etc... turn logging way up... once you get that working go back to docker etc... just a thought might speed up the dev / test cycle.

One thing I notice you are generating a CA with a .pem and a .key ... and when I see the default way the CA has no key as far as I can tell...

But also makes me wonder in the siem.pem (the SSL cert) is missing the "fullchain"

I notice that my default SSL cert is significantly longer than yours.

UPDATE
Looked some more... Think you need your siem.pem to be full chain
ca + cert when I decode mine that works... that is what is there...

Which kinda makes sense ... because you are asking the fingerprint (which is of the CA) to match a cert coming across the wire...

Yeah, this was the issue indeed.

I've added the following line in my container that setup the certs:

cat ca-siem.pem siem.pem > siem.chain.pem

Then Elasticsearch stopped working with a SSL error, like this:

Caused by: org.elasticsearch.ElasticsearchException: failed to initialize SSL KeyManagerFactory

Inverting the order in the chain certificate solved it, so I first need to add the server certificate and after that the ca certificate.

cat siem.pem ca-siem.pem > siem.chain.pem

And have this in the settings:

      - xpack.security.http.ssl.key=certs/siem-key.pem
      - xpack.security.http.ssl.certificate=certs/siem.chain.pem

After that everything worked as expected and I got this message in the agent logs:

CA certificate matching 'ca_trusted_fingerprint' found, adding it to 'certificate_authorities'

I think that I understood how this work now.

The Elasticsearch server will present the agent with the certificate, and then the agent will try to match the ca_trusted_fingerprint with one of the certificates, if it can match, it will then add it to the ssl.certificate_authorities setting, this also explains why it works when adding directly to the ssl.certificate_authorities.

So, for this to work, you need to have the full chain, or at least the server + the ca certificates.

In the end the main issue was a small gap of knowledge on how SSL works in this case :sweat_smile: :man_facepalming:

Thanks!

2 Likes