文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Cilium 如何处理 L7 流量

2024-11-30 12:48

关注

那 Cilium 是如何处理 L7 流量的呢?今天就让我们一探究竟。

注,这篇的内容是基于目前最新的 Cilium 1.13.3 和 proxy 1.23.9,不同版本间会有差异。

在开始之前先搭建先前的“星球大战”环境,或者你也可以直接跳到 Debug 阶段[3]。

环境搭建

集群

export INSTALL_K3S_VERSION=v1.27.1+k3s1
curl -sfL https://get.k3s.io | sh -s - --disable traefik --disable local-storage --disable metrics-server --disable servicelb --flannel-backend=none --write-kubeconfig-mode 644 --write-kubeconfig ~/.kube/config

安装 Cilium

CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/master/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
cilium install

安装示例应用

kubectl apply -n default -f - <

设置策略

kubectl apply -n default -f - <

测试

kubectl exec tiefighter -- curl -s -XPUT deathstar.default.svc.cluster.local/v1/exhaust-port
#Access denied
kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
#Ship landed

查看 pod 信息。

kubectl get po -o wide -n default
NAME                         READY   STATUS    RESTARTS   AGE     IP           NODE          NOMINATED NODE   READINESS GATES
deathstar-7848d6c4d5-58jc8   1/1     Running   0          6h57m   10.0.0.111   ubuntu-dev3              
xwing                        1/1     Running   0          6h57m   10.0.0.209   ubuntu-dev3              
tiefighter                   1/1     Running   0          6h57m   10.0.0.123   ubuntu-dev3              

后面 debug 的操作我们会直接在 cilium 的 agent pod 进行。

agent=$(kubectl get po -l app.kubernetes.io/name=cilium-agent -n kube-system -o jsonpath='{.items[0].metadata.name}')

Debug

先贴上总结的图。

怎么下手呢?

在 深入探索 Cilium 的工作机制[4] 时,我们对 Cilium 的网络策略处理机制一笔带过:

Cilium Agent 中运行着大量的 watcher,其中一个就是 CiliumNetworkPolicy watcher。当策略创建或者更新时,Agent 会对策略进行转换并将规则存储到 BPF Map 中。在网络通信时,BPF 程序会对网络流量进行检查并决定应当允许或者拒绝访问。

实际上这里的处理比较复杂,我们从 watcher 的初始化入手。

至此我们 apply 的网络策略被写入到 map 中。

接下来看下 ebpf 程序有任何使用该策略。

eBPF

还记得在 Kubernetes 网络学习之 Cilium 与 eBPF[15] 中我们分析容器发出的数据包,被 LXC BPF Ingress程序处理。这里不再赘述,处理流程可以看那篇文章。

我们先查看死星的 endpoint id 和 identity 分别为 863 和 2033。

kubectl get ciliumendpoint -n default
NAME                         ENDPOINT ID   IDENTITY ID   INGRESS ENFORCEMENT   EGRESS ENFORCEMENT   VISIBILITY POLICY   ENDPOINT STATE   IPV4         IPV6
tiefighter                   2216          29439                     ready            10.0.0.123
deathstar-7848d6c4d5-58jc8   863           2033                      ready            10.0.0.111
xwing                        775           5513                      ready            10.0.0.209

使用 endpoint id 通过通过命令查看为死星配置的网络策略,可以看到其中的两条 ingress 的策略,其代理端口 19313,这个端口就是 Cilium 中 L7 代理的监听端口。

kubectl exec $agent -n kube-system -c cilium-agent -- cilium bpf policy get 863
POLICY   DIRECTION   LABELS (source:key[=value])                                              PORT/PROTO   PROXY PORT   BYTES   PACKETS
Allow    Ingress     reserved:host                                                            ANY          NONE         0       0
                     reserved:kube-apiserver
