暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Kubernetes中网络控制器之NetworkPolicy

乔克的好奇心 2020-02-13
286
↑ 点击上方“乔边故事”关注我们


在Kubernetes中,网络隔离功能是通过叫NetworkPolicy的API对象来描述的。
如下一个完整的NetworkPolicy定义:

  1. apiVersion: networking.k8s.io/v1

  2. kind: NetworkPolicy

  3. metadata:

  4. name: test-network-policy

  5. namespace: default

  6. spec:

  7. podSelector:

  8. matchLabels:

  9. role: db

  10. policyTypes:

  11. - Ingress

  12. - Egress

  13. ingress:

  14. - from:

  15. - ipBlock:

  16. cidr: 172.17.0.0/16

  17. except:

  18. - 172.17.1.0/24

  19. - namespaceSelector:

  20. matchLabels:

  21. project: myproject

  22. - podSelector:

  23. matchLabels:

  24. role: frontend

  25. ports:

  26. - protocol: TCP

  27. port: 6379

  28. egress:

  29. - to:

  30. - ipBlock:

  31. cidr: 10.0.0.0/24

  32. ports:

  33. - protocol: TCP

  34. port: 5978

解释:

  • podSelector:定义这个NetworkPolicy的限制范围,上面就是定义namespace中标签为role: db的Pod,如果没空,则标识这个namespace下的所有Pod,如果一旦被podSelector选中,则这个Pod就会进入拒绝所有的状态,即这个Pod既不允许被外界访问,也不能对外界发起访问。

  • policyTypes:定义NetworkPolicy的类型,ingress表示流入请求,egress表示流出请求。

  • ingress:定义流入的规则

  • egress:定义流出的规则

其中ingress字段中的from和ports,定义允许流入的白名单和端口,这里面的白名单有三种限制方式:

  • ipBlock:限制IP,上面定义的即为允许172.17.0.0/16但不是172.17.1.0/24的网段请求;

  • namespaceSelector:限制namespace,上面定义即为允许default namespace下标签为project: myproject的的Pod请求;

  • podSelector:限制Pod,上面定义即为允许标签为role: frontend的Pod请求;

而egress字段中的to和ports,则指定允许流出的白名单和端口,这里的限制方式和ingress类似。

注意:下面这两种白名单的定义方式是不一样的。
(1)、第一种

  1. ...

  2. ingress:

  3. - from:

  4. - namespaceSelector:

  5. matchLabels:

  6. user: alice

  7. - podSelector:

  8. matchLabels:

  9. role: client

  10. ...

(2)、第二种

  1. ...

  2. ingress:

  3. - from:

  4. - namespaceSelector:

  5. matchLabels:

  6. user: alice

  7. podSelector:

  8. matchLabels:

  9. role: client

  10. ...

这两种看起来类似,但是其表示的意义是不一样的,对于第一种表示的是一种OR(或)的关系,对于这种情况只要其中一种规则满足要求都可以通过,而对于第二种则表示AND(与)的关系,必须两种同时满足才会通过。
**
Kubernetes对Pod的网络隔离其实是靠宿主机上生成NetworkPolicy对应的iptables规则来实现的。
比如定义好了上面的NetworkPolicy,那么就会生成类似下面的iptables规则:

  1. iptables -A KUBE-NWPLCY-CHAIN -s $srcIP -d $dstIP -p $protocol -m $protocol --dport $port -j ACCEPT

其中:

  • srcIP:原IP

  • dstIP:目的IP

  • protocol:协议

  • port:端口

这些参数都是从我们定义的NetworkPolicy中取出来,然后还将对所有对被隔离Pod的访问请求都转发到KUBE-NWPLCY-CHAIN上去匹配,如果匹配不通过则拒绝。
第一组KUBE-NWPLCY-CHAIN规则如下:

  1. iptables -A FORWARD -d $podIP -m physdev --physdev-is-bridged -j KUBE-POD-SPECIFIC-FW-CHAIN

  2. iptables -A FORWARD -d $podIP -j KUBE-POD-SPECIFIC-FW-CHAIN

