From 3ae04d8a62c8b1536dc84473f0efc7c4307ac836 Mon Sep 17 00:00:00 2001 From: youfak Date: Fri, 7 Aug 2026 21:09:08 +0800 Subject: [PATCH] fix: roll development pods on config changes --- .../overlays/development-mtls/README.md | 4 +++ .../development-mtls/checker-patch.yaml | 3 ++ .../development-mtls/configmap-delete.yaml | 6 ++++ .../development-mtls/controller-patch.yaml | 3 ++ .../development-mtls/gateway-patch.yaml | 3 ++ .../development-mtls/kustomization.yaml | 6 ++-- deploy/kubernetes_overlay_test.go | 29 +++++++++++++++++++ docs/operations/runbook.md | 4 +++ docs/requirements/completion-audit.md | 2 ++ findings.md | 6 ++++ progress.md | 2 ++ 11 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 deploy/kubernetes/overlays/development-mtls/configmap-delete.yaml diff --git a/deploy/kubernetes/overlays/development-mtls/README.md b/deploy/kubernetes/overlays/development-mtls/README.md index d5de0b2..69150f4 100644 --- a/deploy/kubernetes/overlays/development-mtls/README.md +++ b/deploy/kubernetes/overlays/development-mtls/README.md @@ -53,6 +53,10 @@ Overlay 的 Gateway 从 `gateway-a` 证书派生 `worker_id=gateway-a`,Checker `minReplicas=maxReplicas=1`。因此不得在此 Overlay 上增加副本数或放宽 HPA;重复使用 同一证书和 Worker 身份会破坏 session、ownership 和证书角色边界。 +Overlay 的 `proxy-pool-runtime-config` 带内容哈希;修改 `config.yaml` 后,Kustomize 会重写三个 +Deployment 的 ConfigMap volume 引用,从而触发 Kubernetes 滚动更新。控制面 TLS 与 +`proxy-pool-secrets` 使用外部创建的固定名称 Secret,轮换后仍需按运行手册显式滚动对应工作负载。 + 生产环境需要由工作负载身份系统为每个副本签发独立、可轮换的证书,并将该副本的 身份注入 Gateway Client TLS 或 Checker Client TLS,并启用自动身份派生。应用会在每次新 控制面 TLS 握手读取更新后的叶证书和信任根;已有 gRPC 流仍按原会话保留,根轮换时先投放 diff --git a/deploy/kubernetes/overlays/development-mtls/checker-patch.yaml b/deploy/kubernetes/overlays/development-mtls/checker-patch.yaml index 1da5d8a..f02ed84 100644 --- a/deploy/kubernetes/overlays/development-mtls/checker-patch.yaml +++ b/deploy/kubernetes/overlays/development-mtls/checker-patch.yaml @@ -18,6 +18,9 @@ spec: mountPath: /run/proxy-pool-tls/client readOnly: true volumes: + - name: config + configMap: + name: proxy-pool-runtime-config - name: controlplane-checker-tls secret: secretName: proxy-pool-controlplane-checker-tls diff --git a/deploy/kubernetes/overlays/development-mtls/configmap-delete.yaml b/deploy/kubernetes/overlays/development-mtls/configmap-delete.yaml new file mode 100644 index 0000000..2b6626d --- /dev/null +++ b/deploy/kubernetes/overlays/development-mtls/configmap-delete.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: proxy-pool-config + namespace: proxy-pool +$patch: delete diff --git a/deploy/kubernetes/overlays/development-mtls/controller-patch.yaml b/deploy/kubernetes/overlays/development-mtls/controller-patch.yaml index f5987b2..515cfa1 100644 --- a/deploy/kubernetes/overlays/development-mtls/controller-patch.yaml +++ b/deploy/kubernetes/overlays/development-mtls/controller-patch.yaml @@ -14,6 +14,9 @@ spec: mountPath: /run/proxy-pool-tls/server readOnly: true volumes: + - name: config + configMap: + name: proxy-pool-runtime-config - name: controlplane-server-tls secret: secretName: proxy-pool-controlplane-server-tls diff --git a/deploy/kubernetes/overlays/development-mtls/gateway-patch.yaml b/deploy/kubernetes/overlays/development-mtls/gateway-patch.yaml index d19f1ed..9051da6 100644 --- a/deploy/kubernetes/overlays/development-mtls/gateway-patch.yaml +++ b/deploy/kubernetes/overlays/development-mtls/gateway-patch.yaml @@ -19,6 +19,9 @@ spec: mountPath: /run/proxy-pool-tls/client readOnly: true volumes: + - name: config + configMap: + name: proxy-pool-runtime-config - name: controlplane-gateway-tls secret: secretName: proxy-pool-controlplane-gateway-tls diff --git a/deploy/kubernetes/overlays/development-mtls/kustomization.yaml b/deploy/kubernetes/overlays/development-mtls/kustomization.yaml index 327a605..8026270 100644 --- a/deploy/kubernetes/overlays/development-mtls/kustomization.yaml +++ b/deploy/kubernetes/overlays/development-mtls/kustomization.yaml @@ -6,14 +6,12 @@ resources: - controller-service.yaml - checker-networkpolicy.yaml configMapGenerator: - - name: proxy-pool-config + - name: proxy-pool-runtime-config namespace: proxy-pool - behavior: replace files: - config.yaml -generatorOptions: - disableNameSuffixHash: true patches: + - path: configmap-delete.yaml - path: controller-patch.yaml - path: gateway-patch.yaml - path: checker-patch.yaml diff --git a/deploy/kubernetes_overlay_test.go b/deploy/kubernetes_overlay_test.go index 466d0dc..8d515c4 100644 --- a/deploy/kubernetes_overlay_test.go +++ b/deploy/kubernetes_overlay_test.go @@ -1,7 +1,9 @@ package deploy import ( + "os" "os/exec" + "regexp" "strings" "testing" ) @@ -42,3 +44,30 @@ func TestKubernetesDevelopmentMTLSOverlayRendersCertificateDerivedIdentities(t * } } } + +func TestKubernetesDevelopmentMTLSOverlayUsesVersionedConfigMap(t *testing.T) { + payload, err := os.ReadFile("kubernetes/overlays/development-mtls/kustomization.yaml") + if err != nil { + t.Fatalf("read development mTLS kustomization: %v", err) + } + if strings.Contains(string(payload), "disableNameSuffixHash: true") { + t.Fatal("development mTLS overlay disables ConfigMap versioning") + } + kubectl, err := exec.LookPath("kubectl") + if err != nil { + t.Skip("kubectl is required to render the Kubernetes development mTLS overlay") + } + command := exec.Command(kubectl, "kustomize", "kubernetes/overlays/development-mtls") + command.Dir = "." + renderedPayload, err := command.CombinedOutput() + if err != nil { + t.Fatalf("render development mTLS overlay: %v\n%s", err, renderedPayload) + } + matched := regexp.MustCompile(`(?m)^ name: (proxy-pool-runtime-config-[a-z0-9]+)$`).FindStringSubmatch(string(renderedPayload)) + if len(matched) != 2 { + t.Fatalf("rendered overlay has no versioned config map: %s", renderedPayload) + } + if occurrences := strings.Count(string(renderedPayload), "name: "+matched[1]); occurrences != 4 { + t.Fatalf("versioned config map reference count = %d, want config map plus three workload volumes", occurrences) + } +} diff --git a/docs/operations/runbook.md b/docs/operations/runbook.md index 68f4752..da234be 100644 --- a/docs/operations/runbook.md +++ b/docs/operations/runbook.md @@ -113,6 +113,10 @@ Fetch 应表现为 Error 与退避,不应增加 Empty 计数,也不影响已 4. 根据集群 CNI 能力收紧 NetworkPolicy 的外部网段。 5. 在预发布环境完成数据库向前兼容迁移,再发布 Controller。 +环境 Overlay 应保持 ConfigMap 内容哈希,令配置变化进入 Deployment Pod 模板并触发滚动更新。 +由外部系统以固定名称注入的 Secret 不会天然改变 Pod 模板;完成 Secret 轮换后,必须按受影响 +工作负载执行受控滚动,并先验证新旧信任根的重叠窗口。 + ### 3.2 服务端应用顺序 ```bash diff --git a/docs/requirements/completion-audit.md b/docs/requirements/completion-audit.md index 4fba5ff..cd7c7b3 100644 --- a/docs/requirements/completion-audit.md +++ b/docs/requirements/completion-audit.md @@ -106,6 +106,8 @@ CI 已配置 Linux race job。PostgreSQL 18 和 Redis 8.2 的隔离 Adapter fixt mTLS 运行拓扑,并由配置、证书、命令装配和部署契约测试覆盖。Kubernetes base 刻意不直接 启用 Checker;`development-mtls` Overlay 已为单副本 Controller、Gateway 和 Checker 提供固定开发证书、运行时身份派生、mTLS Secret 挂载、最小出站 NetworkPolicy 与渲染/配置契约验证。 +其 ConfigMap 使用内容哈希以在配置变化时触发三个工作负载滚动;固定名称的外部 Secret 仍要求 +受控轮换和显式重启。 Controller、Gateway 与 Checker 的叶证书和信任根已在每个新 TLS 握手时重载,文件短暂 不一致时保留最后一次有效材料。Gateway、Checker 启动派生和 Controller 授权共用同一 SPIFFE URI 解析器:X.509-SVID 叶证书必须且只能包含一个 URI SAN,并精确匹配其角色。 diff --git a/findings.md b/findings.md index 92d6262..fbcb4ad 100644 --- a/findings.md +++ b/findings.md @@ -280,3 +280,9 @@ Routing 自上而下匹配,首条命中停止;支持 Gateway 与 Extract 两 - GitHub Actions 的 Deployment job 在同一组无敏感值 fixture 下渲染生产 Compose、测试 Compose 以及 Kubernetes base/development mTLS Overlay,并对两份配置运行严格校验;它仍不替代 需要镜像网络和真实服务的容器端到端测试。 + +## Kubernetes 配置发布审计(2026-08-07) + +- development mTLS Overlay 的 ConfigMap 采用 Kustomize 内容哈希,渲染契约要求三个工作负载 + 都引用同一版本化名称,因此配置变更进入 Pod 模板并触发滚动。外部固定名称 Secret 不含内容哈希, + 它们的轮换需要平台侧 reloader 或受控显式滚动;这一限制已写入运行手册。 diff --git a/progress.md b/progress.md index d1dcbde..fed352c 100644 --- a/progress.md +++ b/progress.md @@ -2,6 +2,8 @@ ## 2026-08-07 +- Kubernetes 开发 mTLS Overlay 恢复 ConfigMap 内容哈希:配置更新会重写 Controller、Gateway + 和 Checker 的 volume 引用并触发滚动;固定名称 Secret 的轮换仍要求显式受控重启。 - GitHub Actions Deployment job 现同时静态展开生产与测试 Compose,并对本地 Compose 配置和 开发 mTLS 配置执行严格校验,避免仅检查 Kubernetes 覆盖层。 - Docker 构建上下文现由根 `.dockerignore` 保护:本地控制面证书/私钥、环境文件、凭据文件、