QubitProducts / exporter_exporter

A reverse proxy designed for Prometheus exporters
Apache License 2.0
338 stars 55 forks source link

Assistance about TLS #55

Closed VoidAndAny closed 3 years ago

VoidAndAny commented 4 years ago

Hi, After a lot of tests with certificate/TLS, I need some help. Most of my nodes answer with the same domain xxx.uman-it.fr so I generate a node cert with *.uman-it.fr as Common Name

Now I need to monitor one node which answer with another domain lets say uman-it.infra, If I try to use the same certificate, it fail (invalid certificate)

I tried to create a SAN certificate (Common Name = .uman-it.fr ; SAN DNS = .uman-it.infra) but it doesn't work.

Then I found issue #48 about subjectAltName verification, I tried to use web.tls.certmatch but no more success...

Is it possible to make it work or must I generate multiple node certificate ?

Thanks a lot

tcolgate commented 4 years ago

certmatch is the exporter exporter to use when you are using a client ca to determine who to permit requests from. When you say it fails, presumably you mean the thing querying the node cannot validate the cert? It may be that you have generated a new certificate, but it's either from a different CA to the original, or you're using self signed certs and haven't updated the things that is querying, to give it the new cert to trust. Unfortunately you don't say how you are connecting, or if the old names still work with the new cert. If you just want to support more than one domain, the DNS SANs are the correct way to go.

VoidAndAny commented 4 years ago

Hi, sorry for the time, let me explain, show you what I've done and the results.

My nodes key/cert are generated like this : openssl req -x509 -newkey rsa:4096 -keyout prometheus_new_node.key -out prometheus_new_node.crt -days 29220 -nodes -subj /commonName=*.uman-it.fr/ -extensions san -config <( echo '[req]'; echo 'distinguished_name=req'; echo '[san]'; echo 'subjectAltName=DNS:*.umanit.infra')

Here is node cert infos :

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            33:2b:79:c3:d2:c6:27:91:44:f1:80:d2:8b:4f:9a:c7:76:d4:3b:60
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = *.uman-it.fr
        Validity
            Not Before: May 20 11:44:42 2020 GMT
            Not After : May 21 11:44:42 2100 GMT
        Subject: CN = *.uman-it.fr
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (4096 bit)
                Modulus:
                    00:b6:9d:ee:c0:98:d2:6b:58:fd:8f:80:92:26:24:
                    ...
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:*.umanit.infra
    Signature Algorithm: sha256WithRSAEncryption
         7a:9d:2a:32:c3:6e:1b:d0:7d:fb:ca:c1:cc:e6:2d:5e:d2:e0:
         ...

The cert seams to be valid for my 2 domains umanit.infra and uman-it.fr

Server cert/key like this: openssl req -x509 -newkey rsa:4096 -keyout prometheus_new_server.key -out prometheus_new_server.crt -days 29220 -nodes -subj /commonName=prometheus_server/

Maybe I need to specify commonName ??

I made test with 1 prometheus server (obviously) and 2 nodes (with exporter_exporter and node_exporter):

Node key is copied on server1 and server2 Node cert is copied on server1, server2 and prometheus server Server key is only on prometheus server Server cert is on prometheus server and copied on server1 and server2

Here is my job definition in prometheus:

  - job_name: node-new
    bearer_token: xxx
    file_sd_configs:
    - files:
      - /etc/prometheus/file_sd/node-new/*.yml
    metrics_path: /proxy
    params:
      module:
      - node
    scheme: https
    tls_config:
      ca_file: /etc/prometheus/ssl/prometheus_new_node.crt
      cert_file: /etc/prometheus/ssl/prometheus_new_server.crt
      key_file: /etc/prometheus/ssl/prometheus_new_server.key

And my service exporter_exporter command line:

ExecStart=/usr/local/bin/exporter_exporter \
    -web.listen-address=\
    -config.file /etc/expexp.yaml \
    -web.bearer.token xxx \
    -web.tls.ca /etc/prometheus/ssl/prometheus_new_server.crt \
    -web.tls.cert /etc/prometheus/ssl/prometheus_new_node.crt \
    -web.tls.key  /etc/prometheus/ssl/prometheus_new_node.key \
    -web.tls.listen-address 0.0.0.0:9998 \
    -web.tls.verify \

And finally the result :

node-new (1/2 up)

Endpoint State Labels Last Scrape Scrape Duration Error
https://server2.uman-it.fr:9998/proxy module="node" down instance="server2.uman-it.fr:9998" job="node-new" 26.405s ago 57.69ms Get https://server2.uman-it.fr:9998/proxy?module=node: x509: certificate is valid for *.umanit.infra, not server2.uman-it.fr
https://server1.umanit.infra:9998/proxy module="node" up instance="server1.umanit.infra:9998" job="node-new" 19.952s ago 21.93ms

Hope it's more clear like this. I'me problably doing something wrong, I'me not very familiar with self signed certificates

Thanks a lot Yoann

tcolgate commented 4 years ago

If one of the domains works, then the other should, which makes me think this has more to do with the cert options, or something with how go is using the subject alt names. openssl is quite a complex tool and there are easier option now. One suggestion would be to try using mkcert (https://github.com/FiloSottile/mkcert), if I generate a cert with two wildcards with that, but appear in subject altnames

            X509v3 Subject Alternative Name: 
                DNS:*.example.com, DNS:*.example2.com
tcolgate commented 4 years ago

I think I've found your problem. Go will not use the CN is any DNS SANs are present. (CN is depricated). So as soon as you add a SAN, your CN is ignored, which is why only the SAN is valid. If you need the CN, and you need alternatives, add the CN and both names to the SANs.

britcey commented 4 years ago

Chiming in - from personal, painful experience I can confirm that the SAN section should contain all names, and not just the alternatives. As you said, CN is deprecated. This cropped up with Chrome a few months back.

VoidAndAny commented 4 years ago

Thanks a lot, I will try soon. Funny, recently I had to emit a CSR for a customer (big big company) and their IT just say the opposite, they don't want main domain in SAN section :/

VoidAndAny commented 4 years ago

THANKS a lot, it's OK

For information et for documentation, to génrate SNA certifcate with openssl, here are the commands:

Create a openssl-san.conf file containing:

[req]
default_bits = 2048
prompt = no
default_md = sha256
x509_extensions = v3_req
distinguished_name = dn

[dn]
C = ES
ST = MyState
L = MyCity
O = MyOrg
emailAddress = email@mydomain.com
CN = mydomain.com

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = <domain1>
DNS.2 = <domain2>

Generate node key and certificate with the conf file :

openssl req -x509 -newkey rsa:4096 -keyout prometheus_new_node.key -out prometheus_new_node.crt -days 29220 -nodes -subj /commonName=prometheus_node/ -config openssl-san.conf