KubernetesLXXVI · Cluster CertificatesCluster certificates
check-expiration — inventorying the cluster certs
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
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:
| Column | Meaning |
|---|---|
| CERTIFICATE | The cert name (matches the filename in /etc/kubernetes/pki) |
| EXPIRES | The notAfter date in UTC |
| RESIDUAL TIME | Days remaining until expiry |
| CERTIFICATE AUTHORITY | The CA that signed the cert |
| EXTERNALLY MANAGED | yes 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.
$ sudo kubeadm certs check-expirationCERTIFICATE 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 noThe 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_expirymetric 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
Q1. Which column in `kubeadm certs check-expiration` is the operational metric that drives renewal decisions?
Q2. When a cert is marked EXTERNALLY MANAGED: yes, kubeadm will still rotate it during `kubeadm certs renew`.
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.
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.