kubeproxy全伪装的作用
1. 启用kube-proxy 全伪装时
- node 访问svc的包
1.1 node 访问host network模式的svc
curl -k https://kubernetes:443/livez?verbose
[root@(l2)k8s-master-1 ~]# kubectl get svc -A -o wide
default kubernetes ClusterIP 10.96.0.1
[root@(l2)k8s-master-1 ~]# ipvsadm -ln | grep -A 4 10.96.0.1
TCP 10.96.0.1:443 rr
-> 172.32.16.11:6443 Masq 1 1 0
-> 172.32.16.12:6443 Masq 1 0 0
-> 172.32.16.13:6443 Masq 1 0 0
这里只用telnet 10.96.0.1 443
image.png注意:
由于 连接跟踪模块只是完成连接信息的采集和录入功能,并不会修改或丢弃数据包,后者是其 他模块(例如 NAT)基于 Netfilter hook 完成的。 连接跟踪概念是独立于 Netfilter 的,Netfilter 只是 Linux 内核中的一种连接跟踪实现。
contrack记录产生是发生在nat之前的。
只要具备了 hook 能力,能拦截到进出主机的每个包,完全可以在此基础上自 己实现一套连接跟踪。
当前来看,tcpdump是抓不到 src 10.96.0.1 dst=10.96.0.1 dst port 443 的包的,也就是说被netfilter机制拦截并修改了。
也就是说访问 src 10.96.0.1 dst=10.96.0.1 dst port 443 的包 直接被替换为 svc ipvs后端ip的包:
src=172.32.16.11 dst=172.32.16.11 src port 6443 dport=48531
dport=48531 就对应node 本地telnet 10.96.0.1 443发起端的临时端口。
nat的时候创建了一个新的临时端口
可以看到在包进行转发前,进行nat转换,这里是kube-proxy的全伪装模式起了作用,源三元组被替换为ipvs后端的第一个的三元组
NAT构建于nf_conntrack之上,当数据包进入nf_conntrack后,会建立一个tuple以及相应的replay tuple,而应答的数据包,会直接查找与之匹配的repaly tuple
contrack 作用的hook点:
image.png image.pngPRE_ROUTING 和 LOCAL_OUT:调用 nf_conntrack_in() 开始连接跟踪, 正常情况下会创建一条新连接记录,然后将 conntrack entry 放到 unconfirmed list。
为什么是这两个 hook 点呢?因为它们都是新连接的第一个包最先达到的地方,
PRE_ROUTING 是外部主动和本机建连时包最先到达的地方
LOCAL_OUT 是本机主动和外部建连时包最先到达的地方
contrack 和 nat的关系
unsigned int
nf_nat_inet_fn(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
ct = nf_ct_get(skb, &ctinfo);
if (!ct) // conntrack 不存在就做不了 NAT,直接返回,这也是我们为什么说 NAT 依赖 conntrack 的结果
return NF_ACCEPT;
...
疑点为啥sport是6443,不应该是目标port么?
tcpdump只能抓到netfilter哪个阶段的包?
nat 发生在netfilter哪个阶段?
2. 启用kube-proxy 全伪装时
- node 访问svc
可以看到master-1 访问svc 时,源ip和目的ip都经过了伪装
- pod 访问svc
3. 未启用kube-proxy 全伪装时
- node 访问svc
- pod 访问svc
小结: node 访问 svc 确实走了 nat,而且有conntrack 记录。
但是pod 访问svc,并没有conntrack,所有没有走nat,所以机制是??
不太理解为什么没有conntrack记录,后续再深入了解下
参考: