Kubernetes网络策略
hostNetwork介绍
在kubernetes中,若pod使用主机网络,也就是hostNetwork=true则该pod会使用主机的dns以及所有网络配置,默认情况下是无法使用k8s自带的dns解析服务,但是可以修改DNS策略或者修改主机上的域名解析(/etc/resolv.conf),使主机可以用k8s自身的dn 服务。一般通过DNS策略(ClusterFirstWithHostNet)来使用 k8s DNS内部域名解析,k8sDNS策略如下:
Default: 继承Pod所在宿主机的DNS设置,hostNetwork的默认策略。
ClusterFirst(默认DNS策略):优先使用kubernetes环境的dns服务,将无法解析的域名转发到从宿主机继承的dns服务器
ClusterFirstWithHostNet:和ClusterFirst类似,对于以hostNetwork模式运行的Pod应明确知道使用该策略,也是可以同时解析内部和外部的域名
None: 忽略kubernetes环境的dns配置,通过spec.dnsConfig自定义DNS配置
一般使用主机网络就增加如下两行
...
hostNetwork: true
dnsPolicy: "ClusterFirstWithHostNet"
...
hostPort NodePort区别
hostPort 只会在运行的机器上开启端口, NodePort是所有Node上都会开启端口
hostPort是由portmap这个cni提供portMapping能力,同时如果想使用这个能力,在配置文件中一定需要开启portmap
使用hostPort后,会在iptables的nat链中插入相应的规则,而且这些规则是在KUBE-SERVICES 规则之前插入的,也就是说会优先匹配hostPort的规则,常用的NodePort规则其实是在KUBE-SERVICES之中,也排在其后
hostport可以通过iptables命令查看到, 但是无法在ipvsadm中查看到
使用lsof/netstat也查看不到这个端口,这是因为hostport是通过iptables对请求中的目的端口进行转发的,并不是在主机上通过端口监听
在生产环境中不建议使用hostPort
NetworkPolicy网络策略
如果希望在IP地址或端口层面(OSI 第 3 层或第 4 层)控制网络流量, 则可以考虑为集群中特定应用使用 Kubernetes 网络策略(NetworkPolicy) NetworkPolicy是一种以应用为中心的结构,允许你设置如何允许 Pod 与网络上的各类网络“实体” 通信 官方文档
pod可以通信的pod是通过如下三个标识符的组合来辩识的
其他被允许的 Pods(例外:Pod 无法阻塞对自身的访问)
被允许的名字空间
IP 组块(例外:与 Pod 运行所在的节点的通信总是被允许的, 无论 Pod 或节点的 IP 地址)
配置前置条件
网络策略通过网络插件来实现,要使用网络策略,必须使用支持NetworkPolicy 的网络解决方案,创建一个NetworkPolicy资源对象而没有控制器来使它生效的话,是没有任何作用的,常用的网络插件Flannel和Calico
Flannel:只能提供网络通讯,不提供网络策略,如果需要使用网络策略,建议使用下面的 Calico,关于Flannel可以参考k8s网络之Flannel
Calico:支持丰富的网络策略,Calico以其性能、灵活性而闻名,关于Calico可以参考k8s网络之Calico
更多了解更多的网络策略,可以参考官方文档
Pod隔离的两种类型
Pod有两种隔离: 出口的隔离和入口的隔离,默认情况下出口和入口都是非隔离的
网络策略是相加的,所以不会产生冲突。如果策略适用于Pod某一特定方向的流量, Pod在对应方向所允许的连接是适用的网络策略所允许的集合。 因此评估的顺序不影响策略的结果
要允许从源Pod到目的Pod的连接,源Pod的出口策略和目的Pod的入口策略都需要允许连接。 如果任何一方不允许连接,建立连接将会失败
NetworkPolicy资源
NetworkPolicy配置文件
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default #网络策略也属于某个命名空间
spec:
podSelector: #每个NetworkPolicy都包括一个podSelector,它对该策略所适用的一组Pod进行选择。示例中的策略选择带有 "role=db"标签的Pod。空的podSelector选择名字空间下的所有Pod。
matchLabels:
role: db
policyTypes: #每个NetworkPolicy都包含一个policyTypes列表,其中包含Ingress或Egress或两者兼具。policyTypes 字段表示给定的策略是应用于进入所选Pod的入站流量还是来自所选Pod的出站流量,或两者兼有。 如果 NetworkPolicy 未指定 policyTypes 则默认情况下始终设置 Ingress; 如果 NetworkPolicy 有任何出口规则的话则设置 Egress。
- Ingress #如果只写Ingress不写任何规则则默认拒绝所有流量
- Egress #如果只写Egress不写任何规则则默认拒绝所有流量
ingress: #入口配置,每个NetworkPolicy可包含一个ingress规则的白名单列表。 每个规则都允许同时匹配from和ports部分的流量。
- from: #注意以下三种方式如果前面带-为或关系,如果什么不带则为且关系
- ipBlock: #地址块配置方式
cidr: 172.17.0.0/16
except: #排除的地址
- 172.17.1.0/24
- namespaceSelector: #选择某个命名空间下所有pod
matchLabels:
project: myproject
- podSelector: #选择当前命名空间下某个pod
matchLabels:
role: frontend
ports: #允许访问的端口协议配置
- protocol: TCP
port: 6379
egress: #每个NetworkPolicy可包含一个egress规则的白名单列表。 每个规则都允许匹配to和port部分的流量。
- to: #配置与上面ingress相同
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
必需字段:与所有其它的Kubernetes配置一样,NetworkPolicy需要apiVersion、 kind和metadata字段
spec:NetworkPolicy规约中包含了在一个名字空间中定义特定网络策略所需的所有信息
podSelector:每个NetworkPolicy都包括一个podSelector, 它对该策略所适用的一组Pod进行选择。示例中的策略选择带有"role=db"标签的Pod。 空的podSelector选择名字空间下的所有Pod
policyTypes:每个NetworkPolicy都包含一个policyTypes列表,其中包含Ingress或Egress或两者兼具。policyTypes字段表示给定的策略是应用于进入所选Pod的入站流量还是来自所选 Pod 的出站流量,或两者兼有。 如果NetworkPolicy未指定policyTypes则默认情况下始终设置Ingress; 如果NetworkPolicy有任何出口规则的话则设置Egress
ingress:每个NetworkPolicy可包含一个ingress规则的白名单列表。 每个规则都允许同时匹配from和ports部分的流量。示例策略中包含一条简单的规则: 它匹配某个特定端口,来自三个来源中的一个,第一个通过ipBlock指定,第二个通过namespaceSelector指定,第三个通过podSelector指定
egress:每个NetworkPolicy可包含一个egress规则的白名单列表。 每个规则都允许匹配to和 port部分的流量。该示例策略包含一条规则, 该规则将指定端口上的流量匹配到10.0.0.0/24 中的任何目的地
该网络策略示例
隔离 "default"名字空间下"role=db"的 Pod (如果它们不是已经被隔离的话)
(Ingress 规则)允许以下Pod连接到"default"名字空间下的带有"role=db"标签的所有Pod的 6379 TCP端口:
"default"名字空间下带有"role=frontend"标签的所有 Pod
带有"project=myproject"标签的所有名字空间中的Pod
IP地址范围为172.17.0.0–172.17.0.255 和172.17.2.0–172.17.255.255 (除了 172.17.1.0/24 之外的所有 172.17.0.0/16)
(Egress 规则)允许"default"命名空间中任何带有标签"role=db"的Pod到CIDR 10.0.0.0/24 下 5978 TCP端口的连接
选择器to和from
可以在ingress的 from部分或egress的to部分中指定四种选择器:
podSelector:此选择器将在与NetworkPolicy相同的名字空间中选择特定的Pod,应将其允许作为入站流量来源或出站流量目的地
namespaceSelector:此选择器将选择特定的名字空间,应将所有Pod用作其入站流量来源或出站流量目的地
namespaceSelector和podSelector:一个指定namespaceSelector和podSelector的to/from条目选择特定名字空间中的特 Pod, 注意使用正确的YAML 语法
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
podSelector:
matchLabels:
role: client
...
在from数组中仅包含一个元素,只允许来自标有role=client的Pod且该Pod所在的名字空间中标有user=alice的连接
ipBlock: 此选择器将选择特定的 IP CIDR范围以用作入站流量来源或出站流量目的地,这些应该是集群外部IP,因为Pod IP存在时间短暂的且随机产生
NetworkPolicy示例
创建环境
#创建命名空间
[root@k8s01 ~]# kubectl create ns demo-net
#创建mysql服务
[root@k8s01 ~]# kubectl create deploy mysql --image=mysql:5.7.25 -n demo-net
[root@k8s01 ~]# kubectl set env deploy/mysql MYSQL_ROOT_PASSWORD=mysql -n demo-net
#创建redis服务
[root@k8s01 ~]# kubectl create deploy redis --image=redis:6.0.6 -n demo-net
#验证创建的应用
[root@k8s-master-1-kty-sc ~]# kubectl get pod -n demo-net --show-labels
NAME READY STATUS RESTARTS AGE LABELS
mysql-84b57dc776-zztmk 1/1 Running 0 2m24s app=mysql,pod-template-hash=84b57dc776
redis-5b5f667d75-9xs5g 1/1 Running 0 53s app=redis,pod-template-hash=5b5f667d75
默认策略的配置
注意如果需要对pod网络流量镜像控制即可先使用以下默认规则进行控制之后使用其他规则对一个或者多个pod实施其他策略多个策略作用到同一个pod,它们是相加的
默认拒绝所有入站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: demo-net
spec:
podSelector: {} #如果这里为空则表示选择这个策略所在的命名空间所有pod
policyTypes:
- Ingress #如果只写ingress不写任何规则表示拒绝所有入口流量
正确情况下所有外部pod无法访问这两个应用,但是运行pod的node节点是可以访问的
默认拒绝所有出站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
spec:
podSelector: {}
policyTypes:
- Egress
默认拒绝所有入站和所有出站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
设置一个或者一组pod网络策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mysql #策略名称
namespace: demo-net #作用命名空间
spec:
podSelector: #选择命名空间pod
matchLabels:
app: mysql
policyTypes: #配置那些策略
- Ingress #入口流量
ingress: #入口流量规则
- from:
- ipBlock: #允许某个IP的访问
cidr: 172.28.43.0/32
- namespaceSelector: #允许某个命名空间下所有Pod访问
matchLabels: #匹配命名空间标签
project: riped
- podSelector: #允许当前命名空间下某个Pod访问
matchLabels: #匹配Pod标签
app: redis
- namespaceSelector: #允许某个命名空间下某个Pod访问
matchLabels:
project: default
podSelector:
matchLabels:
run: test
ports: #允许访问的端口
- protocol: TCP
port: 6379
- protocol: TCP
port: 80
- from: #如果多个端口不同的访问协议可以写多个from
- namespaceSelector: #允许某个命名空间下所有Pod访问
matchLabels: #匹配命名空间标签
project: riped
- ipBlock: #允许某个IP的访问
cidr: 172.28.43.0/32
ports:
- protocol: TCP
port: 3306
总结
在k8s上网络策略是白名单机制,所谓白名单机制是指,只有明确定义的策略才会被允许放行,默认没有指定的规则就是拒绝的,即条件不匹配的都会被拒绝
其次对于 ingress 或 egress 来说,对应的from或to都是用来指定访问端或被访问端的信息
如果在对应的字段中没有定义namespaceSelector字段,默认ingress或egrss会匹配当前netpol所在名称空间,即在没有明确指定namespaceSelector字段时,对应的其他条件都是针对当前netpol所在名称空间
多个条件组合使用,如果多个条件都在一个列表中,则表示多个条件间是与关系,即指定的条件需要同时满足对应策略才会放行
如果多个条件不再同一个列表中,则多个条件之间是或关系,即满足其中一个条件都会被对应策略放行