
API网关云原生微服务【免费下载链接】kgatewayThe Cloud-Native API Gateway and AI Gateway项目地址https://gitcode.com/gh_mirrors/kg/kgateway点击查看免费下载本篇指南基于 kgateway 仓库中test/e2e/features/frontendtls/testdata/下的客户端证书体系CLIENT_CERTS_README.md系统讲解 kgateway 双向 TLSmTLS端到端测试所需的 CA 与客户端证书的生成、指纹计算、Kubernetes 资源封装方式以及它们如何被verify-certificate-hash注解、verify-subject-alt-names注解和 Gateway API 的FrontendTLSConfig验证机制消费。读完本文你将掌握一套可复现的 mTLS 测试证书生产流程并理解 kgateway 前端 TLS 验证链路的底层实现。背景为什么需要一套专门的 mTLS 测试证书kgateway 作为云原生 API 网关支持在 HTTPS 监听器上启用双向 TLSmutual TLS认证。在 test/e2e/features/frontendtls/ 目录下的端到端测试套件中验证了多种客户端证书校验机制verify-certificate-hash注解基于客户端证书的 SHA256 指纹做证书钉扎certificate pinning只接受指纹匹配的特定证书FrontendTLSConfig基于 CA 证书链校验客户端证书并通过AllowValidOnly/AllowInsecureFallback两种模式控制客户端证书是必需还是可选verify-subject-alt-names注解校验客户端证书的 SANSubject Alternative Name扩展signature-algorithms注解校验客户端证书所使用的签名算法。这些机制对应的注解与 TLS 选项定义在 api/annotations/gateway.go 中包括kgateway.dev/verify-subject-alt-names、kgateway.dev/verify-certificate-hash、kgateway.dev/signature-algorithms、kgateway.dev/alpn-protocols、kgateway.dev/cipher-suites、kgateway.dev/ecdh-curves、kgateway.dev/min-tls-version与kgateway.dev/max-tls-version。为了让测试能够精确覆盖证书指纹匹配 / 不匹配CA 链有效 / 无效SAN 匹配 / 不匹配签名算法受支持 / 不受支持等正反场景测试仓库维护了多套由不同 CA 签发的客户端证书。证书本身不直接存放原始.crt/.key/.pem文件仓库中仅保留少量用于说明的原始文件如certs/ca1/下的client-8443.crt而是以 base64 编码的 Kubernetes Secret 与 ConfigMap 形态提交并配有一份详细的生成文档。证书目录结构证书按照用途组织在 test/e2e/features/frontendtls/testdata/certs/ 下每个子目录对应一组测试场景目录用途关键资源certs/ca1/CA 证书 1 及其签发的客户端证书ca-cert-configmap.yamlCA 1 ConfigMap、client-cert-secret.yamlFrontendTLSConfig 测试用客户端证书、client-certs-8443-9443-secret.yaml8443/9443 端口用客户端证书certs/ca2/CA 证书 2 及其签发的客户端证书ca-cert-2-configmap.yamlCA 2 ConfigMap位于独立命名空间ca-cert-2、client-cert-2-secret.yaml多 CA 测试用客户端证书certs/ca-alt-names/verify-subject-alt-names 测试的 CA 与客户端证书ca-alt-names-configmap.yaml、client-matching-san-secret.yamlSAN 为DNS:mtls.example.com应通过、client-non-matching-san-secret.yamlSAN 为DNS:mtls-alt.example.com应拒绝certs/ca-sigalgs/signature-algorithms 测试的 CA 与客户端证书ca-sigalgs-configmap.yaml、client-matching-signature-secret.yamlRSASHA256 签名应通过、client-non-matching-signature-secret.yamlECDSASHA256 签名应拒绝关于该目录结构有几点需要注意测试只消费 YAML 清单中的 base64 编码证书。原始证书文件.crt、.key、.pem是证书生成的产物仓库中一般不提交可通过下文证书生成一节的命令重新生成。中间产物不提交。生成过程中产生的.csr证书签名请求和.srl序列号文件属于临时工件同样不进入仓库只有最终封装进 YAML 清单的证书才是必需的。服务端 TLS 证书单独存放。服务端证书tls-rsa-secret.yaml、tls-ecdsa-p256-secret.yaml位于 testdata 根目录与gw.yaml、curl-pod-with-certs.yaml、curl-namespace.yaml负责创建curl命名空间、curl Pod 及其挂载的客户端证书 Secret并列。两类验证机制共享同一套 CA。ca1与ca2的 CA 证书同时支撑两种校验路径verify-certificate-hash校验具体证书的指纹FrontendTLSConfig校验证书链是否由受信 CA 签发。也正因为如此gw.yaml的 8443/9443 监听器可以在同一监听器上同时配置这两个机制。证书生成完整的 openssl 流程以下命令来自关联文档的Certificate Generation章节是当前测试证书体系的可复现生产流程。所有证书均使用 RSA 2048 密钥。Step 1生成 CA 证书与私钥openssl genrsa -out ca-key.pem 2048 openssl req -new -x509 -days 365 -key ca-key.pem -out ca-cert.pem \ -subj /CNTest CA/OTest OrgCA 证书CNTest CA, OTest Org随后以 PEM 格式写入 ConfigMap。参考 ca-cert-configmap.yaml其data.ca.crt字段即该证书文本kgateway 从 ConfigMap 中读取该值作为信任锚。Step 2生成 8443 端口客户端证书openssl genrsa -out client-8443.key 2048 openssl req -new -key client-8443.key -out client-8443.csr \ -subj /CUS/STCalifornia/LSan Francisco/OClient Inc./CNclient.example.com openssl x509 -req -days 3650 -in client-8443.csr -CA ca-cert.pem -CAkey ca-key.pem \ -CAcreateserial -out client-8443.crtStep 3生成 9443 端口客户端证书openssl genrsa -out client-9443.key 2048 openssl req -new -key client-9443.key -out client-9443.csr \ -subj /CUS/STCalifornia/LSan Francisco/OClient Inc./CNclient-alt.example.com openssl x509 -req -days 3650 -in client-9443.csr -CA ca-cert.pem -CAkey ca-key.pem \ -CAcreateserial -out client-9443.crt8443 与 9443 两套证书均被封装进 client-certs-8443-9443-secret.yaml字段为client-8443.crt、client-8443.key、client-9443.crt、client-9443.key。由于两者由同一 CA 签发且证书指纹不同正好用于验证跨监听器交叉使用证书必然失败的负向场景。Step 4生成 FrontendTLSConfig 测试客户端证书8444/8445 端口openssl genrsa -out client-frontend.key 2048 openssl req -new -key client-frontend.key -out client-frontend.csr \ -subj /CNclient.example.com/OTest Org openssl x509 -req -days 3650 -in client-frontend.csr -CA ca-cert.pem -CAkey ca-key.pem \ -CAcreateserial -out client-frontend.crt # Base64 encode and update certs/ca1/client-cert-secret.yaml: base64 -i client-frontend.crt | tr -d \n base64 -i client-frontend.key | tr -d \n生成的证书与私钥分别写入 client-cert-secret.yaml 的data.tls.crt与data.tls.key。该 Secret 的tls.crt/tls.key键名与 Kubernetes 标准的kubernetes.io/tls类型 Secret 一致挂载后可直接作为tls.crt/tls.key文件使用参见下文 curl Pod 挂载路径/etc/client-certs-frontend/tls.crt。Step 5生成第二套 CA多 CA 测试# Generate second CA certificate and key openssl genrsa -out ca2-key.pem 2048 openssl req -new -x509 -days 365 -key ca2-key.pem -out ca2-cert.pem \ -subj /CNTest CA 2/OTest Org # Base64 encode and update certs/ca2/ca-cert-2-configmap.yaml: base64 -i ca2-cert.pem | tr -d \n第二套 CA 的 ConfigMap 比较特殊它所在的命名空间为ca-cert-2见 ca-cert-2-configmap.yaml清单内同时声明了该 Namespace。这意味着在网关配置中引用它时必须显式给出namespace字段参见下文gw.yaml中 8446 端口的caCertificateRefs。Step 6生成由第二套 CA 签发的客户端证书8446 端口# Generate client certificate signed by CA 2 openssl genrsa -out client2-key.pem 2048 openssl req -new -key client2-key.pem -out client2.csr \ -subj /CNclient2.example.com/OTest Org openssl x509 -req -days 3650 -in client2.csr -CA ca2-cert.pem -CAkey ca2-key.pem \ -CAcreateserial -out client2-cert.pem # Base64 encode and update certs/ca2/client-cert-2-secret.yaml: base64 -i client2-cert.pem | tr -d \n base64 -i client2-key.pem | tr -d \n除上述命令外SAN 与签名算法测试的证书还涉及两个额外要点记录在对应 Secret 清单的生成注释中SAN 证书需要在req与x509阶段附加扩展openssl req ... -addext subjectAltName DNS:mtls.example.com并在签发时通过-extfile (echo subjectAltName DNS:mtls.example.com)保留 SAN签名算法测试中匹配证书以 RSA 密钥 SHA256 签名对应rsa_pss_rsae_sha256不匹配证书使用 ECDSA 密钥用于验证签名算法白名单的拒绝行为。SHA256 指纹计算verify-certificate-hash注解要求提供客户端证书的 SHA256 指纹。关联文档给出了从证书文件计算冒号分隔大写指纹的命令# For port 8443 certificate openssl x509 -in client-8443.crt -noout -fingerprint -sha256 | cut -d -f2 | \ tr -d : | awk {for(i1;ilength($0);i2) printf %s:, substr($0,i,2); print } | \ sed s/:$// | tr [:lower:] [:upper:] # For port 9443 certificate openssl x509 -in client-9443.crt -noout -fingerprint -sha256 | cut -d -f2 | \ tr -d : | awk {for(i1;ilength($0);i2) printf %s:, substr($0,i,2); print } | \ sed s/:$// | tr [:lower:] [:upper:]该流程依次执行提取-fingerprint输出的等号后指纹、去掉冒号、按两个字符一组重新插入冒号、去掉尾部冒号并转为大写。已计算好的指纹如下Port 8443 cert59:CF:81:16:72:71:C7:17:23:4E:CE:4F:F9:B9:68:B5:B0:40:2A:00:BB:14:64:E0:42:B9:AD:DA:61:C7:03:F0Port 9443 certE8:44:3B:AA:87:7C:DD:71:31:59:02:77:A4:2F:20:C6:B6:F5:7B:02:29:07:E0:F7:8C:21:DE:41:5B:28:CF:BB注解值的底层解析与校验从源码看kgateway.dev/verify-certificate-hash注解的解析位于 pkg/kgateway/translator/sslutils/ssl_utils.go 的ApplyVerifyCertificateHash函数注解值先经splitFakeYamlArray切分——该函数支持以逗号,或连字符-分隔、允许空白填充的伪 YAML 数组语法因此单个监听器可配置多个允许的证书指纹每个 hash 再经validateCertificateHash校验合法形式是 64 个十六进制字符无分隔或由冒号分隔成 32 对十六进制字符对应正则^[[:xdigit:]]{2}(:[[:xdigit:]]{2}){31}$校验通过后写入 IR 结构ir.TLSConfig.VerifyCertificateHash定义于 pkg/pluginsdk/ir/gw2.go。注解常量本身定义在 api/annotations/gateway.go值可以是 7D:86:...冒号分隔或 7D86...连续 hex等格式且受 Gateway API AnnotationValue 规范约 4096 字符长度限制。TLSExtensionOptionFuncs映射见 ssl_utils.go统一将kgateway.dev/前缀下的 8 个 TLS 扩展选项分发到各自的解析函数并保证未知键报错、拼写错误不静默忽略。证书在测试中的挂载与使用curl Pod 与 Secret 挂载测试通过 curl-pod-with-certs.yaml 创建一个curl命名空间下的 Pod镜像ghcr.io/kgateway-dev/curl:8.20.0以只读方式挂载 7 个 Secret并设置defaultMode: 0444。挂载路径与证书来源的对应关系如下Pod 内路径对应 Secret来源清单用途/etc/client-certs/client-8443.crt/client-8443.keyclient-certsclient-certs-8443-9443-secret.yaml8443 监听器verify-certificate-hash/etc/client-certs/client-9443.crt/client-9443.keyclient-certs同上9443 监听器verify-certificate-hash/etc/client-certs-frontend/tls.crt/tls.keyclient-certclient-cert-secret.yamlCA 1 签发8444/8445 端口 FrontendTLSConfig 测试/etc/client-certs-2-frontend/tls.crt/tls.keyclient-cert-2client-cert-2-secret.yamlCA 2 签发8446 端口多 CA 测试/etc/client-matching-san/tls.crt/tls.keyclient-matching-sanclient-matching-san-secret.yamlSANDNS:mtls.example.comverify-subject-alt-names 正向用例/etc/client-non-matching-san/tls.crt/tls.keyclient-non-matching-sanclient-non-matching-san-secret.yamlSANDNS:mtls-alt.example.comverify-subject-alt-names 负向用例/etc/client-matching-signature/tls.crt/tls.keyclient-matching-signaturecerts/ca-sigalgs/下对应 SecretRSA 签名signature-algorithms 正向用例/etc/client-non-matching-signature/tls.crt/tls.keyclient-non-matching-signaturecerts/ca-sigalgs/下对应 SecretECDSA 签名signature-algorithms 负向用例在 test/e2e/features/frontendtls/suite.go 中prerequisiteManifests()将这些 Secret、CA ConfigMap 与服务端证书清单统一收集由SetupSuite在 curl Pod 调度之前按顺序应用——因为 kubelet 若在 Secret 尚不存在时挂载卷会因失败进入指数退避导致 Pod 卡在ContainerCreating超过基础套件的 60s 就绪超时。TearDownSuite则负责清理这些前置资源遵循框架不删除命名空间的规则ca-cert-2与curl命名空间得以保留。网关配置验证机制如何接线gw.yaml 是理解各机制如何协同的关键。它同时使用了两种配置入口入口一Gateway 的spec.tls.frontendFrontendTLSConfig 风格在spec.tls.frontend下通过default与perPort定义全局与按端口的前端 TLS 校验default.validation.mode: AllowValidOnlycaCertificateRefs: [ca-cert]——默认要求客户端证书且必须由 CA 签发端口 443AllowInsecureFallback——允许无客户端证书用于测试 TLS 选项本身而非证书校验端口 8444AllowInsecureFallback——专门验证客户端证书可选的降级模式端口 8446AllowValidOnly两个caCertificateRefsca-cert与命名空间ca-cert-2下的ca-cert-2——验证多 CA 支持对应 issue #12938客户端证书由任一 CA 签发均可被接受端口 8447AllowValidOnly CAca-alt-names-cert——配合监听器上的verify-subject-alt-names做 SAN 校验端口 8448AllowValidOnly CAca-sigalgs-cert——配合监听器上的signature-algorithms做签名算法校验。其中mode的两个取值语义为AllowValidOnly要求必须提供客户端证书且必须验证通过AllowInsecureFallback在客户端未提供证书时降级放行提供证书时仍会验证。入口二Listener 的tls.options注解在具体监听器的tls.options中配置 kgateway 扩展注解https-mtls8443主机mtls.example.comkgateway.dev/verify-certificate-hash: 59:CF:81:16:72:71:C7:17:23:4E:CE:4F:F9:B9:68:B5:B0:40:2A:00:BB:14:64:E0:42:B9:AD:DA:61:C7:03:F0——该值即 8443 客户端证书的 SHA256 指纹与 FrontendTLSConfig 默认配置AllowInsecureFallback叠加https-mtls-alt9443主机mtls-alt.example.comverify-certificate-hash指向 9443 证书指纹https-verify-subject-alt-names8447kgateway.dev/verify-subject-alt-names: mtls.example.com——客户端证书必须携带该 SANhttps-client-signature-algorithms8448kgateway.dev/signature-algorithms: rsa_pss_rsae_sha256,rsa_pkcs1_sha256——客户端证书签名算法必须命中白名单。注意verify-certificate-hash与 FrontendTLSConfig 可以在同一监听器上并存前者做证书钉扎校验特定证书指纹后者做链校验校验证书链可信性两者是互补关系。此外 api/annotations/gateway.go 明确指出verify-subject-alt-names注解要求先配置受信 CA。对应地gw.yaml为每个 mTLS 监听器都定义了指向httpbin服务的 HTTPRoute如mtls-route关联https-mtls、mtls-alt-route关联https-mtls-alt、frontend-tls-multiple-ca-route使用通配主机*.example.com测试通过 curl 携带--cert/--key发起真实请求来断言结果。测试验证四组用例的行为矩阵测试套件注册了 11 个测试用例见 suite.go其中与客户端证书直接相关的是TestVerifyCertificateHash、TestFrontendTLSConfig、TestMultipleCACertificates、TestVerifySubjectAltNames与TestClientSignatureAlgorithms。verify-certificate-hash 测试TestVerifyCertificateHash对应 suite.go使用 curl 的--cert/--key参数携带证书断言8443 监听器上使用指纹匹配的 8443 证书 → 连接成功8443 监听器上使用 9443 证书指纹不匹配→ 连接失败8443 监听器上不提供客户端证书 → 连接失败mTLS 强制校验9443 监听器上使用 9443 证书 → 成功使用 8443 证书 → 失败不提供证书 → 失败端口间交叉验证常规监听器 443 无需客户端证书即可正常工作——证明 mTLS 仅作用于配置过的监听器。verify-subject-alt-names 测试TestVerifySubjectAltNames对应 suite.go针对 8447 监听器要求 SANmtls.example.com使用client-matching-san.crtSAN 为DNS:mtls.example.com→ 握手成功使用client-non-matching-san.crtSAN 为DNS:mtls-alt.example.com→ 握手被拒断言 curl 错误码 55CURLE_SEND_ERROR。该用例确保缺少必需 SAN 的证书在 mTLS 握手阶段即被正确拒绝。signature-algorithms 测试TestClientSignatureAlgorithms对应 suite.go针对 8448 监听器要求rsa_pss_rsae_sha256使用 RSASHA256 签名的client-matching-signature.crt→ 成功使用 ECDSASHA256 签名的client-non-matching-signature.crt→ 失败错误码 55。该用例保证签名算法白名单之外的证书被拒绝。FrontendTLSConfig 测试TestFrontendTLSConfig对应 suite.go8445AllowValidOnly无客户端证书 → 失败错误码 55SSL 错误8445AllowValidOnly携带 CA 1 签发的有效客户端证书 → 成功8444AllowInsecureFallback无客户端证书 → 成功8444AllowInsecureFallback携带有效证书 → 成功。多 CA 证书测试TestMultipleCACertificates对应 suite.go针对 8446 监听器AllowValidOnly 多 CA 引用 通配域*.example.com访问test.example.com使用 CA 1 签发的证书 → 成功使用 CA 2 签发的证书 → 成功不提供证书 → 失败错误码 55。多 CA 支持的关键结论FrontendTLSConfig 的caCertificateRefs数组支持多个 CA 引用配置多个 CA 后由其中任意一个 CA 签发的客户端证书都会被接受。这在 CA 迁移或需要同时服务多个客户组织不同证书颁发机构的场景下非常实用并且该能力与通配域协同工作——同一通配域模式如*.example.com可以对应多个根 CA 证书。源码实现链路小结把上文内容串起来kgateway 对这几类校验的执行路径是配置读取Gateway 的spec.tls.frontendFrontendTLSConfig与监听器tls.options注解kgateway.dev/前缀分别承载 CA 引用与指纹/SAN/签名算法约束注解常量见 api/annotations/gateway.goIR 翻译ApplyTLSExtensionOptions将选项解析进ir.TLSConfigVerifyCertificateHash、VerifySubjectAltNames等字段定义于 pkg/pluginsdk/ir/gw2.go其中指纹解析与格式校验在 ssl_utils.go 完成XDS 下发与握手执行最终由 Envoy 依据 IR 生成下行 TLS 配置在握手阶段执行证书指纹比对、CA 链校验、SAN 校验与签名算法筛选端到端验证测试套件以 curl Pod 挂载的各类证书驱动真实请求断言成功或失败错误码 35/55形成闭环回归保障。若要在本地复现这套证书体系只需按本文的 openssl 命令依次执行并更新对应 ConfigMap/Secret 的 base64 数据即可若只是运行现有 e2e 测试则仓库中的 YAML 清单已经开箱即用无需自行生成证书。赞分享API网关云原生微服务【免费下载链接】kgatewayThe Cloud-Native API Gateway and AI Gateway项目地址https://gitcode.com/gh_mirrors/kg/kgateway点击查看免费下载相关推荐OWASP MASTG 实战指南iOS 证书固定Certificate Pinning与 mTLS 客户端证书验证测试MSTG-NETWORK-4 / MASVS-NETWORK-2OWASP MASTG 实战指南iOS 证书固定Certificate Pinning与 mTLS 客户端证书验证测试MSTG NETWORK 4 /文档教程网络安全Traefik 双向 TLSmTLS测试证书生成与客户端证书透传实践Traefik 双向 TLSmTLS测试证书生成与客户端证书透传实践 本文以 Traefik 仓库集成测试夹具 integration/fixtures/t后端API网关负载均衡微服务网络云原生GPT-Load监控告警配置终极指南实时掌握AI代理系统健康状态 GPT Load监控告警配置终极指南实时掌握AI代理系统健康状态 GPT Load是一款高性能的企业级AI API透明代理服务专为需要集成多个AI服务后端Web框架创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考