PromptHub
Back to Blog
DevOps Observability

enix/x509-certificate-exporter: Kubernetes TLS Monitoring That Scales

B

Bright Coding

Author

12 min read 69 views
enix/x509-certificate-exporter: Kubernetes TLS Monitoring That Scales

enix/x509-certificate-exporter: Kubernetes TLS Monitoring That Scales

TLS certificates expire. In a Kubernetes cluster, that simple fact becomes a distributed failure mode: Secrets in dozens of namespaces, kubelet client certs on every node, webhook caBundles scattered across control-plane resources, and PKCS#12 keystores with passphrases you forgot existed. When one expires, services degrade cryptically—until they don't degrade at all, they just stop.

The enix/x509-certificate-exporter is a Prometheus exporter built to make certificate expiration observable before it becomes an incident. Developed by ENIX and released under the MIT License, it watches TLS material across Kubernetes clusters and on-disk PKI, then exposes time-to-expiry as standard Prometheus metrics. With 937 GitHub stars and active development (last commit July 13, 2026), it has matured through a full v4 rewrite around a pluggable, YAML-driven architecture.

This article walks through what the exporter does, how it differs from polling-based alternatives, and how to deploy it without adding operational complexity to a stack that already has enough.


What is enix/x509-certificate-exporter?

The enix/x509-certificate-exporter is a Prometheus exporter for X.509 certificates, written in Go with no CGO dependencies. It is maintained by ENIX and published under the MIT License. The project sits in the observability layer of a Kubernetes cluster—or any infrastructure running Prometheus-compatible scrapers.

Its core job: parse certificates from multiple sources, compute validity windows, and expose standardized metrics. The exporter is Kubernetes-first but not Kubernetes-only. The same binary runs as a standalone process on Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD, Illumos, and Solaris across amd64, arm64, armv7, and riscv64 architectures.

The v4 release represents a significant architectural shift. The codebase was fully rewritten around a YAML configuration file and a pluggable watcher architecture. Memory usage on Secret-heavy clusters dropped approximately 10× through a rewritten Kubernetes watch implementation that keeps RAM flat rather than spiking with object count. The project also hardened its supply chain: SLSA Build Level 3 provenance, cosign-signed artifacts, and CycloneDX SBOM attestations are now standard for every release.

The exporter's relevance stems from a gap in native Kubernetes tooling. The control plane knows when its own certificates expire, but it has no unified view of workload TLS material, node PKI, or external truststores. Certificate managers like cert-manager handle issuance and renewal, yet they don't expose metrics for certificates they didn't issue—or for the CA bundles that validate them. The exporter fills this blind spot without requiring new CRDs, operators, or sidecars.


Key Features

Multi-source certificate discovery. The exporter watches TLS Secrets of any type (kubernetes.io/tls, Opaque bundles, full chains), ConfigMaps with embedded cert or CRL data, PKCS#12 and JKS/JCEKS keystores and truststores, kubeconfig files with embedded or referenced certificates, and files on disk via glob patterns. For Kubernetes admission control, it parses inline caBundle fields on MutatingWebhookConfiguration, ValidatingWebhookConfiguration, APIService, and CustomResourceDefinition resources.

Memory-safe Kubernetes watch. Instead of polling the API server, the exporter uses a paginated LIST + WATCH loop (50 objects per page by default). Watch traffic scales with object churn, not scrape frequency. Parsed certificates are cached so repeat scrapes don't re-decode the same PEM blocks.

CRL freshness monitoring. Certificate Revocation Lists are first-class citizens. The exporter parses X509 CRL PEM blocks and raw DER *.crl files into a dedicated x509_crl_* metric family. Alerts fire before nextUpdate passes, preventing scenarios where stale CRLs cause cascading validation failures.

Flexible passphrase handling. For PKCS#12 and JKS/JCEKS, passphrases can be sourced from a sibling key in the same Secret, a cross-namespace Secret reference, an external file, or omitted with tryEmptyPassphrase. This accommodates legacy keystores without requiring plaintext secrets in configuration.

Multi-cluster fan-in. A single exporter instance can scrape multiple clusters via distinct kubeconfigs, reducing operational overhead for platform teams managing multiple environments.

Supply-chain verification. Every release is built through a single open GitHub Actions pipeline. Container images, Helm charts, and binaries are signed with sigstore/cosign keyless signing. Binaries carry SLSA Level 3 in-toto provenance attestations; images include CycloneDX SBOMs as cosign attestations.

Broad scraper compatibility. The /metrics endpoint speaks OpenMetrics text format with TLS + BasicAuth support via prometheus/exporter-toolkit. Tested against Prometheus, Grafana Agent/Alloy, VictoriaMetrics, Thanos, Cortex/Mimir, OpenTelemetry Collector, Datadog Agent, Elastic Metricbeat, Splunk OTel Collector, Sysdig, New Relic, Dynatrace, Sumo Logic, Wavefront, and Telegraf.


Use Cases

1. Cluster-wide certificate inventory for platform teams.

A platform engineering team needs visibility into all TLS material across production, staging, and development clusters. The exporter deploys as a Deployment watching in-cluster Secrets and ConfigMaps, plus DaemonSets for node-local PKI (kubelet, etcd, kube-apiserver certificates). A single Grafana dashboard lists every certificate sorted by time remaining, sliced by namespace and source. The platform team sets a 28-day renewal warning threshold and routes alerts through existing Alertmanager configurations—no separate paging path required.

2. CRL freshness for regulated environments.

Financial services and healthcare organizations often maintain private PKIs with CRL distribution points. The exporter monitors both certificates and their CRLs. When a CRL approaches its nextUpdate without refresh, the CRLNeedsRefresh alert fires seven days in advance. This prevents the failure mode where expired CRLs cause mutual TLS connections to reject valid certificates, a failure that typically manifests as cryptic connection errors in application logs.

3. Legacy Java workload migration.

Organizations migrating Java applications to Kubernetes often carry JKS or JCEKS truststores with legacy passphrases. The exporter's auto-detection between JKS and JCEKS formats, combined with flexible passphrase sourcing from existing Secrets, allows monitoring without modifying the keystores or exposing credentials in new locations. This reduces friction in brownfield migrations where certificate formats cannot change immediately.

4. Multi-cluster observability without federation complexity.

A single exporter instance can fan in metrics from multiple clusters via distinct kubeconfigs. For a team managing ten clusters, this eliminates the need to deploy, upgrade, and certificate-rotate ten separate exporter installations. Metrics include cluster-identifying labels, so PromQL queries can still scope to individual environments.

5. Non-Kubernetes infrastructure monitoring.

The statically-linked binary runs on bare metal, VMs, or edge devices without container runtimes. A systemd unit points the exporter at local certificate directories; Prometheus scrapes the endpoint directly. This covers legacy load balancers, VPN concentrators, and IoT gateways that generate or receive certificates outside Kubernetes workflows.


Installation & Setup

The primary installation path is Helm, with the chart distributed as an OCI artifact on quay.io.

# Add the ENIX Helm repository
helm repo add enix https://charts.enix.io
helm repo update

# Install with default configuration
helm install x509-certificate-exporter enix/x509-certificate-exporter \
  --namespace monitoring \
  --create-namespace

The default installation creates a Deployment that watches in-cluster Secrets and ConfigMaps. For node-local PKI, enable the DaemonSet:

# Install with hostPath PKI monitoring via DaemonSet
helm install x509-certificate-exporter enix/x509-certificate-exporter \
  --namespace monitoring \
  --set hostPathsExporter.enabled=true \
  --set hostPathsExporter.hostPath=/etc/kubernetes/pki

For prometheus-operator environments, the chart creates a ServiceMonitor automatically. Without the operator, enable Pod annotations:

helm upgrade x509-certificate-exporter enix/x509-certificate-exporter \
  --namespace monitoring \
  --set prometheusPodMonitor.enabled=false \
  --set prometheusAnnotations.enabled=true

Upgrading from v3? The chart distribution moved to OCI on quay.io, the Alpine image variant was retired, and several values keys changed shape. Consult the v3 → v4 migration guide before upgrading.

For standalone binary deployment, download from the releases page and verify signatures:

# Verify cosign signature (requires cosign CLI)
cosign verify \
  --certificate-identity-regexp='^https://github.com/enix/x509-certificate-exporter/.github/workflows/release.yaml@refs/tags/v.*$' \
  --certificate-oidc-issuer='https://token.actions.githubusercontent.com' \
  ghcr.io/enix/x509-certificate-exporter:latest

Real Code Examples

The exporter is configured through a YAML file. Below are representative configurations from the project's documentation.

Example 1: Basic Kubernetes Secret and ConfigMap watching

# config.yaml — watch TLS Secrets and a ConfigMap with CA certificates
watchers:
  - type: k8s/secrets
    namespaces:
      - default
      - production
    secretTypes:
      - kubernetes.io/tls
      - Opaque
    # Extract certificates from these keys in matching Secrets
    certificateKeys:
      - tls.crt
      - ca.crt

  - type: k8s/configmaps
    namespaces:
      - production
    certificateKeys:
      - ca-bundle.crt

This configuration creates two watchers. The first monitors Secrets in default and production namespaces, looking for tls.crt and ca.crt keys within both standard TLS Secrets and Opaque Secrets. The second watches a ConfigMap in production that stores a CA bundle. Each discovered certificate becomes its own Prometheus series with labels for namespace, source type, and resource name.

Example 2: PKCS#12 keystore with passphrase from sibling Secret key

# config.yaml — PKCS#12 with passphrase sourced from same Secret
watchers:
  - type: k8s/secrets
    namespaces:
      - legacy-apps
    certificateKeys:
      - name: keystore.p12
        format: pkcs12
        passphrase:
          fromSecretKey:
            key: keystore-password

Here the exporter finds a PKCS#12 keystore in the legacy-apps namespace. The passphrase is stored in the same Secret under the key keystore-password. This pattern avoids duplicating credentials in exporter configuration and leverages Kubernetes RBAC for access control. The format: pkcs12 declaration triggers PKCS#12 parsing rather than PEM parsing.

Example 3: File-based watching with glob patterns for certbot renewals

