乐趣区

关于腾讯云:使用-Istio-CNI-支持强安全-TKE-Stack-集群的服务网格流量捕获

作者

陈计节,企业应用云原生架构师,在腾讯企业 IT 负责云原生利用治理产品的设计与研发工作,次要钻研利用容器集群和服务网格等云原生实际模式升高微服务开发与治理门槛并晋升经营效率。

摘要

给须要疾速解决问题的集群管理员:
在 TKE Stack 中正确装置 Istio CNI 有两种形式:如果你的 TKE Stack 集群所应用 Galaxy 版本能够反对 cniVersion 0.3.1,请以默认的形式装置 Istio CNI;否则请应用以“网卡插件”的形式装置 Istio CNI,并在创立 Pod 时指定应用集群默认网络名称。
如果你发现你的 TKE Stack 集群装置完 Istio CNI 之后,无奈创立新的 Pod,请立刻卸载已装置的 Istio CNI,并手动复原各个节点上写入的 Galaxy 配置文件:将 /etc/cni/net.d/00-galaxy.conflist 文件内的 plugins 数组字段的第一个元素提取进去,并保留为独自的 conf 文件:/etc/cni/net.d/00-galaxy.conf。删除正在创立中、但无奈胜利的 Pod,期待其重建,Pod 的创立性能应该能主动复原。

Istio 是风行的服务网格软件,它通过向业务 Pod 注入可捕捉出入口流量的代理软件 Envoy 作为 Sidecar 来实现对流量的观测与治理。

Istio 为了让 Envoy 代理可能捕捉来去业务容器的流量,须要向 Pod 所在网络下发如下 IPTABLES 规定:

*nat
-N ISTIO_INBOUND
-N ISTIO_REDIRECT
-N ISTIO_IN_REDIRECT
-N ISTIO_OUTPUT
-A ISTIO_INBOUND -p tcp --dport 15008 -j RETURN
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
-A PREROUTING -p tcp -j ISTIO_INBOUND
-A ISTIO_INBOUND -p tcp --dport 22 -j RETURN
-A ISTIO_INBOUND -p tcp --dport 15090 -j RETURN
-A ISTIO_INBOUND -p tcp --dport 15021 -j RETURN
-A ISTIO_INBOUND -p tcp --dport 15020 -j RETURN
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
-A OUTPUT -p tcp -j ISTIO_OUTPUT
-A ISTIO_OUTPUT -o lo -s 127.0.0.6/32 -j RETURN
-A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
COMMIT

在惯例装置模式下,下发 IPTABLES 规定的操作,是通过与 Envoy 代理容器一起注入的初始化容器 istio-init 实现的。向 Pod 网络下发 IPTABLES 规定要求 Pod 能够应用 NET_ADMIN 和 NET_RAW 两个高权限性能(Capabilities)。Linux 将传统与超级用户 root 关联的特权划分为不同的单元,称为 Capabilites。Capabilites 每个单元都能够独立启用和禁用。这样当零碎在做权限查看的时候就查看特定的 Capabilites,并决定以后用户其过程是否能够进行相应特权操作。比方如果要设置零碎工夫,就得具备 CAP_SYS_TIME 这个 Capabilites。

Istio 流量捕捉性能面临的平安挑战

容器实质上是是宿主机上运行的过程,尽管容器运行时默认只向容器提供必要 Capabilities,但如果应用 --privileded 模式运行容器,或者向容器追加更多 Capabilities 时,容器就能够像其余过程一样领有很高权限的操作能力。这样,能应用 NET_ADMIN 和 NET_RAW 权限的 Pod 实践上不光能够操作本人这个 Pod 的网络,如果处理不当,还可能影响到同一工作节点的其余 Pod 甚至是宿主机的网络配置。通常,这在一些对容器利用的权限严格限度的环境中,是不举荐应用的。

从 Kubernetes 1.11 版本开始,咱们能够在集群中应用 PodSecurityPolicy 资源(PSP)来限度集群中的 Pod 能够应用的默认权限或能力。通过编写如下 PSP 即可限度集群内的 Pod 均不得应用任何特权 Capabilities:

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: pod-limited
spec:
  allowPrivilegeEscalation: false
  # 不容许应用 Capabilities
  # allowedCapabilities:
  #   - '*'
  fsGroup:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  volumes:
  - configMap
  - downwardAPI
  - emptyDir
  - persistentVolumeClaim
  - secret
  - nfs

