查看原文
其他

一文搞懂Kubernetes网络策略(上)

zouyee DCOS 2022-07-13


今天zouyee为大家带来《一文搞懂Kubernetes网络策略(上)》,其中《kuberneter调度由浅入深:框架》正在编写中,敬请期待,当前涉及版本均为1.20.+。

一、Network Policy简介



随着微服务架构的日渐盛行,Serverless框架的逐步落地,应用上云后带来了模块间网络调用需求的大规模增长,Kubernetes 自 1.3 引入了 Network Policy,其提供以应用为中心, 基于策略的网络控制,用于隔离应用以减少攻击面。Pod之间能否通信可通过如下三种组合进行确认:
   1. 其他被允许的 Pods(例如:Pod 无法限制对自身的访问)
   2. 被允许访问的namespace
   3. IP CIDR(例如:与 Pod 运行所在节点的通信总是被允许的)
    在定义基于 Pod 或namespace的 NetworkPolicy 时,可以使用`标签选择器`来设定哪些流量可以进入或离开 Pod。同时,当创建基于 IP 的 NetworkPolicy 时,可以基于 IP CIDR 来定义策略。
    以下结构体示意图辅助理解,后面章节有具体说明:


版本变迁

Kubernetes版本

Networking API版本

Kubernetes版本

v1.5-v1.6

extension/v1beta1

需要在kube-apiserver启动命令行开启extensions/v1beta1/networkpolicies

v1.7

networking.k8s.io/v1


v1.8

networking.k8s.io/v1

增加Egress及IPBlock特性



二、简要介绍



相关说明

默认情况下,Pod 是非隔离的,它们接受任何流量。

Pod 在被某 NetworkPolicy 选中时进入隔离状态。一旦名字空间中有 NetworkPolicy 选择了特定的 Pod,该 Pod 会拒绝该 NetworkPolicy 所不允许的连接。(名字空间下其他未被 NetworkPolicy 所选择的 Pod 会继续接受所有的流量)

网络策略不会冲突。如果任何一个或多个策略选择了一个 Pod, 则该 Pod 受限于这些策略的 入站(Ingress)/出站(Egress)规则的并集。

⚠️在使用 Network Policy 时,网络插件需要支持 Network Policy,如 Calico、Romana、Weave Net 和 Trireme 等,其中Engress为 出口流量,Ingress为 入口流量。


结构体说明

staging/src/k8s.io/api/networking/v1/types.go


下面是 NetworkPolicy 的一个示例,如需完整说明,可参看结构定义文档:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: network-policy-sample namespace: defaultspec: 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

必需字段:与所有其他的 Kubernetes 对象一样,NetworkPolicy 需要 apiVersion、 kind 和 metadata 字段。

spec:NetworkPolicy 规约中包含了在名字空间中定义特定网络策略所需的所有信息。

podSelector:每个 NetworkPolicy 都包括一个 podSelector,它选择适用该该策略的 Pod。示例中的策略选择带有 “role=db” 标签的 Pod。若podSelector为空的,则选择名字空间下所有 Pod。

policyTypes: 每个 NetworkPolicy 都包含一个 policyTypes 列表,其中包含 Ingress 或 Egress 或(两者亦可)。policyTypes 字段表示给定的策略是应用于 所选 Pod 的入口流量还是来出口流量(两者亦可)。如果 NetworkPolicy 未指定 policyTypes 则默认情况下始终设置 Ingress;如果 NetworkPolicy 有任何出口规则的话则设置 Egress。

ingress: 每个 NetworkPolicy 可包含一个 ingress 规则的白名单列表。每个规则都允许同时匹配 from 和 ports 部分的流量。示例策略中包含一条 简单的规则:它匹配某个特定端口,第一个通过 ipBlock 指定,第二个通过 namespaceSelector 指定,第三个通过 podSelector 指定。

egress: 每个 NetworkPolicy 可包含一个 egress 规则的白名单列表。每个规则都允许匹配 to 和 port 部分的流量。该示例策略包含一条规则, 该规则指定端口上的流量匹配到 10.0.0.0/24 中的任何目的地。

该网络策略总结如下:

1. 隔离 default名字空间下 role=db 的 Pod 。

2. 出口限制:允许符合以下条件的 Pod 连接到 default名字空间下标签为 role=db的所有 Pod 的 6379 TCP 端口:

    a) default名字空间下带有 role=frontend 标签的所有 Pod

    b) 带有 project=myproject 标签的所有名字空间中的 Pod

    c) 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)

3. 入口限制:允许从带有 role=db标签的名字空间下的任何 Pod 到 CIDR 10.0.0.0/24 下 5978 TCP 端口。

简单示例



以 calico 为例看一下 Network Policy 的具体用法。

1) 配置 kubelet 使用 CNI 网络插件(默认已经配置,无需更改)

kubelet --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin ...

2) 安装 calio 网络插件

