Skip to main content
Docs / Configuration

Configuration Reference

The knobs that matter, and the defaults you should leave alone.

PandoCore is configured in three places, and which one you reach for depends on the scope of what you are changing.

Scope Where
How the sensor runs on a node Node sensor Helm values
Where evidence goes Controller Helm values. See Controller
How a namespace behaves A PandoCorePolicy. See CRD Policy
One workload A pod annotation

Node Sensor Helm Values

Value Default Notes
namespace pando-system Where the sensor and mirror run
createNamespace false Leave off and use Helm's own --create-namespace. Setting it true over a namespace Helm did not create fails with invalid ownership metadata
license.key "" Inline key. One of this or license.existingSecret.name must be set
license.existingSecret.name "" An externally managed Secret. Prefer this wherever the values file is committed
sampleIntervalMs 1000 Sampling cadence. Floor is 250; below that the sensor refuses by name at startup rather than clamping. At 250 the cost is roughly four times the default
maxEngines 70 Monitored pods per node. Range 1 to 500. Pods beyond it get no engine
port 9090 Serves /metrics, /healthz, /readyz and /status
excludedNamespaces Eleven names Replaces the list rather than adding to it. See the warning below
includedNamespaces [] Protect a namespace a default rule excludes. See the warning below
resources 250m / 256Mi, limit 2 / 1Gi Per node
nodeSelector {} Restricts which nodes get a sensor. Nodes without one are unwatched
tolerations Tolerate everything Deliberate: a node left unwatched because the sensor would not schedule there is a silent gap
maxUnavailable 1 DaemonSet rollout speed. Each node is briefly unwatched as its sensor restarts
preflight.nodeCapacity true Refuses the install for nodes that cannot allocate the CPU request
controller.* Service name, namespace, port The evidence URL is composed from these parts rather than written by hand
mirror.enabled true The destinations mirror. Off means per-namespace policy integrations do nothing
portalURL The production portal Where the sensor attests its evidence-signing key
metrics.scrapeAnnotations true Prometheus scrape annotations on both pod templates
metrics.podMonitoring.enabled false Required on GKE managed Prometheus. See the warning below
alerts.enabled true Ships PrometheusRules for coverage, absence, refusal and cadence
logging.level info With logging.json: true by default
stateHostPath /var/lib/pando Host path, deliberately not a PersistentVolumeClaim
seLinuxLevel "" Only meaningful where SELinux enforces for containers. Required on Bottlerocket
Two namespace values that do not behave as their names suggest

excludedNamespaces: [] does not mean "exclude nothing". An empty list is read as unconfigured and falls back to the built-in eleven. To protect a default-excluded namespace, add it to includedNamespaces.

includedNamespaces overrides more than the namespace list. The opt-in is read before the exclusion rules and overrides the own-component exclusion as well, so listing pando-system puts PandoCore's own pods back under monitoring. An early soak run in that configuration took 67 false positives in six minutes, 34 of them from the controller pod. It does not override the sensor's own pod, hostPID, hostNetwork, or a pod's own opt-out label.

On GKE managed Prometheus, the shipped alerting rules are inert

Managed Prometheus does not honour the scrape annotations, so metrics.podMonitoring.enabled=true is the only thing that makes it scrape at all. It also reads neither the alert-rules ConfigMap nor a PrometheusRule, so the rules the chart ships are present but do nothing on that platform until they are converted to its own Rules resource.

This matters because the coverage and absence rules are the ones that tell you a node has stopped being watched. If you run managed Prometheus, port those two across by hand rather than assuming the chart covered you.

Per-Pod Annotations

Six annotations apply to one workload. Each is read when the sensor starts watching a pod, so a change applies to pods created after it; kubectl rollout restart is what applies it to pods already running.

Annotation Effect
pandocore.io/mode monitor, alert, isolate or debug. Can only narrow what the license permits
pandocore.io/profile http-server selects that profile's detection weights. Any other value leaves the inferred profile alone
pandocore.io/target-container Which container's processes the engine is for
pandocore.io/audit-network Network auditing for this workload
pandocore.io/network-allowlist Expected network peers, taken verbatim
pandocore.io/egress-allowlist-hosts Expected egress hosts
The annotations do not share one dialect

mode and profile are matched exactly, with no trimming and no case folding. audit-network is trimmed and lowercased. network-allowlist is taken verbatim and egress-allowlist-hosts is trimmed. That inconsistency is inherited from the webhook deliberately, so that migrating to the sensor does not change what an annotation you already had means. A mode value that does not match falls back to the node-wide default and the sensor warns naming the pod.

The opt-out label

Not an annotation, and the one setting that does not need a restart:

kubectl label pod <pod> pandocore.io/protect=false --overwrite

It is evaluated every reconcile pass, so a running pod stops being watched on the next scan. The comparison is byte-for-byte against "false", with no trimming and no case folding, so False and 0 do not opt a pod out. The deprecated webhook's "true" value has no effect at all.

Three Annotations The Sensor Cannot Honour

pandocore.io/full-proc-signals, pandocore.io/provenance-enforce and pandocore.io/node-enforcer were applied at admission, by rewriting a pod before it was created. A sensor is outside the pod and runs after it exists, so none of them can be applied. The sensor warns once per pod carrying one, and the pod is still watched. See Production Hardening.

What You Can't Configure

Detection internals are managed automatically and not user-tunable. Use sensitivity in a policy, and thresholds within it for finer numeric control. If neither settles a workload, contact support.

Two ceilings are also not configuration. The sensor caps its response at isolate in code, and its ClusterRole withholds pods: delete by name, so no value raises it. And a portal-side node clamp is a commercial verdict rather than a cluster setting.

Examples

Production install

helm install pando-node-sensor \
  oci://us-central1-docker.pkg.dev/pandocore-prod/charts/pando-node-sensor \
  --version 2.0.0 \
  --namespace pando-system --create-namespace \
  --set license.existingSecret.name=pando-license \
  --set 'excludedNamespaces={kube-system,kube-public,kube-node-lease,cert-manager,istio-system}' \
  --set metrics.podMonitoring.enabled=true

One workload, narrowed to monitor

kubectl annotate deployment your-app pandocore.io/mode=monitor --overwrite
kubectl rollout restart deployment/your-app

Next Steps