可想而知,在一个增加了上述限度的集群上,istio-init 容器因为无奈取得相应特权,将无奈实现预约工作:无奈让 Envoy 代理软件捕捉 Pod 中的流量。这样整个 Istio 软件的性能也就无从谈起了。此外,从 Kubernetes 1.21 版本开始,PSP 性能将逐渐被弃用。新版集群上可能应用其余代替机制限度 Pod 权限。

应用 Istio CNI 解决权限扩散问题

下面谈到的平安危险来自于在所有须要注入 Sidecar 的业务 Pod 均须要同步注入高权限 istio-init 容器,而业务 Pod 能够由应用集群的任何人来创立和应用。这对于集群来说,就形成了攻击面的有限蔓延。这类问题的解决思路,通常是将攻击面集中化治理。也就是说,由大量可控的高权限 Pod 来侦听 Pod 创立的过程,在 Pod 启动前,为它们实现 IPTABLES 下发过程。

这正是 Istio CNI 所解决的问题。

通常,如果要侦听 Pod 创立、删除的事件,应用 Imformer 机制即可很轻松地获取到集群内各类资源的创立与回收事件。这也是在 Kubernetes 中开发各类 Controller 所常见的做法。但为 Pod 下发 IPTABLES 规定的工作与一般 Controller 有所不同:它须要在 Pod 事件创立或删除时,在 Pod 所在工作节点上,进入相应容器的 Linux Namespace,并下发 IPTABLES 规定。从执行地位来说,这更像是一种 Daemonset。另一方面,对 Pod 的创立和删除事件的解决恰好与 CNI 定义的一些命令吻合,CNI 是 Kubernetes 定义的用于为 Pod、Service 提供网络的机制。正好下发 IPTABLES 也是一种网络相干的操作,所以 Istio 团队也就索性间接以 CNI 插件的形式提供这一性能。

Istio CNI 的工作流程如下图:

Istio CNI DaemonSet 负责将 Istio CNI 插件的可执行程序装置到工作节点上。这些程序稍后在新的业务 Pod 创立或销毁时会收到来自 k8s 的调用,接着它们实现 IPTABLES 规定的配置。因为这些程序是运行在工作节点上,因而具备较高的权限:但它们能够被集中管理,因而权限是受控的,而业务 Pod 此时不再须要高权限来配置这些 IPTABLES,只须要运行一个简略的检查程序,确保业务容器运行之前,这些规定已就绪即可。

上图是 Istio 自注入模板的代码片断,从中能够看出,当启用 Istio CNI 时,如果启用了 Istio CNI 性能,Istio 向 Pod 注入的容器不再须要高权限。

在 TKE Stack 中装置 Istio CNI 的问题

与一般 CNI 插件不同,Istio CNI 并不提供惯例的 IP 地址治理(IPAM)和联网(SDN)性能。它只在 Pod 的网络已建设之后,负责下发上述规定。因而,Istio CNI 并不会、也不能替换集群现有的 CNI 插件的性能。也就是说,在配置 Istio CNI 之外,k8s 集群还须要配置其余负责 IPAM 和 SDN 的软件,比方咱们相熟的 Flannel 或 Calico 等。

为了配合不同品种的现有 CNI 插件,Istio CNI 既能以“网卡插件”(Interface Plugins)的形式运行,也能以“插件链”(Chained Plugins)的形式附加到现有网卡插件运行。依据 CNI 规范的形容,网卡插件是用于创立虚构网卡的 CNI 插件,而插件链则容许多个插件为已创立的网卡提供附加性能。插件链模式很合乎 Istio CNI 的定位,也是 Istio CNI 的默认运行形式。在这种运行形式下,Istio CNI 先会查看集群以后 CNI 插件的配置:如果它曾经是一个插件链,则将本身增加到它的尾部,成为新的性能;如果以后插件是一个“网卡插件”,则先将其转换为插件链,再将本身增加到链的尾部。

TKE Stack 是由腾讯主导的开源 k8s 发行版,与社区版 k8s 相比,TKE Stack 次要提供了更强的网络接入能力、多集群治理能力,以及将容器资源与业务和用户等因素集成治理等丰盛的性能。TKE Stack 也是腾讯云提供的容器服务的开源版本,在腾讯外部部署了超过数十万核的超大规模集群,稳固运行了数年。

TKE Stack 的默认 CNI 插件是 Galaxy,它是一个能让集群接入各类网络插件的“元 CNI”框架:基于它,咱们能够让集群中的 Pod 基于 Flannel 之类的插件取得一般 Overlay 网络的同时,还能够基于其余插件取得诸如 Underlay 网络等弱小的能力。比方,典型的 Underlay 网络能够提供的能力有,能够让 Pod 获取到另一个子网(比方工作节点所在子网)的 IP 地址、获取固定 IP 地址等。

通过测试发现,在一些集群上,Istio CNI 插件默认的插件链运行模式与 Galaxy 不能兼容。起因是,Istio CNI 的配置转换处理过程存在瑕疵:这些集群上的原有 Galaxy CNI 的配置是网卡插件(即 00-galaxy.conf)模式,通过 Istio CNI 的解决之后,相干配置无奈被 Galaxy CNI 辨认和解决。

具体起因是,Istio CNI 在将原有配置复制为插件链模式的过程中,会删除原配置中的 cniVersion 版本号(如果有),在新生成的插件链配置文件 00-galaxy.conflist 时,将此版本号强制改为 Galaxy CNI 尚未反对的 0.3.1。进入 Galaxy CNI 相干 daemonset 容器,并模仿执行 CNI 版本查看命令,能够发现此集群上 Galaxy CNI 反对的 cniVersion 最高为 0.2.0。相干源码可点击此处。

CNI_COMMAND=VERSION /opt/cni/bin/galaxy-sdn </etc/cni/net.d/00-galaxy.conf

在这样的 TKE Stack 集群中以插件链模式运行 Istio CNI 之后,将呈现新 Pod 无奈创立的问题。具体谬误为:plugin galaxy-sdn does not support config version “0.3.1”。从 Pod 创立日志及 kubelet 上都能够找到这一错误信息。

更蹩脚的是,即便此时卸载 Istio CNI,依然不能复原 Galaxy CNI 的性能。这是因为尽管 Istio CNI 卸载过程会尝试回退它做的批改,然而回退过程只是将 Istio CNI 相干内容从新创建的 conflist 格局配置中移除,而并未将 CNI 配置文件复原为原始的 conf 格局,无奈辨认的版本号 0.3.1 被保留了下来。

此时,须要管理员登录每台集群工作节点,手工将 /etc/cni/net.d/00-galaxy.conflist 文件内的 plugins 数组字段的第一个元素提取进去,并保留为独自的 conf 文件:/etc/cni/net.d/00-galaxy.conf。删除正在创立中、但无奈胜利的 Pod,期待其重建,Pod 的创立性能应该能主动复原。

Istio CNI 装置问题的解决思路

明确了问题的原因,要解决这些问题就很间接了。在 TKE Stack 集群中装置 Istio CNI 的两个思路是:

  1. 应用网卡插件的形式运行 Istio CNI
  2. 降级 TKE Stack 集群中的 Galaxy CNI 版本

应用网卡插件的形式运行 Istio CNI

既然 Istio CNI 提供了网卡插件的运行形式,那启用它是一种比拟轻松的处理办法。装置 Istio CNI 时,敞开 chained 参数即能够网卡插件的形式运行 Istio CNI。如果是为已有 Istio 集群补充装置 Istio CNI,则可能须要手工批改位于 istio-system 命名空间的 Istio 注入模板配置 configmap/istio-sidecar-injector 资源中的 values 数据。其中的 istio_cni 配置节:

"istio_cni": {
  "enabled": true,
  "chained": false
}

须要留神的是,以网卡模式运行的 Istio CNI,会在 Pod 创立为其时增加 k8s.v1.cni.cncf.io/networks 注解(Annotation),以便告诉集群上能够反对这个注解的 CNI 插件调用 Istio CNI 实现性能。Galaxy CNI 作为一个元 CNI 插件,是能够反对这个注解的。当 Galaxy 遇到这个注解时,将会跳过默认的 Galaxy 网络插件,而启用注解中配置的 CNI 插件。Istio CNI 并不理论提供联网性能,因而如果只运行 Istio CNI 会导致 Pod 无奈取得正确的 IP,因而还是无奈正确创立。以下代码片断来自 Istio 注入模板,从中能够看出其中的逻辑:

  {{- if and (.Values.istio_cni.enabled) (not .Values.istio_cni.chained) }}
  {{if isset .ObjectMeta.Annotations `k8s.v1.cni.cncf.io/networks`}}
    k8s.v1.cni.cncf.io/networks: "{{index .ObjectMeta.Annotations `k8s.v1.cni.cncf.io/networks`}}, istio-cni"
  {{- else}}
    k8s.v1.cni.cncf.io/networks: "istio-cni"
  {{- end}}
  {{- end}}

