跳转至

005-k8s-NetworkPolicy

Kubernetes之网络策略(Network Policy)

基本原理

Network Policy是kubernetes中的一种资源类型,它从属于某个namespace。其内容从逻辑上看包含两个关键部分,一是pod选择器,基于标签选择相同namespace下的pod,将其中定义的规则作用于选中的pod。另一个就是规则了,就是网络流量进出pod的规则,其采用的是白名单模式,符合规则的通过,不符合规则的拒绝。

Pod 可以与之通信的实体是通过如下三个标识符的组合来辩识的:

  1. 其他被允许的 Pod(例外:Pod 无法阻塞对自身的访问)
  2. 被允许的名字空间
  3. IP 组块(例外:与 Pod 运行所在的节点的通信总是被允许的, 无论 Pod 或节点的 IP 地址)

在定义基于 Pod 或名字空间的 NetworkPolicy 时, 你会使用选择算符来设定哪些流量可以进入或离开与该算符匹配的 Pod。

另外,当创建基于 IP 的 NetworkPolicy 时,我们基于 IP 组块(CIDR 范围)来定义策略。

默认情况下,如果命名空间中不存在任何策略,则所有进出该命名空间中的Pod的流量都被允许。

NetworkPolicy的规则可以选择如下3种:

  • namespaceSelector:根据命名空间的标签选择,具有该标签的命名空间都可以访问。
  • podSelector:根据Pod的标签选择,具有该标签的Pod都可以访问。
  • ipBlock:根据网络选择,网段内的IP地址都可以访问。(仅Egress支持IPBlock)

Pod 隔离的两种类型

Pod 有两种隔离:出口的隔离和入口的隔离。它们涉及到可以建立哪些连接。 这里的“隔离”不是绝对的,而是意味着“有一些限制”。 另外的,“非隔离方向”意味着在所述方向上没有限制。这两种隔离(或不隔离)是独立声明的, 并且都与从一个 Pod 到另一个 Pod 的连接有关。

要允许从源 Pod 到目的 Pod 的某个连接,源 Pod 的出口策略和目的 Pod 的入口策略都需要允许此连接。 如果任何一方不允许此连接,则连接将会失败。

通过 YAML 使用Ingress规则

场景一:通过网络策略限制Pod只能被带有特定标签的Pod访问

img

目标Pod具有 role=db 标签,该 Pod 只允许带有 role=frontend 标签的 Pod 访问其 6379 端口。设置该网络策略的具体操作步骤如下:

1. 创建后端数据库 Pod 和 service

# 1-redis-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis-db
  namespace: default
  labels:
    role: db
spec:
  containers:
  - name: redis
    image: redis:latest
    ports:
    - containerPort: 6379

---

apiVersion: v1
kind: Service
metadata:
  name: redis-service
  namespace: default
spec:
  selector:
    role: db
  ports:
  - protocol: TCP
    port: 6379
    targetPort: 6379

2. 创建前端应用 Pod

创建一个带有 role: frontend 标签的前端应用 Pod。这里以一个简单的 BusyBox 镜像为例,用于测试网络连接。

# 2-frontend-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: frontend-app
  namespace: default
  labels:
    role: frontend
spec:
  containers:
  - name: busybox
    image: busybox:1.36
    command: ['sh', '-c', 'sleep 3600']

3. 创建不满足标签要求的 Pod

为了验证网络策略的效果,我们创建一个不带有 role: frontend 标签的 Pod。

# 3-unauthorized-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: unauthorized-app
  namespace: default
  labels:
    role: other
spec:
  containers:
  - name: busybox
    image: busybox:1.36
    command: ['sh', '-c', 'sleep 3600']

4. 创建网络策略

使用你提供的网络策略配置,确保只有带有 role: frontend 标签的 Pod 可以通过 TCP 协议访问带有 role: db 标签的 Pod 的 6379 端口。

# 4-network-policy.yaml

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-demo1
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379

5. 验证网络策略

a. 验证前端 Pod 能否访问

使用以下命令在前端 Pod 中尝试访问 Redis 数据库:

kubectl exec -it frontend-app -n default -- sh -c 'nc -zv redis-service 6379'

b. 验证未授权 Pod 能否访问

