Istio 服务网格安全实战:mTLS 双向认证与流量加密配置

适用场景

本文适用于运行在 Kubernetes 集群内的微服务架构,当服务间存在敏感数据传输(订单、用户、支付信息)、安全审计要求服务间身份可验证、或需要替代自研加密中间层时,可借助 Istio 服务网格 的 mTLS 双向认证与授权策略实现统一安全治理。以下配置基于 Istio 1.18+ 与 Kubernetes 1.24+。

前置条件

  • 已通过 istioctl 或 Helm 完成 Istio 安装,istiod 运行正常
  • 目标命名空间可开启 sidecar 自动注入(istio-injection=enabled 标签)
  • 具备 kubectl 集群权限,可创建 PeerAuthentication / AuthorizationPolicy CRD 资源

原理说明

Istio 为每个 Pod 注入 Envoy sidecar 代理,服务间流量全部经过 sidecar 转发。istiod 控制面为每个工作负载签发基于 SPIFFE 的身份证书,sidecar 之间通过 mTLS 加密通信并互相验证身份。PeerAuthentication 资源控制 mTLS 模式:PERMISSIVE(兼容明文)或 STRICT(强制双向 TLS);AuthorizationPolicy 提供比网络层更细粒度的 L7 授权(按来源身份、HTTP 方法、路径)。默认集群为 PERMISSIVE 模式,生产环境应切换到 STRICT 并配合授权策略。

操作步骤

第一步:开启命名空间自动注入

# 为目标命名空间开启 sidecar 自动注入
kubectl label namespace default istio-injection=enabled

# 部署测试应用(示例为 Bookinfo 可跳过,直接使用你的服务)
kubectl rollout restart deployment -n default

第二步:配置 STRICT mTLS

创建 PeerAuthentication 资源,将命名空间内全部服务切换为强制双向 TLS:

cat <<'EOF' | kubectl apply -f -
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default-strict
  namespace: default
spec:
  mtls:
    mode: STRICT
EOF

第三步:配置细粒度授权策略

仅允许指定服务账号访问目标服务,并限制 HTTP 方法:

cat <<'EOF' | kubectl apply -f -
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: order-api-allow
  namespace: default
spec:
  selector:
    matchLabels:
      app: order-api
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/default/sa/payment"]
    to:
    - operation:
        methods: ["GET", "POST"]
        paths: ["/api/orders/*"]
EOF

第四步:按端口精细控制 mTLS 策略

若服务同时承载内部业务端口与对外健康检查端口,可对端口单独设置 mTLS 模式,避免误伤健康检查流量:

cat <<'EOF' | kubectl apply -f -
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: order-api-port-mtls
  namespace: default
spec:
  selector:
    matchLabels:
      app: order-api
  mtls:
    mode: STRICT
  portLevelMtls:
    9090:
      mode: PERMISSIVE   # 健康检查端口保持兼容
EOF

第五步:监控 mTLS 覆盖与异常流量

通过 Prometheus 指标监控集群内 mTLS 启用比例与请求失败率,及时发现未加密流量:

# 查询 sidecar 间非 mTLS 请求占比(应趋近于 0)
istio_requests_total{reporter="destination",connection_security_policy!="mutual_tls"}

# 查看 403 授权拒绝次数,辅助调整 AuthorizationPolicy
istio_requests_total{response_code="403"}

# 打开 Grafana Istio 面板查看服务间安全状态
istioctl dashboard grafana

第六步:验证证书与 mTLS 状态

# 查看服务间 TLS 协商结果
istioctl authn tls-check deployment/order-api-v1 default

# 查看 sidecar 中签发的证书与轮换时间
istioctl proxy-config secret order-api-v1 -o json | jq .

配置验证

# 1. 抓包确认 sidecar 间为 8443 加密流量(默认 mTLS 端口)
kubectl exec -it deploy/order-api-v1 -c istio-proxy -- \
  tcpdump -i eth0 -nn -c 20 port 8080

# 2. 验证授权:非授权来源访问应返回 403
kubectl exec -it deploy/unauthorized-app -- \
  curl -s -o /dev/null -w "%{http_code}\n" http://order-api:8080/api/orders/

# 3. 验证 mTLS 后明文端口不可直接访问(被 sidecar 拒绝)
kubectl exec -it deploy/payment-v1 -- curl http://order-api:8080 2>&1 | head

常见问题

Q1:切换 STRICT 后服务调用大面积失败?

通常是目标服务未注入 sidecar 或仍以明文对外通信。先确认所有涉及命名空间都开启注入并完成滚动重启,排查期可先将 PeerAuthentication 改为 PERMISSIVE 过渡,待全部 sidecar 就绪后再切 STRICT。

Q2:mTLS 与 NetworkPolicy 功能重复吗?

不重复。mTLS 负责传输加密与身份认证,NetworkPolicy 负责网络层来源白名单,两者可叠加使用:先由 NetworkPolicy 控制网段可达性,再由 mTLS + AuthorizationPolicy 控制服务身份与方法级访问。

Q3:sidecar 证书过期是否需要人工处理?

不需要。istiod 默认每 24 小时自动轮换工作负载证书,重启进程即可加载新证书。若证书异常,检查 istiod 日志、系统时间同步(NTP)与 CA 配置。

Q4:集群外服务或第三方 API 无法配置 mTLS,如何处理?

对集群外流量使用 Sidecar 资源将目标声明为 mesh-external,流量将以明文(或 TLS origination)出站;对外调用建议启用 egress TLS 并对目标域名做 allowlist,同时确保内部服务间保持 STRICT mTLS,缩小明文流量范围。

总结

Istio 服务网格通过 自动 mTLS + AuthorizationPolicy 将零信任思想落地到集群内服务间通信:STRICT 模式保证流量加密与身份可信,细粒度授权收敛东西向攻击面。建议按命名空间分批灰度切换,先 PERMISSIVE 后 STRICT,并配合监控面板持续观察 mTLS 覆盖率,逐步完成全集群安全加固。