Detection Events Dashboard
In-cluster visibility into what PandoCore is detecting and protecting.
There are three places to see what PandoCore is doing, and which one you want depends on the question. The portal is for detections and entitlements, Prometheus is for coverage and health, and kubectl is for what is true in the cluster right now.
Portal Dashboard
Evidence is delivered by the controller to portal.pandocore.io, which is where detections, their reasons and their outcomes are read. No extra configuration is needed: the portal is a destination the controller carries by default.
Event data flow
- A sensor detects behaviour diverging from a workload's profile
- It seals and signs an evidence record, and delivers it to the controller over mTLS
- The controller writes it to a durable spool and only then acknowledges it
- The controller delivers it onward to the portal, and to any SIEM, Slack or webhook destinations you have configured
- If a response ran, a second
pando.responserecord follows carrying what it actually did
The trip record is sealed and shipped before the response chain resolves, because there is no action without a durable record first. So the first record carries the intended response and the receipt carries the outcome. They are correlated by trip_evidence_id, not by sharing an id. See Evidence Format.
What the portal shows
- Detections, with the reason, severity, pod, namespace and the response taken
- Your license, including the response ceiling it permits and its retention window
- Your plan, as a separate card derived independently of the license, so the two can be cross-checked rather than agreeing by construction
- Node protection, including any node held to monitor by a clamp
- The install commands for your cluster, pre-filled with your license key and the current chart version
Your plan's retention figure is the period the portal undertakes to keep evidence for. Nothing deletes an event at the end of it, so it is not a promise that older evidence is gone, and it is not an availability claim about querying it. If you need evidence for a defined period under your own control, deliver it to your SIEM and apply your retention policy there.
Coverage And Health, In Prometheus
The portal shows what was detected. It does not tell you whether a node stopped being watched, and that is the question worth alerting on.
| Metric | What it answers |
|---|---|
pando_node_sensor_pods_unmonitored |
Pods getting no engine. With reason="cap", pods you wanted watched that the node had no room for |
pando_operating_mode |
The mode in force (0 monitor, 1 alert, 2 isolate, 4 debug) |
pando_mode_ceiling |
The ceiling the license permits, same encoding |
pando_isolations_total |
Isolation policies successfully applied |
The sensor chart ships PrometheusRules covering coverage at the cap, the series going absent, a refusal at startup, and a cadence stretched past its configured interval. Absence matters most: it is the one condition no self-report can distinguish from healthy.
A job selecting on the protect label matches nothing. The sensor's own pod carries pandocore.io/protect: "false", so a Prometheus job written against protect=true finds no targets and reports a clean scrape of nothing, which renders identically to healthy. Select on app.kubernetes.io/name=pando-node-sensor.
On GKE managed Prometheus the shipped rules are inert. It honours neither the chart's scrape annotations nor a PrometheusRule, so set metrics.podMonitoring.enabled=true to get scraping at all, and port the coverage and absence rules across by hand. See Configuration.
Right Now, With kubectl
# One sensor per node, all Ready
kubectl get pods -n pando-system -l app.kubernetes.io/name=pando-node-sensor -o wide
# Engine count, license ceiling, node clamp, for one node
kubectl exec -n pando-system <sensor-pod> -- wget -qO- http://localhost:9090/status
# What is contained at this moment
kubectl get networkpolicy --all-namespaces \
-l app.kubernetes.io/managed-by=pandocore
# Detections as Kubernetes events
kubectl get events -n <namespace> --field-selector reason=PandoCollapse
# Collapse-grade conditions where nothing acted
kubectl get events -n <namespace> --field-selector reason=PandoRefrained
What a detection looks like as an event
| Reason | Type | Meaning |
|---|---|---|
PandoAlert |
Normal | A detection that called for no response chain |
PandoRefrained |
Warning | A collapse-grade condition was detected and nothing acted, because of the mode, the license ceiling or the learning window |
PandoCollapse |
Warning | A containment action was attempted |
PandoRefrained is how you evaluate before you let it actOn a free license nothing is ever contained, so every collapse-grade finding arrives as PandoRefrained: this was serious enough to act on, and nothing did. That is the list to read before deciding whether to raise the ceiling, and it is evidence from your own cluster rather than a projection.
It pairs with pando_collapses_total{outcome="refrained"}, which is deliberately the same word so the event and the metric are recognisably the same fact. The event's machine-readable event_type_label remains would-collapse, unchanged on purpose: it is a selector, and changing one quietly is worse than a stale word inside it.
/status reports the license ceiling and any node clamp as separate lines, deliberately: a clamped node is held to monitor by a portal-side verdict rather than by your license, so an operator reading one must not be sent to upgrade a license that was never the constraint. node_clamp: none means no clamp applies and the node is fully protected.
In-Cluster Dashboard
The in-cluster dashboard shipped as an optional component of the pando-webhook chart, off by default, and it worked by polling each protected pod's sidecar on port 9090. Neither that chart nor those per-pod endpoints is part of the supported install: a node sensor serves one /status per node, not one per pod. It receives no further release.
Use the portal for detections, Prometheus for coverage and health, and kubectl for current state. Between them they cover everything it showed, and the Prometheus route covers the coverage question it never answered.
Troubleshooting
The portal shows no activity
- Confirm the sensors are ready:
/readyzreturns 503 during learning and while refusing - Confirm the controller is running and receiving. It is what delivers to the portal, so healthy sensors with an empty portal is a controller question
- Check the controller's logs for delivery errors, and your egress rules for blocked outbound calls
Prometheus shows no PandoCore data
- Check your job selects
app.kubernetes.io/name=pando-node-sensorrather than the protect label - Confirm the metrics port is 9090
- On GKE managed Prometheus, confirm
metrics.podMonitoring.enabled=true
Some pods never appear
Check pando_node_sensor_pods_unmonitored{reason="cap"} first. Then check whether the pod is opted out, in an excluded namespace, or using hostPID or hostNetwork. See Troubleshooting.
Next Steps
- Evidence Format: the record schema and its wire fields
- Controller: configuring destinations
- Configuration: metrics and alerting values
- Production Hardening: what to alert on before production