# cluster-config/cilium-values.yaml # Cilium CNI — installed via talosctl (not helmfile) during cluster bootstrap. # Applied once: `helm install cilium cilium/cilium -n kube-system -f cilium-values.yaml` # # Why Cilium: Talos Linux does not ship kube-proxy. Cilium's eBPF dataplane # replaces it entirely (kubeProxyReplacement: true) and also handles LB-IPAM # so LoadBalancer services get real IPs without MetalLB. # ── cgroup ──────────────────────────────────────────────────────────────────── # Talos mounts cgroups at boot before any container runtime starts. # autoMount: false tells Cilium to use the existing mount rather than trying # to mount its own — double-mounting on Talos causes init failures. cgroup: autoMount: enabled: false hostRoot: /sys/fs/cgroup # where Talos exposes the cgroup v2 hierarchy # ── IPAM ────────────────────────────────────────────────────────────────────── # kubernetes mode: Cilium allocates pod IPs from the pod CIDR that Talos # configured for each node (--pod-cidr in the kubelet). Alternative is # Cilium's own cluster-pool IPAM, but that requires extra config and # conflicts with the Talos node CIDR assignment. ipam: mode: kubernetes # ── Operator ────────────────────────────────────────────────────────────────── # Single replica is fine for a 3-node homelab. The operator manages CiliumNode # objects and LB-IPAM pools — it does not sit in the data path. operator: replicas: 1 # ── kube-proxy replacement ──────────────────────────────────────────────────── # Talos is deliberately installed without kube-proxy (machineConfig # install.extensions excludes it). Cilium must replace it completely — # partial replacement would leave Service ClusterIPs unreachable. kubeProxyReplacement: true # ── L2 announcements ────────────────────────────────────────────────────────── # Without this, LB-IPAM (k8s/cilium/lb-ipam-pool.yaml) assigns real IPs to # LoadBalancer Services, but nothing ARPs for them on the LAN — the IP shows # up in `kubectl get svc` but is 100% unreachable from outside the cluster # (confirmed: forgejo's .165 and shadowsocks' .166 both had incomplete ARP # entries and 100% ping loss before this). This flag is what actually makes # k8s/cilium/l2-announcement-policy.yaml take effect instead of being inert. l2announcements: enabled: true # ── API server endpoint ─────────────────────────────────────────────────────── # Cilium needs to talk to the Kubernetes API to watch Nodes/Services/Endpoints. # On Talos the API server listens on 127.0.0.1:7445 locally (the external # port 6443 requires the node's external cert, which may not be available # during early bootstrap). This is the standard Talos Cilium bootstrap config. k8sServiceHost: 127.0.0.1 k8sServicePort: 7445 # ── Security context / capabilities ────────────────────────────────────────── # Cilium's eBPF programs run in the kernel and require elevated capabilities. # These are the minimum set needed — removing any of them breaks networking. # # NET_ADMIN / NET_RAW — manipulate iptables/nftables and raw sockets # IPC_LOCK — lock eBPF maps in memory (prevents paging out BPF state) # SYS_ADMIN — call bpf() syscall and mount BPF filesystem # SYS_RESOURCE — raise RLIMIT_MEMLOCK for BPF map memory # DAC_OVERRIDE / FOWNER / SETGID / SETUID — file permission ops during init # CHOWN / KILL — container lifecycle management # # cleanCiliumState runs as a one-shot init container to wipe stale eBPF state # on upgrades — it needs NET_ADMIN, SYS_ADMIN, SYS_RESOURCE only. securityContext: capabilities: ciliumAgent: - CHOWN - KILL - NET_ADMIN - NET_RAW - IPC_LOCK - SYS_ADMIN - SYS_RESOURCE - DAC_OVERRIDE - FOWNER - SETGID - SETUID cleanCiliumState: - NET_ADMIN - SYS_ADMIN - SYS_RESOURCE