From 41a54e8a0f1451ebc8e14d58b1df66650bd9ecb8 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 8 Apr 2024 16:18:21 +0400 Subject: [PATCH] fix: pre-create nftables chain to make kubelet use nftables In Talos, kubelet (and kube-proxy) images use `iptables-wrapper` script to detect which version of `iptables` (legacy or NFT) to use. The script assumes that `kubelet` runs on the host, and uses whatever version of `iptables` which is being used by the host. In Talos, `kubelet` runs in a container which has same `iptables-wrapper` script, and it defaults to `legacy` mode in our case. We can't check the `kubelet` image, as it would affect all Talos version, so instead pre-create the chains/tables in `nftables` so that kubelet will pick up `nft` version of `iptables`, and `kube-proxy` will do the same. Without this fix, the problem arises from the mix of `nft` used by Talos for the firewall and Kubernetes world relying on `legacy` (`xtables`). Fixes https://github.com/siderolabs/kubelet/issues/77 See https://github.com/kubernetes-sigs/iptables-wrappers/blob/e139a115350974aac8a82ec4b815d2845f86997e/iptables-wrapper-installer.sh#L102-L130 Signed-off-by: Andrey Smirnov (cherry picked from commit ff2c427b04963d69ba2eaa1084a0a078d742b9ac) --- hack/release.toml | 10 ++++++ .../pkg/controllers/network/nftables_chain.go | 35 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/hack/release.toml b/hack/release.toml index dfa5cabda7..f806f34a7c 100644 --- a/hack/release.toml +++ b/hack/release.toml @@ -212,6 +212,16 @@ machine: title = "Platforms" description = """\ Talos Linux now supports [Akamai Connected Cloud](https://www.linode.com/) provider (platform `akamai`). +""" + + [notes.iptables] + title = "IPTables" + description = """\ +Talos Linux now forces `kubelet` and `kube-proxy` to use `iptables-nft` instead of `iptables-legacy` (`xtables`) which was the default +before Talos 1.7.0. + +Container images based on `iptables-wrapper` should work without changes, but if there was a direct call to `legacy` mode of `iptables`, make sure +to update to use `iptables-nft`. """ [make_deps] diff --git a/internal/app/machined/pkg/controllers/network/nftables_chain.go b/internal/app/machined/pkg/controllers/network/nftables_chain.go index 26aa0f3b08..9fbbc70a10 100644 --- a/internal/app/machined/pkg/controllers/network/nftables_chain.go +++ b/internal/app/machined/pkg/controllers/network/nftables_chain.go @@ -65,6 +65,10 @@ func (ctrl *NfTablesChainController) Run(ctx context.Context, r controller.Runti var conn nftables.Conn + if err := ctrl.preCreateIptablesNFTable(logger, &conn); err != nil { + return fmt.Errorf("error pre-creating iptables-nft table: %w", err) + } + list, err := safe.ReaderListAll[*network.NfTablesChain](ctx, r) if err != nil { return fmt.Errorf("error listing nftables chains: %w", err) @@ -176,3 +180,34 @@ func (ctrl *NfTablesChainController) Run(ctx context.Context, r controller.Runti r.ResetRestartBackoff() } } + +func (ctrl *NfTablesChainController) preCreateIptablesNFTable(logger *zap.Logger, conn *nftables.Conn) error { + // Pre-create the iptables-nft table, if it doesn't exist. + // This is required to ensure that the iptables universal binary prefers iptables-nft over + // iptables-legacy can be used to manage the nftables rules. + tables, err := conn.ListTablesOfFamily(nftables.TableFamilyIPv4) + if err != nil { + return fmt.Errorf("error listing existing nftables tables: %w", err) + } + + if slices.IndexFunc(tables, func(t *nftables.Table) bool { return t.Name == "mangle" }) != -1 { + return nil + } + + table := &nftables.Table{ + Family: nftables.TableFamilyIPv4, + Name: "mangle", + } + conn.AddTable(table) + + chain := &nftables.Chain{ + Name: "KUBE-IPTABLES-HINT", + Table: table, + Type: nftables.ChainTypeNAT, + } + conn.AddChain(chain) + + logger.Info("pre-created iptables-nft table 'mangle'/'KUBE-IPTABLES-HINT'") + + return nil +}