Skip to main content
RunBook Academy

KubernetesLXXVI · Cluster CertificatesCluster certificates

check-expiration — inventorying the cluster certs

Advanced⏱ ~13 minkubeadm

What you'll learn

  • Run kubeadm certs check-expiration and interpret the output
  • Understand the relationship between check-expiration and the renewal command
  • Wire check-expiration into monitoring and the runbook
  • Identify edge cases (missing certs, externally-managed certs)

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

kubeadm certs check-expiration is the single command that gives the operator a complete inventory of the cluster’s PKI. It is read-only, non-disruptive, and safe to run on any control-plane host. This lesson walks the command, its output, and how to use it as the cluster’s cert inventory.

The command

sudo kubeadm certs check-expiration

Run on a control-plane host. The command reads the PKI directory and prints every cert with its expiry, residual time, signing CA, and whether it is externally managed.

The output

CERTIFICATE                          EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY   EXTERNALLY MANAGED
admin.conf                          Aug 16 10:00:00 2027 UTC  364d            ca                      no
apiserver                           Aug 16 10:00:00 2027 UTC  364d            ca                      no
apiserver-kubelet-client            Aug 16 10:00:00 2027 UTC  364d            ca                      no
controller-manager.conf             Aug 16 10:00:00 2027 UTC  364d            ca                      no
scheduler.conf                      Aug 16 10:00:00 2027 UTC  364d            ca                      no
etcd-ca                             Aug 16 10:00:00 2027 UTC  364d            etcd-ca                 no
etcd-healthcheck-client             Aug 16 10:00:00 2027 UTC  364d            etcd-ca                 no
etcd-peer                           Aug 16 10:00:00 2027 UTC  364d            etcd-ca                 no
etcd-server                         Aug 16 10:00:00 2027 UTC  364d            etcd-ca                 no
front-proxy-ca                      Aug 16 10:00:00 2027 UTC  364d            front-proxy-ca          no
front-proxy-client                  Aug 16 10:00:00 2027 UTC  364d            front-proxy-ca          no

The columns are:

ColumnMeaning
CERTIFICATEThe cert name (matches the filename in /etc/kubernetes/pki)
EXPIRESThe notAfter date in UTC
RESIDUAL TIMEDays remaining until expiry
CERTIFICATE AUTHORITYThe CA that signed the cert
EXTERNALLY MANAGEDyes if the cert is rotated by something other than kubeadm

The output is concise, deterministic, and machine-readable.

flowchart LR
    A[kubeadm certs check-expiration] --> B[Read /etc/kubernetes/pki]
    B --> C[Parse X.509 metadata]
    C --> D[Format table output]
    D --> E[Operator reads residual time]
    E --> F[Plan renewal if 30 days]

The residual time

The RESIDUAL TIME column is the operational metric. The operator checks residual time each week (or runs it from a cron / monitoring job). The convention:

  • 364d–30d: safe. No action.
  • 29d–15d: watch. Schedule the renewal.
  • 14d–7d: action. Renew within the week.
  • 6d–0d: critical. Renew immediately; failure is an incident.

EXTERNALLY MANAGED

The EXTERNALLY MANAGED column is yes when the cert is not rotated by kubeadm. Common cases:

  • A cert-manager managed certificate.
  • An external CA (Vault, Step CA, Let’s Encrypt via ingress).
  • A static cert loaded from a Secret.

When EXTERNALLY MANAGED: yes, kubeadm certs renew skips that cert. The operator is responsible for the rotation.

Embedded JSON output

The command supports a -output=json flag for machine-readable output:

sudo kubeadm certs check-expiration -output=json
[
  {
    "name": "apiserver",
    "ca": "ca",
    "expiry": "2027-08-16T10:00:00Z",
    "externallyManaged": false,
    "residualTime": "364d"
  }
]

The JSON output is suitable for monitoring agents: a Prometheus textfile exporter or a custom configmap JSON Pusher can capture the output and emit metrics.

The kubeconfig’s expiry

