1
0
mirror of https://github.com/ribbybibby/ssl_exporter.git synced 2024-11-27 08:31:02 +02:00
ssl_exporter/README.md

385 lines
15 KiB
Markdown
Raw Normal View History

2017-08-20 20:30:02 +02:00
# SSL Certificate Exporter
Exports metrics for certificates collected from various sources:
- [TCP probes](#tcp)
- [HTTPS probes](#https)
- [PEM files](#file)
- [Kubernetes secrets](#kubernetes)
- [Kubeconfig files](#kubeconfig)
The metrics are labelled with fields from the certificate, which allows for
informational dashboards and flexible alert routing.
2019-08-15 18:08:43 +02:00
2017-08-20 20:30:02 +02:00
## Building
make
2017-08-20 20:30:02 +02:00
./ssl_exporter <flags>
Similarly to the blackbox_exporter, visiting
[http://localhost:9219/probe?target=example.com:443](http://localhost:9219/probe?target=example.com:443)
2020-11-09 14:57:28 +02:00
will return certificate metrics for example.com. The `ssl_probe_success`
metric indicates if the probe has been successful.
2017-08-20 20:30:02 +02:00
### Docker
docker pull ribbybibby/ssl-exporter
2019-12-18 12:48:50 +02:00
docker run -p 9219:9219 ribbybibby/ssl-exporter:latest <flags>
### Release process
2020-03-13 12:26:31 +02:00
- Update the `VERSION` file in this repository and commit to master
- [This github action](.github/workflows/release.yaml) will add a changelog and
upload binaries in response to a release being created in Github
- Dockerhub will build and tag a new container image in response to tags of the
format `/^v[0-9.]+$/`
## Usage
```
usage: ssl_exporter [<flags>]
Flags:
-h, --help Show context-sensitive help (also try --help-long and
--help-man).
--web.listen-address=":9219"
Address to listen on for web interface and telemetry.
--web.metrics-path="/metrics"
Path under which to expose metrics
--web.probe-path="/probe" Path under which to expose the probe endpoint
--config.file="" SSL exporter configuration file
--log.level="info" Only log messages with the given severity or above. Valid
levels: [debug, info, warn, error, fatal]
--log.format="logger:stderr"
Set the log target and format. Example:
"logger:syslog?appname=bob&local=7" or
"logger:stdout?json=true"
--version Show application version.
```
2017-08-20 20:30:02 +02:00
## Metrics
2020-11-16 10:40:48 +02:00
| Metric | Meaning | Labels | Probers |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ---------- |
| ssl_cert_not_after | The date after which a peer certificate expires. Expressed as a Unix Epoch Time. | serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | tcp, https |
| ssl_cert_not_before | The date before which a peer certificate is not valid. Expressed as a Unix Epoch Time. | serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | tcp, https |
| ssl_file_cert_not_after | The date after which a certificate found by the file prober expires. Expressed as a Unix Epoch Time. | file, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | file |
| ssl_file_cert_not_before | The date before which a certificate found by the file prober is not valid. Expressed as a Unix Epoch Time. | file, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | file |
| ssl_kubernetes_cert_not_after | The date after which a certificate found by the kubernetes prober expires. Expressed as a Unix Epoch Time. | namespace, secret, key, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | kubernetes |
| ssl_kubernetes_cert_not_before | The date before which a certificate found by the kubernetes prober is not valid. Expressed as a Unix Epoch Time. | namespace, secret, key, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | kubernetes |
| ssl_kubeconfig_cert_not_after | The date after which a certificate found by the kubeconfig prober expires. Expressed as a Unix Epoch Time. | kubeconfig, name, type, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | kubeconfig |
| ssl_kubeconfig_cert_not_before | The date before which a certificate found by the kubeconfig prober is not valid. Expressed as a Unix Epoch Time. | kubeconfig, name, type, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | kubeconfig |
2020-11-16 10:40:48 +02:00
| ssl_ocsp_response_next_update | The nextUpdate value in the OCSP response. Expressed as a Unix Epoch Time | | tcp, https |
| ssl_ocsp_response_produced_at | The producedAt value in the OCSP response. Expressed as a Unix Epoch Time | | tcp, https |
| ssl_ocsp_response_revoked_at | The revocationTime value in the OCSP response. Expressed as a Unix Epoch Time | | tcp, https |
| ssl_ocsp_response_status | The status in the OCSP response. 0=Good 1=Revoked 2=Unknown | | tcp, https |
| ssl_ocsp_response_stapled | Does the connection state contain a stapled OCSP response? Boolean. | | tcp, https |
| ssl_ocsp_response_this_update | The thisUpdate value in the OCSP response. Expressed as a Unix Epoch Time | | tcp, https |
| ssl_probe_success | Was the probe successful? Boolean. | | all |
| ssl_prober | The prober used by the exporter to connect to the target. Boolean. | prober | all |
| ssl_tls_version_info | The TLS version used. Always 1. | version | tcp, https |
| ssl_verified_cert_not_after | The date after which a certificate in the verified chain expires. Expressed as a Unix Epoch Time. | chain_no, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | tcp, https |
| ssl_verified_cert_not_before | The date before which a certificate in the verified chain is not valid. Expressed as a Unix Epoch Time. | chain_no, serial_no, issuer_cn, cn, dnsnames, ips, emails, ou | tcp, https |
2017-08-20 20:30:02 +02:00
## Configuration
2020-11-09 14:57:28 +02:00
### TCP
Just like with the blackbox_exporter, you should pass the targets to a single
instance of the exporter in a scrape config with a clever bit of relabelling.
This allows you to leverage service discovery and keeps configuration
centralised to your Prometheus config.
2017-08-20 20:30:02 +02:00
```yml
scrape_configs:
- job_name: "ssl"
2017-08-20 20:30:02 +02:00
metrics_path: /probe
static_configs:
- targets:
- example.com:443
- prometheus.io:443
2017-08-20 20:30:02 +02:00
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9219 # SSL exporter.
2017-08-20 20:30:02 +02:00
```
2020-11-09 14:57:28 +02:00
### HTTPS
By default the exporter will make a TCP connection to the target. This will be
suitable for most cases but if you want to take advantage of http proxying you
can use a HTTPS client by setting the `https` module parameter:
```yml
scrape_configs:
- job_name: "ssl"
metrics_path: /probe
params:
module: ["https"] # <-----
static_configs:
- targets:
- example.com:443
- prometheus.io:443
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9219
```
2020-11-09 14:57:28 +02:00
This will use proxy servers discovered by the environment variables `HTTP_PROXY`,
`HTTPS_PROXY` and `ALL_PROXY`. Or, you can set the `proxy_url` option in the module
configuration.
The latter takes precedence.
### File
The `file` prober exports `ssl_file_cert_not_after` and
`ssl_file_cert_not_before` for PEM encoded certificates found in local files.
Files local to the exporter can be scraped by providing them as the target
parameter:
```
curl "localhost:9219/probe?module=file&target=/etc/ssl/cert.pem"
```
The target parameter supports globbing (as provided by the
[doublestar](https://github.com/bmatcuk/doublestar) package),
which allows you to capture multiple files at once:
```
curl "localhost:9219/probe?module=file&target=/etc/ssl/**/*.pem"
```
One specific usage of this prober could be to run the exporter as a DaemonSet in
Kubernetes and then scrape each instance to check the expiry of certificates on
each node:
2020-11-16 10:46:28 +02:00
```yml
2020-11-09 14:57:28 +02:00
scrape_configs:
2020-11-16 00:05:51 +02:00
- job_name: "ssl-kubernetes-file"
2020-11-09 14:57:28 +02:00
metrics_path: /probe
params:
module: ["file"]
target: ["/etc/kubernetes/**/*.crt"]
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: ^(.*):(.*)$
target_label: __address__
replacement: ${1}:9219
```
2020-11-16 00:05:51 +02:00
### Kubernetes
The `kubernetes` prober exports `ssl_kubernetes_cert_not_after` and
`ssl_kubernetes_cert_not_before` for PEM encoded certificates found in secrets
of type `kubernetes.io/tls`.
Provide the namespace and name of the secret in the form `<namespace>/<name>` as
the target:
```
2020-11-16 10:46:28 +02:00
curl "localhost:9219/probe?module=kubernetes&target=kube-system/secret-name"
2020-11-16 00:05:51 +02:00
```
Both the namespace and name portions of the target support glob matching (as provided by the
[doublestar](https://github.com/bmatcuk/doublestar) package):
```
2020-11-16 10:46:28 +02:00
curl "localhost:9219/probe?module=kubernetes&target=kube-system/*"
2020-11-16 00:05:51 +02:00
```
```
2020-11-16 10:46:28 +02:00
curl "localhost:9219/probe?module=kubernetes&target=*/*"
2020-11-16 00:05:51 +02:00
```
The exporter retrieves credentials and context configuration from the following
sources in the following order:
- The `kubeconfig` path in the module configuration
- The `$KUBECONFIG` environment variable
- The default configuration file (`$HOME/.kube/config`)
- The in-cluster environment, if running in a pod
### Kubeconfig
The `kubeconfig` prober exports `ssl_kubeconfig_cert_not_after` and
`ssl_kubeconfig_cert_not_before` for PEM encoded certificates found in the specified kubeconfig file.
Kubeconfigs local to the exporter can be scraped by providing them as the target
parameter:
```
curl "localhost:9219/probe?module=kubeconfig&target=/etc/kubernetes/admin.conf"
```
One specific usage of this prober could be to run the exporter as a DaemonSet in
Kubernetes and then scrape each instance to check the expiry of certificates on
each node:
```yml
scrape_configs:
- job_name: "ssl-kubernetes-kubeconfig"
metrics_path: /probe
params:
module: ["kubeconfig"]
target: ["/etc/kubernetes/admin.conf"]
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: ^(.*):(.*)$
target_label: __address__
replacement: ${1}:9219
```
2020-11-09 14:57:28 +02:00
## Configuration file
You can provide further module configuration by providing the path to a
configuration file with `--config.file`. The file is written in yaml format,
defined by the schema below.
```
modules: [<module>]
```
2020-11-09 14:57:28 +02:00
### \<module\>
```
# The type of probe (https, tcp, file, kubernetes, kubeconfig)
prober: <prober_string>
# How long the probe will wait before giving up.
[ timeout: <duration> ]
# Configuration for TLS
[ tls_config: <tls_config> ]
# The specific probe configuration
[ https: <https_probe> ]
[ tcp: <tcp_probe> ]
2020-11-16 00:05:51 +02:00
[ kubernetes: <kubernetes_probe> ]
```
2020-11-09 14:57:28 +02:00
### <tls_config>
```
# Disable target certificate validation.
[ insecure_skip_verify: <boolean> | default = false ]
# The CA cert to use for the targets.
[ ca_file: <filename> ]
# The client cert file for the targets.
[ cert_file: <filename> ]
# The client key file for the targets.
[ key_file: <filename> ]
# Used to verify the hostname for the targets.
[ server_name: <string> ]
```
2020-11-09 14:57:28 +02:00
### <https_probe>
```
# HTTP proxy server to use to connect to the targets.
[ proxy_url: <string> ]
```
2020-11-09 14:57:28 +02:00
### <tcp_probe>
```
# Use the STARTTLS command before starting TLS for those protocols that support it (smtp, ftp, imap)
[ starttls: <string> ]
```
2020-11-16 00:05:51 +02:00
### <kubernetes_probe>
```
# The path of a kubeconfig file to configure the probe
[ kubeconfig: <string> ]
```
## Example Queries
Certificates that expire within 7 days:
2017-08-20 20:30:02 +02:00
2019-12-08 22:40:43 +02:00
```
ssl_cert_not_after - time() < 86400 * 7
2019-12-08 22:40:43 +02:00
```
2017-08-20 20:30:02 +02:00
Wildcard certificates that are expiring:
2017-08-20 20:30:02 +02:00
2019-12-08 22:40:43 +02:00
```
ssl_cert_not_after{cn=~"\*.*"} - time() < 86400 * 7
2019-12-08 22:40:43 +02:00
```
2017-08-20 20:30:02 +02:00
Certificates that expire within 7 days in the verified chain that expires
latest:
2019-12-08 22:40:43 +02:00
```
ssl_verified_cert_not_after{chain_no="0"} - time() < 86400 * 7
```
Number of certificates presented by the server:
```
count(ssl_cert_not_after) by (instance)
2019-12-08 22:40:43 +02:00
```
2017-08-20 20:30:02 +02:00
2020-11-09 14:57:28 +02:00
Identify failed probes:
2017-08-20 20:30:02 +02:00
2019-12-08 22:40:43 +02:00
```
2020-11-09 14:57:28 +02:00
ssl_probe_success == 0
2019-12-08 22:40:43 +02:00
```
2017-08-20 20:30:02 +02:00
2020-11-09 14:57:28 +02:00
## Peer Certificates vs Verified Chain Certificates
Metrics are exported for the `NotAfter` and `NotBefore` fields for peer
certificates as well as for the verified chain that is
constructed by the client.
The former only includes the certificates that are served explicitly by the
target, while the latter can contain multiple chains of trust that are
constructed from root certificates held by the client to the target's server
certificate.
This has important implications when monitoring certificate expiry.
For instance, it may be the case that `ssl_cert_not_after` reports that the root
certificate served by the target is expiring soon even though clients can form
another, much longer lived, chain of trust using another valid root certificate
held locally. In this case, you may want to use `ssl_verified_cert_not_after` to
alert on expiry instead, as this will contain the chain that the client actually
constructs:
```
ssl_verified_cert_not_after{chain_no="0"} - time() < 86400 * 7
```
Each chain is numbered by the exporter in reverse order of expiry, so that
`chain_no="0"` is the chain that will expire the latest. Therefore the query
above will only alert when the chain of trust between the exporter and the
target is truly nearing expiry.
It's very important to note that a query of this kind only represents the chain
of trust between the exporter and the target. Genuine clients may hold different
root certs than the exporter and therefore have different verified chains of
trust.
2020-03-12 20:06:37 +02:00
## Grafana
You can find a simple dashboard [here](grafana/dashboard.json) that tracks
certificate expiration dates and target connection errors.