Compare commits
base: Home-Network/home-network-k3s-impl:d1a6628a97d2c41d13c7372680c4d321c5565e52
Home-Network/home-network-k3s-impl:main
Home-Network/home-network-k3s-impl:renovate/ghcr.io-renovatebot-renovate-44.x
Home-Network/home-network-k3s-impl:renovate/docker.io-library-python-3.x
Home-Network/home-network-k3s-impl:renovate/ghcr.io-aquasecurity-trivy-0.x
Home-Network/home-network-k3s-impl:feat/vuln-visibility
Home-Network/home-network-k3s-impl:chore/adopt-spec-sync
Home-Network/home-network-k3s-impl:fix/wg-client-mtu-docs
Home-Network/home-network-k3s-impl:fix/wg-home-peer-pihole-sources
Home-Network/home-network-k3s-impl:feat/pihole-explicit-lan-names
Home-Network/home-network-k3s-impl:feat/dns-via-cloudflare-tunnel
Home-Network/home-network-k3s-impl:feature/cloudflare-tunnel-config
Home-Network/home-network-k3s-impl:chore/rotate-cloudflared-tunnel
Home-Network/home-network-k3s-impl:fix/cloudflared-creds-permission
Home-Network/home-network-k3s-impl:feat/cloudflare-tunnel
Home-Network/home-network-k3s-impl:feat/parallel-l0-checks
Home-Network/home-network-k3s-impl:feat/gate-toolbox-container
Home-Network/home-network-k3s-impl:fix/keycloak-servicemonitor-owner
Home-Network/home-network-k3s-impl:feat/runner-capacity-2
Home-Network/home-network-k3s-impl:chore/renovate-config-cleanup
Home-Network/home-network-k3s-impl:fix/keycloak-operator-crds
Home-Network/home-network-k3s-impl:feat/devcontainer-velero-cli
Home-Network/home-network-k3s-impl:feat/gitea-28
Home-Network/home-network-k3s-impl:feat/l0-externaldns-annotation-prefix
Home-Network/home-network-k3s-impl:fix/public-dns-wan-a-record
Home-Network/home-network-k3s-impl:feat/pm-agent-pr-mentions
Home-Network/home-network-k3s-impl:docs/source-comment-audit
Home-Network/home-network-k3s-impl:chore/pm-agent-digest-99
Home-Network/home-network-k3s-impl:fix/pm-agent-triage-exit
Home-Network/home-network-k3s-impl:chore/pm-agent-go-live
Home-Network/home-network-k3s-impl:chore/pm-agent-runner-digest
Home-Network/home-network-k3s-impl:feature/pm-agent-credentials
Home-Network/home-network-k3s-impl:feat/pm-agent-registry-pull-secret
Home-Network/home-network-k3s-impl:feat/pin-pihole-jackett-plex
Home-Network/home-network-k3s-impl:fix/renovate-hold-auth-and-self
Home-Network/home-network-k3s-impl:feat/renovate-track-keycloak-operator
Home-Network/home-network-k3s-impl:fix/renovate-run-hygiene
Home-Network/home-network-k3s-impl:fix/renovate-auth
Home-Network/home-network-k3s-impl:fix/renovate-first-run
Home-Network/home-network-k3s-impl:feat/keycloak-passkey-reconcile
Home-Network/home-network-k3s-impl:fix/gitea-admit-buildkit
Home-Network/home-network-k3s-impl:feat/image-pipeline
Home-Network/home-network-k3s-impl:fix/renovate-config-filename
Home-Network/home-network-k3s-impl:fix/vpn-ingress-l2-lease-collision
Home-Network/home-network-k3s-impl:fix/renovate-cron-window
Home-Network/home-network-k3s-impl:fix/renovate-invalid-config
Home-Network/home-network-k3s-impl:fix/pihole-local-ttl
Home-Network/home-network-k3s-impl:fix/unattended-upgrades-debian-sentinel
Home-Network/home-network-k3s-impl:fix/ha-check-catastrophic-regex
Home-Network/home-network-k3s-impl:feat/automated-upgrades
Home-Network/home-network-k3s-impl:fix/coredns-ha
Home-Network/home-network-k3s-impl:feat/keycloak-passkeys
Home-Network/home-network-k3s-impl:fix/oauth2-proxy-oidc-startup-race
Home-Network/home-network-k3s-impl:feat/graceful-cluster-shutdown
Home-Network/home-network-k3s-impl:plex/volume-expamsion
Home-Network/home-network-k3s-impl:fix/bulk-nfs-truenas
Home-Network/home-network-k3s-impl:fix/peers-configmap-content-hash
Home-Network/home-network-k3s-impl:vpn/add-keith-phone
Home-Network/home-network-k3s-impl:fix/new-peer-ignores-template-comments
Home-Network/home-network-k3s-impl:fix/vpn-ingress-ip-forward
Home-Network/home-network-k3s-impl:feature/add-private-key-for-wireguard
Home-Network/home-network-k3s-impl:fix/vpn-server-key-in-sops
Home-Network/home-network-k3s-impl:docs/pm-agent-registry-pull-prereq
Home-Network/home-network-k3s-impl:fix/vpn-runbook-ansible-command
Home-Network/home-network-k3s-impl:feat/pm-agent-issue-to-pr
Home-Network/home-network-k3s-impl:docs/agents-work-in-their-own-workspace
Home-Network/home-network-k3s-impl:feat/vpn-remote-access-wireguard
Home-Network/home-network-k3s-impl:feat/cilium-roll-out-on-config-change
Home-Network/home-network-k3s-impl:docs/oauth2-sidecar-scrape-verified
Home-Network/home-network-k3s-impl:fix/plex-resolver-independent-advertise
Home-Network/home-network-k3s-impl:fix/plex-unblock-app-tier
Home-Network/home-network-k3s-impl:feat/hubble-flow-export-plex
Home-Network/home-network-k3s-impl:fix/oauth2-sidecar-metrics-scrape-netpol
Home-Network/home-network-k3s-impl:feat/plex-vip-hostname-and-lan-networks
Home-Network/home-network-k3s-impl:fix/plex-advertise-plexdirect
Home-Network/home-network-k3s-impl:docs/pihole-ha-verified
Home-Network/home-network-k3s-impl:feat/pihole-multi-replica
Home-Network/home-network-k3s-impl:feat/pihole-declare-state
Home-Network/home-network-k3s-impl:feat/plex-remote-access-l4
Home-Network/home-network-k3s-impl:fix/cilium-cgroup-hostroot
Home-Network/home-network-k3s-impl:fix/node-keycloak-hosts-pin
Home-Network/home-network-k3s-impl:feat/public-dns-wan-target
Home-Network/home-network-k3s-impl:fix/plex-quicksync-verification
Home-Network/home-network-k3s-impl:sync-39-onto-main
Home-Network/home-network-k3s-impl:fix/admin-approval-override
Home-Network/home-network-k3s-impl:feat/quicksync-via-device-plugin
Home-Network/home-network-k3s-impl:bugfix/arr-to-plex
Home-Network/home-network-k3s-impl:feat/oauth2-proxy-api-route-per-app
Home-Network/home-network-k3s-impl:feat/intel-gpu-device-plugin
Home-Network/home-network-k3s-impl:feat/oauth2-proxy-auth-failure-visible
Home-Network/home-network-k3s-impl:fix/render-selftest-runs-in-gate
Home-Network/home-network-k3s-impl:feat/plex-quicksync
Home-Network/home-network-k3s-impl:feat/sd-hardware-capability
Home-Network/home-network-k3s-impl:fix/jackett-oauth2-proxy-session
Home-Network/home-network-k3s-impl:feat/node-health-render-device
Home-Network/home-network-k3s-impl:fix/oauth2-proxy-cookie-collision-fleet
Home-Network/home-network-k3s-impl:fix/flux-deploy-notification-inhibited
Home-Network/home-network-k3s-impl:feat/flux-deploy-notifications
Home-Network/home-network-k3s-impl:feat/conformance-job-template
Home-Network/home-network-k3s-impl:feat/conformance-trigger-kubeconfig
Home-Network/home-network-k3s-impl:feat/conformance-runner-image
Home-Network/home-network-k3s-impl:fix/crafty-oauth2-proxy-signin
Home-Network/home-network-k3s-impl:chore/decisions-log-conflict-free
Home-Network/home-network-k3s-impl:fix/crafty-bedrock-19132
Home-Network/home-network-k3s-impl:fix/gitea-settings-comment-names-impossible-secret
Home-Network/home-network-k3s-impl:feat/ci-is-the-approver
Home-Network/home-network-k3s-impl:fix/kyverno-policy-was-never-applied
Home-Network/home-network-k3s-impl:docs/handoff-2026-09-29
Home-Network/home-network-k3s-impl:fix/secret-name-and-require-gitea-settings
Home-Network/home-network-k3s-impl:feat/conformance-trigger-admission-boundary
Home-Network/home-network-k3s-impl:fix/cluster-available-would-fake-a-green
Home-Network/home-network-k3s-impl:feat/gitea-settings-drift-check
Home-Network/home-network-k3s-impl:fix/gitea-admins-could-override-the-gate
Home-Network/home-network-k3s-impl:docs/close-out-ci-hardening
Home-Network/home-network-k3s-impl:docs/ci-reality-vs-phase-0
Home-Network/home-network-k3s-impl:docs/runbooks-pr-flow
Home-Network/home-network-k3s-impl:fix/dind-native-sidecar
Home-Network/home-network-k3s-impl:fix/gate-push-trigger-matches-feat-prefix
Home-Network/home-network-k3s-impl:feat/plex-claim-token-013124
Home-Network/home-network-k3s-impl:fix/conformance-context-is-fail-open
Home-Network/home-network-k3s-impl:docs/ci-delivery-flow-for-agents
Home-Network/home-network-k3s-impl:feat/plex-claim-sops-secret
Home-Network/home-network-k3s-impl:feat/prod-hardening
Home-Network/home-network-k3s-impl:prod/deliver-fixes
Home-Network/home-network-k3s-impl:docs/memattr-6-12-backport
Home-Network/home-network-k3s-impl:migration/dns-apex-inversion
Home-Network/home-network-k3s-impl:feat/prod-memattr-and-nodes
Home-Network/home-network-k3s-impl:docs/node2-memory-refine
Home-Network/home-network-k3s-impl:feat/prod-node-2
Home-Network/home-network-k3s-impl:feat/r-state-03-proven
Home-Network/home-network-k3s-impl:feat/ledger-section-parsing
Home-Network/home-network-k3s-impl:feat/conformance-run-ledger
Home-Network/home-network-k3s-impl:chore/cilium-split-merge2
Home-Network/home-network-k3s-impl:feat/cilium-own-kustomization
Home-Network/home-network-k3s-impl:docs/poststart-incident
Home-Network/home-network-k3s-impl:fix/poststart-exit-status
Home-Network/home-network-k3s-impl:fix/strict-postbuild-substitutions
Home-Network/home-network-k3s-impl:docs/phase-7-open-prod-node-1
Home-Network/home-network-k3s-impl:rescued/fix/act-runner-dind-readiness
Home-Network/home-network-k3s-impl:rescued/fix/node-dns-resilient-upstream
Home-Network/home-network-k3s-impl:docs/reconcile-with-reality
..
compare: Home-Network/home-network-k3s-impl:prod/deliver-fixes
Home-Network/home-network-k3s-impl:main
Home-Network/home-network-k3s-impl:renovate/ghcr.io-renovatebot-renovate-44.x
Home-Network/home-network-k3s-impl:renovate/docker.io-library-python-3.x
Home-Network/home-network-k3s-impl:renovate/ghcr.io-aquasecurity-trivy-0.x
Home-Network/home-network-k3s-impl:feat/vuln-visibility
Home-Network/home-network-k3s-impl:chore/adopt-spec-sync
Home-Network/home-network-k3s-impl:fix/wg-client-mtu-docs
Home-Network/home-network-k3s-impl:fix/wg-home-peer-pihole-sources
Home-Network/home-network-k3s-impl:feat/pihole-explicit-lan-names
Home-Network/home-network-k3s-impl:feat/dns-via-cloudflare-tunnel
Home-Network/home-network-k3s-impl:feature/cloudflare-tunnel-config
Home-Network/home-network-k3s-impl:chore/rotate-cloudflared-tunnel
Home-Network/home-network-k3s-impl:fix/cloudflared-creds-permission
Home-Network/home-network-k3s-impl:feat/cloudflare-tunnel
Home-Network/home-network-k3s-impl:feat/parallel-l0-checks
Home-Network/home-network-k3s-impl:feat/gate-toolbox-container
Home-Network/home-network-k3s-impl:fix/keycloak-servicemonitor-owner
Home-Network/home-network-k3s-impl:feat/runner-capacity-2
Home-Network/home-network-k3s-impl:chore/renovate-config-cleanup
Home-Network/home-network-k3s-impl:fix/keycloak-operator-crds
Home-Network/home-network-k3s-impl:feat/devcontainer-velero-cli
Home-Network/home-network-k3s-impl:feat/gitea-28
Home-Network/home-network-k3s-impl:feat/l0-externaldns-annotation-prefix
Home-Network/home-network-k3s-impl:fix/public-dns-wan-a-record
Home-Network/home-network-k3s-impl:feat/pm-agent-pr-mentions
Home-Network/home-network-k3s-impl:docs/source-comment-audit
Home-Network/home-network-k3s-impl:chore/pm-agent-digest-99
Home-Network/home-network-k3s-impl:fix/pm-agent-triage-exit
Home-Network/home-network-k3s-impl:chore/pm-agent-go-live
Home-Network/home-network-k3s-impl:chore/pm-agent-runner-digest
Home-Network/home-network-k3s-impl:feature/pm-agent-credentials
Home-Network/home-network-k3s-impl:feat/pm-agent-registry-pull-secret
Home-Network/home-network-k3s-impl:feat/pin-pihole-jackett-plex
Home-Network/home-network-k3s-impl:fix/renovate-hold-auth-and-self
Home-Network/home-network-k3s-impl:feat/renovate-track-keycloak-operator
Home-Network/home-network-k3s-impl:fix/renovate-run-hygiene
Home-Network/home-network-k3s-impl:fix/renovate-auth
Home-Network/home-network-k3s-impl:fix/renovate-first-run
Home-Network/home-network-k3s-impl:feat/keycloak-passkey-reconcile
Home-Network/home-network-k3s-impl:fix/gitea-admit-buildkit
Home-Network/home-network-k3s-impl:feat/image-pipeline
Home-Network/home-network-k3s-impl:fix/renovate-config-filename
Home-Network/home-network-k3s-impl:fix/vpn-ingress-l2-lease-collision
Home-Network/home-network-k3s-impl:fix/renovate-cron-window
Home-Network/home-network-k3s-impl:fix/renovate-invalid-config
Home-Network/home-network-k3s-impl:fix/pihole-local-ttl
Home-Network/home-network-k3s-impl:fix/unattended-upgrades-debian-sentinel
Home-Network/home-network-k3s-impl:fix/ha-check-catastrophic-regex
Home-Network/home-network-k3s-impl:feat/automated-upgrades
Home-Network/home-network-k3s-impl:fix/coredns-ha
Home-Network/home-network-k3s-impl:feat/keycloak-passkeys
Home-Network/home-network-k3s-impl:fix/oauth2-proxy-oidc-startup-race
Home-Network/home-network-k3s-impl:feat/graceful-cluster-shutdown
Home-Network/home-network-k3s-impl:plex/volume-expamsion
Home-Network/home-network-k3s-impl:fix/bulk-nfs-truenas
Home-Network/home-network-k3s-impl:fix/peers-configmap-content-hash
Home-Network/home-network-k3s-impl:vpn/add-keith-phone
Home-Network/home-network-k3s-impl:fix/new-peer-ignores-template-comments
Home-Network/home-network-k3s-impl:fix/vpn-ingress-ip-forward
Home-Network/home-network-k3s-impl:feature/add-private-key-for-wireguard
Home-Network/home-network-k3s-impl:fix/vpn-server-key-in-sops
Home-Network/home-network-k3s-impl:docs/pm-agent-registry-pull-prereq
Home-Network/home-network-k3s-impl:fix/vpn-runbook-ansible-command
Home-Network/home-network-k3s-impl:feat/pm-agent-issue-to-pr
Home-Network/home-network-k3s-impl:docs/agents-work-in-their-own-workspace
Home-Network/home-network-k3s-impl:feat/vpn-remote-access-wireguard
Home-Network/home-network-k3s-impl:feat/cilium-roll-out-on-config-change
Home-Network/home-network-k3s-impl:docs/oauth2-sidecar-scrape-verified
Home-Network/home-network-k3s-impl:fix/plex-resolver-independent-advertise
Home-Network/home-network-k3s-impl:fix/plex-unblock-app-tier
Home-Network/home-network-k3s-impl:feat/hubble-flow-export-plex
Home-Network/home-network-k3s-impl:fix/oauth2-sidecar-metrics-scrape-netpol
Home-Network/home-network-k3s-impl:feat/plex-vip-hostname-and-lan-networks
Home-Network/home-network-k3s-impl:fix/plex-advertise-plexdirect
Home-Network/home-network-k3s-impl:docs/pihole-ha-verified
Home-Network/home-network-k3s-impl:feat/pihole-multi-replica
Home-Network/home-network-k3s-impl:feat/pihole-declare-state
Home-Network/home-network-k3s-impl:feat/plex-remote-access-l4
Home-Network/home-network-k3s-impl:fix/cilium-cgroup-hostroot
Home-Network/home-network-k3s-impl:fix/node-keycloak-hosts-pin
Home-Network/home-network-k3s-impl:feat/public-dns-wan-target
Home-Network/home-network-k3s-impl:fix/plex-quicksync-verification
Home-Network/home-network-k3s-impl:sync-39-onto-main
Home-Network/home-network-k3s-impl:fix/admin-approval-override
Home-Network/home-network-k3s-impl:feat/quicksync-via-device-plugin
Home-Network/home-network-k3s-impl:bugfix/arr-to-plex
Home-Network/home-network-k3s-impl:feat/oauth2-proxy-api-route-per-app
Home-Network/home-network-k3s-impl:feat/intel-gpu-device-plugin
Home-Network/home-network-k3s-impl:feat/oauth2-proxy-auth-failure-visible
Home-Network/home-network-k3s-impl:fix/render-selftest-runs-in-gate
Home-Network/home-network-k3s-impl:feat/plex-quicksync
Home-Network/home-network-k3s-impl:feat/sd-hardware-capability
Home-Network/home-network-k3s-impl:fix/jackett-oauth2-proxy-session
Home-Network/home-network-k3s-impl:feat/node-health-render-device
Home-Network/home-network-k3s-impl:fix/oauth2-proxy-cookie-collision-fleet
Home-Network/home-network-k3s-impl:fix/flux-deploy-notification-inhibited
Home-Network/home-network-k3s-impl:feat/flux-deploy-notifications
Home-Network/home-network-k3s-impl:feat/conformance-job-template
Home-Network/home-network-k3s-impl:feat/conformance-trigger-kubeconfig
Home-Network/home-network-k3s-impl:feat/conformance-runner-image
Home-Network/home-network-k3s-impl:fix/crafty-oauth2-proxy-signin
Home-Network/home-network-k3s-impl:chore/decisions-log-conflict-free
Home-Network/home-network-k3s-impl:fix/crafty-bedrock-19132
Home-Network/home-network-k3s-impl:fix/gitea-settings-comment-names-impossible-secret
Home-Network/home-network-k3s-impl:feat/ci-is-the-approver
Home-Network/home-network-k3s-impl:fix/kyverno-policy-was-never-applied
Home-Network/home-network-k3s-impl:docs/handoff-2026-09-29
Home-Network/home-network-k3s-impl:fix/secret-name-and-require-gitea-settings
Home-Network/home-network-k3s-impl:feat/conformance-trigger-admission-boundary
Home-Network/home-network-k3s-impl:fix/cluster-available-would-fake-a-green
Home-Network/home-network-k3s-impl:feat/gitea-settings-drift-check
Home-Network/home-network-k3s-impl:fix/gitea-admins-could-override-the-gate
Home-Network/home-network-k3s-impl:docs/close-out-ci-hardening
Home-Network/home-network-k3s-impl:docs/ci-reality-vs-phase-0
Home-Network/home-network-k3s-impl:docs/runbooks-pr-flow
Home-Network/home-network-k3s-impl:fix/dind-native-sidecar
Home-Network/home-network-k3s-impl:fix/gate-push-trigger-matches-feat-prefix
Home-Network/home-network-k3s-impl:feat/plex-claim-token-013124
Home-Network/home-network-k3s-impl:fix/conformance-context-is-fail-open
Home-Network/home-network-k3s-impl:docs/ci-delivery-flow-for-agents
Home-Network/home-network-k3s-impl:feat/plex-claim-sops-secret
Home-Network/home-network-k3s-impl:feat/prod-hardening
Home-Network/home-network-k3s-impl:prod/deliver-fixes
Home-Network/home-network-k3s-impl:docs/memattr-6-12-backport
Home-Network/home-network-k3s-impl:migration/dns-apex-inversion
Home-Network/home-network-k3s-impl:feat/prod-memattr-and-nodes
Home-Network/home-network-k3s-impl:docs/node2-memory-refine
Home-Network/home-network-k3s-impl:feat/prod-node-2
Home-Network/home-network-k3s-impl:feat/r-state-03-proven
Home-Network/home-network-k3s-impl:feat/ledger-section-parsing
Home-Network/home-network-k3s-impl:feat/conformance-run-ledger
Home-Network/home-network-k3s-impl:chore/cilium-split-merge2
Home-Network/home-network-k3s-impl:feat/cilium-own-kustomization
Home-Network/home-network-k3s-impl:docs/poststart-incident
Home-Network/home-network-k3s-impl:fix/poststart-exit-status
Home-Network/home-network-k3s-impl:fix/strict-postbuild-substitutions
Home-Network/home-network-k3s-impl:docs/phase-7-open-prod-node-1
Home-Network/home-network-k3s-impl:rescued/fix/act-runner-dind-readiness
Home-Network/home-network-k3s-impl:rescued/fix/node-dns-resilient-upstream
Home-Network/home-network-k3s-impl:docs/reconcile-with-reality
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
422e1dc7e8 |
feat(ha): the CNI dials the control-plane VIP — kube-vip becomes a CNI prerequisite
OPERATOR DECISION 2026-09-06: "use the VIP as intended — a virtual address to reach
the cluster and provide fault tolerant HA. Without a change it will not work in HA."
THE DEFECT. Cilium's kube-proxy replacement dialled a SINGLE NODE. Re-confirmed live
before changing anything: all three prod cilium-agent pods carried
KUBERNETES_SERVICE_HOST=192.168.2.10 — k3s-prod-1's own address — while the kube-vip
VIP 192.168.2.9 was Running on all three nodes with a held lease. Lose prod-1 and the
CNI's control-plane path is dead on an "HA" cluster. clusters/prod's own comment said
the value must be the VIP and NOT .10, then called it "Not yet decided" — I treated
that stale comment as an open question when the evidence already settled it.
SPLIT, NOT REPOINT, because k3s_api_host had two consumers with opposite needs:
k3s_api_host unchanged — the FOUNDER's IP: the cold-bootstrap join
target and a tls-san. infra/tofu/outputs.tf GENERATES this
name, so renaming would ripple into tofu and the runbooks.
k3s_apiserver_endpoint NEW = {{ kube_vip_address }} — the HA address; what Cilium
consumes. Derived, not restated, so an environment overrides
ONE line and the VIP, the SAN and the CNI endpoint move
together. Prod needed no new override.
THE SECOND HAZARD, WHICH MY BRIEF DID NOT NAME and the agent found: pointing Cilium at
the VIP breaks a COLD bootstrap for the same reason the join would — site.yml ran
node-baseline -> k3s -> cilium, so Cilium would install against an address nothing
announced yet. That is the 2026-09-01 deadlock shape. Fixed by SEQUENCE, not value:
site.yml now imports kube-vip.yml BETWEEN k3s and cilium. It cannot go earlier
(kube-vip is a k3s auto-deploy manifest, so it needs a cluster) and it works there
because the DaemonSet is hostNetwork with KUBERNETES_SERVICE_HOST=127.0.0.1 — needing
neither CNI nor kube-proxy. roles/kube_vip gained a read-only `wait_for` on the VIP so
a cold run stops THERE with a named cause instead of surfacing as unreachable agents.
Also fixed a pre-existing bug that only mattered once this play joined site.yml: the
role's read-only interface probe ran without `check_mode: false`, so under --check it
was skipped and the assert fired with a misleading "set kube_vip_interface explicitly".
VERIFIED BY ME, not just reported:
renders dev K3S_API_HOST=192.168.1.49 prod=192.168.2.9 (each environment's VIP)
cilium template consumes k3s_apiserver_endpoint, not k3s_api_host
cold join still `--server https://{{ k3s_api_host }}:6443` — the founder
order site.yml: node-baseline -> k3s -> kube-vip -> cilium -> verify -> flux
gate full CI gate PASS
Agent-side, additionally: in-memory render of cilium-values.yaml.j2 per host showing
k8sServiceHost=the VIP with the join still on the founder; k3s_tls_sans renders
['.10','.9','127.0.0.1','.11','.12'] so NO cert reissue and NO k3s restart is involved
— .9 already answers under full CA verification; and --check --diff of kube-vip.yml
against prod reported 6 ok / 0 changed, i.e. the role edits change nothing about the
kube-vip prod already runs.
ha-control-plane-as-code 92 -> 112 assertions, turning two escalations into machine
checks: the Cilium template must use the endpoint var; the endpoint must derive from
kube_vip_address and k3s_api_host must not; per environment K3S_API_HOST must equal
that environment's VIP and be none of its node IPs (the [parity] contract, now
machine-checked rather than a comment); site.yml must order k3s -> kube-vip -> cilium.
Every new assertion mutation-tested and bites. One honest negative recorded: reverting
only the BASE default is not caught, because both overlays patch the key — the check
reads effective per-environment values, so the base default is unguarded.
APPLY ORDER, and this is the operator's step — nothing was applied:
PROD FIRST, and it is the low-risk direction (prod is the broken one). Push and let
Flux reconcile platform/cilium: the value change rolls the cilium-agent DaemonSet
ONE NODE AT A TIME (maxUnavailable: 1 — the knob that bounded the 2026-09-01
incident), it will not proceed past an unready pod, existing datapath survives an
agent restart, and .9 is already live before the change lands.
DEV SEPARATELY, operator present. Same mechanics but live dev agents dial
192.168.1.50, and dev is mid-DNS-migration on dev-live. Do not fold it into that.
ANSIBLE: nothing to run for either live cluster; the Ansible half matters only for a
cold build. Remove the now-redundant standalone kube-vip.yml step from any runbook.
NEW NAMED GAP, unwritten: the L2 test cannot assert the running agents' live
KUBERNETES_SERVICE_HOST, which is the drift the L0 check cannot see. Recorded in that
test's gap list.
Refs R-PLAT-01, R-NET-01, R-ENV-02.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
b7d6ba3d5f |
fix(kyverno): unblock CDI imports by SATISFYING the label requirement, not exempting it
Prod's UniFi VM has no disk. `DataVolume unifi/unifi-rootdisk` stuck in
ImportScheduled for hours, because Kyverno denied CDI's own generated pod:
validate.kyverno.svc-fail denied Pod/unifi/importer-prime-<uid>
require-auth-mode-label (R-IDP-02)
require-egress-class-label (R-NET-05)
Both policies match any Pod in an `app-namespace: "true"` namespace with no
exclusion, and CDI generates `importer-*` itself — it cannot carry repo labels.
A COLD-START defect, not a prod quirk: dev's identical import Succeeded 9 days
ago, before the policies enforced, so dev has never exercised it and would hit it
on any rebuild. Fourth bug of this shape in two days.
MECHANISM: a MUTATE ClusterPolicy that ADDS
`egress-class: internet` + `auth-mode: none` (add-if-absent anchor) to Pods on
CREATE in app namespaces WHEN the requesting subject is ServiceAccount
`cdi/cdi-sa`. Both validate policies are untouched — no exclude, no exception,
`background: true` preserved on them.
Why mutate beats exempting: the requirement stays literally true ("every pod in an
app namespace declares both labels") and the values are HONEST — the importer does
pull over the default WAN path, and `internet` is the least-reach class (it does
not grant the VPN path); a transient worker pod with no UI genuinely is
`auth-mode: none`.
THE MATCH IS IDENTITY, NOT A NAME. `subjects: ServiceAccount cdi/cdi-sa` is the
AdmissionReview userInfo, taken from the real prod denial
(`system:serviceaccount:cdi:cdi-sa`, name importer-prime-…, op CREATE). A name
prefix is attacker-choosable; a requesting ServiceAccount is not — and the test
proves it, with a fixture `importer-prime-forged-by-an-app` that copies both the
name prefix AND CDI's labels and is still DENIED. Covers every CDI worker kind
(importer/uploader/cloner) without enumerating names that change per release.
Confirmed on prod that cdi-sa is the only cdi-namespace SA that can create pods.
REJECTED, and the first one is a trap worth recording:
* PolicyException — the CRD EXISTS (v2/v2beta1, from the pre-applied bundle) but
all controllers run `--enablePolicyException=false` (verified live on prod:
admission, background and reports controllers all carry the flag). An exception
would apply cleanly through Flux and be SILENTLY IGNORED. Enabling the gate is a
cluster-wide capability change for no gain over the mutate.
* `exclude` scoped to cdi-sa — sound identity, worse consequences: any userInfo
match forces `background: false`, which would drop background scanning and
policy-report coverage of R-NET-05/R-IDP-02 for ALL EXISTING PODS to fix one pod
class. It also leaves the importer with no labels at all — the unlabelled
fall-through that require-egress-class-label's own header calls a fail-open leak.
* name-prefix / CDI-label matching — attacker-choosable, and proven walkable.
TWO-WAY PROOF, non-vacuous by construction — same resource, different requester,
opposite outcomes (verified by me, not just reported):
userinfo cdi-sa -> mutate pass, require-egress-class pass, require-auth-mode pass
userinfo ordinary -> mutate SKIP, require-egress-class FAIL, require-auth-mode FAIL
Kyverno L0 went 17 -> 29 tests passed, 0 failed. The mutate policy is deliberately
kept OUT of the existing tests/kyverno-test.yaml: that suite declares no userinfo,
and without userinfo the offline engine does not discriminate on subjects — it
mutates everything, which would have silently turned its negative rows into passes.
platform-config/kustomization.yaml is the live apply path for these ClusterPolicies;
without it the policy never reaches a cluster.
RESIDUAL TRADE-OFF, reversible by deleting one file: anything created by cdi-sa in
an app namespace now has these labels supplied rather than being rejected for not
declaring them — including a pod that is not a CDI worker. That identity already
holds `pods create/delete` cluster-wide via ClusterRole `cdi`, so it is not a new
capability; what changes is that for that one identity the declaration is assumed
rather than demanded. restrict-host-namespaces, the namespace default-deny baseline
and the CiliumNetworkPolicies all still apply.
FIRST resource-mutating policy on this cluster: kyverno-resource-mutating-webhook-cfg
holds 0 webhooks today; with autoUpdateWebhooks=true Kyverno registers
mutate.kyverno.svc-fail for Pods within seconds of this applying. Prod's
forceFailurePolicyIgnore=false makes it failurePolicy: Fail — same posture as the
validating webhook already in that path.
CDI retries importer creation on a loop, so the stuck import should proceed once
this lands. The detached prime-be3f9d1c-… 40 GiB scratch PVC is separate operator
cleanup; untouched, as is the DataVolume.
VERIFIED: full CI gate PASS. Nothing applied to any cluster.
Refs R-IDP-02, R-NET-05, R-PLAT-01.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
834928c237 |
fix(gitops): CDI cold-start deadlock repaired IN THE GRAPH, not by a pre-apply
`platform-config` applied the CDI CR *and* cdi-storageprofiles.yaml in ONE pass.
StorageProfile's CRD does not exist until cdi-operator reconciles that CR, and
Flux server-side dry-runs every object before applying any — so the unknown kind
aborted the tier, the CR was never applied, the CRD was never created, and the
tier could NEVER converge. Observed on prod: cdi-operator Available 12h, no CDI
CR, no storageprofiles CRD, every downstream tier blocked.
The profiles now live in their own tier ./platform-config-cdi with
dependsOn: platform-config and wait: true. Because dependsOn is REVISION-gated
and platform-config runs wait: true, the CDI CR must be applied AND healthy —
exactly the event that creates the CRD — before the profiles are applied. Cold
clusters order themselves. `standup.sh crds` is retained as a fallback for
clusters already stuck, and because it is idempotent.
THE GENERALISABLE RULE (recorded in clusters/README.md): a CR whose CRD is
created by a CONTROLLER AT RUNTIME is second-order and needs its own pass.
cdi-operator.yaml registers exactly ONE CRD (cdis.cdi.kubevirt.io); storageprofiles,
datavolumes, datasources and dataimportcrons appear only after it reconciles the
CDI CR. An audit found StorageProfile is the only second-order kind in
platform-config — KubeVirt, CDI, KeycloakRealmImport, CNPG Cluster,
VolumeSnapshotClass, ClusterIssuer, PrometheusRule, ServiceMonitor and the Cilium
L2 CRs all have their CRD in git or in a chart.
Moving the CDI CR up into `platform` was rejected: that would put CDI's health on
the tier the CNI gates and everything waits on — the mistake the oauth2-proxy and
headlamp splits exist to undo.
apps-vms gains dependsOn: platform-config-cdi. LOAD-BEARING, not cosmetic:
apps/vms/unifi/20-datavolume.yaml provisions on storageClassName: longhorn-vm and
its comment claimed platform-config guaranteed the profiles — which this move
would have silently falsified.
THE PRUNE TRANSIENT, MEASURED RATHER THAN ASSUMED. platform-config has
prune: true, so it deletes both profiles once, CDI recreates them with empty spec,
and the new tier re-applies the overrides ~30-60s later. Compared our override
against CDI's unaided inference for the same Longhorn provisioner on dev:
longhorn-vm (we override) spec RWX/Block -> status ReadWriteMany/Block
longhorn-static (no override) spec unset -> status ReadWriteOnce/Block
Both infer cloneStrategy: snapshot. So cloneStrategy is NOT at risk; accessModes
IS — unaided CDI gives RWO. A DataVolume provisioned on longhorn-vm inside the
window would be stamped RWO/Block and be PERMANENTLY non-live-migratable. Flux can
no longer cause it (apps-vms gates on the new tier); a human must not do it by hand.
Corroborating evidence that the recreate happens at all: dev has 5 StorageClasses
and 5 StorageProfiles, three with fluxOwner=NONE, spec unset and status populated
— CDI creating and inferring them with no Flux involvement.
MERGE PRECONDITION: `flux get kustomization platform-config` must be Ready on the
target first. If it is not, the profiles are pruned and sit at CDI defaults until
it recovers — and prod was in that state hours earlier. Fallback is the two-step
the Cilium move used (merge with prune: false, verify the ownership label moved,
restore prune: true).
substituteFrom: cluster-vars is declared even though the manifest has no ${TOKEN},
deliberately: conformance/tests/l0-static/flux-postbuild-substitution only audits
paths whose Kustomization declares it, so omitting it would move the file OUT of
the audited set — a blind spot for a future literal-token ship. Gate confirms it
stayed in (path=./platform-config-cdi files=2 defined=0 hazards=0). No SOPS
decryption stanza: the moved file is two plain CRs, so no overlay change was needed.
VERIFIED INDEPENDENTLY OF THE AGENT: platform-config renders 0 StorageProfile
while keeping the CDI and KubeVirt CRs; platform-config-cdi renders exactly the
two profiles; the graph is byte-identical across dev and prod with apps-vms
carrying both edges and no cycle. Full CI gate PASS.
KNOWN FOLLOW-UP: bootstrap/standup.sh TIER_ORDER does not yet include
platform-config-cdi, so `resume` will not wait on it. Another agent holds that
file; the PM will add it.
Refs R-GITOPS-01, R-ENV-02.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
1 changed files with 3 additions and 19 deletions
@@ -185,25 +185,9 @@ patches:
|
||||
name: flux-system
|
||||
namespace: flux-system
|
||||
spec:
|
||||
# CUTOVER DONE 2026-09-06 (operator direction: "move the repo to prod"). Prod now reconciles
|
||||
# from PROD'S OWN in-cluster Gitea. The workstation bootstrap container
|
||||
# (http://192.168.2.132:3000) is retired as prod's source — it was a podman container on the
|
||||
# operator's workstation holding a DHCP lease on WIFI, i.e. production's source of truth was a
|
||||
# laptop. It is kept only as a recovery path (bootstrap/gitea/bootstrap-gitea.sh).
|
||||
#
|
||||
# THIS LINE IS SELF-REFERENTIAL AND THAT IS THE WHOLE DIFFICULTY. The root Kustomization
|
||||
# renders ./clusters/prod, which contains this patch — so a live `kubectl patch` of
|
||||
# GitRepository.spec.url is REVERTED on the next reconcile unless the authored value moves
|
||||
# too. The cutover therefore had to be: (1) push the repo to prod's Gitea, (2) fast-forward
|
||||
# its `main` to the exact commit prod was already running so the source swap changed nothing
|
||||
# else, (3) live-patch the url to open a window, (4) land THIS commit through that window so
|
||||
# the authored value agrees. Dev hit the identical trap on 2026-09-05
|
||||
# (infra/PROD-PROVISIONING.md §10a "D0/D1 as executed").
|
||||
#
|
||||
# Verified before the switch: a throwaway pod INSIDE prod resolved this host through
|
||||
# in-cluster CoreDNS to the Gateway VIP and cloned over the public LE cert with no CA
|
||||
# supplied. The workstation being able to reach it proves nothing about pod egress.
|
||||
url: https://gitea.prod.home.keithjackson.dev/Home-Network/home-network-k3s-impl.git
|
||||
# TEMPORARY bootstrap source — workstation container, NOT in any cluster. See the block
|
||||
# above for the cutover to https://gitea.home.keithjackson.dev/... . Do not treat as final.
|
||||
url: http://192.168.2.132:3000/Home-Network/home-network-k3s-impl.git
|
||||
ref:
|
||||
branch: main
|
||||
- target:
|
||||
|
||||
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.