The Namespaces That Must Never Route Through Harbor: Every Loop, Written Down

Harbor pulling through itself is the obvious loop — but kyverno with failurePolicy=Fail is the measured worst case: Harbor down means no pod creation cluster-wide, including the pods needed to repair Harbor.

The Namespaces That Must Never Route Through Harbor: Every Loop, Written Down

Every exclusion in the routing policy exists because routing that namespace would make Harbor depend on something that depends on Harbor. Some are obvious. The worst one is measured, not assumed.

The loop table

NamespaceImagesWhy routing it breaks recovery
harbor10 goharbor/*cannot pull itself through itself — unrecoverable after a full outage
kyverno6 reg.kyverno.io/*webhooks are failurePolicy=Fail — the single most important exclusion
flux-system4 fluxcd/*Flux deploys the fix — losing it mid-incident is the worst moment
envoy-gateway-system2 envoyproxy/*terminates Harbor's ingress — no Envoy, no reachable Harbor
cert-manager3 jetstack/*issues Harbor's TLS — expiry plus inability to start is a deadlock
external-secrets1supplies Harbor's credentials — no secrets, no Harbor
dragonfly-operator-system2runs Harbor's Redis — Harbor will not start without it

Plus kube-system: Cilium is the CNI Harbor itself needs to serve traffic. Routing the control plane is routing your own recovery.

Each exclusion is a loop: Harbor needs it, it needs Harbor
Each exclusion is a loop: Harbor needs it, it needs Harbor

The full exclusion list with its failure modes — and the kyverno row, which deserves its own sentence.

The kyverno row, measured

The manifest comment does not assert the risk; it walks the chain: Harbor down → Kyverno cannot pull → Kyverno down → its admission webhooks have failurePolicy=Fail, so the API server refuses matching pod creation cluster-wide — including the pods needed to repair Harbor. That is why the kyverno exclusion is called the single most important one.

A finer point from the same analysis: dragonflydb/dragonfly itself is routable — it also runs in gitlab, so it gets cached and scanned through that namespace while harbor keeps pulling direct. Only the operator is excluded. The exclusions apply to namespaces, and an image's fate follows every namespace it runs in.

Reading a loop aloud

Each exclusion is easier to trust when the loop is spoken as a sentence. The kyverno one, at full length: Harbor is down; a Kyverno pod needs to start (or restart); its image lives on reg.kyverno.io, which — if kyverno were routed — Harbor would fetch through itself; Harbor cannot fetch, so Kyverno stays down; Kyverno's admission webhooks have failurePolicy=Fail, so the API server rejects matching pod creation cluster-wide; the Harbor pods someone just tried to create to fix Harbor are themselves rejected. The loop closes. No ordering of recovery steps breaks it, because every recovery step requires creating a pod, and pod creation is the thing that is down.

The harbor exclusion is the same sentence with the middle removed: Harbor cannot pull itself through itself. After a full outage — control-plane included — the first Harbor pod has no cache, no source, and no path.

The near-loops that are not on the list

The analysis also identified couplings that look like exclusions but are not, and the distinction matters for future components:

  • dragonflydb/dragonfly runs in gitlab as well as harbor — the gitlab instance is routable and gets cached and scanned; only the operator (solely in dragonfly-operator-system) is excluded. An image's fate follows every namespace it runs in; an image with one safe home is a routable image.
  • flux-system is "not a strict loop" — Flux does not serve Harbor's traffic — but it deploys the fix, and losing the deployer during a Harbor incident is the worst possible moment. Excluded on operational grounds, and labeled as such.

The documentation therefore records, per exclusion, which kind of reason applies: hard loop, recovery-path loss, or governance. That taxonomy is what makes the list extendable — a new component is classified, not argued.

The test for candidates

The runbook's implicit test, made explicit: for component X to be routable, there must exist a recovery path for Harbor that does not require creating a pod whose image X serves, guards, authenticates, or deploys. Harbor's recovery path currently runs through: the CNI (Cilium), ingress (Envoy), TLS (cert-manager), credentials (external-secrets), cache (dragonfly), policy (Kyverno), and deployment (Flux). Seven components, seven exclusions, one sentence each.

Next: the bare reference — the one image tag in the repo that must never be fully qualified.