使用 iptables 限制 Kubernetes 的 NodePort 服务
背景
在搭建了 Kubernetes 集群后,在 master 节点上部署了 Dashboard。我们需要在办公网内访问它,修改 service 端口暴露为 NodePort 模式后就可以达到目的。由于 master 节点部署在公网,我们希望对 NodePort 暴露的端口做限制,换句话说,只允许办公网内的 ip 对其进行访问。开始以为会很简单,用 iptables 在 INPUT 链上加一个 DROP 和 ACCEPT 操作就可以了,但事实上并非如此。
NodePort
查看 kubernetes-dashboard 命名空间里的 service,kubernetes 创建了一个名为 kubernetes-dashboard 的 NodePort,在主机端口上监听50000端口。
1 | root@localhost:~# kubectl get svc --namespace=kubernetes-dashboard |
只要我们访问 MASTER-IP:50000 就可以进入 Dashboard,是在 iptables 里经历了很多条规则才到达的。
经过 PREROUTING 进入 KUBE-SERVICES。由于 nat 在 filter 之前,所以在 INPUT 链做限制不会起作用。
1
2
3Chain PREROUTING (policy ACCEPT)
target prot opt source destination
KUBE-SERVICES all -- anywhere anywhere /* kubernetes service portals */对应的 iptables 规则( iptables-save 可查看)
1
-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
经过 KUBE-SERVICES 进入 KUBE-NODEPORTS
1
2
3
4Chain KUBE-SERVICES (2 references)
target prot opt source destination
......
KUBE-NODEPORTS all -- anywhere anywhere /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL对应的 iptables 规则,可以看到其会是链里的最后一条规则,只有当上边的所有服务规则都不匹配时才会进入 NODEPORTS
1
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS
经过 KUBE-NODEPORTS 后,首先经过 KUBE-MARK-MASQ 打上标签,之后进入 KUBE-SVC-CEZPIJSAUFW5MYPQ
1
2
3
4Chain KUBE-NODEPORTS (1 references)
target prot opt source destination
KUBE-MARK-MASQ tcp -- anywhere anywhere /* kubernetes-dashboard/kubernetes-dashboard */ tcp dpt:50000
KUBE-SVC-CEZPIJSAUFW5MYPQ tcp -- anywhere anywhere /* kubernetes-dashboard/kubernetes-dashboard */ tcp dpt:50000对应的 iptables 规则
1
2-A KUBE-NODEPORTS -p tcp -m comment --comment "kubernetes-dashboard/kubernetes-dashboard" -m tcp --dport 50000 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "kubernetes-dashboard/kubernetes-dashboard" -m tcp --dport 50000 -j KUBE-SVC-CEZPIJSAUFW5MYPQ经过 KUBE-SVC-CEZPIJSAUFW5MYPQ 进入 KUBE-SEP-QXJL632FHGWBBYEF
1
2
3Chain KUBE-SVC-CEZPIJSAUFW5MYPQ (2 references)
target prot opt source destination
KUBE-SEP-QXJL632FHGWBBYEF all -- anywhere anywhere /* kubernetes-dashboard/kubernetes-dashboard */对应的 iptables 规则
1
-A KUBE-SVC-CEZPIJSAUFW5MYPQ -m comment --comment "kubernetes-dashboard/kubernetes-dashboard" -j KUBE-SEP-QXJL632FHGWBBYEF
经过 KUBE-SEP-QXJL632FHGWBBYEF 的 DNAT 操作转给了 10.244.0.12。正是 kubernetes-dashboard pods 的 IP。
1
2
3
4Chain KUBE-SEP-QXJL632FHGWBBYEF (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 10.244.0.12 anywhere /* kubernetes-dashboard/kubernetes-dashboard */
DNAT tcp -- anywhere anywhere /* kubernetes-dashboard/kubernetes-dashboard */ tcp to:10.244.0.12:8443对应的 iptables 规则
1
2-A KUBE-SEP-QXJL632FHGWBBYEF -s 10.244.0.12/32 -m comment --comment "kubernetes-dashboard/kubernetes-dashboard" -j KUBE-MARK-MASQ
-A KUBE-SEP-QXJL632FHGWBBYEF -p tcp -m comment --comment "kubernetes-dashboard/kubernetes-dashboard" -m tcp -j DNAT --to-destination 10.244.0.12:8443
解决问题
在知道了原理后,再要解决我们的问题就很容易了,方式其实也有很多种,我直接选择了最粗暴的,那就是在 PREROUTING 中加入一条规则,将不属于公司办公网 sip 的请求直接 DNAT 到65535,一个没有运行任何服务的端口。就解决了问题。
1 | iptables -t nat -I PREROUTING -p tcp ! -s x.x.x.x/30 --dport 50000 -j REDIRECT --to-ports 65535 |
Reference
https://juejin.cn/post/6844904098605563912
https://zhaohuabing.com/istio-practice/content/ingress/nodeport.html
https://www.jianshu.com/p/c6d560d12d50
https://developer.aliyun.com/article/745086