十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Dapr 0.11.1 补丁解析:HA 模式下 Sentry 根证书竞态引发 Sidecar 认证失败的根因与修复

Dapr 0.11.1 补丁解析:HA 模式下 Sentry 根证书竞态引发 Sidecar 认证失败的根因与修复 Dapr 0.11.1 补丁解析HA 模式下 Sentry 根证书竞态引发 Sidecar 认证失败的根因与修复【免费下载链接】daprDapr is a portable runtime for building distributed applications across cloud and edge, combining event-driven architecture with workflow orchestration.项目地址: https://gitcode.com/GitHub_Trending/da/daprDapr 0.11.1 是紧随 0.11.0 特性版发布的一个补丁版本其唯一使命是修复一个在高可用HA模式下导致 Dapr 控制平面与 Sidecar 全线不可用的认证回归问题issue #2187。本文以该补丁为核心结合当前仓库中 pkg/sentry 的源码实现与 Helm 图表 配置完整还原问题现象、根因推导、修复思路并给出 HA 模式下信任捆绑Trust Bundle的正确运维与升级姿势。版本定位为什么 0.11.0 之后紧接着发布 0.11.10.11.0 发布说明 引入了一批重量级能力声明式 pub/sub 订阅、基于 SPIFFE 的服务调用访问控制、密钥作用域secrets scoping、跨命名空间服务调用、全新的 Helm chart 仓库迁移至 dapr.github.io/helm-charts等。同时0.11.0 也为 Sentry 工作负载证书加入了强 SPIFFE ID见 v0.11.0.md 中 Dapr Runtime 部分的 Added strong SPIFFE based IDs to sentry workload certificates。正是在这样一次涉及 mTLS 证书体系的大版本迭代中一个回归悄悄溜了进来当集群以 HA 模式部署时Dapr 控制平面服务无法正常工作。0.11.1 作为补丁版本专门回滚了这条回归因此它没有新特性只有一项 Fixes。问题现象HA 模式下一启动就全线崩溃根据 v0.11.1.md 的 Overview 描述该问题表现为在启用 HA高可用模式时Dapr 控制平面服务整体无法工作。需要说明的是HA 模式在当时的 Helm 图表中意味着控制平面各组件operator、placement、sentry、sidecar-injector 等以多副本典型为 3 副本方式运行。当前仓库 charts/dapr/values.yaml 中仍保留了这套语义ha: enabled: false topologyKey: topology.kubernetes.io/zone podAntiAffinityPolicy: preferredDuringSchedulingIgnoredDuringExecution replicaCount: 3 disruption: minimumAvailable: maximumUnavailable: 25%Sentry 的 Deployment 模板 也据此在单副本与 HA 多副本之间切换spec: {{- if eq .Values.global.ha.enabled true }} replicas: {{ .Values.global.ha.replicaCount }} {{- else }} replicas: {{ .Values.replicaCount }} {{- end }}而 charts/dapr/README.md 对 HA 相关参数的说明如下参数说明默认值global.ha.enabled控制平面启用高可用模式falseglobal.ha.replicaCountHA 模式下控制平面服务副本数Placement 固定 3 副本不可配置3global.ha.podAntiAffinityPolicyPod 反亲和调度策略preferredDuringSchedulingIgnoredDuringExecution软或requiredDuringSchedulingIgnoredDuringExecution硬preferredDuringSchedulingIgnoredDuringExecutionglobal.ha.disruption.minimumAvailable控制平面允许的最小可用实例数数字或百分比空global.ha.disruption.maximumUnavailable控制平面允许的最大不可用实例数数字或百分比25%根因分析多个 Sentry 实例竞态创建根证书这是 0.11.1 文档给出的核心结论也是全文最值得深挖的部分。逐条拆解Sentry 是 Dapr 的证书颁发机构CA。Dapr 的 mTLS 体系里Sentry 负责签发根证书、中间证书以及为控制平面组件和 Sidecar 签发工作负载证书基于 SPIFFE 身份。HA 模式下 Sentry 有 3 个副本同时运行。在 0.11.0 的实现中每个 Sentry 实例在启动时如果没有发现已存在的根证书就会各自独立生成一套全新的根证书。竞态窗口3 个实例几乎同时启动、同时判断没有根证书、同时各自生成了一套互不相同的根 CA。直到 Pod 重启并从 Secret 存储中重新加载证书为止每个实例都持有不同的根 CA于是不同 Sentry 实例给控制平面 Pod 和 Sidecar 签发了来自不同信任根的证书对端在校验证书链时无法把对方证书回溯到自己的信任锚点连接被拒绝。结果就是文档所述HA 模式下控制平面服务不可用且表现为启动即失败、重启也难以自愈——因为只要没有正确从共享存储加载每个副本依然持有各自的根。源码印证当前仓库中 Sentry 的加载优先、缺失才生成模型虽然 0.11.1 是 2020 年的补丁但它的修复方向——所有 Sentry 副本共享同一个信任捆绑只有在捆绑缺失时才生成并持久化——在后继版本中被保留并持续强化。当前仓库的 ca.go 可以清楚地看到这一模型的最终形态func New(ctx context.Context, conf config.Config) (Signer, error) { var castore store if conf.Mode modes.KubernetesMode { // 使用 Kubernetes Secret 存储信任捆绑 castore kube{...} } else { // 自托管模式使用本地文件系统 castore selfhosted{config: conf} } bndle, err : castore.get(ctx) if err ! nil { return nil, fmt.Errorf(failed to get CA bundle: %w, err) } var needsWrite bool if bndle.X509 nil { needsWrite true log.Info(Root and issuer certs not found: generating self signed CA) // 生成 Ed25519 根密钥 → bundle.GenerateX509(...) → 自签名 CA } else { log.Info(Root and issuer certs found: using credentials from store) } ... if needsWrite { if err : castore.store(ctx, bndle); err ! nil { ... } } }关键点读取优先启动后第一件事是castore.get()从存储加载信任捆绑kube.go缺失才生成只有bndle.X509 nil时才走bundle.GenerateX509生成自签名 CAbundle.go生成即持久化生成后立即castore.store()写回存储并触发monitoring.IssuerCertChanged()指标。信任捆绑存放在哪里在 Kubernetes 模式下信任捆绑存放在名为dapr-trust-bundle的 Secret 与 ConfigMap 中kube.goconst ( TrustBundleK8sName dapr-trust-bundle )Secret保存私密材料——ca.crt信任锚点、issuer.crt签发证书链、issuer.key签发私钥ConfigMap保存公开的根证书ca.crt供集群内其他组件如 sidecar、operator获取信任锚点。kube.get()会同时读取 Secret 和 ConfigMap并校验两者中的ca.crt是否一致不一致时判定需要重新生成kube.goconfigMap, err : k.client.CoreV1().ConfigMaps(k.namespace).Get(ctx, TrustBundleK8sName, ...) if configMapRootCert, ok : configMap.Data[filepath.Base(k.config.RootCertPath)]; !ok || (hasRootCert configMapRootCert ! string(trustAnchors)) { generateX509 true }kube.store()则把证书与密钥原子地写回 Secret并把公开根证书同步进 ConfigMapkube.go。对应地dapr_sentry_deployment.yaml 中 Sentry Pod 以只读方式挂载该 Secret 作为凭证卷serviceAccountName: dapr-sentry volumes: - name: credentials secret: secretName: dapr-trust-bundle证书如何生成bundle.go 的GenerateX509展示了证书体系的三层结构根证书Root CertgenerateRootCert生成IsCAtrue、KeyUsageCertSignTTL 默认 365 天cert.go签发证书Issuer CertgenerateIssuerCert生成Subject 使用 SPIFFE IDspiffe://trust-domain/ns/namespace/dapr-sentrycert.go工作负载证书Workload CertGenerateWorkloadCert按请求者身份生成携带 SPIFFE URI 与ServerAuth/ClientAuth扩展用途cert.go。签发入口SignIdentity位于 ca.go它为每个请求构造 SPIFFE IDspiffe.FromStrings(td, namespace, appID)然后以 issuer 证书为模板、以根私钥签发。这正是 0.11.1 问题的放大镜这套生成 → 持久化 → 复用的流程只要多个副本在没有共享存储兜底时各自走一遍生成分支就会出现多套根证书并存而一旦共享存储成为常态路径读取优先所有副本必然收敛到同一套证书竞态即被消除。修复方案PR #2185 干了什么v0.11.1.md 明确记录该问题由 PR #2185 修复。结合文档描述与后续源码形态可以还原修复的核心思路消除多实例各自的根证书生成竞态Sentry 启动时优先从共享的 Secret 存储加载已有证书而不是无脑各自生成统一信任锚点让 HA 模式下所有 Sentry 副本、控制平面 Pod 与 Sidecar 都收敛到同一套根 CA 与签发链保证互相校验通过生成结果必须落盘共享即便需要生成如首次部署或证书轮换也必须在 Pod 重启前把证书持久化到共享存储避免重启前各持一套的窗口。从当前仓库的 kube_test.go 测试可以看出Secret 不存在则报错、ConfigMap 不存在则报错、两者内容不一致则触发重新生成这些行为都有对应的单元测试覆盖如 if secret doesnt exist, expect error、if configmap doesnt exist, expect error 等用例说明信任捆绑的一致性校验已成为受测试保障的既定行为。运维视角HA 模式下信任捆绑的正确管理理解了根因之后HA 集群的信任捆绑运维就有章可循了1. 启用 HA 模式当前仓库 charts/dapr/README.md 给出的安装命令helm install dapr dapr/dapr --namespace dapr-system --create-namespace --set global.ha.enabledtrue --waitHA 模式下 Sentry 会以global.ha.replicaCount默认 3个副本运行并通过 PodDisruptionBudget默认maxUnavailable: 25%保护滚动升级期间的可用性。dapr-trust-bundleSecret/ConfigMap 在安装时即由 Helm 模板创建见 dapr_sentry_deployment.yaml 中的 Secret/ConfigMap 定义成为所有副本共享的唯一信任源。2. 备份与轮换信任捆绑信任捆绑属于一旦丢失/不一致就必须整体重建的关键资产。0.11.0 升级指南v0.11.0.md中给出的导出命令至今仍是备份的实用手段dapr mtls export -o ./certs该命令会导出ca.crt、issuer.crt、issuer.key三个文件可用于灾难恢复或跨集群复制。3. 升级时显式指定证书避免重新生成在升级控制平面时0.11.0 指南v0.11.0.md建议把导出的证书通过--set-file显式注入 Helm chart确保新旧控制平面持有同一套信任锚点杜绝升级过程中部分副本持有新根、部分持有旧根的混用helm upgrade dapr dapr/dapr --version 0.11.0 --namespace dapr-system --reset-values \ --set-file dapr_sentry.tls.root.certPEM./certs/ca.crt \ --set-file dapr_sentry.tls.issuer.certPEM./certs/issuer.crt \ --set-file dapr_sentry.tls.issuer.keyPEM./certs/issuer.keySentry 子图表 values 中tls.issuer.certPEM / keyPEM与tls.root.certPEM正是承接这些注入值的入口模板会将其写入dapr-trust-bundleSecret/ConfigMap。4. 升级后验证升级完成后用以下命令确认控制平面各组件均为 Running 且 HEALTHYkubectl get pods -w -n dapr-system dapr status -k随后对 Dapr 应用执行滚动重启以拉取新版本 Sidecarkubectl rollout restart deploy/deployment-name质量保障补强e2e 测试纳入 HA 模式0.11.1 文档还记录了一项配套改进issue #2188 提出除了单 Pod 部署e2e 测试还必须在 HA 模式下运行该 issue 随后由 PR #2189 关闭。这背后是测试基建的务实补课此前 e2e 只覆盖单副本部署天然无法暴露多实例竞态这类只有并发才会触发的问题。把 HA 模式纳入回归矩阵后未来任何涉及 Sentry 证书生成/加载的改动都会被 HA 场景兜住避免同类回归再次漏网。总结Dapr 0.11.1 是一个小补丁、大教训的版本回归源点0.11.0 大版本迭代中HA 模式下多 Sentry 副本各自生成根证书的竞态被引入失效链路多套根 CA → 各副本签发不同证书 → 控制平面与 Sidecar 无法互信 → 连接被拒绝修复本质信任捆绑读取优先、缺失才生成、生成即共享持久化让所有组件收敛到唯一信任锚点PR #2185防复发机制e2e 测试增加 HA 模式覆盖issue #2188 / PR #2189。从当前仓库 pkg/sentry/server/ca 的源码看这一修复方向已被完整继承Kubernetes 模式下 Sentry 通过dapr-trust-bundleSecret/ConfigMap 共享信任捆绑ca.go 以加载 → 校验 → 缺失才生成 → 生成即持久化的流程从机制上杜绝了多副本证书分叉。对于 HA 集群的运维者牢记三条即可启用 HA 时确认共享信任捆绑就位、升级时显式注入证书、升级后滚动重启应用。【免费下载链接】daprDapr is a portable runtime for building distributed applications across cloud and edge, combining event-driven architecture with workflow orchestration.项目地址: https://gitcode.com/GitHub_Trending/da/dapr创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表