Cilium Gateway API 实战:用 BackendTLSPolicy 为 Gateway 到后端服务的流量启用 TLS
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
本篇基于 Cilium 仓库中的Documentation/network/servicemesh/gateway-api/backendtlspolicy.rst示例文档展开,完整演示如何在 Cilium Gateway 中利用 Gateway API 的BackendTLSPolicy资源,让网关(数据面 Envoy)与后端服务之间建立并验证 TLS 连接。读完本文,你可以掌握:如何用mkcert生成演示证书、如何将证书装入 Kubernetes Secret/ConfigMap、如何把后端echo-server切换为 TLS 模式,以及 Cilium operator 侧是如何校验BackendTLSPolicy并把策略下发到数据面的。
背景:BackendTLSPolicy 解决什么问题
Cilium 的 Gateway API 支持分两段处理 TLS:客户端到 Gateway 的 TLS(由 Gateway Listener 的tls字段处理)与 Gateway 到后端服务的 TLS。BackendTLSPolicy属于后者,它挂在 Gateway 的命名空间中,通过targetRefs指向一个后端 Service,告诉网关"访问该后端时必须使用 TLS 连接,并可以用指定 CA 验证后端证书"。
该示例使用 Gateway API 社区的echo-server演示应用(镜像gcr.io/k8s-staging-gateway-api/echo-basic)。这个应用读取环境变量TLS_SERVER_CERT与TLS_SERVER_PRIVKEY:当两个变量都设置时,它会额外在 8443 端口启动 TLS 监听;且当请求经过 TLS 时,响应 JSON 中会多出一个tls字段,用于验证加密确实生效。整个任务使用自签名 CA,仅用于演示目的,不要直接照搬到生产环境。
第一步:部署 echo-server 与 Gateway/HTTPRoute
示例清单位于 echo-server.yaml 与 echo-server-gatewaypi-httproute.yaml,直接kubectl apply即可。核心内容如下:
Service 与 Deployment(初始为纯 HTTP,3000 端口):
apiVersion: v1 kind: Service metadata: name: backend labels: app: backend service: backend spec: ports: - name: http port: 3000 targetPort: 3000 selector: app: backend --- apiVersion: apps/v1 kind: Deployment metadata: name: backend spec: replicas: 1 selector: matchLabels: app: backend version: v1 template: metadata: labels: app: backend version: v1 spec: serviceAccountName: backend containers: - image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e imagePullPolicy: IfNotPresent name: backend ports: - containerPort: 3000 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespaceGateway 与 HTTPRoute(gatewayClassName: cilium,即由 Cilium 处理该 Gateway):
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: my-gateway spec: gatewayClassName: cilium listeners: - name: http protocol: HTTP port: 80 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: backend spec: parentRefs: - name: my-gateway hostnames: - "www.example.com" rules: - backendRefs: - group: "" kind: Service name: backend port: 3000 weight: 1 matches: - path: type: PathPrefix value: /用 curl 验证基线(把<GATEWAY_IP_ADDRESS>替换为你的 Gateway 地址):
$ curl -v --resolve www.example.com:80:<GATEWAY_IP_ADDRESS> http://www.example.com/get正常应返回请求信息的 JSON,例如:
{ "path": "/get", "host": "www.example.com", "method": "GET", "proto": "HTTP/1.1", "headers": { "Accept": ["*/*"], "User-Agent": ["curl/8.20.0"], "X-Envoy-Internal": ["true"], "X-Forwarded-For": ["172.19.0.1"], "X-Forwarded-Proto": ["http"], "X-Request-Id": ["bb913f3e-7538-4873-88e4-25499fe5b3ff"] }, "namespace": "default", "ingress": "", "service": "", "pod": "backend-86c6c76f-ptczl" }响应中出现了X-Envoy-Internal: true头,说明请求确实经过了 Cilium 内置的 Envoy 数据面。此时尚无tls字段,因为后端走的是明文 HTTP。
第二步:用 mkcert 生成演示证书
需要安装mkcert(上游项目,文档通过github-mkcert链接引用)。它会生成一个本地自签名 CA,并为指定域名签发该 CA 签名的证书。在本地目录执行:
mkcert www.example.com完成后当前目录会生成两个文件:
www.example.com.pem—— 服务端证书;www.example.com-key.pem—— 服务端私钥。
再执行一次mkcert -install(或按 mkcert 提示)可以信任本地 CA;本示例不走系统信任,而是把 CA 通过 ConfigMap 交给 Gateway 做后端校验,因此无需安装到系统。
再次强调:自签名 CA 只用于演示,生产环境应使用正式的证书签发体系(如 cert-manager、云厂商证书服务等)。
第三步:把证书和 CA 装入集群
把服务端证书与私钥存入一个 TLS Secret:
kubectl create secret tls example-cert --key=www.example.com-key.pem --cert=www.example.com.pem把 CA 证书存入 ConfigMap,键名必须是ca.crt:
kubectl create configmap example-ca --from-file=ca.crt=www.example.com.pem键名ca.crt不是可有可无的约定——Cilium operator 的校验逻辑会显式检查这一点。在 operator/pkg/gateway-api/policychecks/backendtlspolicy.go 中可以看到:
- ConfigMap 中不存在
ca.crt键时,策略被标记为拒绝,原因是InvalidCACertificateRef(消息为 "CA Certificate ConfigMap does not contain aca.crtkey"); ca.crt的内容还会经过helpers.IsValidPemFormat校验,不是合法 PEM 编码的证书同样会被拒绝("does not contain at least one valid PEM-encoded certificate")。
此外该校验还要求:CACertificateRefs与wellKnownCACertificates不可同时设置;CACertificateRefs最多只能有一个引用;引用必须是group: ''、kind: ConfigMap,否则会以InvalidKind拒绝(见同文件 ValidateSpec)。这些约束解释了为什么后文的BackendTLSPolicy示例中group为空字符串、kind为ConfigMap。
第四步:把后端切换为 TLS 模式
用kubectl patch给backendDeployment 挂载证书 Secret,并注入两个环境变量:
kubectl patch deployment backend --type=json --patch ' - op: add path: /spec/template/spec/containers/0/volumeMounts value: - name: secret-volume mountPath: /etc/secret-volume - op: add path: /spec/template/spec/volumes value: - name: secret-volume secret: secretName: example-cert items: - key: tls.crt path: crt - key: tls.key path: key - op: add path: /spec/template/spec/containers/0/env/- value: name: TLS_SERVER_CERT value: /etc/secret-volume/crt - op: add path: /spec/template/spec/containers/0/env/- value: name: TLS_SERVER_PRIVKEY value: /etc/secret-volume/key '说明两点:
- Secret 中的
tls.crt/tls.key两个键分别映射为容器内/etc/secret-volume/crt与/etc/secret-volume/key; - 环境变量
TLS_SERVER_CERT与TLS_SERVER_PRIVKEY是echo-basic镜像识别 TLS 模式的开关,设置后应用会在 8443 端口启用 TLS 监听。
然后更新backendService,把端口暴露为 443 并把流量引到后端的 8443:
apiVersion: v1 kind: Service metadata: labels: app: backend service: backend name: backend spec: selector: app: backend ports: - name: https port: 443 protocol: TCP targetPort: 8443注意https这个端口名后面会被BackendTLSPolicy的sectionName引用。
第五步:创建 BackendTLSPolicy 并指向 443
创建策略,告诉 Cilium Gateway 以 TLS 方式访问该后端,并用example-caConfigMap 中的 CA 验证后端证书、期望主机名为www.example.com:
apiVersion: gateway.networking.k8s.io/v1 kind: BackendTLSPolicy metadata: name: enable-backend-tls namespace: default spec: targetRefs: - group: '' kind: Service name: backend sectionName: https validation: caCertificateRefs: - name: example-ca group: '' kind: ConfigMap hostname: www.example.com字段要点:
spec.targetRefs:定位要施加 TLS 的后端,此处是default命名空间的backendService 的https端口(sectionName: https,对应上一步 Service 中的端口名);spec.validation.hostname:期望后端证书的 SNI/主机名,即www.example.com,与mkcert签发时使用的域名一致;spec.validation.caCertificateRefs:验证后端证书所用的 CA,必须是含ca.crt键的 ConfigMap(见第三步源码分析)。
最后,把 HTTPRoute 中后端引用端口从 3000 改为 443,让路由指向新的 TLS 端口:
kubectl patch HTTPRoute backend --type=json --patch ' - op: replace path: /spec/rules/0/backendRefs/0/port value: 443 '验证:curl 观察响应中的 TLS 详情
再次通过 Gateway 访问:
$ curl -vI --resolve "www.example.com:80:<YOUR_GATEWAY_EXTERNAL_IP>" http://www.example.com:80/get应收到200 OK。与最初基线响应的差别在于,现在响应中出现了tls字段:
{ "tls": { "version": "TLSv1.3", "serverName": "www.example.com", "negotiatedProtocol": "http/1.1", "cipherSuite": "TLS_AES_128_GCM_SHA256" } }这证明 Gateway 与后端之间的连接已经升级为 TLS(本例协商出 TLSv1.3 与TLS_AES_128_GCM_SHA256加密套件,SNI 为www.example.com)。而客户端到 Gateway 这一段仍然是第 1 步里配置的 HTTP Listener(80 端口明文),两段连接的安全属性由不同资源分别控制。
深入:Cilium 侧如何处理 BackendTLSPolicy 事件
除了上面的操作步骤,仓库源码还能回答"改动了 CA ConfigMap 之后,集群如何感知并重新下发数据面配置"这个问题。在 operator/pkg/gateway-api/watch-handlers/backendtlspolicy.go 中注册了两类事件处理器:
- EnqueueRequestForBackendTLSPolicy:当某个
BackendTLSPolicy变化时,从targetRefs中收集 Service 引用(updateReconcileRequestsForBackendTLSPolicy会把它们整理为命名空间/服务名),再利用BackendServiceHTTPRouteIndex字段索引反查出所有backendRefs引用了这些 Service 的 HTTPRoute,最终汇总出需要 reconcile 的 Gateway 集合。也就是说:策略 → Service → HTTPRoute → Gateway 这条"反向所有链"是 operator 主动推导的; - EnqueueRequestForBackendTLSPolicyConfigMap:当 ConfigMap(如 CA 证书)变化时,通过
BackendTLSPolicyConfigMapIndex索引查出引用它的 BackendTLSPolicy,再走同样的反查逻辑入队。这意味着你只更新 ConfigMap 里的ca.crt,operator 也会自动重新触发相关 Gateway 的调和,无需手工 patch 策略。
校验层面,调和流程会调用 BackendTLSPolicyInput.ValidateSpec,校验失败时通过setRejectedConditions在status.ancestors上写入Accepted=False与ResolvedRefs=False条件并附具体原因,可用kubectl get backendtlspolicy enable-backend-tls -o yaml观察这些条件来排错(例如忘记在 ConfigMap 中建ca.crt键、PEM 内容损坏、引用了 Secret 而非 ConfigMap 等场景都有明确报错文案)。策略与 Gateway 的关联调和细节另见 operator/pkg/gateway-api/gateway_reconcile.go,相关测试用例覆盖在 operator/pkg/gateway-api/testdata/gateway 目录下(如httproute-backendtlspolicy-reencrypt、httproute-backendtlspolicy-invalid-kind等场景)。
小结
本文按仓库示例文档走通了 Cilium Gateway 后端 TLS 的完整闭环:部署echo-server建立明文基线 →mkcert生成演示证书 → Secret/ConfigMap 入集群(CA 键名必须为ca.crt)→ patch Deployment 启用 8443 端口 TLS 并把 Service 切到 443 → 创建BackendTLSPolicy绑定targetRefs与validation→ 修改 HTTPRoute 端口 → 用 curl 响应中的tls字段确认生效。源码层面的校验与事件反查逻辑说明,Cilium operator 会把 BackendTLSPolicy、CA ConfigMap 的变化自动传导到对应 Gateway 的数据面配置中,配置错误也会以标准 Gateway API 条件形式暴露在资源状态里,便于排查。
【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考