69 lines
3.8 KiB
YAML
69 lines
3.8 KiB
YAML
# ZITADEL alert parity with the Authentik rules it will replace.
|
|||
|
|
#
|
||
|
|
# Only two signals are ported at this point. The metrics endpoint
|
||
|
|
# (/debug/metrics, scraped by the chart's own ServiceMonitor in ns iam) exposes
|
||
|
|
# no request or error counters that this cluster has verified, so no error-rate
|
||
|
|
# rule is written here. Writing one against a guessed series name would produce
|
||
|
|
# a permanently-firing or permanently-silent alert — both worse than none.
|
||
|
|
# AuthentikOutpostDown is deliberately not ported: it monitors an outpost that
|
||
|
|
# carries zero providers and is deleted with the migration, not migrated.
|
||
|
|
apiVersion: monitoring.coreos.com/v1
|
||
|
|
kind: PrometheusRule
|
||
|
|
metadata:
|
||
|
|
name: zitadel-rules
|
||
|
|
namespace: iam
|
||
|
|
spec:
|
||
|
|
groups:
|
||
|
|
- name: zitadel.rules
|
||
|
|
interval: 30s
|
||
|
|
rules:
|
||
|
|
- alert: ZitadelDown
|
||
|
|
# absent() is required: equality alone cannot fire when the series is
|
||
|
|
# gone (ServiceMonitor deleted, Service selector changed, pods scaled
|
||
|
|
# to zero). Those are exactly the outages a target-down rule exists for.
|
||
|
|
expr: absent(up{job="zitadel"}) or up{job="zitadel"} == 0
|
||
|
|
for: 10m
|
||
|
|
labels:
|
||
|
|
severity: critical
|
||
|
|
annotations:
|
||
|
|
summary: "ZITADEL API target is down"
|
||
|
|
description: "Prometheus cannot scrape the ZITADEL API for 10 minutes. Token issuance and every OIDC login depend on it. Check the zitadel pods and the zitadel-db cluster in namespace iam. Value: {{ $value }}"
|
||
|
|
|
||
|
|
- alert: ZitadelLoginUIDown
|
||
|
|
expr: absent(kube_deployment_status_replicas_available{namespace="iam",deployment="zitadel-login"}) or kube_deployment_status_replicas_available{namespace="iam",deployment="zitadel-login"} == 0
|
||
|
|
for: 10m
|
||
|
|
labels:
|
||
|
|
severity: warning
|
||
|
|
annotations:
|
||
|
|
summary: "ZITADEL login UI has no available replica"
|
||
|
|
description: "The login UI serves /ui/v2/login. With zero available replicas a browser login completes at the IdP but cannot render. Value: {{ $value }}"
|
||
|
|
|
||
|
|
- alert: ZitadelRestarting
|
||
|
|
# pod!~"zitadel-db-.*" matters: the CNPG database pods share the
|
||
|
|
# `zitadel` name prefix, and a database restart must not page as an
|
||
|
|
# IdP crash loop.
|
||
|
|
expr: absent(kube_pod_container_status_restarts_total{namespace="iam",pod=~"zitadel.*",pod!~"zitadel-db-.*"}) or increase(kube_pod_container_status_restarts_total{namespace="iam",pod=~"zitadel.*",pod!~"zitadel-db-.*"}[1h]) > 3
|
||
|
|
for: 5m
|
||
|
|
labels:
|
||
|
|
severity: warning
|
||
|
|
annotations:
|
||
|
|
summary: "ZITADEL pod restarts more than 3 times per hour"
|
||
|
|
description: "A crash loop on the IdP is a cluster-wide login outage. Check the pod logs and the masterkey/database secret references. Value: {{ $value }}"
|
||
|
|
|
||
|
|
# The chart's zitadel-init and zitadel-setup Jobs are PreSync hooks with
|
||
|
|
# restartPolicy: Never, so their restart counter stays 0. Without this
|
||
|
|
# rule a failed schema init or first-instance setup reaches nobody but
|
||
|
|
# the person who runs `kubectl -n iam get job`.
|
||
|
|
# No absent() guard here on purpose: the chart ships only
|
||
|
|
# `before-hook-creation`, so a successful hook Job is replaced at the
|
||
|
|
# next PreSync. Once the jobs are retired, absent() would fire on a
|
||
|
|
# healthy cluster.
|
||
|
|
- alert: ZitadelSetupJobFailed
|
||
|
|
expr: kube_job_status_failed{namespace="iam",job_name=~"zitadel-(init|setup).*"} > 0
|
||
|
|
for: 5m
|
||
|
|
labels:
|
||
|
|
severity: critical
|
||
|
|
annotations:
|
||
|
|
summary: "ZITADEL init/setup job failed"
|
||
|
|
description: "A PreSync job failed, so ArgoCD aborted the sync before the Deployment was applied. Read the job pod logs, then delete the Job object to let the next sync retry. Value: {{ $value }}"
|