Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow passing tls_config.server_name as a query parameter #74

Open
johanfleury opened this issue Jul 19, 2021 · 3 comments
Open

Allow passing tls_config.server_name as a query parameter #74

johanfleury opened this issue Jul 19, 2021 · 3 comments

Comments

@johanfleury
Copy link
Contributor

Hello

I’m using ssl_exporter to monitor certificates for a bunch of websites that are hosted behind multiple load balancers. My goal being to monitor that all the LB’s use the same certificate and that it’s not expired.

At the moment, to be able to specify which SNI to use when connecting to the LB, I need add a module in the configuration for every websites:

config.yaml: |
  modules:
    https:
      prober: https
    site1.example.com:
      prober: https
      tls_config:
        server_name: site1.example.com
    www.site1.example.com:
      prober: https
      tls_config:
        server_name: www.site1.example.com
    site2.example.com:
      prober: https
      tls_config:
        server_name: site1.example.com
    www.site2.example.com:
      prober: https
      tls_config:
        server_name: www.site1.example.com

   # And so on and so forth

This way I can scrape with target set as the load balancer’s IP (e.g.: curl -s 'http://127.0.0.1:9219/probe?module=site1.example.com&target=https://192.0.2.1 will give me the TLS metrics for site1.example.com on 192.0.2.1).

This works fine, but it’s quite cumbersome as I need to do this for every websites I want to monitor that way. It would be great to be able to pass server_name as a query parameter instead (e.g.: curl -s 'http://127.0.0.1:9219/probe?module=https&target=https://192.0.2.1&server_name=site1.example.com)

I’m willing to write a PR for that feature, but wanted to know your thoughts on that.

@ribbybibby
Copy link
Owner

What does your scrape config look like for this setup? Just so I can understand the setup more fully.

@johanfleury
Copy link
Contributor Author

johanfleury commented Jul 20, 2021

I’m using file_sd_config with a json file that looks like this:

[
  {
    "targets": [
      "https://site1.example.com"
    ],
    "labels": {}
  },
  {
    "targets": [
      "https://site2.example.com"
    ],
    "labels": {
      "__meta_ssl_exporter_module": "foo"
    }
  },
  {
    "targets": [
      "https://site3.example.com"
    ],
    "labels": {
      "__meta_ssl_exporter_target": "https://192.0.2.1"
    }
  }
]

My current scrape config looks like this:

- job_name: https
  scrape_interval: 2m
  scrape_timeout: 60s
  metrics_path: /probe
  params:
    module:
      - https
  file_sd_configs:
    - files:
        - /etc/prometheus/file-sd/websites.json
  relabel_configs:
    # Set __param_target to the value of __address__ by default
    - source_labels: [__address__]
      target_label: __param_target
    # If __meta_ssl_exporter_target is set, set __param_target to its value and __param_server_name to the value of __address__
    - source_labels: [__meta_ssl_exporter_target]
      regex: (.+)
      target_label: __param_target
      replacement: ${1}
    - source_labels: [__meta_ssl_exporter_target, __address__]
      regex: (.+);(?:https?://)([^/]*)
      target_label: __param_server_name
      replacement: ${2}
    # If __meta_ssl_exporter_module is set, set __param_module to its value
    - source_labels: [__meta_ssl_exporter_module]
      regex: (.+)
      target_label: __param_module
      replacement: ${1}
    # Set instance to the value of __address__ (minus the path)
    - source_labels: [__address__]
      regex: (https://[^/]*)(/.*)?
      target_label: instance
      replacement: ${1}
    # Set __address__ to ssl_exporter endpoint
    - target_label: __address__
      replacement: ssl-exporter:9219

With this setup, targets appears like this in Prometheus:

Endpoint State Labels Last Scrape Scrape Duration Error
http://ssl-exporter:9219/probe module="https" target="https://site1.example.com" UP instance="https://site1.example.com" job="https" -- -- --
http://ssl-exporter:9219/probe module="foo" target="https://site2.example.com" UP instance="https://site2.example.com" job="https" -- -- --
http://ssl-exporter:9219/probe module="https" target="https://192.0.2.1" server_name="site3.example.com" UP instance="https://site3.example.com" job="https" -- -- --

It could be done the other way around (by setting __address__ to the actual target and have a __meta_ssl_exporter_server_name label), but I made it that way to deal with the way the source of the file_sd works.

The patch on ssl_exporter is quite simple:

diff --git a/ssl_exporter.go b/ssl_exporter.go
index 2051c53..6a30b68 100644
--- a/ssl_exporter.go
+++ b/ssl_exporter.go
@@ -35,6 +35,12 @@ func probeHandler(logger log.Logger, w http.ResponseWriter, r *http.Request, con
                return
        }

+       if serverName := r.URL.Query().Get("server_name"); serverName != "" {
+               level.Debug(logger).Log("msg", fmt.Sprintf("Using %s as server name", serverName))
+               logger = log.With(logger, "server_name", serverName)
+               module.TLSConfig.ServerName = serverName
+       }
+
        timeout := module.Timeout
        if timeout == 0 {
                // The following timeout block was taken wholly from the blackbox exporter

@johanfleury
Copy link
Contributor Author

I’ve opened a PR, let me know what you think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants