Skip to content

网络安全

概述

网络安全是Kubernetes集群安全的重要组成部分。通过网络策略(NetworkPolicy),可以控制Pod之间的网络流量,实现网络隔离和访问控制。网络策略允许你定义哪些Pod可以相互通信,从而实现细粒度的网络安全控制。

核心概念

1. NetworkPolicy(网络策略)

NetworkPolicy是Kubernetes中用于控制Pod之间网络流量的资源。它定义了Pod如何与其他网络端点通信的规则。

2. 网络插件要求

NetworkPolicy需要支持的网络插件(CNI)才能生效,如:

  • Calico
  • Cilium
  • Weave Net
  • Flannel(需要额外配置)

3. 入站规则(Ingress)

控制进入Pod的流量,指定允许哪些源Pod或命名空间访问目标Pod。

4. 出站规则(Egress)

控制从Pod发出的流量,指定目标Pod可以访问哪些外部端点。

5. 默认策略

如果没有定义NetworkPolicy,所有Pod之间默认可以互相通信。

NetworkPolicy工作原理

┌─────────────────────────────────────────────────────┐
│                  Namespace A                         │
│                                                     │
│  ┌──────────┐        NetworkPolicy       ┌──────────┐│
│  │  Pod A   │◄─────────────────────────►│  Pod B   ││
│  │          │        允许通信             │          ││
│  └──────────┘                           └──────────┘│
│                                                     │
└─────────────────────────────────────────────────────┘
         │                                    ▲
         │ 拒绝                               │ 允许
         ▼                                    │
┌─────────────────────────────────────────────────────┐
│                  Namespace B                         │
│                                                     │
│  ┌──────────┐                           ┌──────────┐│
│  │  Pod C   │                           │  Pod D   ││
│  │          │                           │          ││
│  └──────────┘                           └──────────┘│
│                                                     │
└─────────────────────────────────────────────────────┘

YAML配置示例

示例1:拒绝所有入站流量

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
  namespace: default
spec:
  podSelector: {}  # 选择所有Pod
  policyTypes:
  - Ingress
  # 没有ingress规则,表示拒绝所有入站流量

示例2:拒绝所有出站流量

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-egress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  # 没有egress规则,表示拒绝所有出站流量

示例3:允许特定Pod访问

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080

示例4:允许特定命名空间访问

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-namespace
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: development
    ports:
    - protocol: TCP
      port: 80

示例5:允许特定IP段访问

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-ip
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 192.168.1.0/24
        except:
        - 192.168.1.100/32
    ports:
    - protocol: TCP
      port: 80

示例6:完整的网络策略配置

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: complete-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: frontend
    - namespaceSelector:
        matchLabels:
          env: production
    - ipBlock:
        cidr: 10.0.0.0/8
    ports:
    - protocol: TCP
      port: 8080
    - protocol: TCP
      port: 8443
  egress:
  - to:
    - podSelector:
        matchLabels:
          role: database
    ports:
    - protocol: TCP
      port: 3306
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

示例7:多端口和多协议配置

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: multi-port-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: client
    ports:
    - protocol: TCP
      port: 80
    - protocol: TCP
      port: 443
    - protocol: TCP
      port: 8080

kubectl操作命令

查看网络策略

bash
# 查看所有NetworkPolicy
kubectl get networkpolicies --all-namespaces

# 查看特定命名空间的NetworkPolicy
kubectl get networkpolicies -n default

# 简写形式
kubectl get netpol -n default

# 查看NetworkPolicy详细信息
kubectl describe networkpolicy deny-all-ingress -n default

# 以YAML格式查看NetworkPolicy
kubectl get networkpolicy deny-all-ingress -n default -o yaml

# 查看NetworkPolicy的选择器
kubectl get networkpolicy -n default -o jsonpath='{.items[*].spec.podSelector}'

创建和删除网络策略

bash
# 通过YAML文件创建NetworkPolicy
kubectl apply -f networkpolicy.yaml

# 删除NetworkPolicy
kubectl delete networkpolicy deny-all-ingress -n default

# 删除命名空间中的所有NetworkPolicy
kubectl delete networkpolicies --all -n default

测试网络策略

bash
# 创建测试Pod
kubectl run test-pod --image=busybox --rm -it --restart=Never -- sh

# 在测试Pod中测试连接
wget -qO- http://backend-service:8080
nc -zv backend-service 8080
curl http://backend-service:8080

# 测试DNS解析
nslookup backend-service
dig backend-service.default.svc.cluster.local

# 测试外部连接
curl http://example.com

查看Pod的网络标签

bash
# 查看Pod的标签
kubectl get pods --show-labels

# 根据标签选择Pod
kubectl get pods -l app=backend

# 查看命名空间的标签
kubectl get namespace --show-labels

# 为命名空间添加标签
kubectl label namespace development name=development

调试网络策略

bash
# 查看Pod的IP地址
kubectl get pods -o wide

# 查看Service的ClusterIP
kubectl get svc

# 查看网络插件状态
kubectl get pods -n kube-system | grep -E 'calico|cilium|weave|flannel'

# 查看网络策略影响的Pod
kubectl get pods -l app=backend -n default

# 进入Pod测试网络连接
kubectl exec -it <pod-name> -- sh

真实场景实践示例

场景1:多层级应用网络隔离

需求:三层架构应用,前端只能访问后端,后端只能访问数据库,数据库不接受任何入站连接(除了后端)。

解决方案

yaml
---
# 前端网络策略:允许外部访问,可以访问后端
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      tier: frontend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0
    ports:
    - protocol: TCP
      port: 80
    - protocol: TCP
      port: 443
  egress:
  - to:
    - podSelector:
        matchLabels:
          tier: backend
    ports:
    - protocol: TCP
      port: 8080
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
---
# 后端网络策略:只接受前端访问,可以访问数据库
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          tier: database
    ports:
    - protocol: TCP
      port: 3306
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
---
# 数据库网络策略:只接受后端访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      tier: database
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: backend
    ports:
    - protocol: TCP
      port: 3306
  egress:
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

验证

bash
# 应用配置
kubectl apply -f multi-tier-networkpolicy.yaml

# 创建测试Pod
kubectl run test-frontend --image=busybox --rm -it --restart=Never --labels="tier=frontend" -- sh
# 在Pod中测试:可以访问后端
wget -qO- http://backend:8080

kubectl run test-backend --image=busybox --rm -it --restart=Never --labels="tier=backend" -- sh
# 在Pod中测试:可以访问数据库
nc -zv database 3306

场景2:命名空间隔离

需求:不同命名空间之间完全隔离,但允许访问公共服务(如监控、日志)。

解决方案

yaml
---
# 为命名空间添加标签
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    name: production
    env: prod
---
apiVersion: v1
kind: Namespace
metadata:
  name: development
  labels:
    name: development
    env: dev
---
# 生产环境:拒绝其他命名空间访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: production-isolation
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: production
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: production
  - to:
    - namespaceSelector:
        matchLabels:
          name: monitoring
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
---
# 开发环境:拒绝其他命名空间访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: development-isolation
  namespace: development
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: development
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: development
  - to:
    - namespaceSelector:
        matchLabels:
          name: monitoring
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

验证

bash
# 应用配置
kubectl apply -f namespace-isolation.yaml

# 测试命名空间隔离
kubectl run test-prod --image=busybox --rm -it --restart=Never -n production -- sh
# 在Pod中测试:无法访问开发环境
wget -qO- http://service.development.svc.cluster.local
# 应该失败

# 测试可以访问监控
kubectl run test-monitoring --image=busybox --rm -it --restart=Never -n monitoring -- sh

场景3:限制外部访问

需求:只允许特定IP范围的外部流量访问Web服务。

解决方案

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: restrict-external-access
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 10.0.0.0/8  # 内部网络
    - ipBlock:
        cidr: 192.168.0.0/16  # VPN网络
    - ipBlock:
        cidr: 172.16.0.0/12  # 办公网络
    ports:
    - protocol: TCP
      port: 80
    - protocol: TCP
      port: 443

验证

bash
# 应用配置
kubectl apply -f restrict-external-access.yaml

# 从允许的IP测试
curl http://web-service.default.svc.cluster.local

