在上篇文章中,我们在阿里云环境安装了 k8s 以及 cilium,这里我们将跟随 cilium 官方上的一个 Demo 示例,来实际体验 cilium。
 环境说明
在这个例子中,将启动三个微服务程序:
- deathstar:在 80 端口上运行一个 HTTP 微服务,该服务通过 
k8s service 的形式暴露,从而可以将请求负载分担到上游的两个 Pod 中。从业务角度上来讲,该服务提供提供了 landing 接口,允许整个 empire 的飞船进行 着陆 
- tiefighter:代表一个客户端服务,它会发出一个 
empire ship 的 着陆 请求 
- xwing:也代表一个类似的客户端服务,但是发出的是 
alliance ship 的 着陆 请求 
使用如下命令下载我们的 k8s 配置文件,该 http-sw-app.yaml 文件定义了上述 service 以及 Pod:
1
   | wget https://raw.githubusercontent.com/cilium/cilium/1.14.4/examples/minikube/http-sw-app.yaml
   | 
 
根据该配置文件,创建应用:
1 2 3 4 5
   |  service/deathstar created deployment.apps/deathstar created pod/tiefighter created pod/xwing created
 
  | 
 
之后 kubectl 会在后台部署服务、创建对应的 Pod,使用如下命令确认所有 Service、Pod 都处于 Running 状态:
1 2 3 4 5 6 7 8 9 10
   |  NAME                            READY   STATUS    RESTARTS   AGE pod/deathstar-f449b9b55-klltm   1/1     Running   0          14m pod/deathstar-f449b9b55-psh9w   1/1     Running   0          14m pod/tiefighter                  1/1     Running   0          14m pod/xwing                       1/1     Running   0          14m
  NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE service/deathstar    ClusterIP   10.111.234.48   <none>        80/TCP    14m service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   14h
 
  | 
 
每个 Pod 在 cilium 中都会表示为 cilium agent 中的一个 endpoint,可以通过如下命令查看所有的 cilium agent,然后选择某个 cilium agent 查看其中的 endpoint:
1 2 3 4 5 6 7 8
   |  NAME           READY   STATUS    RESTARTS   AGE cilium-9sxk7   1/1     Running   0          14h cilium-fmst8   1/1     Running   0          14h cilium-xjtb8   1/1     Running   0          14h
 
  ......
 
  | 
 
 检查当前连通性
由于当前没有配置任何网络策略,所以 xwing 和 tiefighter 发出的 着陆 请求都可以被响应:
1 2 3 4 5
   |  Ship landed
 
  Ship landed
 
  | 
 
其实这个并不符合业务预期,因为我们只希望 org=empire 的 ship 才能 着陆。后面我们会通过网络策略来解决这个问题。
 应用 L3/L4 policy
在 Cilium 中,endpoint 的 IP 其实对安全策略是无关紧要的,因为 Cilium 会使用 Pod 的标签来定义安全策略,所以只要 Pod 的标签能够匹配安全规则,这些规则就会对这些 Pod 生效,而不管这些 Pod 的 IP 是什么。
如下定义了一条网络策略,只允许拥有 org=empire 标签的 endpoint 才能访问 deathstar(org=empire, class=deathstar)的 80 端口,由于该策略是在 IP 层和 TCP 层生效,因此通常称为 L3/L4 网络安全策略。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | apiVersion: "cilium.io/v2" kind: CiliumNetworkPolicy metadata:   name: "rule1" spec:   description: "L3-L4 policy to restrict deathstar access to empire ships only"   endpointSelector:     matchLabels:       org: empire       class: deathstar   ingress:   - fromEndpoints:     - matchLabels:         org: empire     toPorts:     - ports:       - port: "80"         protocol: TCP
 
   | 
 
应用如下策略:
1 2
   |  ciliumnetworkpolicy.cilium.io/rule1 created
 
  | 
 
此时再次发送请求,可以看到拥有 org=empire 标签 的 tiefighter 可以访问 deathstar 的 着陆 服务,
而 xwing 访问则一直卡主:
1
   | kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
   | 
 
再次查看 cilium endpoint 的网络策略,可以看到 ingress enabled:
1 2
   |  437        Enabled            Disabled          12079      k8s:app.kubernetes.io/name=deathstar
 
  | 
 