Allow    Ingress     k8s:app.kubernetes.io/name=deathstar                                     80/TCP       19313        0       0
                     k8s:class=deathstar
                     k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default
                     k8s:io.cilium.k8s.policy.cluster=default
                     k8s:io.cilium.k8s.policy.serviceaccount=default
                     k8s:io.kubernetes.pod.namespace=default
                     k8s:org=empire
Allow    Ingress     k8s:app.kubernetes.io/name=tiefighter                                    80/TCP       19313        0       0
                     k8s:class=tiefighter
                     k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default
                     k8s:io.cilium.k8s.policy.cluster=default
                     k8s:io.cilium.k8s.policy.serviceaccount=default
                     k8s:io.kubernetes.pod.namespace=default
                     k8s:org=empire
Allow    Egress      reserved:unknown                                                         ANY          NONE         0       0

BPF 程序处理流量在检查策略时 bpf_lxc.c#L1842[16],检查配置的策略带有代理端口执行 POLICY_ACT_PROXY_REDIRECT 将流量重定向给代理(端口 19313,地址为主机地址)。

Cilium Proxy

Cilium agent 提供了 xds server 实现,通过 Unix Domain Socket /var/run/cilium/xds.sock 与 proxy 进行通信,下发配置。

我们参考 cilium-bugtool 的 dump 源码[17],dump 代理的配置。

kubectl exec $agent -n kube-system -c cilium-agent -- curl -s --unix-socket /var/run/cilium/envoy-admin.sock http://admin/config_dump?include_eds

从配置 config.json 中可以看到 Cilium 在 envoy proxy 中实现了如下三个不同类型的过滤器(Filter):

监听器过滤器

监听器过滤器(Listener Filter)`cilium.BpfMetadata`[18] 会从几个数据源中准备元数据:策略、监听器设置、请求方的标识等。数据源包括 xds 配置、BPF map cilium_ipcache、cilium_ct4_global(ct:connection tracking。当然还包括 ct6 相关的 map)。