# 从不允许的IP测试(应该失败)
# 需要从外部网络测试

场景4:允许访问外部服务

需求:应用需要访问外部API服务,但不能访问其他外部地址。

解决方案

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-external-api
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: api-client
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 10.0.0.0/8
        - 172.16.0.0/12
        - 192.168.0.0/16
    ports:
    - protocol: TCP
      port: 443
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

验证

bash
# 应用配置
kubectl apply -f allow-external-api.yaml

# 创建测试Pod
kubectl run api-client --image=curlimages/curl --rm -it --restart=Never --labels="app=api-client" -- sh

# 测试访问外部API
curl https://api.example.com
# 应该成功

# 测试访问内部服务
curl http://internal-service.default.svc.cluster.local
# 应该失败

场景5:数据库访问控制

需求:数据库只允许特定的应用Pod访问,且只能访问特定端口。

解决方案

yaml
---
# MySQL数据库网络策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: mysql-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: mysql
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: backend
    - podSelector:
        matchLabels:
          app: admin
    ports:
    - protocol: TCP
      port: 3306
---
# PostgreSQL数据库网络策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: postgres-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: backend
    ports:
    - protocol: TCP
      port: 5432
---
# Redis网络策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: redis-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: redis
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: backend
    ports:
    - protocol: TCP
      port: 6379

验证

bash
# 应用配置
kubectl apply -f database-networkpolicy.yaml

# 测试后端可以访问数据库
kubectl run backend --image=mysql:5.7 --rm -it --restart=Never --labels="app=backend" -- mysql -h mysql -u root -p

# 测试其他应用无法访问数据库
kubectl run unauthorized --image=mysql:5.7 --rm -it --restart=Never --labels="app=unauthorized" -- mysql -h mysql -u root -p
# 应该失败

场景6:监控和日志服务访问

需求:允许Prometheus和Fluentd访问所有Pod收集指标和日志。

解决方案

yaml
---
# 允许Prometheus访问所有Pod
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-prometheus
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: monitoring
      podSelector:
        matchLabels:
          app: prometheus
    ports:
    - protocol: TCP
      port: 9090
    - protocol: TCP
      port: 8080
---
# 允许Fluentd访问所有Pod
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-fluentd
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: logging
      podSelector:
        matchLabels:
          app: fluentd

验证

bash
# 应用配置
kubectl apply -f monitoring-access.yaml

# 检查Prometheus是否可以访问目标
kubectl logs -n monitoring prometheus-pod | grep "target health"

故障排查指南

问题1:网络策略不生效

症状:创建了NetworkPolicy但Pod之间仍然可以互相访问。

排查步骤

bash
# 1. 检查网络插件是否支持NetworkPolicy
kubectl get pods -n kube-system | grep -E 'calico|cilium|weave'

# 2. 检查NetworkPolicy是否正确创建
kubectl get networkpolicy -n <namespace>
kubectl describe networkpolicy <policy-name> -n <namespace>

# 3. 检查Pod的标签是否匹配
kubectl get pods --show-labels -n <namespace>

# 4. 检查命名空间的标签
kubectl get namespace --show-labels

# 5. 检查网络插件日志
kubectl logs -n kube-system <network-plugin-pod>

# 6. 查看网络策略的详细信息
kubectl get networkpolicy <policy-name> -n <namespace> -o yaml

解决方案

  • 确保使用支持NetworkPolicy的网络插件
  • 检查Pod标签是否正确匹配
  • 检查命名空间标签是否正确配置
  • 重启网络插件Pod

问题2:Pod无法访问DNS

症状:应用无法解析域名。

排查步骤

bash
# 1. 测试DNS解析
kubectl exec -it <pod-name> -- nslookup kubernetes

# 2. 检查DNS服务
kubectl get svc -n kube-system kube-dns

# 3. 检查DNS Pod
kubectl get pods -n kube-system -l k8s-app=kube-dns

# 4. 检查网络策略是否阻止了DNS
kubectl get networkpolicy -n <namespace> -o yaml | grep -A 10 "port: 53"

# 5. 测试直接访问DNS
kubectl exec -it <pod-name> -- nslookup kubernetes.default.svc.cluster.local 10.96.0.10

解决方案

yaml
# 确保网络策略允许DNS访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

问题3:无法访问外部服务

症状:Pod无法访问外部API或服务。

排查步骤

bash
# 1. 测试外部连接
kubectl exec -it <pod-name> -- curl -v https://api.example.com

# 2. 检查网络策略的egress规则
kubectl get networkpolicy -n <namespace> -o yaml | grep -A 20 "egress"

# 3. 检查是否有默认拒绝策略
kubectl get networkpolicy -n <namespace>

# 4. 测试IP连接
kubectl exec -it <pod-name> -- ping -c 3 8.8.8.8

# 5. 检查NAT配置
kubectl exec -it <pod-name> -- ip route

解决方案

yaml
# 允许访问外部服务
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-external-egress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 10.0.0.0/8
        - 172.16.0.0/12
        - 192.168.0.0/16

问题4:Service无法访问

症状:无法通过Service访问Pod。

排查步骤

bash
# 1. 检查Service是否存在
kubectl get svc -n <namespace>

# 2. 检查Service的Endpoints
kubectl get endpoints <service-name> -n <namespace>

# 3. 检查Pod是否健康
kubectl get pods -l app=<app-name> -n <namespace>

# 4. 测试直接访问Pod IP
kubectl exec -it <test-pod> -- curl http://<pod-ip>:<port>

# 5. 测试访问Service ClusterIP
kubectl exec -it <test-pod> -- curl http://<service-name>:<port>

# 6. 检查网络策略
kubectl describe networkpolicy -n <namespace>

解决方案

  • 确保网络策略允许访问Service端口
  • 检查Pod标签是否正确
  • 确保Service selector正确匹配Pod

问题5:命名空间隔离失败

症状:不同命名空间的Pod仍然可以互相访问。

排查步骤

bash
# 1. 检查命名空间标签
kubectl get namespace --show-labels

# 2. 检查网络策略的namespaceSelector
kubectl get networkpolicy -n <namespace> -o yaml | grep -A 5 "namespaceSelector"

# 3. 测试跨命名空间访问
kubectl exec -it <pod-name> -n namespace-a -- curl http://service.namespace-b.svc.cluster.local

# 4. 检查网络插件配置
kubectl get configmap -n kube-system <network-plugin-config>

解决方案

yaml
# 确保命名空间有正确的标签
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    name: production
---
# 网络策略使用正确的namespaceSelector
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: isolate-namespace
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: production

问题6:网络策略冲突

症状:多个NetworkPolicy导致预期之外的行为。

排查步骤

bash
# 1. 列出所有NetworkPolicy
kubectl get networkpolicy -n <namespace>

# 2. 查看每个NetworkPolicy的详细配置
kubectl describe networkpolicy -n <namespace>

# 3. 检查Pod匹配的所有NetworkPolicy
kubectl get networkpolicy -n <namespace> -o json | \
  jq -r '.items[] | select(.spec.podSelector.matchLabels.app=="<app-name>") | .metadata.name'

# 4. 测试网络连接
kubectl exec -it <pod-name> -- curl -v http://<target-service>

解决方案

  • NetworkPolicy是累加的,多个策略会合并
  • 删除冲突的策略
  • 使用更精确的podSelector

最佳实践建议

1. 默认拒绝所有流量

yaml
# 第一步:创建默认拒绝策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
---
# 第二步:逐个添加允许规则
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-specific
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend

2. 始终允许DNS访问

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-access
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

3. 使用命名空间标签

yaml
# 为命名空间添加标签
kubectl label namespace production env=prod
kubectl label namespace development env=dev

# 在网络策略中使用
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-prod
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          env: prod

4. 分层管理网络策略

yaml
# 基础策略:允许DNS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: baseline-allow-dns
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
---
# 应用策略:允许特定应用通信
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: app-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: database

5. 使用注释记录策略用途

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-policy
  namespace: default
  annotations:
    description: "允许前端访问后端API"
    owner: "backend-team@example.com"
    created-by: "admin"
    last-updated: "2024-01-15"
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend

6. 定期审计网络策略

bash
# 列出所有NetworkPolicy
kubectl get networkpolicies --all-namespaces

# 检查没有NetworkPolicy的命名空间
kubectl get namespaces -o json | \
  jq -r '.items[] | select(.metadata.name != "kube-system") | .metadata.name' | \
  while read ns; do
    count=$(kubectl get networkpolicy -n $ns -o json | jq '.items | length')
    if [ "$count" -eq 0 ]; then
      echo "Namespace $ns has no NetworkPolicy"
    fi
  done

# 检查过于宽松的策略
kubectl get networkpolicies --all-namespaces -o json | \
  jq -r '.items[] | select(.spec.podSelector=={}) | "\(.metadata.namespace)/\(.metadata.name)"'

7. 测试网络策略

bash
# 创建测试脚本
cat > test-network-policy.sh << 'EOF'
#!/bin/bash

NAMESPACE=$1
SOURCE_POD=$2
TARGET_SERVICE=$3
PORT=$4

echo "Testing connection from $SOURCE_POD to $TARGET_SERVICE:$PORT"

kubectl exec -n $NAMESPACE $SOURCE_POD -- \
  nc -zv $TARGET_SERVICE $PORT

if [ $? -eq 0 ]; then
  echo "Connection successful"
else
  echo "Connection failed (expected behavior if blocked by NetworkPolicy)"
fi
EOF

chmod +x test-network-policy.sh

8. 使用版本控制

bash
# 将网络策略纳入Git管理
git add networkpolicies/
git commit -m "Update network policies for production namespace"

# 使用GitOps工具管理网络策略
# 例如:ArgoCD, Flux

9. 监控网络策略效果

yaml
# 使用Prometheus监控网络连接
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-rules
  namespace: monitoring
data:
  network.rules: |
    groups:
    - name: network
      rules:
      - alert: NetworkPolicyBlockingTraffic
        expr: rate(connection_refused_total[5m]) > 0.1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Network policy may be blocking traffic"
          description: "High rate of connection refused errors detected"

10. 文档化网络策略

yaml
# 在README中记录网络策略设计
# network-policy-design.md

# 网络策略设计文档

## 概述
本文档描述了生产环境的网络策略设计。

## 策略层级
1. 基础策略:默认拒绝所有流量
2. DNS策略:允许所有Pod访问DNS
3. 应用策略:根据应用需求添加特定规则

## 命名空间隔离
- production: 完全隔离
- development: 允许访问测试服务
- monitoring: 可以访问所有命名空间

## 应用通信矩阵
| 源应用 | 目标应用 | 端口 | 说明 |
|--------|----------|------|------|
| frontend | backend | 8080 | API调用 |
| backend | database | 3306 | 数据库访问 |
| backend | redis | 6379 | 缓存访问 |

网络策略设计模式

模式1:零信任网络

yaml
# 默认拒绝所有流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: zero-trust
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
# 只允许明确授权的流量

模式2:分层安全

yaml
# 前端层
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-layer
spec:
  podSelector:
    matchLabels:
      layer: frontend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0
  egress:
  - to:
    - podSelector:
        matchLabels:
          layer: backend
---
# 后端层
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-layer
spec:
  podSelector:
    matchLabels:
      layer: backend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          layer: frontend
  egress:
  - to:
    - podSelector:
        matchLabels:
          layer: database

模式3:服务网格集成

yaml
# 允许Istio sidecar通信
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-istio
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: istio-system
    ports:
    - protocol: TCP
      port: 15090

总结

网络安全策略是Kubernetes集群安全的关键组成部分,通过网络策略可以实现:

  1. 网络隔离:控制Pod之间的网络流量
  2. 访问控制:限制哪些Pod可以访问服务
  3. 多租户安全:实现命名空间级别的隔离
  4. 零信任架构:默认拒绝,按需允许

关键要点

  • NetworkPolicy需要支持的网络插件
  • 默认情况下所有Pod可以互相通信
  • NetworkPolicy是累加的,多个策略会合并
  • 始终允许DNS访问
  • 使用标签选择器精确控制流量
  • 定期审计和测试网络策略

下一步学习

参考资料