From 47896eb1fce1d7289e9923368cee7e42ffb6dc79 Mon Sep 17 00:00:00 2001 From: YuryHrytsuk Date: Wed, 8 Jul 2026 11:17:25 +0200 Subject: [PATCH] Kubernetes: (re)add reflector chart Add reflector chart respecting security guidelines. We have to introduce our own chart as there is no way to add network policy. Once https://github.com/emberstack/kubernetes-reflector/pull/664 is merged, we can ditch our own chart and use reflector chart directly. Related PR/s * config (helmfile) changes https://git.speag.com/oSparc/osparc-ops-deployment-configuration/-/merge_requests/2135 --- charts/.trivy-config/config.yaml | 1 + charts/.trivyignore.yaml | 34 +++++++++++++++++++ charts/helmfile.ci.yaml | 12 ++++++- charts/reflector/Chart.lock | 6 ++++ charts/reflector/Chart.yaml | 29 ++++++++++++++++ charts/reflector/namespace.yaml | 15 ++++++++ charts/reflector/templates/networkpolicy.yaml | 24 +++++++++++++ charts/reflector/values.yaml.gotmpl | 29 ++++++++++++++++ 8 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 charts/reflector/Chart.lock create mode 100644 charts/reflector/Chart.yaml create mode 100644 charts/reflector/namespace.yaml create mode 100644 charts/reflector/templates/networkpolicy.yaml create mode 100644 charts/reflector/values.yaml.gotmpl diff --git a/charts/.trivy-config/config.yaml b/charts/.trivy-config/config.yaml index 3206f1bc..6b45fe57 100644 --- a/charts/.trivy-config/config.yaml +++ b/charts/.trivy-config/config.yaml @@ -2,3 +2,4 @@ ksv0125: trusted_registries: - "quay.io" + - "docker.io" diff --git a/charts/.trivyignore.yaml b/charts/.trivyignore.yaml index d6644d44..08e0bf05 100644 --- a/charts/.trivyignore.yaml +++ b/charts/.trivyignore.yaml @@ -57,3 +57,37 @@ misconfigurations: Ingress must allow the Kubernetes API server (webhook calls), which is not a selectable Pod. We therefore scope the source by CIDR (nets) instead of pod/namespace selectors. + + # + # reflector + # + - id: AVD-KSV-0038 + paths: + - "reflector/templates/networkpolicy.yaml" + statement: > + Egress must reach the Kubernetes API server, which runs as a hostNetwork + static pod and is not a selectable Calico workload. We therefore scope the + destination by CIDR (nets) instead of pod/namespace selectors. + + - id: AVD-KSV-0041 + paths: + - "reflector/charts/reflector/templates/clusterRole.yaml" + statement: > + Reflector's core function is to mirror Secrets across namespaces, so it + must manage Secrets cluster-wide. Defined by the upstream chart and cannot + be narrowed without breaking reflection. + + - id: AVD-KSV-0045 + paths: + - "reflector/charts/reflector/templates/clusterRole.yaml" + statement: > + The upstream reflector ClusterRole grants a wildcard verb on ConfigMaps + and Secrets to watch, read and mirror them across namespaces. This is + required by the upstream chart and cannot be narrowed. + + - id: AVD-KSV-0049 + paths: + - "reflector/charts/reflector/templates/clusterRole.yaml" + statement: > + Reflector must create/update ConfigMaps in target namespaces to mirror + them. Granted by the upstream chart and required for reflection. diff --git a/charts/helmfile.ci.yaml b/charts/helmfile.ci.yaml index e30bf173..0b5d7d9a 100644 --- a/charts/helmfile.ci.yaml +++ b/charts/helmfile.ci.yaml @@ -1,8 +1,10 @@ # CI-only stub for Trivy chart scanning. repositories: - - name: jetstack + - name: jetstack # cert-manager url: https://charts.jetstack.io + - name: emberstack # reflector + url: https://emberstack.github.io/helm-charts releases: - name: security-hardening @@ -11,9 +13,17 @@ releases: values: - security-hardening/values.yaml + - name: reflector + namespace: reflector + chart: ./reflector + values: + - ./reflector/values.yaml.gotmpl + - name: cert-manager chart: ./cert-manager namespace: cert-manager + needs: + - reflector/reflector values: - cert-manager/values.common.yaml.gotmpl - cert-manager/values.selfsigned.yaml.gotmpl diff --git a/charts/reflector/Chart.lock b/charts/reflector/Chart.lock new file mode 100644 index 00000000..248ce0f0 --- /dev/null +++ b/charts/reflector/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: reflector + repository: https://emberstack.github.io/helm-charts + version: 10.0.41 +digest: sha256:f4ba6c324bc34f2d32c324b50272075083f0b07be6f97e58edca971c427c738e +generated: "2026-07-08T11:06:20.812483313+02:00" diff --git a/charts/reflector/Chart.yaml b/charts/reflector/Chart.yaml new file mode 100644 index 00000000..9c78da28 --- /dev/null +++ b/charts/reflector/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +name: reflector +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: &version 10.0.41 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: *version + +dependencies: + - name: reflector + version: *version + repository: "https://emberstack.github.io/helm-charts" diff --git a/charts/reflector/namespace.yaml b/charts/reflector/namespace.yaml new file mode 100644 index 00000000..e8a5b007 --- /dev/null +++ b/charts/reflector/namespace.yaml @@ -0,0 +1,15 @@ +# namespace with defined pod security standard +# inspired from https://aro-labs.com/pod-security-standards/ +# official doc: https://kubernetes.io/docs/concepts/security/pod-security-standards/ +# +# Warning: if pod / container does not meet enforced standards, it will not be deployed (silently) +# execute `kubectl -n events` to see errors (e.g.) +# Error creating: pods "xyz" is forbidden: violates PodSecurity "baseline:latest": privileged +# container "xyz" must not set securityContext.privileged to true +# +apiVersion: v1 +kind: Namespace +metadata: + name: reflector + labels: + pod-security.kubernetes.io/enforce: restricted diff --git a/charts/reflector/templates/networkpolicy.yaml b/charts/reflector/templates/networkpolicy.yaml new file mode 100644 index 00000000..1d61e7ed --- /dev/null +++ b/charts/reflector/templates/networkpolicy.yaml @@ -0,0 +1,24 @@ +# The security-hardening chart applies a Calico GlobalNetworkPolicy that +# default-denies ingress + egress for all non-system namespaces (only DNS egress +# is globally allowed). Reflector must reach the Kubernetes API server to watch +# and mirror Secrets/ConfigMaps, so we explicitly allow that egress. +# https://docs.tigera.io/calico/latest/network-policy/get-started/kubernetes-default-deny +apiVersion: projectcalico.org/v3 +kind: NetworkPolicy +metadata: + name: reflector-network-policy +spec: + egress: + # TCP: reflector -> Kubernetes API server + - action: Allow + protocol: TCP + destination: + # we cannot use selectors as the kube apiserver is deployed as a static + # pod with hostNetwork: true. Calico does not see it as a selectable + # workload so selectors don't work + nets: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + ports: + - 6443 diff --git a/charts/reflector/values.yaml.gotmpl b/charts/reflector/values.yaml.gotmpl new file mode 100644 index 00000000..6454697d --- /dev/null +++ b/charts/reflector/values.yaml.gotmpl @@ -0,0 +1,29 @@ +reflector: + configuration: + watcher: + # https://github.com/emberstack/kubernetes-reflector/issues/560#issuecomment-3415122791 + timeout: 30 # seconds + + # Resource limits are mandatory: the security-hardening ValidatingAdmissionPolicy + # `require-resource-limits-for-all-containers` denies any pod without cpu+memory limits. + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 100m + memory: 128Mi + + # harden the container securityContext to satisfy Trivy (KSV-0001, KSV-0104). + # NOTE: helm replaces (does not merge) .Values.securityContext, so the chart + # defaults must be repeated here. + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault