fix(installer): drop labeler Job hook in favour of caller-applied Namespace

The pre-install Job approach (added in c0b76b16, b46151a4) hits a fatal
chicken-and-egg on Talos clusters that enforce PodSecurity baseline:latest
on bare namespaces:

    pods "cozy-system-labeler-..." is forbidden:
      violates PodSecurity "baseline:latest": host namespaces (hostNetwork=true)

The labeler needs hostNetwork=true (no CNI yet) which requires the namespace
to be PSA-privileged, but the labeler's whole job is to add that label.
Cannot work from inside the namespace it's labeling.

Drop the labeler Job + ServiceAccount + ClusterRole + ClusterRoleBinding.
The chart now only removes the chart-defined Namespace and assumes the
caller pre-creates cozy-system with the right labels — same pattern as
kube-prometheus-stack, argo-cd, cert-manager, and other mainstream charts.

Install procedure becomes two-step:

    kubectl apply -f - <<EOF
    apiVersion: v1
    kind: Namespace
    metadata:
      name: cozy-system
      labels:
        cozystack.io/system: "true"
        cozystack.io/deletion-protected: "true"
        pod-security.kubernetes.io/enforce: privileged
    EOF
    helm upgrade installer packages/core/installer \
      --install --namespace cozy-system ...

The cozystack-operator pod (hostNetwork=true) is then admitted because the
namespace already has enforce=privileged.

Verified end-to-end on a kind cluster — clean install in 0.1s, no hooks
involved, no PSA conflict, no retry needed.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
This commit is contained in:
Myasnikov Daniil 2026-04-28 13:46:14 +05:00
parent 4754f57f43
commit be0a66877c
No known key found for this signature in database
GPG key ID: FA953A439C637F04

View file

@ -1,111 +0,0 @@
{{/*
Pre-install/upgrade hook that labels the cozy-system namespace with the
PodSecurity and cozystack identity labels. The chart no longer ships a
Namespace resource (helm v3 cannot adopt a namespace pre-created by
--create-namespace because it lacks helm meta annotations; without
--create-namespace, helm fails to write its release-secret because the
namespace does not exist yet — chicken-and-egg).
Install commands now use --create-namespace to bootstrap the namespace,
and this hook patches the labels the operator depends on (notably
pod-security.kubernetes.io/enforce=privileged for the host-network
operator pod).
*/}}
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: cozy-system-labeler
namespace: cozy-system
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-weight: "-200"
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cozy-system-labeler
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-weight: "-180"
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
rules:
- apiGroups: [""]
resources: ["namespaces"]
resourceNames: ["cozy-system"]
verbs: ["get", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cozy-system-labeler
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-weight: "-160"
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
subjects:
- kind: ServiceAccount
name: cozy-system-labeler
namespace: cozy-system
roleRef:
kind: ClusterRole
name: cozy-system-labeler
apiGroup: rbac.authorization.k8s.io
---
apiVersion: batch/v1
kind: Job
metadata:
name: cozy-system-labeler
namespace: cozy-system
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-weight: "-100"
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
spec:
backoffLimit: 3
ttlSecondsAfterFinished: 60
template:
spec:
serviceAccountName: cozy-system-labeler
restartPolicy: OnFailure
# The hook runs BEFORE Cilium / kube-ovn / any CNI is installed, so the
# cluster's nodes are NotReady-NoSchedule and have no pod network. Mirror
# the cozystack-operator deployment's scheduling: hostNetwork=true so the
# pod doesn't need CNI, plus the same tolerations the operator uses.
hostNetwork: true
tolerations:
- key: "node.kubernetes.io/not-ready"
operator: "Exists"
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
- key: "node.cilium.io/agent-not-ready"
operator: "Exists"
- key: "node.cloudprovider.kubernetes.io/uninitialized"
operator: "Exists"
containers:
- name: kubectl
image: alpine/k8s:1.32.0
imagePullPolicy: IfNotPresent
{{- if eq .Values.cozystackOperator.variant "talos" }}
env:
# Talos KubePrism endpoint — same as cozystack-operator uses to reach
# the apiserver before CNI is up.
- name: KUBERNETES_SERVICE_HOST
value: "localhost"
- name: KUBERNETES_SERVICE_PORT
value: "7445"
{{- else if eq .Values.cozystackOperator.variant "generic" }}
env:
- name: KUBERNETES_SERVICE_HOST
value: {{ required "cozystack.apiServerHost is required in generic mode" .Values.cozystack.apiServerHost | quote }}
- name: KUBERNETES_SERVICE_PORT
value: {{ .Values.cozystack.apiServerPort | quote }}
{{- end }}
command:
- kubectl
- label
- --overwrite
- namespace
- cozy-system
- cozystack.io/system=true
- pod-security.kubernetes.io/enforce=privileged