# config.yaml — on-disk certificates with symlink-following
watchers:
  - type: files
    paths:
      - /etc/letsencrypt/live/**/*.pem
      - /etc/kubernetes/pki/*.crt
    # Follow atomic symlink swaps (certbot, kubelet projected volumes)
    followSymlinks: true

This configuration watches certificate files on disk using glob patterns. The ** recursive glob finds all .pem files under /etc/letsencrypt/live/, matching certbot's directory structure. The followSymlinks: true setting ensures that atomic symlink swaps—used by certbot during renewal and by kubelet for projected ConfigMap/Secret volumes—are detected on the next poll cycle rather than caching stale paths.


Advanced Usage & Best Practices

Cardinality control. The exporter surfaces workload metadata by lifting watched resource labels onto emitted certificate series. In clusters with high label cardinality, this can increase metric cardinality significantly. Consider using metricRelabelings in your scrape configuration to drop unnecessary labels, or configure the exporter's label allowlist if supported in your version.

Memory sizing. The v4 watch implementation keeps memory flat, but initial LIST operations still require temporary overhead. For clusters with 10,000+ Secrets, size memory limits based on observed startup behavior rather than steady-state usage. The FAQ documentation provides specific guidance for large clusters.

Dual-deployment pattern. The most complete coverage uses both a Deployment (for in-cluster resources) and DaemonSets (for node-local PKI). This avoids over-privileging a single Deployment with hostPath access while keeping the in-cluster watcher co-located with the API server for low-latency watches.

CRL monitoring in air-gapped environments. CRL freshness alerts require that the exporter can access CRL distribution points, or that you mirror CRLs into the cluster. For air-gapped environments, consider a separate mirroring process or disable CRL watchers to avoid spurious CRLNeedsRefresh alerts.

Supply-chain verification in CI/CD. Pin to immutable digests rather than floating tags, and verify cosign signatures in your image admission pipeline. The hardening guide provides copy-paste verification recipes for common CI platforms.


Comparison with Alternatives

Tool Scope Kubernetes-native Multi-source CRL support Supply-chain hardening
enix/x509-certificate-exporter Certificates + CRLs Yes (also standalone) Secrets, ConfigMaps, files, kubeconfigs, PKCS#12, JKS/JCEKS, webhooks Yes SLSA L3, cosign, SBOM
cert-manager's cmctl cert-manager issued only Yes cert-manager Certificates only No Project-dependent
ssl-exporter (ribbybibby) TLS endpoints + files No (can run in K8s) Files, probes, Kubernetes Secrets No Standard releases
node-exporter textfile User-provided metrics No Any (manual scripting) No Standard releases

cert-manager's cmctl status command provides expiration data but only for certificates that cert-manager itself manages. It cannot observe manually created Secrets, node PKI, or external truststores.

ssl-exporter excels at probing TLS endpoints from the outside but lacks deep Kubernetes integration—no watch-based Secret monitoring, no webhook caBundle parsing, no CRL tracking.

node-exporter's textfile collector requires writing custom scripts to parse certificates and emit metrics, placing maintenance burden on operators.

The enix exporter occupies a middle ground: deeper Kubernetes integration than ssl-exporter, broader source coverage than cert-manager tooling, and less operational burden than custom textfile scripts.


FAQ

What license covers enix/x509-certificate-exporter?

MIT License. Commercial use, modification, and distribution are permitted.

Does it require cert-manager?

No. It monitors any certificate source, regardless of how certificates were created or renewed.

Can it run outside Kubernetes?

Yes. Statically-linked binaries for nine operating systems and four architectures are available.

How does v4 memory usage compare to v3?

Approximately 10× lower on Secret-heavy clusters due to the rewritten watch implementation.

What Prometheus versions are compatible?

Any Prometheus-compatible scraper. Explicitly tested against 13 collectors including Prometheus, VictoriaMetrics, Thanos, and OpenTelemetry Collector.

How are alerts configured?

A bundled PrometheusRule provides six alerts with tunable thresholds. Alertmanager routes them through existing channels.

Is there a Grafana dashboard?

Yes. Dashboard ID 13922 on Grafana.com, deployable via the Helm chart as a sidecar-discovered ConfigMap.


Conclusion

The enix/x509-certificate-exporter solves a specific, recurring problem in Kubernetes operations: certificate expiration is easy to forget until it causes an outage. By unifying monitoring across Secrets, node PKI, keystores, and CRLs—then exposing everything through standard Prometheus metrics—it integrates into existing observability stacks without requiring new tools or operational patterns.

The v4 rewrite demonstrates mature engineering priorities: flat memory usage, pluggable architecture, and supply-chain hardening that matches the security posture of the certificates it monitors. For platform teams running multiple clusters, the multi-cluster fan-in capability reduces operational overhead. For organizations with legacy Java or PKCS#12 assets, the flexible passphrase handling removes migration blockers.

It is best suited for teams already invested in Prometheus-compatible observability who need comprehensive certificate visibility without adopting a separate certificate management platform. It complements rather than replaces cert-manager: cert-manager handles issuance and renewal; the exporter handles monitoring and alerting for everything cert-manager cannot see.

To get started, review the Helm chart documentation, verify the latest release signatures, and deploy to your monitoring namespace. The project source, issue tracker, and contribution guidelines are available at https://github.com/enix/x509-certificate-exporter.

For related monitoring strategies, see our guide on [INTERNAL_LINK: Prometheus operator best practices for multi-cluster setups].

Comments (0)

Comments are moderated before appearing.

No comments yet. Be the first to share your thoughts!

Recommended Prompts

View All