$ kubectl patch kubecontrollersconfigurations default \ --type=merge -p '{"spec": {"controllers": {"node":{"hostEndpoint":{"autoCreate": "Enabled"}}}}}' $ kubectl get hep -l kubernetes.io/os NAME CREATED AT 10.xxx.xx.170-auto-hep 2025-10-15T09:18:37
看了下选择器文档,直接改成 selector: all() 后可以了,外部 IP 不在上面的白名单里 curl nodeport 不通
> -A cali-fh-any-interface-at-all -m comment --comment "cali:_hnIU4TYdSt--CFh" -m mark --mark 0x0/0x20000 -j cali-pi-_Ddz2TLFtYPs0Zt3iUZs
来懒人办法,清理掉链的统计信息看生效在哪块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
$ iptables -t mangle -Z cali-pi-_Ddz2TLFtYPs0Zt3iUZs $ iptables -t mangle -nvL cali-pi-_Ddz2TLFtYPs0Zt3iUZs Chain cali-pi-_Ddz2TLFtYPs0Zt3iUZs (1 references) pkts bytes target prot opt in out source destination 10 600 MARK all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:5eFTXO3b0B-Tbiq8 */ /* Policy default.allow-cluster-nodeport-only ingress */ MARK and 0xffe7ffff 0 0 MARK all -- * * 10.xxx.41.110 0.0.0.0/0 /* cali:L5TwSbHWsELZIAEd */ MARK or 0x80000 0 0 MARK all -- * * 10.xxx.195.118 0.0.0.0/0 /* cali:noUEAlswvbgG5j7d */ MARK or 0x80000 0 0 MARK all -- * * 10.187.0.0/16 0.0.0.0/0 /* cali:TxEjJz-IsLiJzVDK */ MARK or 0x80000 0 0 MARK all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:SBosizM5mtjxTsOe */ mark match 0x80000/0x80000 MARK or 0x10000 0 0 NFLOG all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:5w4NEetZaXhF7wjm */ mark match 0x10000/0x10000 nflog-prefix "API0|default.allow-cluster-nodeport-only" nflog-group 1 nflog-range 80 0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:NMym66CfdBVWGhc6 */ mark match 0x10000/0x10000 0 0 MARK tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:HONlGpSGnitWLUh- */ multiport dports 30008 MARK or 0x40000 0 0 NFLOG all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:9vcFh92OaOMP06xg */ mark match 0x40000/0x40000 nflog-prefix "DPI1|default.allow-cluster-nodeport-only" nflog-group 1 nflog-range 80 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:URAeOCUsDbThanFp */ mark match 0x40000/0x40000
然后外部的不在白名单里的 curl 下 NodePort,再看下统计信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
$ iptables -t mangle -nvL cali-pi-_Ddz2TLFtYPs0Zt3iUZs Chain cali-pi-_Ddz2TLFtYPs0Zt3iUZs (1 references) pkts bytes target prot opt in out source destination 44 2640 MARK all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:5eFTXO3b0B-Tbiq8 */ /* Policy default.allow-cluster-nodeport-only ingress */ MARK and 0xffe7ffff 0 0 MARK all -- * * 10.xxx.41.110 0.0.0.0/0 /* cali:L5TwSbHWsELZIAEd */ MARK or 0x80000 0 0 MARK all -- * * 10.xxx.195.118 0.0.0.0/0 /* cali:noUEAlswvbgG5j7d */ MARK or 0x80000 0 0 MARK all -- * * 10.187.0.0/16 0.0.0.0/0 /* cali:TxEjJz-IsLiJzVDK */ MARK or 0x80000 0 0 MARK all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:SBosizM5mtjxTsOe */ mark match 0x80000/0x80000 MARK or 0x10000 0 0 NFLOG all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:5w4NEetZaXhF7wjm */ mark match 0x10000/0x10000 nflog-prefix "API0|default.allow-cluster-nodeport-only" nflog-group 1 nflog-range 80 0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:NMym66CfdBVWGhc6 */ mark match 0x10000/0x10000 2 120 MARK tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:HONlGpSGnitWLUh- */ multiport dports 30008 MARK or 0x40000 2 120 NFLOG all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:9vcFh92OaOMP06xg */ mark match 0x40000/0x40000 nflog-prefix "DPI1|default.allow-cluster-nodeport-only" nflog-group 1 nflog-range 80 2 120 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 /* cali:URAeOCUsDbThanFp */ mark match 0x40000/0x40000
其实就是用 mark 做条件 flag 匹配处理,主要看这几个规则就行:
1 2 3 4 5 6 7 8 9 10
> -A cali-pi-_Ddz2TLFtYPs0Zt3iUZs -m comment --comment "cali:5eFTXO3b0B-Tbiq8" -m comment --comment "Policy default.allow-cluster-nodeport-only ingress" -j MARK --set-xmark 0x0/0x180000 > -A cali-pi-_Ddz2TLFtYPs0Zt3iUZs -s 10.xxx.41.110/32 -m comment --comment "cali:L5TwSbHWsELZIAEd" -j MARK --set-xmark 0x80000/0x80000 > -A cali-pi-_Ddz2TLFtYPs0Zt3iUZs -s 10.xxx.195.118/32 -m comment --comment "cali:noUEAlswvbgG5j7d" -j MARK --set-xmark 0x80000/0x80000 > -A cali-pi-_Ddz2TLFtYPs0Zt3iUZs -s 10.187.0.0/16 -m comment --comment "cali:TxEjJz-IsLiJzVDK" -j MARK --set-xmark 0x80000/0x80000 > -A cali-pi-_Ddz2TLFtYPs0Zt3iUZs -m comment --comment "cali:SBosizM5mtjxTsOe" -m mark --mark 0x80000/0x80000 -j MARK --set-xmark 0x10000/0x10000 > -A cali-pi-_Ddz2TLFtYPs0Zt3iUZs -m comment --comment "cali:5w4NEetZaXhF7wjm" -m mark --mark 0x10000/0x10000 -j NFLOG --nflog-prefix "API0|default.allow-cluster-nodeport-only" --nflog-group 1 --nflog-range 80 > -A cali-pi-_Ddz2TLFtYPs0Zt3iUZs -m comment --comment "cali:NMym66CfdBVWGhc6" -m mark --mark 0x10000/0x10000 -j RETURN > -A cali-pi-_Ddz2TLFtYPs0Zt3iUZs -p tcp -m comment --comment "cali:HONlGpSGnitWLUh-" -m multiport --dports 30008 -j MARK --set-xmark 0x40000/0x40000 > -A cali-pi-_Ddz2TLFtYPs0Zt3iUZs -m comment --comment "cali:9vcFh92OaOMP06xg" -m mark --mark 0x40000/0x40000 -j NFLOG --nflog-prefix "DPI1|default.allow-cluster-nodeport-only" --nflog-group 1 --nflog-range 80 > -A cali-pi-_Ddz2TLFtYPs0Zt3iUZs -m comment --comment "cali:URAeOCUsDbThanFp" -m mark --mark 0x40000/0x40000 -j DROP
白名单会打上 0x80000/0x80000 标记
-m mark --mark 0x80000/0x80000 -j MARK --set-xmark 0x10000/0x10000 匹配上 0x80000/0x80000 的打新 mark 0x10000/0x10000 ,这里按照二进制理解,两者都存在
// https://github.com/projectcalico/calico/blob/v3.30.3/felix/dataplane/linux/hostip_mgr.go#L81-L103 func(m *hostIPManager) OnUpdate(msg interface{}) { switch msg := msg.(type) { case *ifaceAddrsUpdate: log.WithField("update", msg).Info("Interface addrs changed.") if m.nonHostIfacesRegexp.MatchString(msg.Name) { log.WithField("update", msg).Debug("Not a real host interface, ignoring.") return } if msg.Addrs != nil { m.hostIfaceToAddrs[msg.Name] = msg.Addrs } else { delete(m.hostIfaceToAddrs, msg.Name) }
// Host ip update is a relative rare event. Flush entire ipsets to make it simple. metadata := ipsets.IPSetMetadata{ Type: ipsets.IPSetTypeHashIP, SetID: m.hostIPSetID, MaxSize: m.maxSize, } m.ipsetsDataplane.AddOrReplaceIPSet(metadata, m.getCurrentMembers()) } }
设计
一个 ipset 存储白名单 whiteiplist,匹配上就 ACCEPT
一个 ipset 存储 Port whiteportlist,此刻还匹配就说明不是白名单走过来,打 mark 2
# 白名单 IP 直接放行 iptables --wait --table mangle --append test-from-host-endpoint -m set --match-set whiteiplist src -j ACCEPT # 非白名单 ip 访问白名单端口拒绝 iptables --wait --table mangle --append test-from-host-endpoint -m set --match-set whiteportlist dst -j DROP
filter 表的 INPUT 链里我们也加了下类似 this-host 的逻辑:
1 2 3 4 5 6
-A INPUT -j BASE-RULE
-A BASE-RULE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A BASE-RULE -m set --match-set whiteiplist src -j ACCEPT -A BASE-RULE -m set --match-set this-host src -j ACCEPT -A BASE-RULE -m set --match-set whiteportlist dst -j DROP
if [ -d /sys/devices/virtual/net/cni0/ ];then ipset add this-host $(get_if_inet cni0| sed 's#/\d+#/16#') -exist fi
ip -o -4 a s scope global | grep -Ev ':\s+(cali|tunl|vxlan|flannel|docker0|veth|wireguard|wg|cni0|kube|dummy|veth)' | awk -F'[ /]+' '{print $4}'| \ while read ip;do ipset add this-host $ip -exist done
}
function get_if_inet6(){ local if=$1 ignore=$2 inet6 inet6=ip -6 -o a s $if | awk '{print $4}' if [ -n "$ignore" ];then inet6=$(echo $inet6 | grep -Ev "$2") fi echo $inet6 }
function this_host6(){ ipset create this-host6 hash:net maxelem 1000000 family inet6 -exist ipset add this-host6 ::1 -exist
if [ -d /sys/devices/virtual/net/cni0/ ];then cni0_inet6=$(get_if_inet6 cni0| sed 's#/\d+#/56#') if [ -n "$cni0_inet6" ];then ipset add this-host6 $cni0_inet6 -exist fi fi
ip -o -6 a s scope global | grep -Ev ':\s+(cali|tunl|vxlan|flannel|docker0|veth|wireguard|wg|cni0|kube|dummy|veth)' |\ grep -Ev '^fe80::.+/64' | awk -F'[ /]+' '{print $4}'| \ while read ip;do ipset add this-host6 $ip -exist done