从下面的代码中能够看出,Istio 模板尝试读取 Pod 上已有的注解值,并将 istio-cni 追加到开端。这样,咱们只须要在创立 Pod 时将 Galaxy 默认的网络配置名称以注解的形式提前列出,即可正确创立 Pod。从 kube-system 命名空间中的 configmap/galaxy-etc 配置的 DefaultNetworks 能够找到以后 Galaxy CNI 的默认网络名称。

kind: Pod
metadata:
  annotations:
    k8s.v1.cni.cncf.io/networks: galaxy-flannel
  name: my-pod

理论测试结果表明,以网卡插件模式运行 Istio CNI,并在 Pod 上标记原有网络模式,即可在 TKE Stack 上胜利运行 Pod 并失常应用 Istio 的各项性能。

降级 TKE Stack 集群中的 Galaxy CNI

尽管以独立网卡插件模式运行 Istio CNI 是能够解决 Pod 无奈创立的问题的,然而因为须要向 Pod 上增加额定的注解,所以给利用开发者或者部署流水线减少了额定的复杂度,甚至有可能影响 Pod 应用 Galaxy CNI 提供的其余网络性能。比拟现实的成果是,能像 Istio CNI 原生提供的那样,能通明地反对相干性能。

侥幸的是,在最新的 1.0.8 版本 的 Galaxy CNI 的代码中,曾经反对了 0.4.0 及之前版本的各个 cniVersion。因而将 Galaxy CNI 的版本升级到最新版,就能以默认插件链模式运行 Istio CNI 了。如果你的集群中的组件通过了本人团队的定制,则须要分割这些定制组件的开发团队核实他们所应用的上游版本,并揭示他们降级 Galaxy 组件的版本。

降级到最新版本的 Galaxy 组件之后,再运行相应的验证脚本,能够发现新版本的 Galaxy 已反对包含 0.3.1 在内的多个 cniVersion。

总结

作为风行的服务网格软件,Istio 能够为微服务提供靠近无侵入的弱小流量治理能力和丰盛的观测能力。而 Istio 这些能力都来源于它对来往业务容器的网络流量的齐全捕捉能力。

尽管 Istio 自身提供了多种在指定命名空间装置的个性,但将 Istio 作为一个集群级根底平台能力是泛滥团队的首选。而在一些公开的多租户集群、有非凡安全策略要求等简单的集群环境,装置和经营 Istio 会面临一些独特的挑战。

本文简要介绍了在平安限度严格的集群中,要应用 Istio 流量治理性能所依赖的 IPTABLES 网络策略须要的 Istio CNI 插件的运行原理,以及要在 TKE Stack 集群中运行 Istio CNI 会遇到的问题和解决办法。使用这些办法,能够较好地应用较低的权限运行业务利用的同时,以兼容集群现有网络性能的形式,提供 Istio 的残缺性能。

参考资料

  • Istio CNI 的装置办法
  • Kubernetes CNI 插件规范
  • 在 OpenShift 上打消 Istio Pod 高权限并进步安全性
  • [Linux 上的 Capabilities](https://www.qikqiak.com/post/… “Linux 上的 Capabilities

对于咱们

更多对于云原生的案例和常识,可关注同名【腾讯云原生】公众号~

福利:

①公众号后盾回复【手册】,可取得《腾讯云原生路线图手册》&《腾讯云原生最佳实际》~

②公众号后盾回复【系列】,可取得《15 个系列 100+ 篇超实用云原生原创干货合集》,蕴含 Kubernetes 降本增效、K8s 性能优化实际、最佳实际等系列。

③公众号后盾回复【白皮书】,可取得《腾讯云容器平安白皮书》&《降本之源 - 云原生老本治理白皮书 v1.0》

④公众号后盾回复【光速入门】,可取得腾讯云专家 5 万字精髓教程,光速入门 Prometheus 和 Grafana。

⑤公众号后盾回复【精选集】,可取得腾讯 24 位腾讯云专家精彩演讲——4 万字《腾讯云技术实际精选集 2021》。

【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!

退出移动版