Skip to content

Cheat sheet — Monitoring & Detection in Zero Trust (Sigma / metrics)

Companion to Module 09 — Monitoring & Detection in Zero Trust · CC BY 4.0 — print it, pin it, share it.

Last reviewed: 2026-07

Sigma rule anatomy (detection-as-code)

title: Successful access from unexpected country
id: 7a1c...           # a UUID
status: experimental
logsource:
  product: zta-proxy
  service: access
detection:
  selection:
    event_type: access_allowed        # the proxy allowed a VALID identity
  filter:
    country:                          # the operating set you DO expect
      - US
      - DE
  condition: selection and not filter # fire on allowed access from anywhere else
level: high

The selection and not filter pattern is the workhorse: match the event, subtract the benign known-good.

Convert / test a Sigma rule

pip install sigma-cli                                   # the sigma converter
sigma convert -t <backend> rule.yml                     # compile to a target query language
sigma check rule.yml                                    # validate rule structure/fields
# fire it against bundled events (backend-specific) and confirm it selects the anomaly, not the benign

Scoring a detection — the confusion matrix

                 actual ANOMALY   actual BENIGN
rule FIRED          TP               FP
rule SILENT         FN               TN

precision = TP / (TP + FP)     # of what it flagged, how much was real
recall    = TP / (TP + FN)     # of the real anomalies, how many it caught   ← load-bearing
FP-rate   = FP / (FP + TN)     # benign events it fired on = analyst-time cost
accuracy  = (TP+TN)/total      # MISLEADS on imbalanced data — a rule that never fires is 99% "accurate"

For a leading-indicator geo-detection, recall is the metric that matters: a missed credential-compromise can be a breach; a false positive costs an analyst a few minutes.

Held-out corpus — the honest test

Score the rule on data it was NEVER tuned on. Stock it with the cases that BREAK a naive geo-rule:
  malicious:  foreign login · session that STARTS in-country then continues abroad · impossible-travel pair
  benign:     executive on a real (HR-logged) trip · dev whose VPN egresses abroad · cloud job in a DC region

Regression gate (in CI):
  recall drops below threshold  → build RED (rule went too NARROW — stopped catching a variant)
  FP-rate climbs above threshold → build RED (rule went too BROAD — fires on legit travel)
Prove the gate goes RED on a deliberately over-broad/over-narrow copy — a gate you've only seen pass isn't a gate.

Drift detector — posture over time (declare → observe → diff → reconcile)

Declare (as code) the intended baseline:  max token lifetime · allowed policy exceptions · required posture checks
Observe the running config.
Diff observed vs declared; exit non-zero when they differ.
Reconcile back to the baseline.

The three silent drifts to catch:
  token-lifetime creep       (15 min quietly bumped to 8 hrs — every stolen token lives 32× longer)
  accreted allow-exceptions  (the "temporary" contractor→DB rule that outlived the contractor)
  disabled posture checks     (device-compliance flipped to "log only" and never flipped back)

Gotchas worth remembering

  • A detection measured only on the demo set is a memorised exam. The events you watched it fire on are the ones you tuned against — the number only means something on a held-out corpus the rule never saw. Never let AI generate the corpus and score against it; that's the contamination this module warns against — you label each near-miss by hand.
  • Recall over accuracy for leading indicators. Accuracy hides both a missed breach and a flood of false positives on imbalanced data. Choose the metric deliberately and justify it — a model defaults to accuracy; override it.
  • A regression gate you've only seen pass is not a gate. Prove it goes RED on a deliberately too-broad and too-narrow copy of the rule.
  • Coverage ≠ effectiveness. A 500-event corpus of easy traffic is worse than a 30-event one that includes the VPN-egress near-miss and the impossible-travel pair. Sample the failure modes; don't count items.
  • The eval must fail closed. If the score is missing or the eval errors, the build must go RED — a broken eval that silently passes is worse than no eval.
  • "Trust nothing" is a posture you hold over time, not a switch you flip once. None of the three posture drifts throws an alarm on its own — only a declared-vs-observed diff catches them.

Comments

Sign in with GitHub to comment. Choose the type: Feedback (errors or suggestions on this page) · Hints (help for fellow learners — no spoilers) · General (anything else).