From ae84884fe5636ed987d828ad70d0055d5a92702c Mon Sep 17 00:00:00 2001 From: Adam Weingarten <6517820+aweingarten@users.noreply.github.com> Date: Tue, 28 Jul 2026 10:55:02 -0400 Subject: [PATCH] feat(netpols): ship the Harbor database allow-rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under default-deny the CloudNativePG operator can't poll the Harbor Postgres instances for status (8000) or metrics (9187) across namespaces, so the replica never starts and the stack stalls: Instance Status Extraction Error → ClusterIsNotReady → Degraded. As with the other gaps, nothing in that symptom points at a NetworkPolicy. Adds `netpols.harborDb`, driven by `apps.harbor.networkPolicies.enabled` (default false) and only rendered when harbor is enabled. The policy is scoped to the harbor-otomi-db instances rather than the whole harbor namespace. Harbor's component surface is wide — core, jobservice, registry, trivy, exporter, redis — and a namespace-wide Ingress policy would have to enumerate all of it correctly or take the registry down. The database is where the documented gap is, so that is what this selects. Alongside the operator it allows the harbor namespace itself (components reaching Postgres, instances replicating to each other) and prometheus on 9187, so enabling the policy doesn't trade one silent breakage for another. Refs #3387 --- .../templates/networkpolicies/harbor-db.yaml | 47 +++++++++++++++++++ charts/apl-network-policies/values.yaml | 9 ++++ helmfile.d/snippets/defaults.yaml | 2 + values-schema.yaml | 2 + .../apl-network-policies.gotmpl | 2 + 5 files changed, 62 insertions(+) create mode 100644 charts/apl-network-policies/templates/networkpolicies/harbor-db.yaml diff --git a/charts/apl-network-policies/templates/networkpolicies/harbor-db.yaml b/charts/apl-network-policies/templates/networkpolicies/harbor-db.yaml new file mode 100644 index 0000000000..7a02e43b9a --- /dev/null +++ b/charts/apl-network-policies/templates/networkpolicies/harbor-db.yaml @@ -0,0 +1,47 @@ +{{- if .Values.netpols.harborDb }} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: harbor-db-platform-policy + namespace: harbor + labels: + {{- include "apl-network-policies.labels" . | nindent 4 }} + app: harbor +spec: + # Scoped to the Harbor CloudNativePG instances rather than the whole harbor namespace: Harbor has + # a wide component surface (core, jobservice, registry, trivy, exporter, redis) and a + # namespace-wide Ingress policy would have to enumerate all of it correctly or take the registry + # down. The database is where the documented default-deny gap actually is. + podSelector: + matchLabels: + cnpg.io/cluster: harbor-otomi-db + policyTypes: + - Ingress + ingress: + # Allow the CloudNativePG operator to poll instance status (8000) and metrics (9187). + # Without this the operator cannot read instance status, the Harbor Postgres replica never + # starts, and the stack stalls on Instance Status Extraction Error → ClusterIsNotReady → + # Degraded — with nothing in the symptom pointing at a NetworkPolicy. + - from: + - namespaceSelector: + matchLabels: + name: cnpg-system + # Allow the Harbor components (core, jobservice, registry, exporter, trivy) to reach Postgres, + # and the instances to reach each other for replication. + - from: + - namespaceSelector: + matchLabels: + name: harbor + # Allow monitoring access + - from: + - namespaceSelector: + matchLabels: + name: monitoring + podSelector: + matchLabels: + app.kubernetes.io/instance: po-prometheus + ports: + - protocol: TCP + port: 9187 +{{- end }} diff --git a/charts/apl-network-policies/values.yaml b/charts/apl-network-policies/values.yaml index 7c0f0a7adb..d12df3a02e 100644 --- a/charts/apl-network-policies/values.yaml +++ b/charts/apl-network-policies/values.yaml @@ -32,5 +32,14 @@ # * Monitoring namespace (for metrics scraping) # * Internal otomi namespace communication # +# For harbor (netpols.harborDb: true): +# - Creates a NetworkPolicy in the harbor namespace, scoped to the CloudNativePG instances of +# harbor-otomi-db (not the whole namespace — Harbor's component surface is wide) +# - Allows ingress from: +# * cnpg-system (operator polling instance status on 8000 and metrics on 9187) +# * the harbor namespace (components reaching Postgres; instances replicating to each other) +# * Monitoring namespace on 9187 (for metrics scraping) +# - Only rendered when harbor is enabled +# # The complex network policy rules are baked into the chart templates, # so users only need to toggle network policies on/off per application. diff --git a/helmfile.d/snippets/defaults.yaml b/helmfile.d/snippets/defaults.yaml index 7d9d569960..b8f3683fc0 100644 --- a/helmfile.d/snippets/defaults.yaml +++ b/helmfile.d/snippets/defaults.yaml @@ -199,6 +199,8 @@ environments: _rawValues: {} harbor: enabled: false + networkPolicies: + enabled: false oidcAutoOnboard: true oidcUserClaim: email registry: diff --git a/values-schema.yaml b/values-schema.yaml index ce355a21ee..52a04f227c 100644 --- a/values-schema.yaml +++ b/values-schema.yaml @@ -1690,6 +1690,8 @@ properties: properties: _rawValues: $ref: '#/definitions/rawValues' + networkPolicies: + $ref: '#/definitions/appNetworkPolicyConfig' enabled: type: boolean default: true diff --git a/values/apl-network-policies/apl-network-policies.gotmpl b/values/apl-network-policies/apl-network-policies.gotmpl index cb3798134e..d5a54f043e 100644 --- a/values/apl-network-policies/apl-network-policies.gotmpl +++ b/values/apl-network-policies/apl-network-policies.gotmpl @@ -1,12 +1,14 @@ {{- $v := .Values }} {{- $a := $v.apps }} {{- $oa := $v.apps | get "otomi-api" }} +{{- $h := $v.apps | get "harbor" }} # Simple per-app network policy configuration netpols: gitServer: {{ not ($a | get "git-server.enabled") }} gitea: {{ $a.gitea.networkPolicies.enabled}} otomiApi: {{ $oa.networkPolicies.enabled}} + harborDb: {{ and ($h.networkPolicies.enabled) ($h.enabled) }} ingressGatewaySelectors: - namespaceSelector: