云原生安全:攻防实践与体系构建
上QQ阅读APP看书,第一时间看更新

4.5.1 背景知识

1.中间人攻击

中间人攻击(Man-in-the-middle Attack)是一类经典的攻击方式。它包括许多种具体的类型,如ARP欺骗、DNS劫持和SMB会话劫持等。

许多读者对中间人攻击的概念可能都不陌生。通常情况下,在不受干扰时,逻辑上看两台计算机设备之间的通信应该如图4-13所示(高度抽象,略去了复杂的协议栈)。

图4-13 正常情况下两个设备间的通信

此时,如果有一个攻击者劫持了张三和李四的通信,分别在张三面前冒充李四,在李四面前冒充张三,那么通信场景就变成了如图4-14所示。

图4-14 中间人攻击场景

在此过程中,张三和李四可能对攻击者浑然不觉。然而,作为“通信的中间人”,攻击者却能够读取甚至修改双方交互的信息。欲了解更多关于中间人攻击的内容,可以参考维基百科[1]

理论上,几乎所有的通信交互都可能存在中间人攻击的风险。其中,针对ARP和DNS协议的攻击尤为经典。但是,结合Linux系统Capabilities知识可知,如果想要发送ARP包,需要具有CAP_NET_RAW权限。那么,容器内部的root用户是否具有此权限呢?

首先,在Pod内执行命令查看Capabilities的值:


root@k8s:~# kubectl exec -it attacker -- grep CapEff /proc/self/status
CapEff:    00000000a80425fb

然后,在宿主机上使用capsh命令解析上一步获取的值:


root@k8s:~# capsh --decode=00000000a80425fb
0x00000000a80425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_
    kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_
    raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap

可以看到,解析结果包含cap_net_raw,这意味着在Pod中攻击者具有足够权限来发送恶意的ARP包。

2.Kubernetes与DNS

我们首先介绍一下Kubernetes中的DNS服务。首先,Kubernetes以服务资源kube-dns的形式提供集群级别的DNS服务:


root@k8s:~# kubectl get svc -n kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP   202d

kube-dns服务依赖的是集群中kube-system命名空间下的CoreDNS Pod:


root@k8s:~# kubectl describe svc kube-dns -n kube-system
Name:              kube-dns
Namespace:         kube-system
Labels:            k8s-app=kube-dns
                   kubernetes.io/cluster-service=true
                   kubernetes.io/name=KubeDNS
Annotations:       prometheus.io/scrape: true
Selector:          k8s-app=kube-dns
Type:              ClusterIP
IP:                10.96.0.10
Port:              dns  53/UDP
TargetPort:        53/UDP
Endpoints:         10.244.0.134:53,10.244.0.187:53
Port:              dns-tcp  53/TCP
TargetPort:        53/TCP
Endpoints:         10.244.0.134:53,10.244.0.187:53
Session Affinity:  None
Events:            <none>

如果新建一个Pod,我们会发现,它的内部resolv.conf文件中记录的DNS服务器IP地址正是kube-dns服务的地址:


root@test:/# cat /etc/resolv.conf
nameserver 10.96.0.10

当这个Pod向kube-dns服务发起DNS查询请求时,查询请求会经过Kubernetes配置的iptables规则,最终被发送到服务后端的CoreDNS Pod中:


root@k8s:~# iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt  source              destination
KUBE-SERVICES   all  --  anywhere        anywhere     /* kubernetes service portals */

Chain KUBE-MARK-MASQ (8 references)
target     prot opt  source              destination
MARK            all  --  anywhere        anywhere     MARK or 0x4000

Chain KUBE-SEP-SFEHAAPK7JVDTVUX (1 references)
target     prot opt source               destination
KUBE-MARK-MASQ  all  --  10.244.0.134    anywhere     /* kube-system/kube-dns:dns */
DNAT            udp  --  anywhere        anywhere     /* kube-system/kube-dns:dns */ udp
                                                         to:10.244.0.134:53

Chain KUBE-SERVICES (2 references)
target     prot opt source               destination
KUBE-MARK-MASQ  udp  --  !10.244.0.0/16  10.96.0.10   /* kube-system/kube-dns:dns cluster IP */ udp dpt:domain
KUBE-SVC-TCOU7JCQXEZGVUNU  udp  --  anywhere             10.96.0.10  
    /* kube-system/kube-dns:dns cluster IP */ udp dpt:domain

Chain KUBE-SVC-TCOU7JCQXEZGVUNU (1 references)
target     prot opt source               destination
KUBE-SEP-SFEHAAPK7JVDTVUX  all  --  anywhere             anywhere    
    /* kube-system/kube-dns:dns */ statistic mode random probability 0.50000000000

欲了解更多关于CoreDNS的内容,可以参考官方文档[2]

3.Kubernetes与ARP

图4-12给出了一般性的Kubernetes网络架构。可以发现,Pod内的eth0网卡的对端被连接到cni0网桥上。此时,该对端就成为了cni0网桥的一个接口。当Pod向外发出ARP请求时,该请求会被网桥转发给其他接口,这样一来,其他Pod就能够收到ARP请求,其中网卡MAC地址与ARP请求相符的Pod就会发送ARP响应,该响应同样会被网桥转发给最初发出ARP请求的Pod。这就是Kubernetes内部同一个节点上的ARP请求响应流程。

[1] https://en.wikipedia.org/wiki/Man-in-the-middle_attack。

[2] https://kubernetes.io/docs/tasks/administer-cluster/coredns/。