在上篇文章中,我们在阿里云环境安装了 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