# SCAFFOLDING for a later phase (Phase 2, task T-2.7) -- NOT applied in Phase 0 # (no cluster exists yet). Installs Kyverno so the SAME L0 policies run in-cluster # as an admission controller (defense in depth per docs/07, ADR-0011). Flux # HelmRelease skeleton; chart/app versions are pinned and bumped via the update path. --- apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmRepository metadata: name: kyverno namespace: kyverno spec: interval: 24h url: https://kyverno.github.io/kyverno/ --- apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: kyverno namespace: kyverno spec: interval: 1h chart: spec: chart: kyverno version: "3.3.x" # pin to the exact chart the operator vendors sourceRef: kind: HelmRepository name: kyverno namespace: kyverno install: remediation: retries: 3 upgrade: remediation: retries: 3 values: # Admission controller replicas — cluster-vars knob (prod 3 / dev 1). HA so a single pod # restart cannot open an enforcement gap; dev drops to 1 to save RAM during bootstrap. admissionController: replicas: ${KYVERNO_ADMISSION_REPLICAS} backgroundController: enabled: true # needed for generate (default-deny baseline) + sync reportsController: enabled: true cleanupController: enabled: true # Webhook failure policy — cluster-vars knob (prod Fail / dev Ignore). Fail is fail-CLOSED # (reject rather than silently admit when the webhook is unreachable, coordination-protocol.md # #8); dev uses Ignore (fail-open) so a cold/unhealthy Kyverno cannot brick admission during # bootstrap. The namespaceSelector ALSO excludes system + platform namespaces at the webhook # layer — belt-and-suspenders: policies already scope to app-namespace=true, but this # guarantees kube-system/flux-system/CNI/storage/monitoring admission never routes to Kyverno. config: webhooks: - failurePolicy: ${KYVERNO_WEBHOOK_FAILURE_POLICY} namespaceSelector: matchExpressions: - key: kubernetes.io/metadata.name operator: NotIn values: - kube-system - flux-system - kyverno - longhorn-system - monitoring