Skip to content

Metrics

The controller serves Prometheus metrics on port 8443. Alongside the standard controller-runtime, Go runtime and client-go families, cmp-issuer publishes what its own enrollments did.

Every series carries the same three labels:

Label Values
issuer_kind CMPIssuer or CMPClusterIssuer
issuer namespace/name for a CMPIssuer, name for a CMPClusterIssuer
operation enrollment or renewal

operation separates the first issuance of a certificate from a re-enrollment. cert-manager stamps each CertificateRequest with the revision it will become, so anything past the first is a renewal. A CertificateRequest written by hand carries no revision and counts as an enrollment. Note that cmp-issuer renews by sending a fresh P10CR rather than a CMP Key Update Request, so a renewal is the same protocol exchange as an enrollment. See P10CR renewal and KUR.

What is published

Metric Type Labels beyond the three above Meaning
cmp_issuer_enrollment_total counter result is issued or failed Completed attempts. A wait for a server that has not answered is not an attempt
cmp_issuer_enrollment_duration_seconds histogram result Time from recording the CMP transaction to its outcome, including every poll and confirmation wait
cmp_issuer_enrollment_failures_total counter failure, classification Failures by the CMP failure that ended them and whether that failure is retried
cmp_issuer_enrollment_polls_total counter none Waits for a server that accepted a request but has not returned or confirmed the certificate
cmp_issuer_enrollment_confirmations_total counter confirmation is Explicit or Implicit Completed enrollments by whether the server required certConf

failure carries the CMP failure name, such as badRequest, badMessageCheck, signerNotTrusted or systemUnavail, plus issuerConfiguration for a failure that never reached the server and unclassified for one that carries no CMP failure information. classification is Permanent, Retryable, Security or Unknown, matching the classification field of the CMP enrollment failed log line, which also names the protocol step the failure came from.

The duration is measured from the CMPTransaction record, not from the current reconcile, so an enrollment a server queued for ten minutes is observed as ten minutes rather than as several short reconciles. A retried failure is counted once per attempt.

Example queries

Enrollment failure rate over the last hour, split by whether it was a renewal:

sum by (operation) (rate(cmp_issuer_enrollment_total{result="failed"}[1h]))
  / sum by (operation) (rate(cmp_issuer_enrollment_total[1h]))

Renewals that are failing, by cause, which is the query that tells you whether a CA changed a profile:

sum by (issuer, failure) (increase(cmp_issuer_enrollment_failures_total{operation="renewal"}[24h]))

The 95th percentile enrollment time per issuer, to catch a CA that has started queueing:

histogram_quantile(0.95, sum by (le, issuer) (rate(cmp_issuer_enrollment_duration_seconds_bucket{result="issued"}[30m])))

Authentication failures, which usually mean a rotated shared secret or an expired signing certificate:

sum by (issuer) (increase(cmp_issuer_enrollment_failures_total{failure="badMessageCheck"}[15m])) > 0

Reaching the endpoint

Every scrape is authenticated with a TokenReview and authorized with a SubjectAccessReview, so the scraping ServiceAccount needs the cmp-issuer-metrics-reader ClusterRole the installation creates:

kubectl create clusterrolebinding prometheus-cmp-issuer-metrics --clusterrole=cmp-issuer-metrics-reader --serviceaccount=monitoring:prometheus

Set prometheus.enabled=true to have the chart create a ServiceMonitor. By default the endpoint presents a certificate the controller generates for localhost, which no scraper that checks the server name can verify, so the ServiceMonitor skips verification. Set metrics.tls.certManager.enabled=true to have cert-manager issue a certificate for the Service name instead, and the ServiceMonitor verifies it. See installation.

metrics.secure=false serves plain HTTP with no authentication, for a collector that cannot present a token. Pair it with networkPolicy.enabled=true.