1
2
3
4
# 注意修改 CIDR,需要跟 k8s pod-network-cidr 一致,默认为 192.168.0.0/16
# 当前选择的是小于50节点的安装方式,具体安装可查看
# https://docs.projectcalico.org/getting-started/kubernetes/self-managed-onprem/onpremises
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

3) 部署应用

部署 nginx 服务

1
2
3
4
$ kubectl create deployment nginx --image=nginx
deployment "nginx" created
$ kubectl expose deployment nginx --port=80
service "nginx" exposed

测试网络

$ kubectl get svc,podNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEservice/kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 186dservice/nginx ClusterIP 10.233.27.142 <none> 80/TCP 2s
NAME READY STATUS RESTARTS AGEpod/nginx-f89759699-kfmbj 1/1 Running 0 62s
$ kubectl run busybox --rm -ti --image=busybox /bin/shIf you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=1 nginxConnecting to nginx (10.233.27.142:80)remote file exists/ #

测试网络策略

如果只让那些拥有标签 `access: true` 的 Pod 访问 `nginx` 服务, 那么可以创建一个如下所示的 NetworkPolicy 对象:
$ cat nginx-policy.yamlapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: access-nginxspec: podSelector: matchLabels: app: nginx ingress: - from: - podSelector: matchLabels: access: "true"
$ kubectl create -f nginx-policy.yamlnetworkpolicy "access-nginx" created
# 不带 access=true 标签的 Pod 还是无法访问 nginx 服务$ kubectl run busybox --rm -ti --image=busybox /bin/shIf you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=1 nginxConnecting to nginx (10.233.27.142:80)wget: download timed out/ #
# 而带有 access=true 标签的 Pod 可以访问 nginx 服务$ kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/shIf you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=1 nginxConnecting to nginx (10.233.27.142:80)/ #

三、应用场景


一般场景

    a. 禁止访问指定服务    
kubectl run web --image=nginx --labels app=web --expose --port 80# 未有策略限制时,可以访问$ kubectl run busybox --rm -ti --image=busybox /bin/shIf you don't see a command prompt, try pressing enter./ # wget -qO- http://web<!DOCTYPE html><html><head>

    创建网络策略

# cat web-deny-all.yamlkind: NetworkPolicyapiVersion: networking.k8s.io/v1metadata: name: web-deny-allspec: podSelector: matchLabels: app: web  ingress: []$ kubectl apply -f web-deny-all.yamlnetworkpolicy "web-deny-all" created

    访问测试

$ kubectl run busybox --rm -ti --image=busybox /bin/shIf you don't see a command prompt, try pressing enter./ # wget -qO- --timeout=2 http://webwget: download timed out

    


 b. 限制访问指定服务
kubectl run apiserver --image=nginx --labels app=bookstore,role=api --expose --port 80


     创建网络
# cat api-allow.yamlkind: NetworkPolicyapiVersion: networking.k8s.io/v1metadata: name: api-allowspec: podSelector: matchLabels: app: bookstore role: api ingress: - from: - podSelector: matchLabels: app: bookstore# kubectl apply -f api-allow.yamlnetworkpolicy "api-allow" created

访问测试

创建不加label的pod,预期结果,访问被限制$ kubectl run busybox --rm -ti --image=busybox /bin/shIf you don't see a command prompt, try pressing enter./ # wget -qO- --timeout=2 http://apiserverwget: download timed out/ # exit创建带app=bookstore标签的pod,预期结果,访问被限制$ kubectl run busybox --rm -ti --image=busybox --labels app=bookstore,role=frontend /bin/shIf you don't see a command prompt, try pressing enter./ # wget -qO- --timeout=2 http://apiserver<!DOCTYPE html><html><head>/ # exit
 c. 放通访问限制
kubectl run apiserver --image=nginx --labels app=bookstore,role=api --expose --port 80

应用a中的网络策略,限制所有流量

# cat web-deny-all.yamlkind: NetworkPolicyapiVersion: networking.k8s.io/v1metadata: name: web-deny-allspec: podSelector: matchLabels: app: web  ingress: []$ kubectl apply -f web-deny-all.yamlnetworkpolicy "web-deny-all" created

创建网络策略

# cat web-deny-all.yamlkind: NetworkPolicyapiVersion: networking.k8s.io/v1metadata: name: web-allow-all namespace: defaultspec: podSelector: matchLabels: app: web ingress:  - {}$ kubectl apply -f web-allow-all.yamlnetworkpolicy "web-allow-all" created# 需要注意deny跟allow的细微差别就是[]与{},其中{}代表- from: podSelector: {} namespaceSelector: {}



namespace限制

    a. 禁止namespace中非白名单流量

    

    创建网络策略

