NetworkPolicy
在Kubernetes中,网络隔离功能是通过叫NetworkPolicy的API对象来描述的。
如下一个完整的NetworkPolicy定义:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: test-network-policy namespace: default spec: podSelector: matchLabels: role: db policyTypes: - Ingress - Egress ingress: - from: - ipBlock: cidr: 172.17.0.0/16 except: - 172.17.1.0/24 - namespaceSelector: matchLabels: project: myproject - podSelector: matchLabels: role: frontend ports: - protocol: TCP port: 6379 egress: - to: - ipBlock: cidr: 10.0.0.0/24 ports: - protocol: TCP 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)、第一种
... ingress: - from: - namespaceSelector: matchLabels: user: alice - podSelector: matchLabels: role: client ...
(2)、第二种
... ingress: - from: - namespaceSelector: matchLabels: user: alice podSelector: matchLabels: role: client ...
这两种看起来类似,但是其表示的意义是不一样的,对于第一种表示的是一种OR(或)的关系,对于这种情况只要其中一种规则满足要求都可以通过,而对于第二种则表示AND(与)的关系,必须两种同时满足才会通过。
Kubernetes对Pod的网络隔离其实是靠宿主机上生成NetworkPolicy对应的iptables规则来实现的。
比如定义好了上面的NetworkPolicy,那么就会生成类似下面的iptables规则:
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规则如下:
iptables -A FORWARD -d $podIP -m physdev --physdev-is-bridged -j KUBE-POD-SPECIFIC-FW-CHAIN iptables -A FORWARD -d $podIP -j KUBE-POD-SPECIFIC-FW-CHAIN
其中:
- 第一条FORWARD链的作用是通过本机网桥设备发往podIP的IP包;
- 第二条就是拦截跨主机通信,定义规则都到KUBE-POD-SPECIFIC-FW-CHAIN规则上
第二组KUBE-POD-SPECIFIC-FW-CHAIN规则如下:
iptables -A KUBE-POD-SPECIFIC-FW-CHAIN -j KUBE-NWPLCY-CHAIN
iptables -A KUBE-POD-SPECIFIC-FW-CHAIN -j REJECT --reject-with icmp-port-unreachable
其中:
- 第一条是把数据包发到KUBE-NWPLCY-CHAIN去匹配;
- 第二条就是把不满足NetworkPolicy中定义的请求都拒绝掉,从而实现对容器的隔离;
默认的Policies:
(1)、默认拒绝所有Ingress:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Ingress
(2)、默认允许所有ingress:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-all spec: podSelector: {} ingress: - {} policyTypes: - Ingress
(3)、默认拒绝所有Egress:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Egress
(4)、默认允许所有Egress:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-all spec: podSelector: {} egress: - {} policyTypes: - Egress
(5)、拒绝所有Ingress和Egress:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny spec: podSelector: {} policyTypes: - Ingress - Egress
例子:
1、创建两个namespace
kubectl create ns dev
kubectl create ns sit
2、给dev下的所有pod配置Ingress权限,不允许所有人访问
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: networkpolicy-ingress-demo spec: podSelector: {} policyTypes: - Ingress
然后使其作用于dev
kubectl apply -f ingress-demo.yaml -n dev
我们在dev里创建一个Pod,在外部访问查看情况
apiVersion: v1 kind: Pod metadata: name: myapp spec: containers: - name: myapp image: nginx:1.7.9 imagePullPolicy: IfNotPresent command: - "/bin/sh" - "-c" args: - "nginx && sleep 3600"
启动Pod
kubectl apply -f pod-demo.yaml -n dev