也可以这样确认:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
   |  NAME    AGE rule1   5m53s
 
  Name:         rule1 Namespace:    default Labels:       <none> Annotations:  <none> API Version:  cilium.io/v2 Kind:         CiliumNetworkPolicy Metadata:   Creation Timestamp:  2023-11-30T04:13:23Z   Generation:          1   Resource Version:    110474   UID:                 4737ae78-a155-401c-8aa1-893f215b5f5a Spec:   Description:  L3-L4 policy to restrict deathstar access to empire ships only   Endpoint Selector:     Match Labels:       Class:  deathstar       Org:    empire   Ingress:     From Endpoints:       Match Labels:         Org:  empire     To Ports:       Ports:         Port:      80         Protocol:  TCP Events:            <none>
 
  | 
 
 能够感知 HTTP 协议的 L7 Policy
对于简单的场景,的确能够控制 tiefighter/xwing 的访问权限,但是如果想实现最小安全原则,例如 tiefighter 虽然能够访问  deathstar 的 landing 接口,但是不能访问其 maintenance API。对于该需求,L3/L4 网络策略就无能为力了,因为这涉及 HTTP 协议内容,需要 L7 policy。
Cilium 支持使用 HTTP 层的 L7 policy 来限制 tiefighter 能够访问的 API 接口,如下是一个示例,它只允许 tiefighter 访问 deathstar 的 POST /v1/request-landing API,而其他 API 都无法访问:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | apiVersion: "cilium.io/v2" kind: CiliumNetworkPolicy metadata:   name: "rule1" spec:   description: "L7 policy to restrict access to specific HTTP call"   endpointSelector:     matchLabels:       org: empire       class: deathstar   ingress:   - fromEndpoints:     - matchLabels:         org: empire     toPorts:     - ports:       - port: "80"         protocol: TCP       rules:         http:         - method: "POST"           path: "/v1/request-landing"
   | 
 
应用该规则:
1
   | kubectl apply -f sw_l3_l4_l7_policy.yaml
   | 
 
之后再次访问,可以看到 tiefighter 只能访问 request-landing API,而其他 API 则无法访问:
1 2 3 4 5
   |  Ship landed
 
  Access denied
 
  | 
 
而 xwing 仍然无法访问,一直卡主:
1
   | kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
   | 
 
可以通过如下方式查看 L7 policy:
1
   | kubectl describe ciliumnetworkpolicies
   | 
 
或者
1
   | kubectl -n kube-system exec cilium-9sxk7 -- cilium policy get
   | 
 
可以通过 cilium monitor 实时监控流量:
1
   | kubectl -n kube-system exec cilium-9sxk7 -- cilium monitor
   | 
 
如下方式只监控 http 请求:
1 2 3 4 5 6
   |  Defaulted container "cilium-agent" out of: cilium-agent, config (init), mount-cgroup (init), apply-sysctl-overwrites (init), mount-bpf-fs (init), clean-cilium-state (init), install-cni-binaries (init) Listening for events on 4 CPUs with 64x4096 of shared memory Press Ctrl-C to quit <- Request http from 854 ([k8s:app.kubernetes.io/name=tiefighter k8s:class=tiefighter k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default k8s:io.cilium.k8s.policy.cluster=kubernetes k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.kubernetes.pod.namespace=default k8s:org=empire]) to 437 ([k8s:org=empire k8s:app.kubernetes.io/name=deathstar k8s:class=deathstar k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default k8s:io.cilium.k8s.policy.cluster=kubernetes k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.kubernetes.pod.namespace=default]), identity 1110->12079, verdict Forwarded POST http://deathstar.default.svc.cluster.local/v1/request-landing => 0 <- Response http to 854 ([k8s:app.kubernetes.io/name=tiefighter k8s:class=tiefighter k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default k8s:io.cilium.k8s.policy.cluster=kubernetes k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.kubernetes.pod.namespace=default k8s:org=empire]) from 437 ([k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.kubernetes.pod.namespace=default k8s:org=empire k8s:app.kubernetes.io/name=deathstar k8s:class=deathstar k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default k8s:io.cilium.k8s.policy.cluster=kubernetes]), identity 12079->1110, verdict Forwarded POST http://deathstar.default.svc.cluster.local/v1/request-landing => 200
 
  | 
 
 清理环境
以上就完成了 cilium demo 的体验,如果需要清理环境,可以执行如下命令:
1 2
   | $ kubectl delete -f http-sw-app.yaml $ kubectl delete cnp rule1
   | 
 
 Reference