网络策略(NetworkPolicy)是Kubernetes中的一种资源对象,用于定义和控制Pod之间的网络通信规则。它允许您在Kubernetes集群中定义详细的网络规则,以控制哪些Pod可以相互通信,以及允许或禁止的流量。网络策略提供了一种实现细粒度网络访问控制的方式,帮助管理员和开发者确保集群中的网络通信符合特定的安全性和策略需求。
Pod隔离的两种类型
Pod 有两种隔离:
- 出口隔离
- 入口隔离
它们涉及到可以建立哪些连接。这里的“隔离”不是绝对的,而是意味着“有一些限制”。另外的,“非隔离方向”意味着在所述方向上没有限制。这两种隔离(或不隔离)是独立声明的, 并且都与从一个 Pod 到另一个 Pod 的连接有关。
默认情况下,一个 Pod 的出口是非隔离的,即所有外向连接都是被允许的。如果有任何的 NetworkPolicy 选择该 Pod 并在其policyTypes 中包含 Egress
,则该 Pod 是出口隔离的, 称这样的策略适用于该 Pod 的出口。当一个 Pod 的出口被隔离时, 唯一允许的来自 Pod 的连接是适用于出口的 Pod 的某个 NetworkPolicy 的 egress 列表所允许的连接。这些 egress 列表的效果是相加的。
默认情况下,一个 Pod 对入口是非隔离的,即所有入站连接都是被允许的。如果有任何的 NetworkPolicy 选择该 Pod 并在其 policyTypes 中包含 Ingress
,则该 Pod 被隔离入口, 称这种策略适用于该 Pod 的入口。当一个 Pod 的入口被隔离时,唯一允许进入该 Pod 的连接是来自该 Pod 节点的连接和适用于入口的 Pod 的某个 NetworkPolicy 的 ingress 列表所允许的连接。这些 ingress 列表的效果是相加的。
网络策略是相加的,所以不会产生冲突。如果策略适用于 Pod 某一特定方向的流量,Pod 在对应方向所允许的连接是适用的网络策略所允许的集合。因此,评估的顺序不影响策略的结果。
要允许从源 Pod 到目的 Pod 的连接,源 Pod 的出口策略和目的 Pod 的入口策略都需要允许连接。如果任何一方不允许连接,建立连接将会失败。
NetworkPolicy 配置详解
以下是一个NetworkPolicy
的示例,参阅 NetworkPolicy 来了解资源的完整定义。
apiVersion networking.k8s.io/v1 kind NetworkPolicy metadata name test-network-policy namespace default #策略应用在那个名称空间,就说对那个命名空间的pod做限制(目标) spec podSelector#选择匹配哪些标签的pod,选择一组pod做网络策略,写{}表示该命名空间下pod matchLabels role db policyTypes #入网,谁访问pod(即谁访问default名称空间下有role=db标签的pod) Ingress #出网,role=db的pod可以访问谁 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 port6379 egress to ipBlock cidr 10.0.0.0/24 ports protocol TCP port5978
应用场景
是一个kuebenetes资源,用于限制pod出入流量,提供pod级别和namespace级别网络访问控制。
- 应用程序间的访问控制,例如项目A不能访问项目B的pod
- 开发环境命名空间不能访问测试环境命名空间Pod
- 当pod暴露到外部时,需要做Pod白名单
- 多租户网络环境隔离
网络访问控制案例
案例1:拒绝命名空间下所有pod入、出站流量
apiVersion networking.k8s.io/v1 kind NetworkPolicy metadata name deny-all namespace test spec podSelector #匹配本命名空间所有pod policyTypes Ingress Egress
上述网络策略是禁止test
命名空间的所有pod进出流量。
在没有创建网络策略时,test命名空间的Pod都能访问外网,如下:
root@k8s-master:~# kubectl run busybox --image=busybox -n test sleep 12h pod/busybox created root@k8s-master:~# kubectl get pod -n test -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES busybox 1/1 Running 0 31s 10.244.169.137 k8s-node2 <none> <none> root@k8s-master:~# kubectl exec busybox -n test ping baidu.com kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. PING baidu.com (39.156.66.10): 56 data bytes 64 bytes from 39.156.66.10: seq=0 ttl=49 time=51.555 ms 64 bytes from 39.156.66.10: seq=1 ttl=49 time=51.611 ms 64 bytes from 39.156.66.10: seq=2 ttl=49 time=51.237 ms 64 bytes from 39.156.66.10: seq=3 ttl=49 time=51.056 ms 64 bytes from 39.156.66.10: seq=4 ttl=49 time=50.914 ms 64 bytes from 39.156.66.10: seq=5 ttl=49 time=51.145 ms
在deny-all网络策略后,test命名空间下的容器就不能访问外网
root@k8s-master:/home/yaml# kubectl apply -f deny-all.yml networkpolicy.networking.k8s.io/deny-all created root@k8s-master:/home/yaml# kubectl exec busybox -n test ping baidu.com kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. ping: bad address 'baidu.com' command terminated with exit code 1
外部Pod之间相互也不能访问了。这里在test命名空间启动一个nginx容器作为测试。
root@k8s-master:/home/yaml# kubectl run web --image=nginx -n test pod/web created root@k8s-master:/home/yaml# kubectl get pod -n test -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES busybox 1/1 Running 0 9m33s 10.244.169.137 k8s-node2 <none> <none> web 1/1 Running 0 76s 10.244.169.138 k8s-node2 <none> <none> root@k8s-master:/home/yaml# kubectl exec busybox -n test ping 10.244.169.138 kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
案例2:拒绝其他命名空间pod访问
在生成环境中或许有这样的需求,运行相同命名空间的pod相互访问,拒绝其他命名空间访问该命名空间的所有Pod。
apiVersion networking.k8s.io/v1 kind NetworkPolicy metadata name deny-ingress namespace test spec podSelector #test下的所有pod policyTypes Ingress ingress from podSelector #匹配本命名空间所有pod
这里用两个命名空间进行模拟,一个是开发环境dev
,一个是生成环境pro
。现在有这样一个需求,生成环境的pro
下的所有Pod
不能访问dev开发环境的所有Pod
。
root@k8s-master:/home/yaml# kubectl create ns pro namespace/pro created root@k8s-master:/home/yaml# kubectl create ns dev namespace/dev created root@k8s-master:/home/yaml# kubectl run pro-busybox --image=busybox -n pro sleep 12h pod/pro-busybox created root@k8s-master:/home/yaml# kubectl run dev-busybox --image=busybox -n dev sleep 12h pod/dev-busybox created root@k8s-master:/home/yaml# kubectl run pro-web --image=nginx -n pro pod/pro-web created root@k8s-master:/home/yaml# kubectl run dev-web --image=nginx -n dev root@k8s-master:/home/yaml# kubectl run pro-db --image=mysql --env="MYSQL_ROOT_PASSWORD=@root@" -n pro pod/pro-db created root@k8s-master:/home/yaml# kubectl run dev-db --image=mysql --env="MYSQL_ROOT_PASSWORD=@root@" -n dev pod/dev-db created root@k8s-master:/home/yaml# kubectl get pod -n pro -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pro-busybox 1/1 Running 0 21s 10.244.169.142 k8s-node2 <none> <none> pro-db 1/1 Running 0 11m 10.244.36.72 k8s-node1 <none> <none> pro-web 1/1 Running 0 20m 10.244.36.69 k8s-node1 <none> <none> root@k8s-master:/home/yaml# kubectl get pod -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES dev-busybox 1/1 Running 0 20s 10.244.36.75 k8s-node1 <none> <none> dev-db 1/1 Running 0 10m 10.244.36.73 k8s-node1 <none> <none> dev-web 1/1 Running 0 20m 10.244.169.139 k8s-node2 <none> <none>
在没有做网络策略时,pro命名空间下的pod可以与dev命名空间下的Pod相互通讯,如下:
root@k8s-master:/home/yaml# kubectl exec pro-busybox -n pro ping 10.244.36.73 kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. PING 10.244.36.73 (10.244.36.73): 56 data bytes 64 bytes from 10.244.36.73: seq=0 ttl=62 time=2.427 ms 64 bytes from 10.244.36.73: seq=1 ttl=62 time=1.235 ms 64 bytes from 10.244.36.73: seq=2 ttl=62 time=1.167 ms ^C root@k8s-master:/home/yaml# kubectl exec dev-busybox -n dev ping 10.244.36.72 kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. PING 10.244.36.72 (10.244.36.72): 56 data bytes 64 bytes from 10.244.36.72: seq=0 ttl=63 time=0.511 ms 64 bytes from 10.244.36.72: seq=1 ttl=63 time=0.238 ms
创建网络策略,如下:
root@k8s-master:/home/yaml# cat deny-ingress.yaml apiVersion networking.k8s.io/v1 kind NetworkPolicy metadata name deny-ingress namespace pro spec podSelector #test下的所有pod policyTypes Ingress ingress from podSelector #匹配本命名空间所有pod root@k8s-master:/home/yaml# kubectl apply -f deny-ingress.yaml networkpolicy.networking.k8s.io/deny-ingress created
验证结果,如下,dev命名空间下的pod不能访问pro命名空间下的所有pod,dev命名空间的pod可以相互访问
root@k8s-master:/home/yaml# kubectl exec dev-busybox -n dev ping 10.244.36.72 kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. ^C root@k8s-master:/home/yaml# kubectl exec dev-busybox -n dev ping 10.244.36.73 kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. PING 10.244.36.73 (10.244.36.73): 56 data bytes 64 bytes from 10.244.36.73: seq=0 ttl=63 time=0.853 ms 64 bytes from 10.244.36.73: seq=1 ttl=63 time=0.336 ms
案例3:允许其他命名空间pod访问指定应用
现在有这样一个需求,允许其他命名空间访问pro命名空间指定pod,pod标签app=web
。
先给pro-web
pod 添加上标签,如下:
root@k8s-master:/home/yaml# kubectl label pods pro-web app=web -n pro pod/pro-web labeled root@k8s-master:/home/yaml# kubectl get pod -n pro --show-labels NAME READY STATUS RESTARTS AGE LABELS pro-busybox 1/1 Running 0 16m run=pro-busybox pro-db 1/1 Running 0 27m run=pro-db pro-web 1/1 Running 0 36m app=web,run=pro-web
创建网络策略,网络策略内容如下,创建之前把之前测试的网络测试删除。
apiVersion networking.k8s.io/v1 kind NetworkPolicy metadata name allow-all-nmespace namespace pro spec podSelector matchLabels app web #pro名称空间下的有app=web的标签 policyTypes Ingress ingress from namespaceSelector #匹配所有命名空间的pod
root@k8s-master:/home/yaml# kubectl delete -f deny-ingress.yaml networkpolicy.networking.k8s.io "deny-ingress" deleted root@k8s-master:/home/yaml# kubectl apply -f allow-all-namespace.yml networkpolicy.networking.k8s.io/allow-all-nmespace created
即所有名称空间的pod都可以访问pro名称空间下的app=web的pod,和K8s默认一样,没意义。但和案列1搭配即可实现一个可访问,一个不可访问。
单独此规则,和K8S默认一样的,如下:
root@k8s-master:~# kubectl get pod -n pro -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pro-busybox 1/1 Running 0 69m 10.244.169.142 k8s-node2 <none> <none> pro-db 1/1 Running 0 80m 10.244.36.72 k8s-node1 <none> <none> pro-web 1/1 Running 0 89m 10.244.36.69 k8s-node1 <none> <none> root@k8s-master:~# kubectl get pod -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES dev-busybox 1/1 Running 0 69m 10.244.36.75 k8s-node1 <none> <none> dev-db 1/1 Running 0 79m 10.244.36.73 k8s-node1 <none> <none> dev-web 1/1 Running 0 89m 10.244.169.139 k8s-node2 <none> <none> root@k8s-master:~# kubectl exec dev-busybox -n dev ping 10.244.36.69 kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. PING 10.244.36.69 (10.244.36.69): 56 data bytes 64 bytes from 10.244.36.69: seq=0 ttl=63 time=0.269 ms 64 bytes from 10.244.36.69: seq=1 ttl=63 time=0.245 ms ^C root@k8s-master:~# kubectl exec dev-busybox -n dev ping 10.244.36.72 kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. PING 10.244.36.72 (10.244.36.72): 56 data bytes 64 bytes from 10.244.36.72: seq=0 ttl=63 time=0.301 ms 64 bytes from 10.244.36.72: seq=1 ttl=63 time=0.279 ms
结合案例1拒绝命名空间所以pod入,出站流量规则,如下:
root@k8s-master:/home/yaml# cat deny-all.yml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all namespace: pro spec: podSelector: {} #匹配本命名空间所有pod policyTypes: - Ingress - Egress root@k8s-master:/home/yaml# kubectl apply -f deny-all.yml networkpolicy.networking.k8s.io/deny-all created root@k8s-master:/home/yaml# kubectl exec dev-busybox -n dev ping 10.244.36.72 kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. ^C root@k8s-master:/home/yaml# kubectl exec dev-busybox -n dev ping 10.244.36.69 kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. PING 10.244.36.69 (10.244.36.69): 56 data bytes 64 bytes from 10.244.36.69: seq=0 ttl=63 time=0.372 ms 64 bytes from 10.244.36.69: seq=1 ttl=63 time=0.369 ms
CKA真题
题目1
切换 k8s 集群环境:kubectl config use-context hk8s
Task
在现有的 namespace internal 中创建一个名为 allow-port-from-namespace 的新 NetworkPolicy。
确保新的 NetworkPolicy 允许 namespace 中的 Pods 连接到 namespace internal 中的Pods 的 9000 端口。
进一步确保新的NetworkPolicy:
- 不允许对没有在监听端口 9000 的 Pods 的访问
- 不允许不来自namespace internal的pods的访问
kubectl config use-context hk8s # 编写一个 yaml 文件,注意先输入 ":set paste",防止复制时 yaml 文件空格错序 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-port-from-namespace namespace: internal spec: podSelector: {} policyTypes: - Ingress ingress: - from: - podSelector: {} ports: - protocol: TCP port: 9000 # 创建网络策略资源 kubectl apply -f networkpolicy.yaml
题目2
[candidate@node-1] $ kubectl config use-context hk8s
Task
在现有的 namespace my-app 中创建一个名为 allow-port-from-namespace 的新 NetworkPolicy。
确保新的 NetworkPolicy 允许 namespace echo 中的 Pods 连接到 namespace my-app 中的 Pods 的 9000 端口。
进一步确保新的 NetworkPolicy:
-- 不允许对没有在监听 端口 9000 的 Pods 的访问
-- 不允许非来自 namespace echo 中的 Pods 的访问
kubectl config use-context hk8s # 编写一个 yaml 文件,注意先输入 ":set paste",防止复制时 yaml 文件空格错序 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-port-from-namespace namespace: my-app spec: podSelector: {} policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLables: app: echo ports: - protocol: TCP port: 9000 # 创建网络策略资源 kubectl apply -f networkpolicy.yaml