Kubernetes — алерт когда secret не ротировался дольше N дней
Compliance требует rotation k8s-secrets (DB-passwords, API-tokens) каждые 90 дней. Никто не делает auto-rotate, secrets живут с момента создания cluster-а. Аудитор найдёт первый.
Рецепт
#!/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)"
То же самое в Enterno.io
Подключите Enterno heartbeat с retention 365 — будет история «что и когда мы ротировали» для compliance-audit-а.
Похожие рецепты
Readiness-probe внутри пода есть, но никто не видит, что LB отказался роутить трафик на новый deploy.
CrashLoopBackOff в одном пространстве имён — kubectl показывает restart-count = 47, но никто не видит. Хочется endpoint, который вернёт high когда счётчик прыгает.
etcd в кластере K8s переизбирает лидера каждые 30 сек — kube-apiserver лагает, controller-manager не успевает применять reconcile. Это видно только в etcd-метриках.