NetworkPolicy可以从IP地址或者端口层面控制网络流量,网络策略通过网络插件来实现,如果要使用网络策略,必须使用支持networkPolicy的网络解决方案。创建一个NetworkPolicy资源对象,如果没有控制器来使用,那么这个NetworkPolicy不会有任何作用。当网络策略选择了某些Pod后,这些被选中的Pod就会遵循NetworkPolicy中定义的规则。另外,网络测试不会冲突,如果有一个或者多个策略选择了一个Pod,那么该Pod会使用多个策略的和集。在定义NetworkPolicy规则时有一些关键字段,具体字段含义如下所示:
spec:包含了在一个namespace中定义特定网络策略所需的所有信息。
podSelector:用于选择一组Pod,如果podSelector字段是空,代表选择namespace下的所有Pod
policyTypes:policyType包含Ingress或者Egress或者两者都有,如果policyTypes没有指定,那么默认是Ingress。
Ingress:Ingress规则白名单列表,每个允许同时匹配from和ports部分的流量
Egress:Egress规则的白名单列表,每个规则允许匹配to和port部分的流量
例如下面的规则是:选择打了标签role=db的pod。
podSelector:
matchLabels:
role:db
下面的规则是允许所有的流量,如果ingress后面没有-{},则是拒绝所有的流量。
spec:
podSelector:{}
policyType:
- Ingress
spec:
podSelector:{}
ingress:
-{}
policyTypes:
-Ingress
NetworkPolicy是命名空间级别的资源,规则应用与标签选择器匹配的endpoint的集合。GlobalNetworkPolicy与NetworkPolicy功能一样,是整个集群级别的资源,GlobalNetworkPolicy会在集群中所有Namespace生效,并且能限制主机(HostEndpoint).
接下来通过实际例子演示NetworkPolicy工作过程,集群使用的网络插件是Calico。首先部署两个应用,部署的yaml文件如下,toolbox是用于访问部署的calico-demo的pod的。
apiVersion: v1
kind: Namespace
metadata:
name: calico-demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: calico-demo
name: calico-demo
labels:
app: calico-demo
spec:
replicas: 1
selector:
matchLabels:
app: calico-demo
template:
metadata:
labels:
app: calico-demo
access: "true"
spec:
containers:
- name: calico-demo
image: nginx
ports:
- containerPort: 80
apiVersion: apps/v1
kind: Deployment
metadata:
# namespace: default
name: toolbox
spec:
replicas: 1
selector:
matchLabels:
app: toolbox
template:
metadata:
labels:
app: toolbox
access: "true"
spec:
containers:
- name: toolbox
image: centos
command:
- tail
- -f
- /dev/null
toolbox一个部署在calico-demo的namespace下,一个部署在default的namespace下面,部署完成后,登录到toolbox pod里面,用curl和ping命令访问calico-demo服务,可以看到都访问成功。同理进入在default namespace下的toolbox,curl和ping都能成功。
此时让NetworkPolicy生效,NetworkPolicy的规则如下,表示不允许任何流量。NetworkPolicy生效后,在两个namespace下的toolbox pod里面再用curl和ping命令,都不通了
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: default-deny
namespace: calico-demo
spec:
podSelector: {}
接着让下面的GlobalNetworkPolicy生效,这个规则是开通ping命令。因为是Global的policy,所以在两个namespace下用ping命令都能成功,curl命令仍然失败。
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: allow-ping-in-cluster
spec:
selector: all()
types:
- Ingress
ingress:
- action: Allow
protocol: ICMP
source:
selector: all()
icmp:
type: 8 # Ping request
- action: Allow
protocol: ICMPv6
source:
selector: all()
icmp:
type: 128 # Ping request
接着在开通80端口,但是该端口的流量要来源于default namespace中的pod才行。所以下面的NetworkPolicy生效后,在default namespace下的toolbox中用curl命令访问calico-demo服务是通的。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-http
namespace: calico-demo
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: default
ports:
- protocol: TCP
port: 80
上面演示了NetworkPolicy工作过程,而NetworkPolicy实际是通过防火墙规则进行控制,而Iptables项目最早出来就是为了解决防火墙规则配置。所以查看Calico的Iptables即可知道背后控制的逻辑。查看Calico的防火墙规则会看到有cali-INPUT的chain。
通过命令ip a命令查看网络配置,可以看到有cali开头的配置。实际如果采用了cali的网络插件,那么通过网络插件的请求,都会以cali开头。
下面是添加了第一条NetworkPolicy后Iptables的主要内容。这里对cali开头的请求打了标签0x0/0x20000,而对于打了这些标签的请求,-j的处理是DROP,即被抛弃了,不处理。通过这样显示了拒绝请求的NetworkPolicy。
在开通ICMP后,防火墙规则进行了变更,变化点如下。对于matchle icmp-type 8的请求打了0x10000标签,而对于打了这样标签的请求,-j操作是RETURN,即直接返回,而不是被DROP掉.
以上就是NetworkPolicy工作原理,可以看到通过配置NetworkPolicy可以在网络层面对请求进行定制好的控制,保证集群安全。