diff --git a/charts/app-reverse-proxy/Chart.yaml b/charts/app-reverse-proxy/Chart.yaml index d3be339..22487d2 100644 --- a/charts/app-reverse-proxy/Chart.yaml +++ b/charts/app-reverse-proxy/Chart.yaml @@ -2,9 +2,9 @@ apiVersion: v2 name: charts-app-reverse-proxy description: EcoVadis Helm chart for application exposed with nginx reverse proxy type: application -version: 3.2.0 +version: 3.3.0 appVersion: 1.16.0 dependencies: - name: charts-core - version: 2.10.0 + version: 2.11.0 repository: "https://ecovadiscode.github.io/charts/" diff --git a/charts/core/Chart.yaml b/charts/core/Chart.yaml index 7e1a607..c528d0c 100644 --- a/charts/core/Chart.yaml +++ b/charts/core/Chart.yaml @@ -2,4 +2,4 @@ apiVersion: v2 name: charts-core description: A Helm chart for Kubernetes type: application -version: 2.10.0 +version: 2.11.0 diff --git a/charts/core/templates/_helpers.tpl b/charts/core/templates/_helpers.tpl index 35e4da2..e349f0c 100644 --- a/charts/core/templates/_helpers.tpl +++ b/charts/core/templates/_helpers.tpl @@ -94,4 +94,26 @@ Construct Prometheus host with port {{- fail ".Values.global.envVars is present, bud does not contain ASPNETCORE_ENVIRONMENT" }} {{- end }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} + +{{/* +Dataplane detection. + +Returns "true" when the target cluster runs Cilium, which decides whether +cilium-network-policy.yaml or network-policy.yaml renders. Detection is +automatic - there is no value to set and no per-cluster configuration. + +A cluster is treated as Cilium when the API server serves the cilium.io/v2 CRD. +Azure CNI Powered by Cilium registers it, NPM clusters do not, so the same chart +version deploys correctly to both during the migration. + +Caveat: `helm template` runs offline and reports no cluster capabilities, so it +always renders the Kubernetes NetworkPolicy. Pass --api-versions cilium.io/v2 to +preview the Cilium output. `helm install` / `helm upgrade` query the live +cluster, so detection works as intended for real deployments. +*/}} +{{- define "charts-core.useCilium" -}} +{{- if or (.Capabilities.APIVersions.Has "cilium.io/v2") (.Capabilities.APIVersions.Has "cilium.io/v2/CiliumNetworkPolicy") -}} +true +{{- end -}} +{{- end -}} diff --git a/charts/core/templates/cilium-network-policy.yaml b/charts/core/templates/cilium-network-policy.yaml new file mode 100644 index 0000000..f35b008 --- /dev/null +++ b/charts/core/templates/cilium-network-policy.yaml @@ -0,0 +1,161 @@ +{{- if and .Values.global.defaultNetworkPolicyEnabled (eq (include "charts-core.useCilium" .) "true") -}} +{{/* + CiliumNetworkPolicy equivalent of network-policy.yaml, for clusters running + Azure CNI powered by Cilium. + + Only one of the two templates renders per release - see the + "charts-core.useCilium" helper in _helpers.tpl. + + This is NOT a line-for-line translation. Cilium enforces policy through a + per-endpoint BPF map (cilium_policy_v2_, default 16384 entries) keyed on + (identity, port, protocol, direction), so a selector matching every pod in the + cluster costs one entry per identity PER PORT. The `namespaceSelector: {}` + peers in network-policy.yaml cost ~18 entries per cluster identity, which + overflows the map on a large cluster and blocks pod creation on the node. + + Rules, in both directions: + - pods talk to any pod in the SAME ENVIRONMENT, on any port + - plus explicit exceptions: kube-dns, and the monitoring namespace when + monitoring is enabled + - nodes and the API server are always reachable + Everything leaving the cluster is allowed on any port - outbound traffic is + filtered by Azure Firewall, not here. +*/}} +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: {{ include "charts-core.fullname" . }} + labels: + {{- include "charts-core.labels" . | nindent 4 }} + networkPolicyType: default +spec: + endpointSelector: + matchLabels: + {{- include "charts-core.selectorLabels" . | nindent 6 }} + + ingress: + # --- same namespace, all ports (NP ingress rule 1) --- + - fromEndpoints: + - matchLabels: + k8s:io.kubernetes.pod.namespace: {{ .Release.Namespace }} + + {{- if .Values.global.allowAllInternalClusterTrafficNetworkPolicy }} + # --- any pod in the cluster, all ports (NP ingress rule 2, allowAll variant) --- + # + # `- {}` would mean "all endpoints in THIS namespace" - a namespaced CNP + # implicitly scopes an empty selector to its own namespace. Matching every + # namespace requires the Exists operator on the namespace label. + - fromEndpoints: + - matchExpressions: + - key: "k8s:io.kubernetes.pod.namespace" + operator: "Exists" + {{- else }} + # --- same environment (*-infra, *-backend, *-frontend), all ports (NP ingress rule 2) --- + - fromEndpoints: + - matchLabels: + k8s:io.cilium.k8s.namespace.labels.environment: {{ (split "-" .Release.Namespace)._0 }} + {{- end }} + + {{- if .Values.global.monitoring.servicemonitor.enabled }} + # --- prometheus scrape, all ports (NP ingress rule 3) --- + - fromEndpoints: + - matchLabels: + k8s:io.cilium.k8s.namespace.labels.environment: {{ .Values.global.monitoring.prometheusNamespace }} + {{- end }} + + # --- outside world + node-sourced traffic (NP ingress rule 4) --- + # + # world : genuine external clients (sentry, optimizely, probes) + # host / + # remote-node : LoadBalancer and NodePort Services on the default + # externalTrafficPolicy: Cluster SNAT the client to a node IP. + # Node addresses resolve to host/remote-node, which no CIDR + # selector can ever match. NPM did not enforce ingress policy + # on this path at all; Cilium does, so it must be stated. + # + # The namespaceSelector/podSelector peers on the NPM rule are NOT translated + # here - in-cluster clients are already covered by the same-namespace and + # same-environment rules above. Those peers are what cost 6 entries per + # cluster identity on ingress. + - fromEntities: + - world + - host + - remote-node + toPorts: + - ports: + - port: "443" + protocol: TCP + - port: "80" + protocol: TCP + - port: "8443" + protocol: TCP + - port: "8000" + protocol: TCP + {{- if .Values.global.monitoring.metrics.enabled }} + - port: "{{ .Values.global.monitoring.metrics.port }}" #metrics port + protocol: TCP + {{- end }} + {{- if .Values.global.servicebusNetworkPolicyEnabled }} + - port: "5671" #servicebus + protocol: TCP + {{- end }} + + egress: + # --- same namespace, all ports --- + - toEndpoints: + - matchLabels: + k8s:io.kubernetes.pod.namespace: {{ .Release.Namespace }} + + {{- if .Values.global.allowAllInternalClusterTrafficNetworkPolicy }} + # --- any pod in the cluster, all ports (allowAll variant) --- + - toEndpoints: + - matchExpressions: + - key: "k8s:io.kubernetes.pod.namespace" + operator: "Exists" + {{- else }} + # --- same environment, all ports --- + - toEndpoints: + - matchLabels: + k8s:io.cilium.k8s.namespace.labels.environment: {{ (split "-" .Release.Namespace)._0 }} + {{- end }} + + # --- kube-dns --- + # + # The namespace MUST be stated. A selector in a namespaced CNP is implicitly + # scoped to the policy's own namespace, so `k8s-app: kube-dns` alone matches + # nothing and all DNS is denied. + - toEndpoints: + - matchLabels: + k8s:io.kubernetes.pod.namespace: kube-system + k8s:k8s-app: kube-dns + toPorts: + - ports: + - port: "53" + protocol: UDP + - port: "53" + protocol: TCP + + {{- if .Values.global.monitoring.servicemonitor.enabled }} + # --- monitoring namespace, all ports --- + - toEndpoints: + - matchLabels: + k8s:io.cilium.k8s.namespace.labels.environment: {{ .Values.global.monitoring.prometheusNamespace }} + {{- end }} + + # --- nodes and API server, all ports --- + # + # Node addresses resolve to host/remote-node and are never matched by a CIDR + # selector. kube-apiserver is its own reserved identity on managed AKS. + - toEntities: + - host + - remote-node + - kube-apiserver + + # --- everything outside the cluster, all ports --- + # + # `world` is any address Cilium has no more specific identity for: the + # internet and PaaS private endpoints, not pods or nodes. Outbound traffic is + # filtered by Azure Firewall, so no port list here. + - toEntities: + - world +{{- end -}} diff --git a/charts/core/templates/network-policy.yaml b/charts/core/templates/network-policy.yaml index 6beb36a..4d3fcd9 100644 --- a/charts/core/templates/network-policy.yaml +++ b/charts/core/templates/network-policy.yaml @@ -1,4 +1,14 @@ -{{- if .Values.global.defaultNetworkPolicyEnabled -}} +{{- if and .Values.global.defaultNetworkPolicyEnabled (ne (include "charts-core.useCilium" .) "true") -}} +{{/* + Kubernetes NetworkPolicy for clusters running the Azure NPM dataplane. + + On clusters running Azure CNI powered by Cilium this template is skipped and + cilium-network-policy.yaml renders instead. Detection is automatic - see the + "charts-core.useCilium" helper in _helpers.tpl. + + Do not add Cilium workarounds here. This file is the NPM baseline; rule order + is asserted by templates/tests/networkpolicy_test.py. +*/}} apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: @@ -37,12 +47,6 @@ spec: - from: #outside world - sentry, optimizely, etc - ipBlock: cidr: 0.0.0.0/0 - # Cilium never matches Pod IPs through ipBlock, so without these peers - # in-cluster clients lose access to the ports below. Under NPM they change - # nothing: 0.0.0.0/0 already covers Pods. Reference: - # https://learn.microsoft.com/en-us/azure/aks/migrate-from-npm-to-cilium-network-policy - - namespaceSelector: {} - - podSelector: {} ports: - port: 443 - port: 80 @@ -88,12 +92,6 @@ spec: - to: #outside world - sentry, optimizely, etc - ipBlock: cidr: 0.0.0.0/0 - # Cilium never matches Pod IPs through ipBlock, so without these peers - # in-cluster destinations lose access to the ports below. Under NPM they - # change nothing: 0.0.0.0/0 already covers Pods. - # https://learn.microsoft.com/en-us/azure/aks/migrate-from-npm-to-cilium-network-policy - - namespaceSelector: {} - - podSelector: {} ports: - port: 443 - port: 80 diff --git a/charts/cron-job/Chart.yaml b/charts/cron-job/Chart.yaml index 762bbda..0596d21 100644 --- a/charts/cron-job/Chart.yaml +++ b/charts/cron-job/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 description: EcoVadis Helm chart for K8s Cron Job name: charts-cron-job type: application -version: 2.12.0 +version: 2.13.0 dependencies: - name: charts-core - version: 2.10.0 + version: 2.11.0 repository: "https://ecovadiscode.github.io/charts/" \ No newline at end of file diff --git a/charts/dotnet-core/Chart.yaml b/charts/dotnet-core/Chart.yaml index a614884..a43c35d 100644 --- a/charts/dotnet-core/Chart.yaml +++ b/charts/dotnet-core/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 description: EcoVadis Helm chart for .Net Core app name: charts-dotnet-core type: application -version: 4.12.0 +version: 4.13.0 dependencies: - name: charts-core - version: "2.10.0" + version: "2.11.0" repository: "https://ecovadiscode.github.io/charts/" \ No newline at end of file diff --git a/charts/event-worker/Chart.yaml b/charts/event-worker/Chart.yaml index 0587c62..7a3fe32 100644 --- a/charts/event-worker/Chart.yaml +++ b/charts/event-worker/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 description: EcoVadis Helm chart for K8s Event driven Deployment name: charts-event-worker type: application -version: 1.8.0 +version: 1.9.0 dependencies: - name: charts-core - version: 2.10.0 + version: 2.11.0 repository: "https://ecovadiscode.github.io/charts/" \ No newline at end of file diff --git a/charts/job/Chart.yaml b/charts/job/Chart.yaml index 60d0b54..53d40b6 100644 --- a/charts/job/Chart.yaml +++ b/charts/job/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 description: EcoVadis Helm chart for K8s Event driven Job name: charts-job type: application -version: 2.10.0 +version: 2.11.0 dependencies: - name: charts-core - version: 2.10.0 + version: 2.11.0 repository: "https://ecovadiscode.github.io/charts/" \ No newline at end of file