The EXTERNALLY MANAGED column does not appear for the admin.conf, controller-manager.conf, scheduler.conf, or kubelet.conf kubeconfigs in the regular output, but these are also certs in the same PKI. The command reads them from /etc/kubernetes/*.conf and includes their expiry.

The host-by-host inventory

check-expiration is per-host. On a multi-control-plane cluster, run it on each host:

for host in cp-1 cp-2 cp-3; do
  echo "=== $host ==="
  ssh $host sudo kubeadm certs check-expiration
done

The output should be identical unless a host has been upgraded or restored out-of-band. Diverging expiry times across the cluster indicate a host that has been re-bootstrapped or restored from a different snapshot.

Read-only / Safe
$ sudo kubeadm certs check-expiration
CERTIFICATE                          EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY   EXTERNALLY MANAGED
admin.conf                          Aug 16 10:00:00 2027 UTC  364d            ca                      no
apiserver                           Aug 16 10:00:00 2027 UTC  364d            ca                      no
apiserver-kubelet-client            Aug 16 10:00:00 2027 UTC  364d            ca                      no
controller-manager.conf             Aug 16 10:00:00 2027 UTC  364d            ca                      no
scheduler.conf                      Aug 16 10:00:00 2027 UTC  364d            ca                      no
etcd-ca                             Aug 16 10:00:00 2027 UTC  364d            etcd-ca                 no
etcd-healthcheck-client             Aug 16 10:00:00 2027 UTC  364d            etcd-ca                 no
etcd-peer                           Aug 16 10:00:00 2027 UTC  364d            etcd-ca                 no
etcd-server                         Aug 16 10:00:00 2027 UTC  364d            etcd-ca                 no
front-proxy-ca                      Aug 16 10:00:00 2027 UTC  364d            front-proxy-ca          no
front-proxy-client                  Aug 16 10:00:00 2027 UTC  364d            front-proxy-ca          no

The integration with monitoring

The conventional wiring:

#!/bin/bash
# /usr/local/bin/k8s-cert-inventory.sh
# Run daily; emit Prometheus textfile metrics.
sudo kubeadm certs check-expiration -output=json |
  jq -r '.[] | "kube_cert_expiry_seconds{cert=\(.name),ca=\(.ca)} " + (.expiry | fromdateiso8601) | tostring' \
  > /var/lib/node_exporter/textfile/kube_certs.prom

The emitted metrics:

# HELP kube_cert_expiry_seconds Unix timestamp of cert expiry.
# TYPE kube_cert_expiry_seconds gauge
kube_cert_expiry_seconds{cert="apiserver",ca="ca"} 1794842400
kube_cert_expiry_seconds{cert="etcd-server",ca="etcd-ca"} 1794842400

The alert:

- alert: KubeCertExpiringSoon
  expr: (kube_cert_expiry_seconds - time()) < 30 * 86400
  for: 1d
  labels:
    severity: warning
  annotations:
    summary: "Cert {{ $labels.cert }} expires in < 30 days"

Cross-course references

  • The Observability course covers the probe_ssl_earliest_cert_expiry metric for externally-accessible services.
  • The Linux course covers cron-based monitoring agents.
  • The VyOS course covers CA chain validation when integrating external services.

Quiz

Knowledge check · 4 questions

  1. Q1. Which column in `kubeadm certs check-expiration` is the operational metric that drives renewal decisions?

  2. Q2. When a cert is marked EXTERNALLY MANAGED: yes, kubeadm will still rotate it during `kubeadm certs renew`.

  3. Q3. Walk the weekly cert inventory run.

    3-control-plane cluster (cp-1, cp-2, cp-3). Today's date: 2027-08-09. Last renewal: 358 days ago. The team checks the inventory.

  4. Q4. How do you emit a Prometheus metric per cert from `kubeadm certs check-expiration`?

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Run check-expiration weekly. Capture the output in the runbook.
  • Run on every control-plane host. Cross-host divergence is a signal.
  • Wire into Prometheus. The textfile collector emits the residual time as a metric.
  • Alert at 30/15/7 days. Three thresholds, escalating severity.
  • Treat 7 days as critical. Failure to renew within 7 days is an incident.
  • Document the inventory. The list of certs is finite; capture it once.

The inventory is the source of truth for the cluster’s PKI. Operating it well is keeping the inventory current and acting on the residual time before it is too late.