58·网络进阶

网络策略

kubernetesnetworkingsecuritynetwork-policy

网络策略

学习目标

  1. 理解 NetworkPolicy 的作用和重要性
  2. 掌握 NetworkPolicy 的配置方法
  3. 了解网络策略的最佳实践

核心概念

一句话解释

NetworkPolicy 用于控制 Pod 之间以及 Pod 与外部网络之间的网络访问,默认情况下所有 Pod 都可以互相通信,NetworkPolicy 可以限制这种访问。

为什么需要 NetworkPolicy

默认情况:所有 Pod 可以互相通信

┌─────────────────────────────────────────┐
│              Kubernetes 集群             │
│  ┌───────┐  ┌───────┐  ┌───────┐      │
│  │ Web   │  │ API   │  │ DB    │      │
│  │       │←→│       │←→│       │      │
│  └───────┘  └───────┘  └───────┘      │
│      ↑          ↑          ↑           │
│      └──────────┴──────────┘           │
│         所有 Pod 可以互相访问           │
└─────────────────────────────────────────┘

问题:
- 安全性差:任何 Pod 都可以访问数据库
- 无法限制:无法阻止恶意流量
- 不符合最小权限原则

解决方案:NetworkPolicy

┌─────────────────────────────────────────┐
│              Kubernetes 集群             │
│  ┌───────┐  ┌───────┐  ┌───────┐      │
│  │ Web   │  │ API   │  │ DB    │      │
│  │       │─→│       │─→│       │      │
│  └───────┘  └───────┘  └───────┘      │
│      │          │          ↑           │
│      │          └──────────┘           │
│      │           只有 API 可以访问 DB   │
│      │                                  │
│      └──────────────────────────────────┘
│         Web 可以访问 API,不能访问 DB    │
└─────────────────────────────────────────┘

NetworkPolicy 基本概念

NetworkPolicy 包含三个部分:

1. Pod 选择器:策略应用到哪些 Pod
2. 入站规则(Ingress):允许哪些流量进入
3. 出站规则(Egress):允许哪些流量出去

┌─────────────────────────────────────────┐
│         NetworkPolicy                   │
│                                         │
│  Pod 选择器:app=db                     │
│                                         │
│  入站规则(Ingress):                   │
│  - 来源:app=api                        │
│  - 端口:5432                           │
│                                         │
│  出站规则(Egress):                    │
│  - 目标:app=logging                    │
│  - 端口:514                            │
└─────────────────────────────────────────┘

NetworkPolicy 示例

# 基本的 NetworkPolicy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy
  namespace: default
spec:
  podSelector:          # 策略应用到的 Pod
    matchLabels:
      app: db
  policyTypes:          # 策略类型
  - Ingress            # 入站规则
  - Egress             # 出站规则
  ingress:             # 入站规则
  - from:
    - podSelector:     # 允许来自哪些 Pod
        matchLabels:
          app: api
    ports:             # 允许的端口
    - protocol: TCP
      port: 5432
  egress:              # 出站规则
  - to:
    - podSelector:     # 允许访问哪些 Pod
        matchLabels:
          app: logging
    ports:
    - protocol: TCP
      port: 514

入站规则(Ingress)

# 入站规则配置
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: ingress-policy
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  # 规则 1:允许来自同一 namespace 的 Pod
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 80

  # 规则 2:允许来自特定 namespace 的 Pod
  - from:
    - namespaceSelector:
        matchLabels:
          env: production
    ports:
    - protocol: TCP
      port: 80

  # 规则 3:允许来自特定 IP 范围
  - from:
    - ipBlock:
        cidr: 10.0.0.0/8
        except:
        - 10.0.1.0/24
    ports:
    - protocol: TCP
      port: 80

出站规则(Egress)

# 出站规则配置
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-policy
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Egress
  egress:
  # 规则 1:允许访问 DNS
  - to:
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

  # 规则 2:允许访问特定 Pod
  - to:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 8080

  # 规则 3:允许访问外部服务
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
    ports:
    - protocol: TCP
      port: 443

策略组合

# 完整的网络策略示例
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: comprehensive-policy
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Ingress
  - Egress
  ingress:
  # 允许 Web 访问
  - from:
    - podSelector:
        matchLabels:
          app: web
    ports:
    - protocol: TCP
      port: 8080

  # 允许 Health Check
  - from: []  # 空 from 表示允许所有来源
    ports:
    - protocol: TCP
      port: 8080

  egress:
  # 允许访问数据库
  - to:
    - podSelector:
        matchLabels:
          app: db
    ports:
    - protocol: TCP
      port: 5432

  # 允许访问 DNS
  - to:
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53

默认策略

# 默认拒绝所有入站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}  # 应用到所有 Pod
  policyTypes:
  - Ingress
  # 没有 ingress 规则 = 拒绝所有入站
# 默认拒绝所有出站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
spec:
  podSelector: {}
  policyTypes:
  - Egress
  # 没有 egress 规则 = 拒绝所有出站
# 默认拒绝所有流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

策略优先级

NetworkPolicy 优先级规则:

1. 如果没有 NetworkPolicy 应用到 Pod → 允许所有流量
2. 如果有 NetworkPolicy 应用到 Pod → 只允许明确允许的流量
3. 多个 NetworkPolicy 取并集

示例:
┌─────────────────────────────────────────┐
│  Policy A:允许 Web 访问 API            │
│  Policy B:允许 Health Check 访问 API   │
│                                         │
│  结果:Web 和 Health Check 都可以访问    │
└─────────────────────────────────────────┘

实践练习

练习 1:创建默认拒绝策略

# 默认拒绝所有入站流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
  - Ingress
# 应用策略
kubectl apply -f default-deny-ingress.yaml

# 测试:应该无法访问
kubectl run test-pod --image=busybox --rm -it -- wget -qO- http://web-service

练习 2:允许特定 Pod 访问

# 允许 frontend 访问 backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080
# 应用策略
kubectl apply -f allow-frontend-to-backend.yaml

# 测试:从 frontend 应该可以访问
kubectl exec frontend-pod -- wget -qO- http://backend-service:8080

# 测试:从其他 Pod 应该无法访问
kubectl run test-pod --image=busybox --rm -it -- wget -qO- http://backend-service:8080

练习 3:配置 DNS 访问

# 允许访问 DNS(重要!否则 Pod 无法解析域名)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53
# 应用策略
kubectl apply -f allow-dns.yaml

# 测试 DNS 解析
kubectl exec test-pod -- nslookup kubernetes.default

常见误解

1. NetworkPolicy 是默认启用的

错误理解:Kubernetes 默认启用 NetworkPolicy
正确理解:需要 CNI 插件支持

支持 NetworkPolicy 的 CNI:
- Calico
- Cilium
- Weave Net

不支持的 CNI:
- Flannel(默认)
- 基本的桥接网络

2. 没有 NetworkPolicy 就是不安全的

错误理解:没有 NetworkPolicy 一定不安全
正确理解:

NetworkPolicy 是 Pod 级别的网络隔离
还有其他安全措施:
- RBAC(权限控制)
- Pod Security Policy
- Service Mesh(如 Istio)

小结

要点说明
NetworkPolicy控制 Pod 网络访问
策略类型Ingress(入站)、Egress(出站)
选择方式podSelector、namespaceSelector、ipBlock
默认行为没有策略 = 允许所有,有策略 = 只允许明确的
最佳实践先默认拒绝,再按需允许
注意事项需要 CNI 插件支持

练习编辑器

bash
Loading...

继续学习

完成本课后,建议继续学习下一课「CNI 插件」 以巩固所学知识。