{"id":13561867,"url":"https://github.com/ribbybibby/ssl_exporter","last_synced_at":"2025-05-15T10:00:51.743Z","repository":{"id":24212307,"uuid":"100881075","full_name":"ribbybibby/ssl_exporter","owner":"ribbybibby","description":"Exports Prometheus metrics for TLS certificates","archived":false,"fork":false,"pushed_at":"2024-11-11T23:42:05.000Z","size":5147,"stargazers_count":558,"open_issues_count":38,"forks_count":104,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-14T16:53:41.999Z","etag":null,"topics":["certificate","expiry","metrics","prometheus","prometheus-exporter","prometheus-metrics","ssl","ssl-certificate","ssl-certificates","ssl-exporter","tls"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ribbybibby.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-08-20T18:31:09.000Z","updated_at":"2025-04-04T09:20:12.000Z","dependencies_parsed_at":"2025-03-17T01:11:00.252Z","dependency_job_id":"57f5394f-3459-4217-8f6d-bc408ba3138f","html_url":"https://github.com/ribbybibby/ssl_exporter","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ribbybibby%2Fssl_exporter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ribbybibby%2Fssl_exporter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ribbybibby%2Fssl_exporter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ribbybibby%2Fssl_exporter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ribbybibby","download_url":"https://codeload.github.com/ribbybibby/ssl_exporter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254319715,"owners_count":22051072,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["certificate","expiry","metrics","prometheus","prometheus-exporter","prometheus-metrics","ssl","ssl-certificate","ssl-certificates","ssl-exporter","tls"],"created_at":"2024-08-01T13:01:02.089Z","updated_at":"2025-05-15T10:00:51.358Z","avatar_url":"https://github.com/ribbybibby.png","language":"Go","funding_links":[],"categories":["Go","Go (531)","Prometheus-Exporter"],"sub_categories":[],"readme":"# SSL Certificate Exporter\n\nExports metrics for certificates collected from various sources:\n- [TCP probes](#tcp)\n- [HTTPS probes](#https)\n- [PEM files](#file)\n- [Remote PEM files](#http_file)\n- [Kubernetes secrets](#kubernetes)\n- [Kubeconfig files](#kubeconfig)\n\nThe metrics are labelled with fields from the certificate, which allows for\ninformational dashboards and flexible alert routing.\n\n## Building\n\n    make\n    ./ssl_exporter \u003cflags\u003e\n\nSimilarly to the blackbox_exporter, visiting\n[http://localhost:9219/probe?target=example.com:443](http://localhost:9219/probe?target=example.com:443)\nwill return certificate metrics for example.com. The `ssl_probe_success`\nmetric indicates if the probe has been successful.\n\n### Docker\n\n    docker run -p 9219:9219 ribbybibby/ssl-exporter:latest \u003cflags\u003e\n\n### Release process\n\n- Create a release in Github with a semver tag and GH actions will:\n  - Add a changelog\n  - Upload binaries\n  - Build and push a Docker image\n\n## Usage\n\n```\nusage: ssl_exporter [\u003cflags\u003e]\n\nFlags:\n  -h, --help                     Show context-sensitive help (also try --help-long and\n                                 --help-man).\n      --web.listen-address=\":9219\"\n                                 Address to listen on for web interface and telemetry.\n      --web.metrics-path=\"/metrics\"\n                                 Path under which to expose metrics\n      --web.probe-path=\"/probe\"  Path under which to expose the probe endpoint\n      --config.file=\"\"           SSL exporter configuration file\n      --log.level=\"info\"         Only log messages with the given severity or above. Valid\n                                 levels: [debug, info, warn, error, fatal]\n      --log.format=\"logger:stderr\"\n                                 Set the log target and format. Example:\n                                 \"logger:syslog?appname=bob\u0026local=7\" or\n                                 \"logger:stdout?json=true\"\n      --version                  Show application version.\n```\n\n## Metrics\n\n| Metric                         | Meaning                                                                                                          | Labels                                                                      | Probers    |\n| ------------------------------ | ---------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ---------- |\n| 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 |\n| 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 |\n| 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       |\n| 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       |\n| 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 |\n| 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 |\n| 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 |\n| 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 |\n| ssl_ocsp_response_next_update  | The nextUpdate value in the OCSP response. Expressed as a Unix Epoch Time                                        |                                                                             | tcp, https |\n| ssl_ocsp_response_produced_at  | The producedAt value in the OCSP response. Expressed as a Unix Epoch Time                                        |                                                                             | tcp, https |\n| ssl_ocsp_response_revoked_at   | The revocationTime value in the OCSP response. Expressed as a Unix Epoch Time                                    |                                                                             | tcp, https |\n| ssl_ocsp_response_status       | The status in the OCSP response. 0=Good 1=Revoked 2=Unknown                                                      |                                                                             | tcp, https |\n| ssl_ocsp_response_stapled      | Does the connection state contain a stapled OCSP response? Boolean.                                              |                                                                             | tcp, https |\n| ssl_ocsp_response_this_update  | The thisUpdate value in the OCSP response. Expressed as a Unix Epoch Time                                        |                                                                             | tcp, https |\n| ssl_probe_success              | Was the probe successful? Boolean.                                                                               |                                                                             | all        |\n| ssl_prober                     | The prober used by the exporter to connect to the target. Boolean.                                               | prober                                                                      | all        |\n| ssl_tls_version_info           | The TLS version used. Always 1.                                                                                  | version                                                                     | tcp, https |\n| 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 |\n| 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 |\n\n## Configuration\n\n### TCP\n\nJust like with the blackbox_exporter, you should pass the targets to a single\ninstance of the exporter in a scrape config with a clever bit of relabelling.\nThis allows you to leverage service discovery and keeps configuration\ncentralised to your Prometheus config.\n\n```yml\nscrape_configs:\n  - job_name: \"ssl\"\n    metrics_path: /probe\n    static_configs:\n      - targets:\n          - example.com:443\n          - prometheus.io:443\n    relabel_configs:\n      - source_labels: [__address__]\n        target_label: __param_target\n      - source_labels: [__param_target]\n        target_label: instance\n      - target_label: __address__\n        replacement: 127.0.0.1:9219 # SSL exporter.\n```\n\n### HTTPS\n\nBy default the exporter will make a TCP connection to the target. This will be\nsuitable for most cases but if you want to take advantage of http proxying you\ncan use a HTTPS client by setting the `https` module parameter:\n\n```yml\nscrape_configs:\n  - job_name: \"ssl\"\n    metrics_path: /probe\n    params:\n      module: [\"https\"] # \u003c-----\n    static_configs:\n      - targets:\n          - example.com:443\n          - prometheus.io:443\n    relabel_configs:\n      - source_labels: [__address__]\n        target_label: __param_target\n      - source_labels: [__param_target]\n        target_label: instance\n      - target_label: __address__\n        replacement: 127.0.0.1:9219\n```\n\nThis will use proxy servers discovered by the environment variables `HTTP_PROXY`,\n`HTTPS_PROXY` and `ALL_PROXY`. Or, you can set the `https.proxy_url` option in the module\nconfiguration.\n\nThe latter takes precedence.\n\n### File\n\nThe `file` prober exports `ssl_file_cert_not_after` and\n`ssl_file_cert_not_before` for PEM encoded certificates found in local files.\n\nFiles local to the exporter can be scraped by providing them as the target\nparameter:\n\n```\ncurl \"localhost:9219/probe?module=file\u0026target=/etc/ssl/cert.pem\"\n```\n\nThe target parameter supports globbing (as provided by the\n[doublestar](https://github.com/bmatcuk/doublestar) package),\nwhich allows you to capture multiple files at once:\n\n```\ncurl \"localhost:9219/probe?module=file\u0026target=/etc/ssl/**/*.pem\"\n```\n\nOne specific usage of this prober could be to run the exporter as a DaemonSet in\nKubernetes and then scrape each instance to check the expiry of certificates on\neach node:\n\n```yml\nscrape_configs:\n  - job_name: \"ssl-kubernetes-file\"\n    metrics_path: /probe\n    params:\n      module: [\"file\"]\n      target: [\"/etc/kubernetes/**/*.crt\"]\n    kubernetes_sd_configs:\n      - role: node\n    relabel_configs:\n      - source_labels: [__address__]\n        regex: ^(.*):(.*)$\n        target_label: __address__\n        replacement: ${1}:9219\n```\n\n### HTTP File\n\nThe `http_file` prober exports `ssl_cert_not_after` and\n`ssl_cert_not_before` for PEM encoded certificates found at the\nspecified URL.\n\n```\ncurl \"localhost:9219/probe?module=http_file\u0026target=https://www.paypalobjects.com/marketing/web/logos/paypal_com.pem\"\n```\n\nHere's a sample Prometheus configuration:\n\n```yml\nscrape_configs:\n  - job_name: 'ssl-http-files'\n    metrics_path: /probe\n    params:\n      module: [\"http_file\"]\n    static_configs:\n      - targets:\n        - 'https://www.paypalobjects.com/marketing/web/logos/paypal_com.pem'\n        - 'https://d3frv9g52qce38.cloudfront.net/amazondefault/amazon_web_services_inc_2024.pem'\n    relabel_configs:\n      - source_labels: [__address__]\n        target_label: __param_target\n      - source_labels: [__param_target]\n        target_label: instance\n      - target_label: __address__\n        replacement: 127.0.0.1:9219\n```\n\nFor proxying to the target resource, this prober will use proxy servers\ndiscovered in the environment variables `HTTP_PROXY`, `HTTPS_PROXY` and\n`ALL_PROXY`. Or, you can set the `http_file.proxy_url` option in the module\nconfiguration.\n\nThe latter takes precedence.\n\n### Kubernetes\n\nThe `kubernetes` prober exports `ssl_kubernetes_cert_not_after` and\n`ssl_kubernetes_cert_not_before` for PEM encoded certificates found in secrets\nof type `kubernetes.io/tls`.\n\nProvide the namespace and name of the secret in the form `\u003cnamespace\u003e/\u003cname\u003e` as\nthe target:\n\n```\ncurl \"localhost:9219/probe?module=kubernetes\u0026target=kube-system/secret-name\"\n```\n\nBoth the namespace and name portions of the target support glob matching (as provided by the\n[doublestar](https://github.com/bmatcuk/doublestar) package):\n\n```\ncurl \"localhost:9219/probe?module=kubernetes\u0026target=kube-system/*\"\n\n```\n\n```\ncurl \"localhost:9219/probe?module=kubernetes\u0026target=*/*\"\n\n```\n\nThe exporter retrieves credentials and context configuration from the following\nsources in the following order:\n\n- The `kubeconfig` path in the module configuration\n- The `$KUBECONFIG` environment variable\n- The default configuration file (`$HOME/.kube/config`)\n- The in-cluster environment, if running in a pod\n\n```yml\n- job_name: \"ssl-kubernetes\"\n  metrics_path: /probe\n  params:\n    module: [\"kubernetes\"]\n  static_configs:\n   - targets:\n      - \"test-namespace/nginx-cert\"\n  relabel_configs:\n   - source_labels: [ __address__ ]\n     target_label: __param_target\n   - source_labels: [ __param_target ]\n     target_label: instance\n   - target_label: __address__\n     replacement: 127.0.0.1:9219\n```\n\n### Kubeconfig\n\nThe `kubeconfig` prober exports `ssl_kubeconfig_cert_not_after` and\n`ssl_kubeconfig_cert_not_before` for PEM encoded certificates found in the specified kubeconfig file.\n\nKubeconfigs local to the exporter can be scraped by providing them as the target\nparameter:\n\n```\ncurl \"localhost:9219/probe?module=kubeconfig\u0026target=/etc/kubernetes/admin.conf\"\n```\n\nOne specific usage of this prober could be to run the exporter as a DaemonSet in\nKubernetes and then scrape each instance to check the expiry of certificates on\neach node:\n\n```yml\nscrape_configs:\n  - job_name: \"ssl-kubernetes-kubeconfig\"\n    metrics_path: /probe\n    params:\n      module: [\"kubeconfig\"]\n      target: [\"/etc/kubernetes/admin.conf\"]\n    kubernetes_sd_configs:\n      - role: node\n    relabel_configs:\n      - source_labels: [__address__]\n        regex: ^(.*):(.*)$\n        target_label: __address__\n        replacement: ${1}:9219\n```\n\n## Configuration file\n\nYou can provide further module configuration by providing the path to a\nconfiguration file with `--config.file`. The file is written in yaml format,\ndefined by the schema below.\n\n```\n# The default module to use. If omitted, then the module must be provided by the\n# 'module' query parameter\ndefault_module: \u003cstring\u003e\n\n# Module configuration\nmodules: [\u003cmodule\u003e]\n```\n\n### \\\u003cmodule\\\u003e\n\n```\n# The type of probe (https, tcp, file, kubernetes, kubeconfig)\nprober: \u003cprober_string\u003e\n\n# The probe target. If set, then the 'target' query parameter is ignored.\n# If omitted, then the 'target' query parameter is required.\ntarget: \u003cstring\u003e\n\n# How long the probe will wait before giving up.\n[ timeout: \u003cduration\u003e ]\n\n# Configuration for TLS\n[ tls_config: \u003ctls_config\u003e ]\n\n# The specific probe configuration\n[ https: \u003chttps_probe\u003e ]\n[ tcp: \u003ctcp_probe\u003e ]\n[ kubernetes: \u003ckubernetes_probe\u003e ]\n[ http_file: \u003chttp_file_probe\u003e ]\n```\n\n### \u003ctls_config\u003e\n\n```\n# Disable target certificate validation.\n[ insecure_skip_verify: \u003cboolean\u003e | default = false ]\n\n# Configure TLS renegotiation support.\n# Valid options: never, once, freely\n[ renegotiation: \u003cstring\u003e | default = never ]\n\n# The CA cert to use for the targets.\n[ ca_file: \u003cfilename\u003e ]\n\n# The client cert file for the targets.\n[ cert_file: \u003cfilename\u003e ]\n\n# The client key file for the targets.\n[ key_file: \u003cfilename\u003e ]\n\n# Used to verify the hostname for the targets.\n[ server_name: \u003cstring\u003e ]\n```\n\n### \u003chttps_probe\u003e\n\n```\n# HTTP proxy server to use to connect to the targets.\n[ proxy_url: \u003cstring\u003e ]\n```\n\n### \u003ctcp_probe\u003e\n\n```\n# Use the STARTTLS command before starting TLS for those protocols that support it (smtp, ftp, imap, pop3, postgres)\n[ starttls: \u003cstring\u003e ]\n```\n\n### \u003ckubernetes_probe\u003e\n\n```\n# The path of a kubeconfig file to configure the probe\n[ kubeconfig: \u003cstring\u003e ]\n```\n\n### \u003chttp_file_probe\u003e\n\n```\n# HTTP proxy server to use to connect to the targets.\n[ proxy_url: \u003cstring\u003e ]\n```\n\n## Example Queries\n\nCertificates that expire within 7 days:\n\n```\nssl_cert_not_after - time() \u003c 86400 * 7\n```\n\nWildcard certificates that are expiring:\n\n```\nssl_cert_not_after{cn=~\"\\*.*\"} - time() \u003c 86400 * 7\n```\n\nCertificates that expire within 7 days in the verified chain that expires\nlatest:\n\n```\nssl_verified_cert_not_after{chain_no=\"0\"} - time() \u003c 86400 * 7\n```\n\nNumber of certificates presented by the server:\n\n```\ncount(ssl_cert_not_after) by (instance)\n```\n\nIdentify failed probes:\n\n```\nssl_probe_success == 0\n```\n\n## Peer Certificates vs Verified Chain Certificates\n\nMetrics are exported for the `NotAfter` and `NotBefore` fields for peer\ncertificates as well as for the verified chain that is\nconstructed by the client.\n\nThe former only includes the certificates that are served explicitly by the\ntarget, while the latter can contain multiple chains of trust that are\nconstructed from root certificates held by the client to the target's server\ncertificate.\n\nThis has important implications when monitoring certificate expiry.\n\nFor instance, it may be the case that `ssl_cert_not_after` reports that the root\ncertificate served by the target is expiring soon even though clients can form\nanother, much longer lived, chain of trust using another valid root certificate\nheld locally. In this case, you may want to use `ssl_verified_cert_not_after` to\nalert on expiry instead, as this will contain the chain that the client actually\nconstructs:\n\n```\nssl_verified_cert_not_after{chain_no=\"0\"} - time() \u003c 86400 * 7\n```\n\nEach chain is numbered by the exporter in reverse order of expiry, so that\n`chain_no=\"0\"` is the chain that will expire the latest. Therefore the query\nabove will only alert when the chain of trust between the exporter and the\ntarget is truly nearing expiry.\n\nIt's very important to note that a query of this kind only represents the chain\nof trust between the exporter and the target. Genuine clients may hold different\nroot certs than the exporter and therefore have different verified chains of\ntrust.\n\n## Grafana\n\nYou can find a simple dashboard [here](contrib/grafana/dashboard.json) that tracks\ncertificate expiration dates and target connection errors.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fribbybibby%2Fssl_exporter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fribbybibby%2Fssl_exporter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fribbybibby%2Fssl_exporter/lists"}