从数据源中获取的数据保存在 socket option 中(proxy 源码 bpf_metadata.cc#L364[19]),作为上下文元数据的在其他的过滤器中使用。

元数据数据源

xds filter 配置,这里提供了 bpf map 的根目录 /sys/fs/bpf,以及 is_ingress: true 表示当前 filter 是在入口监听器上(ingress listener):

{
 "name": "cilium.bpf_metadata",
 "typed_config": {
  "@type": "type.googleapis.com/cilium.BpfMetadata",
  "bpf_root": "/sys/fs/bpf",
  "is_ingress": true
 }

xds network policy 配置(截取了 proxy 的部分配置),从配置中可以找到 endpoint 的 IP 和 id,以及前面我们设置的 规则[20]:

{
 "@type": "type.googleapis.com/cilium.NetworkPoliciesConfigDump",
 "networkpolicies": [
  {
   "endpoint_ips": [
    "10.0.0.111"
   ],
   "endpoint_id": "863",
   "ingress_per_port_policies": [
    {
     "port": 80,
     "rules": [
      {
       "http_rules": {
        "http_rules": [
         {
          "headers": [
           {
            "name": ":method",
            "safe_regex_match": {
             "google_re2": {},
             "regex": "POST"
            }
           },
           {
            "name": ":path",
            "safe_regex_match": {
             "google_re2": {},
             "regex": "/v1/request-landing"
            }
           }
          ]
         }
        ]
       }
      }
     ]
    }
   ],
   "egress_per_port_policies": [
    {}
   ],
   "conntrack_map_name": "global"
  },
  ...
}

Map cilium_ipcache,可以通过连接信息中的 IP 地址获取身份标识,如死星的 `identity`[21] 为 2033(见 proxy 源码 bpf_metadata.cc#L165[22]):

kubectl exec $agent -n kube-system -c cilium-agent -- cilium bpf ipcache list
IP PREFIX/ADDRESS   IDENTITY
10.0.0.67/32        identity=1 encryptkey=0 tunnelendpoint=0.0.0.0 nodeid=0
10.0.0.111/32       identity=2033 encryptkey=0 tunnelendpoint=0.0.0.0 nodeid=0
10.0.0.123/32       identity=29439 encryptkey=0 tunnelendpoint=0.0.0.0 nodeid=0
10.0.0.243/32       identity=4 encryptkey=0 tunnelendpoint=0.0.0.0 nodeid=0
10.0.0.160/32       identity=19608 encryptkey=0 tunnelendpoint=0.0.0.0 nodeid=0
10.0.0.209/32       identity=5513 encryptkey=0 tunnelendpoint=0.0.0.0 nodeid=0
192.168.1.13/32     identity=1 encryptkey=0 tunnelendpoint=0.0.0.0 nodeid=0
0.0.0.0/0           identity=2 encryptkey=0 tunnelendpoint=0.0.0.0 nodeid=0

Map cilium_ct4_global,从连接跟踪(connection tracking)中获取请求方的 identity(SourceSecurityID 29439,钛战机的标识):

cilium bpf ct list global
TCP OUT 10.0.0.123:48954 -> 10.0.0.111:80 expires=58774 RxPackets=4 RxBytes=435 RxFlagsSeen=0x1b LastRxReport=58764 TxPackets=6 TxBytes=522 TxFlagsSeen=0x1b LastTxReport=58764 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=4 SourceSecurityID=29439 IfIndex=0
TCP IN 10.0.0.67:33988 -> 10.0.0.111:80 expires=58776 RxPackets=6 RxBytes=659 RxFlagsSeen=0x1b LastRxReport=58766 TxPackets=4 TxBytes=386 TxFlagsSeen=0x1b LastTxReport=58766 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=29439 IfIndex=0
TCP IN 10.0.0.123:48954 -> 10.0.0.111:80 expires=80364 RxPackets=6 RxBytes=522 RxFlagsSeen=0x1b LastRxReport=58764 TxPackets=0 TxBytes=0 TxFlagsSeen=0x00 LastTxReport=0 Flags=0x0051 [ RxClosing SeenNonSyn ProxyRedirect ] RevNAT=0 SourceSecurityID=29439 IfIndex=0

过滤器

过滤器(Filter)`cilium.NetworkFilter`[23] 工作在 L4,用于处理已建立的链接,应用端口级的策略,即 L4 策略。

从上下文元数据中保存的 endpoint 相关的策略中查找与目标端口相关的策略,检查请求方证书中的 sni 和请求方的身份标识 identity 是否在白名单中,见 proxy 源码 network_filter.cc#L169[24]。

假如策略上设置了 L7 的协议,会使用 Golang 编写的解析器对 L7 的数据进行解析。

在本示例中并未使用 L4 的策略。

HTTP 过滤器

HTTP 过滤器(HTTP Filter)`cilium.L7Policy`[25] 是本文的重点,但相对其他两个过滤器来说逻辑就简单多了。

"http_filters": [
 {
  "name": "cilium.l7policy",
  "typed_config": {
   "@type": "type.googleapis.com/cilium.L7Policy",
   "access_log_path": "/var/run/cilium/access_log.sock"
  }
 }

在过滤器对 HTTP 请求头进行解码时(见 proxy 源码 l7policy.cc#L97[26]),依然是从上下文元数据中获取策略等内容。拿到策略后,与请求方(对于这里 ingress 的场景检查请求方,如果是 egress 的场景,检查上游的标识)的标识、请求头的信息进行比对,决定放行还是拒绝请求。

总结

整篇看下来,Cilium 在处理 L7 流量上的实现还是比较复杂的,牵扯多个组件协同。eBPF 在 L3/L4 流量处理上有着优异的性能优势,但是对 L7 流量处理仍然无法脱离 sidecar 代理(不论 sidecar 是 per pod 还是 per node)。而 L7 流量处理也恰恰有着非常多的使用场景,不仅仅是 HTTP 协议。

参考资料

[1] 使用 Cilium 增强 Kubernetes 网络安全: https://atbug.com/enhance-kubernetes-network-security-with-cilium/

[2] Envoy Proxy: https://github.com/cilium/proxy

[3] Debug 阶段: #debug

[4] 深入探索 Cilium 的工作机制: https://atbug.com/deep-dive-into-cilium/#网络策略

[5] #enableK8sWatchers: https://github.com/cilium/cilium/blob/f9bdd00c4910bfe3bac3b208fdfbb9452487e776/pkg/k8s/watchers/watcher.go#L525

[6] #ciliumNetworkPoliciesInit: https://github.com/cilium/cilium/blob/f9bdd00c4910bfe3bac3b208fdfbb9452487e776/pkg/k8s/watchers/cilium_network_policy.go#L85

[7] #addCiliumNetworkPolicyV2: https://github.com/cilium/cilium/blob/f9bdd00c4910bfe3bac3b208fdfbb9452487e776/pkg/k8s/watchers/cilium_network_policy.go#L159

[8] #PolicyAdd: https://github.com/cilium/cilium/blob/f9bdd00c4910bfe3bac3b208fdfbb9452487e776/daemon/cmd/policy.go#L224

[9] Daemon: https://atbug.com/deep-dive-into-cilium/#agent

[10] #policyAdd: https://github.com/cilium/cilium/blob/f9bdd00c4910bfe3bac3b208fdfbb9452487e776/daemon/cmd/policy.go#L249

[11] PolicyReactionEvent.Handle: https://github.com/cilium/cilium/blob/f9bdd00c4910bfe3bac3b208fdfbb9452487e776/daemon/cmd/policy.go#L454

[12] EndpointRegenerationEvent#Handle: https://github.com/cilium/cilium/blob/f9bdd00c4910bfe3bac3b208fdfbb9452487e776/pkg/endpoint/events.go#L27

[13] Endpoint.regenerate: https://github.com/cilium/cilium/blob/f9bdd00c4910bfe3bac3b208fdfbb9452487e776/pkg/endpoint/policy.go#L286

[14] Endpoint.regenerateBPF: https://github.com/cilium/cilium/blob/f9bdd00c4910bfe3bac3b208fdfbb9452487e776/pkg/endpoint/bpf.go#L584

[15] Kubernetes 网络学习之 Cilium 与 eBPF: https://atbug.com/learn-cilium-and-ebpf/#第-2-步pod1-lxc-bpf-ingress

[16] bpf_lxc.c#L1842: https://github.com/cilium/cilium/blob/f9bdd00c4910bfe3bac3b208fdfbb9452487e776/bpf/bpf_lxc.c#L1842

[17] dump 源码: https://github.com/cilium/cilium/blob/f9bdd00c4910bfe3bac3b208fdfbb9452487e776/bugtool/cmd/root.go#L505

[18] cilium.BpfMetadata: https://github.com/cilium/proxy/blob/v1.23/cilium/bpf_metadata.cc

[19] bpf_metadata.cc#L364: https://github.com/cilium/proxy/blob/v1.23/cilium/bpf_metadata.cc#L364

[20] 规则: #设置策略

[21] identity: https://atbug.com/deep-dive-into-cilium/#端点-endpoint

[22] bpf_metadata.cc#L165: https://github.com/cilium/proxy/blob/v1.23/cilium/bpf_metadata.cc#L165

[23] cilium.NetworkFilter: https://github.com/cilium/proxy/blob/v1.23/cilium/network_filter.cc

[24] network_filter.cc#L169: https://github.com/cilium/proxy/blob/v1.23/cilium/network_filter.cc#L169

[25] cilium.L7Policy: https://github.com/cilium/proxy/blob/v1.23/cilium/l7policy.cc

[26] l7policy.cc#L97: https://github.com/cilium/proxy/blob/v1.23/cilium/l7policy.cc#L97

来源:云原生指北内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