在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