使用以下命令在未授权 Pod 中尝试访问 Redis 数据库:

kubectl exec -it unauthorized-app -n default -- sh -c 'nc -zv redis-service 6379'

场景二:通过网络策略限制Pod只能被指定命名空间下的Pod访问

img

1. 创建后端数据库 Pod 和 service

创建带有 role=db 标签的目标 Pod,这里以 Redis 为例。

# 1-redis-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis-db
  namespace: default
  labels:
    role: db
spec:
  containers:
  - name: redis
    image: redis:latest
    ports:
    - containerPort: 6379

---

apiVersion: v1
kind: Service
metadata:
  name: redis-service
  namespace: default
spec:
  selector:
    role: db
  ports:
  - protocol: TCP
    port: 6379
    targetPort: 6379

2. 创建指定命名空间及测试 Pod

创建带有 project=myproject 标签的命名空间,并且在该命名空间下创建一个测试 Pod。

# 2-myproject.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: myproject-namespace
  labels:
    project: myproject
---
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: myproject-namespace
spec:
  containers:
  - name: busybox
    image: busybox:1.36
    command: ['sh', '-c', 'sleep 3600']

3. 创建不满足标签要求的 Pod

创建带有 project=myproject 标签的命名空间,并且在该命名空间下创建一个测试 Pod。

# 2-myproject-1.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: myproject1-namespace
  labels:
    project: myproject
---
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: myproject1-namespace
spec:
  containers:
  - name: busybox
    image: busybox:1.36
    command: ['sh', '-c', 'sleep 3600']

4. 创建网络策略

创建网络策略,让目标 Pod 仅允许 project=myproject 标签的命名空间中的 Pod 访问其 6379 端口。

# 4-network-policy.yaml

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-demo
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          project: myproject
    ports:
    - protocol: TCP
      port: 6379

5. 验证网络策略

a. 验证前端 Pod 能否访问

使用以下命令在前端 Pod 中尝试访问 Redis 数据库:

kubectl exec -it test-pod -n myproject-namespace -- sh -c 'nc -zv redis-service.default 6379'

b. 验证未授权 Pod 能否访问

使用以下命令在未授权 Pod 中尝试访问 Redis 数据库:

kubectl exec -it test-pod -n myproject1-namespace -- sh -c 'nc -zv redis-service.default 6379'

场景三:通过网络策略限制Pod只能被指定命名空间下的带特定标签的Pod访问

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-demo3
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          project: myproject
      podSelector:
        matchLabels:
          app: web
    ports:
    - protocol: TCP
      port: 6379 

通过YAML使用Egress规则

场景一:通过网络策略限制Pod只能访问指定地址

img

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-demo3
  namespace: default
spec:
  policyTypes:                  # 使用Egress必须指定policyType
    - Egress
  podSelector:                  # 规则对具有role=db标签的Pod生效
    matchLabels:
      role: db
  egress:                       # 表示出规则
  - to:
    - ipBlock:
        cidr: 172.16.0.16/16    # 允许在出方向访问此网段
        except:
        - 172.16.0.40/32        # 不允许在出方向访问此网段,except网段需在cidr网段内

场景二:通过网络策略限制Pod只能被带有特定标签的Pod访问,且只能访问指定Pod

img

目标Pod具有role=db标签,该Pod只允许带有role=frontend标签的Pod访问其6379-6380端口,且该Pod只能访问带有role=web标签的Pod。网络策略中的Ingress和Egress可以定义在同一个规则中,具体操作步骤如下:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-demo4
  namespace: default
spec:
  policyTypes:
  - Ingress
  - Egress
  podSelector:                  # 规则对具有role=db标签的Pod生效
    matchLabels:
      role: db
  ingress:                      # 表示入规则
  - from:
    - podSelector:              # 只允许具有role=frontend标签的Pod访问
        matchLabels:
          role: frontend
    ports:                      # 只能使用TCP协议访问6379端口
    - protocol: TCP
      port: 6379
      endPort: 6380
  egress:                       # 表示出规则
  - to:
    - podSelector:              # 只允许访问具有role=web标签的Pod
        matchLabels:
          role: web
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

https://support.huaweicloud.com/basics-cce/kubernetes_0027.html#section1