# cat default-deny-all.yamlkind: NetworkPolicyapiVersion: networking.k8s.io/v1metadata: name: default-deny-all namespace: defaultspec: podSelector: {} ingress: []# kubectl apply -f default-deny-all.yaml

    说明:   

  • namespace: default 该策略部署于default

  • podSelector{}指匹配所有pod,因而该策略对default命名空间的所有pod都有效

  • ingress未指定,因而对于所有进入流量都禁止

    b. 禁止其他namespace流量
kubectl create namespace secondarykubectl run web --namespace secondary --image=nginx \ --labels=app=web --expose --port 80

创建网络策略

kind: NetworkPolicyapiVersion: networking.k8s.io/v1metadata: namespace: secondary name: web-deny-other-namespacesspec: podSelector: matchLabels: ingress: - from: - podSelector: {}

访问测试

# default命名空间访问$ kubectl run busybox --rm -ti --image=busybox /bin/shIf you don't see a command prompt, try pressing enter./ # wget -qO- --timeout=2 http://web.secondarywget: download timed out/ # exit# secondary命名空间访问$ kubectl run busybox --rm -ti --image=busybox --namespace=secondary /bin/shIf you don't see a command prompt, try pressing enter./ # wget -qO- --timeout=2 http://web.secondary<!DOCTYPE html><html>
      c. 放通所有namespace流量
kubectl run web --image=nginx --labels app=web --expose --port 80

    创建网络策略

# cat web-allow-all-namespaces.yamlkind: NetworkPolicyapiVersion: networking.k8s.io/v1metadata: namespace: default name: web-allow-all-namespacesspec: podSelector: matchLabels: app: web ingress: - from: - namespaceSelector: {}# kubectl apply -f web-allow-all-namespaces.yaml# kubectl create namespace secondary

说明:   

  • app: web网络策略应用到该标签pod

  • namespaceSelector: {}匹配所有命名空间

访问测试

# kubectl run busybox --rm -ti --image=busybox --namespace=secondary /bin/shIf you don't see a command prompt, try pressing enter./ # wget -qO- --timeout=2 http://web.secondary<!DOCTYPE html><html>
    d. 指定namespace访问服务
# kubectl run web --image=nginx \ --labels=app=web --expose --port 80# kubectl create namespace dev# kubectl label namespace/dev purpose=testing# kubectl create namespace prod# kubectl label namespace/prod purpose=production


创建网络策略

# cat web-allow-prod.yamlkind: NetworkPolicyapiVersion: networking.k8s.io/v1metadata: name: web-allow-prodspec: podSelector: matchLabels: app: web ingress: - from: - namespaceSelector: matchLabels: purpose: production# kubectl apply -f web-allow-prod.yaml
    e. 允许其他namespace指定pod的流量

    ⚠️ Kubernetes 1.11后支持podSelector 与namespaceSelector的运算符操作,同时需要网络插件支持

    

# kubectl run web --image=nginx \ --labels=app=web --expose --port 80# kubectl create namespace other# kubectl create namespace other

创建网络策略

# cat web-allow-all-ns-monitoring.yamlkind: NetworkPolicyapiVersion: networking.k8s.io/v1metadata: name: web-allow-all-ns-monitoring namespace: defaultspec: podSelector: matchLabels: app: web ingress: - from: - namespaceSelector: # 选择namespaces中带有team=operations标签的pod matchLabels: team: operations podSelector: # 选择带有type=monitoring标签的pod matchLabels: type: monitoring# kubectl apply -f web-allow-all-ns-monitoring.yaml

访问测试

kubectl run busybox --rm -ti --image=busybox /bin/shIf you don't see a command prompt, try pressing enter./ # wget -qO- --timeout=2 http://web.defaultwget: download timed out
(访问限制)/ # exit
# kubectl run busybox --rm -ti --image=busybox --labels type=monitoring /bin/shIf you don't see a command prompt, try pressing enter./ # wget -qO- --timeout=2 http://web.defaultwget: download timed out(访问限制)# kubectl run busybox --rm -ti --image=busybox --namespace=other /bin/shIf you don't see a command prompt, try pressing enter./ # wget -qO- --timeout=2 http://web.defaultwget: download timed out(访问限制)# kubectl run busybox --rm -ti --image=busybox --namespace=other --labels type=monitoring /bin/shIf you don't see a command prompt, try pressing enter./ # wget -qO- --timeout=2 http://web.default<!DOCTYPE html><html><head>...(允许访问)


未完,待续


参考资料

1. Kubernetes 官网:https://kubernetes.io/docs/concepts/services-networking/network-policies/

2. Declare Network Policy: https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy/

3. Securing Kubernetes Cluster Networking: https://ahmet.im/blog/kubernetes-network-policy/

4. fesikyer network policy: https://github.com/feiskyer/kubernetes-handbook/blob/master/concepts/network-policy.md


END



 往期 · 精选 

1、干货分享 | K8S调度系统由浅入深:简介

2、干货分享 | CloudEvents三部曲:实践篇

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存