Documentation menu

Any Kubernetes cluster

What the StackRadar scanner needs from any conformant Kubernetes cluster — k3s, kubeadm, OpenShift, Rancher or managed cloud — plus upgrades and uninstall.

The scanner is a standard Kubernetes workload installed with Helm — it doesn't depend on any cloud provider API, CRDs, or admission webhooks. If your distribution runs upstream Kubernetes (k3s, kubeadm, OpenShift, Rancher, VMware Tanzu, DigitalOcean, Hetzner, a homelab…), this guide applies. For EKS, GKE, and AKS there are dedicated guides with platform-specific networking notes: EKS, GKE, AKS.

Want to see the dashboard before installing anything? Open the live demo — read-only, no account needed.

What the scanner needs from a cluster

Every platform difference reduces to these five things:

RequirementDetail
A working kubectl contextWith permission to create a namespace and install workloads. How you obtain credentials is the main thing that varies per platform.
Kubernetes1.24 or newer.
Helm3.8 or newer (or Helm 4) — 3.8 is the floor for OCI charts.
Ability to pull the scanner imageFrom the public registry, or from your own registry if you mirror it (see restricted-network installs).
Outbound HTTPS to api.stackradar.ioPort 443, the single endpoint used for SBOM uploads and heartbeats. NAT, egress proxies, and firewalls are fine as long as this path exists.

A useful rule of thumb: if your workloads can pull public container images, the scanner will run and report. There are no privileged host requirements, node agents, or kernel modules involved.

  1. Install

    Create a cluster in the StackRadar dashboard and copy its cluster ID and cluster-scoped API key (see API keys & cluster scoping):

    bash
    export STACKRADAR_API_KEY=<your-api-key>
    export STACKRADAR_CLUSTER_ID=<your-cluster-id>

    Then install the scanner chart (Helm 3.8+ for the OCI method). The command pins the current release, 0.3.0 — published versions are immutable, so the install is reproducible.

    bash
    helm install stackradar-scanner \
        oci://ghcr.io/lockdep/charts/stackradar-scanner \
        --version 0.3.0 \
        --namespace stackradar --create-namespace \
        --set stackradar.apiKey=$STACKRADAR_API_KEY \
        --set stackradar.clusterId=$STACKRADAR_CLUSTER_ID
  2. Verify

    bash
    kubectl get pods --namespace stackradar

    Once the pod is Running, the scanner sends a heartbeat and the cluster shows as connected in the dashboard. Expect the first findings within minutes. If the cluster never connects, see Troubleshooting.

Configuration

The two required values are stackradar.apiKey and stackradar.clusterId. Everything else has defaults; list the full set of configurable values with:

bash
helm show values oci://ghcr.io/lockdep/charts/stackradar-scanner

You don't have to hand the credentials to Helm at all. The chart's canonical flow is to install without them and create the Secret yourself:

bash
kubectl create secret generic stackradar-scanner \
    --namespace stackradar \
    --from-literal=cluster-id=$STACKRADAR_CLUSTER_ID \
    --from-literal=api-key=$STACKRADAR_API_KEY

Until that Secret exists the scanner pod waits in CreateContainerConfigError — expected, not broken — and the kubelet picks the Secret up by itself once created, usually within a minute, with no helm upgrade or pod restart needed. (The Secret name matches the release name; the chart's install notes print the exact command.) Worth knowing before you choose: --set stackradar.apiKey also lands the key in the Helm release Secret and in your shell history.

For anything beyond the two credentials, prefer a values file over a chain of --set flags — it can live in git (minus the key) and makes upgrades reproducible:

bash
helm upgrade --install stackradar-scanner \
    oci://ghcr.io/lockdep/charts/stackradar-scanner \
    --namespace stackradar --create-namespace \
    --set stackradar.apiKey=$STACKRADAR_API_KEY \
    --values my-values.yaml
Keep the API key out of the values file and out of git — inject it at deploy time from your CI secret store or secret manager, as above. See API keys & cluster scoping.

Choosing what gets scanned

By default every namespace is scanned except kube-system, kube-public, and kube-node-lease. scanner.excludeNamespaces extends that denylist; scanner.includeNamespaces turns it around into an allowlist — set it and only the namespaces you name are scanned. For images that run everywhere (pause containers, injected sidecars), scanner.excludeImages takes glob patterns matched against the image name with its tag stripped, e.g. registry.k8s.io/*,*/pause — a matching image is never pulled, scanned, or uploaded.

The chart also writes a NetworkPolicy for the scanner pod by default (networkPolicy.enabled) — see restricted-network installs for what it allows.

Upgrading

bash
helm upgrade stackradar-scanner \
    oci://ghcr.io/lockdep/charts/stackradar-scanner \
    --version 0.3.0 \
    --namespace stackradar --reuse-values

Pin --version here too — published versions are immutable, so the upgrade is a pin to exact bytes. Note that --reuse-values carries your old values forward frozen, including any defaults that changed between chart versions; when in doubt, pass your values file explicitly instead. The dashboard shows each cluster's reported scanner version, so you can see at a glance which clusters are behind.

Uninstalling

bash
helm uninstall stackradar-scanner --namespace stackradar
kubectl delete namespace stackradar

Then revoke the cluster's API key in the dashboard. Already-uploaded SBOMs and scan history remain until you delete the cluster there too.

Notes for common distributions

  • GitOps (Argo CD / Flux) — the chart works as a normal Helm source. Rather than putting the key in values, deliver a Secret with cluster-id and api-key keys through your sealed-secrets, external-secrets, or SOPS pipeline and point the chart at it with stackradar.existingSecret — the chart then creates no Secret of its own. If your Secret uses different key names, map them with stackradar.existingSecretKeyApiKey and stackradar.existingSecretKeyClusterId.
  • OpenShift and other policy-enforcing platforms — the scanner runs as an ordinary unprivileged workload, but the chart pins a fixed UID (runAsUser: 65534), which OpenShift's restricted SCC typically rejects in favour of a namespace-assigned UID range — expect to review and adjust the security context defaults there. Inspect them with helm template, or browse its manifests, values, and version history on Artifact Hub — the same way you vet any third-party chart.
  • Single-node / edge clusters (k3s, k0s, microk8s) — no special configuration; the scanner is a single deployment requesting 50m CPU and 512Mi of memory, with a 1Gi memory limit. It runs one scan at a time because syft can use 300–600 MiB on a large image — so budget for that peak before running it on genuinely constrained hardware.
  • Clusters behind proxies or with filtered egress — see private registry & restricted-network installs.

What happens after install

The scanner reports the cluster's workload inventory first — namespaces, workloads, containers, plus the Helm releases and GitOps applications that deliver them — so the dashboard shows every discovered workload and its scan coverage right away. Its first pass covers the whole cluster, not just new deploys: the initial sync lists every pod already running, and each container image is queued for scanning immediately. The scanner generates a CycloneDX SBOM per image and uploads it for matching against 900K+ OSV.dev advisories, then keeps coverage current as pods start, restart, or change — no scan schedules to configure. See architecture & data flow for what runs where and exactly what data leaves the cluster.

Next steps