Kubernetes — alert when a Secret has not rotated in N days
Compliance mandates rotating k8s Secrets (DB passwords, API tokens) every 90 days. Nobody auto-rotates, Secrets live since cluster creation. The auditor finds it first.
Recipe
#!/usr/bin/env bash
# /etc/cron.d/k8s-secret-age
# 0 7 * * * root /opt/k8s-secret-age.sh
CONTEXT=${KUBE_CONTEXT:-prod}
NS=${NS:-prod}
MAX_DAYS=${MAX_DAYS:-90}
EXCLUDE_TYPE='kubernetes.io/service-account-token|helm.sh/release.v1'
NOW=$(date -u +%s)
STALE=$(kubectl --context "$CONTEXT" -n "$NS" get secrets -o json \
| jq --argjson now "$NOW" --argjson max "$MAX_DAYS" --arg ex "$EXCLUDE_TYPE" '
[.items[] |
select(.type | test($ex) | not) |
{name: .metadata.name,
days: (($now - (.metadata.creationTimestamp | fromdateiso8601)) / 86400 | floor)} |
select(.days > $max)]')
COUNT=$(echo "$STALE" | jq 'length')
if [ "${COUNT:-0}" -gt 0 ]; then
EXAMPLES=$(echo "$STALE" | jq -r '.[] | "\(.name)=\(.days)d"' | head -5 | tr '\n' ',')
curl -fsS "$HEARTBEAT_URL" --data-urlencode "stale_secrets=$COUNT,examples=$EXAMPLES"
exit 2
fi
echo "OK (no Secrets older than ${MAX_DAYS}d)"
Same thing in Enterno.io
Wire to an Enterno heartbeat with 365-day retention — keeps a history of "what and when we rotated" for the compliance audit.
Related recipes
Readiness probes pass inside the pod, but no one sees that the LB refused to route traffic to the new deploy.
A CrashLoopBackOff in one namespace — kubectl shows a restart count of 47, but nobody sees it. Want an endpoint that returns high when the counter jumps.
Inside a K8s cluster etcd re-elects the leader every 30 s — kube-apiserver lags, controller-manager can't keep reconciling. Only visible in etcd metrics.