其中:

  • 第一条FORWARD链的作用是通过本机网桥设备发往podIP的IP包;

  • 第二条就是拦截跨主机通信,定义规则都到KUBE-POD-SPECIFIC-FW-CHAIN规则上

第二组KUBE-POD-SPECIFIC-FW-CHAIN规则如下:

  1. iptables -A KUBE-POD-SPECIFIC-FW-CHAIN -j KUBE-NWPLCY-CHAIN

  2. iptables -A KUBE-POD-SPECIFIC-FW-CHAIN -j REJECT --reject-with icmp-port-unreachable

其中:

  • 第一条是把数据包发到KUBE-NWPLCY-CHAIN去匹配;

  • 第二条就是把不满足NetworkPolicy中定义的请求都拒绝掉,从而实现对容器的隔离;

默认的Policies:
(1)、默认拒绝所有Ingress:

  1. apiVersion: networking.k8s.io/v1

  2. kind: NetworkPolicy

  3. metadata:

  4. name: default-deny

  5. spec:

  6. podSelector: {}

  7. policyTypes:

  8. - Ingress

(2)、默认允许所有ingress:

  1. apiVersion: networking.k8s.io/v1

  2. kind: NetworkPolicy

  3. metadata:

  4. name: allow-all

  5. spec:

  6. podSelector: {}

  7. ingress:

  8. - {}

  9. policyTypes:

  10. - Ingress

(3)、默认拒绝所有Egress:

  1. apiVersion: networking.k8s.io/v1

  2. kind: NetworkPolicy

  3. metadata:

  4. name: default-deny

  5. spec:

  6. podSelector: {}

  7. policyTypes:

  8. - Egress

(4)、默认允许所有Egress:

  1. apiVersion: networking.k8s.io/v1

  2. kind: NetworkPolicy

  3. metadata:

  4. name: allow-all

  5. spec:

  6. podSelector: {}

  7. egress:

  8. - {}

  9. policyTypes:

  10. - Egress

(5)、拒绝所有Ingress和Egress:

  1. apiVersion: networking.k8s.io/v1

  2. kind: NetworkPolicy

  3. metadata:

  4. name: default-deny

  5. spec:

  6. podSelector: {}

  7. policyTypes:

  8. - Ingress

  9. - Egress

例子:
1、创建两个namespace

  1. # kubectl create ns dev

  2. # kubectl create ns sit

2、给dev下的所有pod配置Ingress权限,不允许所有人访问

  1. apiVersion: networking.k8s.io/v1

  2. kind: NetworkPolicy

  3. metadata:

  4. name: networkpolicy-ingress-demo

  5. spec:

  6. podSelector: {}

  7. policyTypes:

  8. - Ingress

然后使其作用于dev

  1. # kubectl apply -f ingress-demo.yaml -n dev

我们在dev里创建一个Pod,在外部访问查看情况

  1. apiVersion: v1

  2. kind: Pod

  3. metadata:

  4. name: myapp

  5. spec:

  6. containers:

  7. - name: myapp

  8. image: nginx:1.7.9

  9. imagePullPolicy: IfNotPresent

  10. command:

  11. - "/bin/sh"

  12. - "-c"

  13. args:

  14. - "nginx && sleep 3600"

启动Pod

  1. # kubectl apply -f pod-demo.yaml -n dev



-----------------------

公众号:乔边故事(ID:qiaobiangushi)

知乎: 乔边故事

头条号:乔边故事

只要脸皮够厚,整个世界都将被你踩在脚下。

-----------------------

扫码二维码关注公众号,不定期维护优质内容,技术干货!


温馨提示

如果你喜欢本文,请分享到朋友圈,想要获得更多信息,请关注我。




文章转载自乔克的好奇心,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论