Skip to content

feat(arc): GitOps-enforce arm64 node taint via Kyverno + ARC toleration - #8

Merged
emmanuelbruno merged 1 commit into
mainfrom
preservation/arc-kyverno-arm64-taint
Sep 14, 2026
Merged

emmanuelbruno merged 1 commit into
mainfrom
preservation/arc-kyverno-arm64-taint

Conversation

@emmanuelbruno

Copy link
Copy Markdown
Contributor

Summary

Enforces the kubernetes.io/arch=arm64:NoSchedule taint on arm64 nodes (lima-k3s-agent) under GitOps via Kyverno so the taint persists across kubelet re-provisioning, and lets the ARC ARM runner pod tolerate it.

Closes finding #10 (untainted arm64 test node) from docs/cluster.md.

Changes

File Change
kubernetes/arc/node-arm64-arch-taint.yaml new Kyverno ClusterPolicy (admission+background) re-applying the arch taint on arm64 Nodes
kubernetes/arc/kyverno-node-mutation-rbac.yaml new ClusterRole kyverno:update-nodes, aggregated into the Kyverno background controller via the rbac.kyverno.io/aggregate-to-background-controller label (no extra binding needed)
kubernetes/arc/kustomization.yaml wire the two new resources
helm/releases/arc/arm-scale-set-values.yaml template.spec.tolerations for the arch taint (listeners intentionally stay on x64)
helm/releases/kyverno/values.yaml config.resourceFiltersExclude: ['[Node,*,*]'] so the admission webhook processes Node objects (keeps [Node/?*,*,*]); documents the one-off live-CM patch
bootstrap/app-arc-arm-runners.yaml valueURL ?v=3?v=4
bootstrap/appset-helm.yaml kyverno valueURL ?v=1?v=2
docs/cluster.md node/taint inventory + finding #10 marked resolved
kubernetes/arc/README.md new "Node taint & toleration (arm64)" section

Why both admission + background

Kubelet is in Kyverno's excludeGroups: system:nodes, so admission alone would miss kubelet-driven Node updates. The policy runs admission (real-time) and background (rescan) to keep the taint persistent; background Node mutation is authorized by the aggregated kyverno:update-nodes ClusterRole.

Validation (offline)

  • kubectl kustomize kubernetes/arc → renders cleanly (EXIT 0, no errors); both new resources present and correct.
  • helm template kyverno …/values.yaml[Node,*,*] removed, [Node/?*,*,*] kept, system:nodes kept. Diff vs. the pure chart default confirms the exclude surgically removes only the standalone [Node,*,*].

⚠️ Manual post-merge follow-up (NOT part of this diff)

The live kyverno/kyverno ConfigMap is annotated helm.sh/resource-policy: keep and is not managed by ArgoCD/Helm, so the values.yaml change only takes effect on a fresh install/rebuild. After merge + sync, apply the single sanctioned data-level patch documented in helm/releases/kyverno/values.yaml to drop the standalone [Node,*,*] from the running cluster (the exact INTENDED resourceFilters string is in that comment block):

kubectl patch configmap kyverno -n kyverno --type merge -p '{"data":{"resourceFilters":"<INTENDED STRING>"}}'

Post-merge verification checklist

  • ArgoCD arc-arm-runners app Synced/Healthy after ?v=4
  • ArgoCD kyverno app picks up ?v=2 values (fresh render only — live CM needs the manual patch)
  • Kyverno ClusterPolicy node-arm64-arch-taint is Ready (background + admission enabled)
  • kyverno:update-nodes aggregated into kyverno:background-controller (verify the role includes node update/patch)
  • ARC ARM runner pod carries the kubernetes.io/arch=arm64:NoSchedule toleration and schedules on lima-k3s-agent
  • Apply the one-off live-CM patch, then confirm resourceFilters no longer contains the standalone [Node,*,*]
  • Reboot the Lima VM / re-provision the node and confirm Kyverno re-asserts the taint with no manual action

Enforce kubernetes.io/arch=arm64:NoSchedule on arm64 nodes (lima-k3s-agent)
under GitOps so the taint persists across kubelet re-provisioning, and let the
ARM runner pod tolerate it:

- kubernetes/arc/node-arm64-arch-taint.yaml: Kyverno ClusterPolicy
  (admission+background) re-applying the taint on arm64 Nodes.
- kubernetes/arc/kyverno-node-mutation-rbac.yaml: ClusterRole
  kyverno:update-nodes aggregated into the Kyverno background controller
  (rbac.kyverno.io/aggregate-to-background-controller label; no extra binding).
- kubernetes/arc/kustomization.yaml: wire the two new resources.
- helm/releases/arc/arm-scale-set-values.yaml: template.spec.tolerations for the
  arch taint (listeners stay on x64).
- helm/releases/kyverno/values.yaml: config.resourceFiltersExclude ['[Node,*,*]']
  so the admission webhook processes Node objects (keeps [Node/?*,*,*]).
- bootstrap/app-arc-arm-runners.yaml: valueURL ?v=3 -> ?v=4.
- bootstrap/appset-helm.yaml: kyverno valueURL ?v=1 -> ?v=2.
- docs/cluster.md, kubernetes/arc/README.md: document the taint/toleration.

Post-merge manual follow-up (NOT in this diff): the live kyverno/kyverno
ConfigMap is keep-annotated and unmanaged, so apply the one-off data-level patch
documented in helm/releases/kyverno/values.yaml to drop the standalone
[Node,*,*] from the running cluster.
Copilot AI lite review requested due to automatic review settings September 13, 2026 20:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The Kyverno policy does not restore the taint during background scans, and the sync-wave is in labels instead of annotations.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds GitOps-managed Kyverno taint enforcement for the arm64 node and an ARC runner toleration.

Changes:

  • Adds Kyverno policy and RBAC for arm64 node tainting.
  • Adds ARC ARM runner toleration.
  • Updates Kyverno values, bootstrap references, and documentation.
File summaries
File Summary
kubernetes/arc/README.md Documents arm64 taint and toleration behavior.
kubernetes/arc/node-arm64-arch-taint.yaml Adds the arm64 node mutation policy. Critical (3 votes): background scanning will not restore the taint; use mutate-existing or another reconciler.
kubernetes/arc/kyverno-node-mutation-rbac.yaml Adds Kyverno Node mutation permissions. Moderate (2 votes): sync-wave is under labels instead of annotations.
kubernetes/arc/kustomization.yaml Includes the new resources.
helm/releases/kyverno/values.yaml Adjusts Kyverno Node resource filters.
helm/releases/arc/arm-scale-set-values.yaml Adds the ARM runner toleration.
docs/cluster.md Updates node inventory and finding status.
bootstrap/appset-helm.yaml Updates the Kyverno values cache version.
bootstrap/app-arc-arm-runners.yaml Updates the ARC values cache version.
Review details
  • Files reviewed: 9/9 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

selector:
matchLabels:
kubernetes.io/arch: arm64
mutate:
Comment on lines +17 to +19
labels:
rbac.kyverno.io/aggregate-to-background-controller: "true"
argocd.argoproj.io/sync-wave: "-1"
@emmanuelbruno
emmanuelbruno merged commit 0a68e71 into main Sep 14, 2026
1 check passed
emmanuelbruno added a commit that referenced this pull request Sep 14, 2026
…state consistency

Follow-up to #8 (Copilot review on PR #8).

- fix(arc): argocd.argoproj.io/sync-wave must be an annotation, not a label.
  The label value '-1' is rejected by K8s label validation, which blocked
  creation of the kyverno:update-nodes ClusterRole and put the whole arc
  ArgoCD app into SyncError.
- docs(cluster): align stale 'untainted' arm64 node statements (capacity
  section, finding #5 evidence) with the GitOps-enforced taint.

Assessment of #8 Copilot points:
- critical (background scan not restoring taint): false positive for
  Kyverno 1.15 (background: true re-applies mutation to existing
  resources; mutateExisting defaults true since v1.12). The live
  resourceFilters Node exclusion is addressed by the values
  resourceFiltersExclude hook plus the sanctioned one-off patch to the
  keep-annotated ConfigMap.
- moderate (sync-wave under labels): valid, fixed in this commit.

Pending fresh Copilot re-review did not land within the polling window;
only delta since last Copilot review is the docs fix addressing its own nit.
emmanuelbruno added a commit that referenced this pull request Sep 15, 2026
…lt drift + correct kyverno CM comment (#17)

Close-out for the merged ARC/Kyverno PR #8.

The Kyverno clusterpolicies.kyverno.io CRD sets rule-level
skipBackgroundRequests to default: true. The arc policy's manifest omitted
the field, so the API server defaulted it to true live -> the arc app stayed
permanently OutOfSync AND the background rescan was disabled (defeating the
policy's purpose of re-asserting the arm64 taint after node re-provisioning).
ArgoCD SSA cannot clear a defaulted field, so only an explicit value in git
fixes it durably.

- kubernetes/arc/node-arm64-arch-taint.yaml: add skipBackgroundRequests: false
  to the taint-arm64-nodes rule.
- helm/releases/kyverno/values.yaml: correct the stale comment block. The
  kyverno ConfigMap IS ArgoCD-managed (ArgoCD owns its data keys; the keep
  annotation only prevents deletion, not update), and the
  resourceFiltersExclude hook already drops [Node,*,*] at render time, so NO
  manual one-off ConfigMap patch is required. Remove the stale/wrong literal
  resourceFilters string.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants