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 e139a11535/iptables-wrapper-installer.sh (L102-L130)

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
This commit is contained in:
Andrey Smirnov 2024-04-08 16:18:21 +04:00
parent 5622f0e450
commit ff2c427b04
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811
2 changed files with 45 additions and 0 deletions

View File

@ -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]

View File

@ -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
}