Private registries & restricted networks
Run the StackRadar scanner behind private registries or restricted egress: registry credentials, chart and image mirroring, proxies, and the endpoint to allow.
Many clusters can't pull from public registries or have tightly filtered egress. This guide covers the four patterns that make the StackRadar scanner work there: giving it credentials for your private registries, mirroring the chart and image into your own registry, routing through an egress proxy, and allowlisting the one endpoint the scanner needs.
api.stackradar.io. Everything else — the chart, the image, all image pulls — can come from inside your network.What the scanner needs, exactly
| Requirement | Can be internal? |
|---|---|
Helm chart (stackradar-scanner) | Yes — mirror to any OCI registry or internal chart repo |
| Scanner container image | Yes — mirror to your private registry |
| Read access to the registries your workloads run from | Yes — the scanner pulls images over your own network, never through StackRadar |
SBOM uploads & heartbeats — HTTPS to api.stackradar.io | No — allowlist directly or route via egress proxy |
Notably, the scanner does not need to download a vulnerability database into your cluster. Vulnerability matching happens server-side against StackRadar's continuously synced OSV.dev mirror, so there is no nightly feed download to allowlist and no stale in-cluster database to maintain. See how vulnerability matching works.
Authenticating to a private registry
The scanner pulls every image it scans itself, from the registry, rather than reading layers off the node. So for any workload running from a private registry it needs credentials of its own. This is what the cluster page's coverage card means when it shows “Registry authentication failed” naming a registry host: the registry rejected the scanner's pull, and those images will never get an SBOM until it has credentials — waiting does not fix it. (A “rate-limited, retrying” row is different: that one heals on its own and needs no credentials.) There are two ways the scanner gets credentials, and they combine. Once configured, the next scan uploads and the error clears on its own — no manual reset.
Reusing the pull Secrets your workloads already have
When a pod declares imagePullSecrets, the scanner can read those Secrets in the pod's own namespace and use them to pull that pod's images. It is off by default, because it costs one permission — secrets get in the scanner's ClusterRole — and the chart will not grant that on every Secret in the cluster. Turning it on means naming the pull Secrets it may read, which the chart translates into an RBAC resourceNames restriction; leave the list empty and the install fails rather than rendering a cluster-wide grant.
Find the Secret names on the pods that pull from the private registry. Ask the pods, not the Deployment or CronJob: when the Secret is attached to a ServiceAccount (DigitalOcean's registry integration does this), Kubernetes copies it onto each pod at creation and the controller's template stays empty.
kubectl get pods -n <namespace> -o jsonpath='{range .items[*]}{.metadata.name}: {.spec.imagePullSecrets[*].name}{"\n"}{end}'If the pods are gone — a finished Job — read the ServiceAccounts in that namespace instead:
kubectl get sa -n <namespace> -o jsonpath='{range .items[*]}{.metadata.name}: {.imagePullSecrets[*].name}{"\n"}{end}'helm upgrade stackradar-scanner oci://ghcr.io/lockdep/charts/stackradar-scanner \
--namespace stackradar --reuse-values \
--set-string scanner.resolveImagePullSecrets=true \
--set 'scanner.imagePullSecretNames={regcred,ghcr-creds}'Two things to know before you set it. Names match in every namespace — a Secret called regcred anywhere in the cluster becomes readable — so use distinct names if that distinction matters to you. And a Secret left off the list is simply denied: images that needed it fall back to an anonymous pull, and the scanner logs a warning naming the Secret and its namespace rather than failing the sweep.
imagePullSecrets on the pod at all, which is the common setup on a managed cluster — there is nothing for the scanner to reuse, and those images fall back to an anonymous pull that fails. Give it a credential of its own, below.Giving the scanner its own credential
dockerConfigSecret points the scanner at a standard Docker config Secret, mounted read-only. It covers every pull that the pod's own imagePullSecrets did not; where both apply to the same registry, the workload's credential wins.
kubectl create secret docker-registry stackradar-registry \
--namespace stackradar \
--docker-server=<registry-host> \
--docker-username=<username> \
--docker-password=<password>
helm upgrade stackradar-scanner oci://ghcr.io/lockdep/charts/stackradar-scanner \
--namespace stackradar --reuse-values \
--set dockerConfigSecret=stackradar-registryThe credential should be read-only and scoped to the repositories you want scanned. Note that on ECR a registry password is a 12-hour token, so a static Secret there needs a refresh job of your own — a robot account with a long-lived credential, where your registry offers one, is the easier path.
Cloud workload identity
On EKS, GKE and AKS the idiomatic alternative to a static credential is giving the scanner's ServiceAccount a cloud identity with read access to your registry, so the pod receives short-lived credentials from the cloud instead. The chart exposes the hooks each cloud's mechanism expects:
- EKS (IRSA) — annotate the ServiceAccount with
serviceAccount.annotations."eks.amazonaws.com/role-arn", pointing at a role with ECR read access. - GKE (Workload Identity) —
serviceAccount.annotations."iam.gke.io/gcp-service-account", bound to a Google service account with Artifact Registry reader. - AKS (Azure Workload Identity) — set
podLabels."azure.workload.identity/use": "true"and the client ID viapodAnnotations."azure.workload.identity/client-id", for an identity withAcrPull.
The per-platform install guides carry the full setup for each; where workload identity is not an option, dockerConfigSecret above is the fallback known to work everywhere.
imagePullSecrets value, which is how the kubelet pulls the scanner's own image when you have mirrored it into a private registry. That one is about starting the scanner; the two above are about what the scanner can scan once it is running.Mirroring the chart and image
Check the current chart version and default values on Artifact Hub, then pull the chart from the public OCI registry on a connected machine:
helm pull oci://ghcr.io/lockdep/charts/stackradar-scanner --version <version>Pin --version — for a mirror, reproducibility is the point: the .tgz you push is then exactly the bytes you reviewed, not whatever the registry considered latest that day. Push it to your internal registry (any OCI-compliant registry works — Harbor, ECR, Artifact Registry, ACR, Nexus):
helm push stackradar-scanner-<version>.tgz oci://registry.internal.example.com/chartsMirror the scanner image the same way you mirror other public images (e.g. with crane copy, skopeo copy, or your registry's proxy-cache feature). One constraint: released charts pin the scanner image by digest (image.digest), so your mirror must hold a byte-identical copy — crane copy and skopeo copy preserve digests, as does a proxy-cache. If you rebuild or re-sign the image, its digest changes, and you must clear image.digest (and set image.tag) — the digest wins over the tag, so without clearing it the pull asks your registry for bytes it doesn't hold and fails. List the chart's default image references and configurable values with:
helm show values oci://ghcr.io/lockdep/charts/stackradar-scannerThen install from your internal registry, overriding the image repository values shown by helm show values to point at your mirror:
helm install stackradar-scanner \
oci://registry.internal.example.com/charts/stackradar-scanner \
--namespace stackradar --create-namespace \
--set stackradar.apiKey=$STACKRADAR_API_KEY \
--set stackradar.clusterId=$STACKRADAR_CLUSTER_ID \
--values internal-registry-overrides.yamlIn these environments credentials rarely belong on the command line at all. If a sealed-secrets, external-secrets, or SOPS pipeline delivers your Secrets, give it a Secret with cluster-id and api-key keys and point the chart at it with stackradar.existingSecret instead of the two --set flags above — the chart then creates no credentials Secret of its own.
Restricted egress
- Firewall allowlist — allow outbound HTTPS (TCP 443) to
api.stackradar.io. No other StackRadar endpoint is contacted by the scanner. - Egress proxy — set
proxy.httpsProxy(andproxy.noProxyfor your internal registries) and the chart putsHTTPS_PROXY/NO_PROXYon the pod and routes the agent's own API calls through the proxy too. Include the scheme —proxy.corp:8080is rejected at install time. The in-cluster Kubernetes API is always exempted, so you only list your own hosts. If the proxy terminates TLS, add your CA withcaBundle.configMapName— orcaBundle.secretNamewhen your secrets pipeline delivers the bundle as a Secret. - NetworkPolicy — the chart ships its own, on by default (
networkPolicy.enabled): a policy allowing egress to DNS, the Kubernetes API server, and TCP 443 (the StackRadar API and your registries), and nothing else —networkPolicy.egressreplaces those defaults when you want to narrow the 443 rule to known CIDRs, or add a registry on another port. The flip side under default-deny ingress: the kubelet must still reach the scanner's health port, or its probes fail and the pod restarts in a loop — the chart's policy already allows that ingress, so prefer it over hand-writing one.
What actually leaves the network
Uploads are CycloneDX SBOM documents: package names, versions, and identifiers (PURLs) for each container image, plus cluster/workload metadata so results are attributable. No source code, no environment variables, no secrets, and no image contents are transmitted — and all data is stored in the EU. Details in architecture & data flow.
Next steps
- Architecture & data flowHow the StackRadar scanner works: what runs in your cluster, exactly what data leaves it, how SBOMs are matched to vulnerabilities, and where data is stored.
- TroubleshootingFixes for common StackRadar scanner issues: 401/403 API errors, a cluster that never appears in the dashboard, Helm install failures, and missing SBOMs.