diff --git a/bindata/networking-console-plugin/003-deployment.yaml b/bindata/networking-console-plugin/003-deployment.yaml index 777fc4d6ce..b24ffedf14 100644 --- a/bindata/networking-console-plugin/003-deployment.yaml +++ b/bindata/networking-console-plugin/003-deployment.yaml @@ -33,6 +33,7 @@ spec: annotations: target.workload.openshift.io/management: '{"effect": "PreferredDuringScheduling"}' openshift.io/required-scc: restricted-v2 + network.operator.openshift.io/config-hash: "{{.NetworkingConsolePluginConfigHash}}" labels: app.kubernetes.io/component: networking-console-plugin app.kubernetes.io/managed-by: cluster-network-operator diff --git a/pkg/network/render.go b/pkg/network/render.go index 632aa8e3df..610cfc7e7d 100644 --- a/pkg/network/render.go +++ b/pkg/network/render.go @@ -2,6 +2,9 @@ package network import ( "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" "fmt" "log" "net" @@ -823,6 +826,25 @@ func renderNetworkingConsolePlugin(manifestDir string, bootstrapResult *bootstra addTLSInfoToRenderData(data.Data, bootstrapResult, true) + // Calculate hash of the ConfigMap to trigger pod restarts when TLS config changes + h := sha256.New() + configMapPath := filepath.Join(manifestDir, "networking-console-plugin", "002-config-map.yaml") + configMapManifests, err := render.RenderTemplate(configMapPath, &data) + if err != nil { + return nil, fmt.Errorf("failed to render ConfigMap template: %w", err) + } + + for _, m := range configMapManifests { + bytes, err := json.Marshal(m) + if err != nil { + return nil, fmt.Errorf("failed to marshal ConfigMap manifest: %w", err) + } + if _, err := h.Write(bytes); err != nil { + return nil, fmt.Errorf("failed to hash ConfigMap data: %w", err) + } + } + data.Data["NetworkingConsolePluginConfigHash"] = hex.EncodeToString(h.Sum(nil)) + manifests, err := render.RenderDir(filepath.Join(manifestDir, "networking-console-plugin"), &data) if err != nil { return nil, fmt.Errorf("failed to render networking-console-plugin manifests: %w", err) diff --git a/pkg/network/render_test.go b/pkg/network/render_test.go index 0e45ec1b92..b5f9d726c4 100644 --- a/pkg/network/render_test.go +++ b/pkg/network/render_test.go @@ -782,4 +782,41 @@ func Test_renderNetworkingConsolePlugin(t *testing.T) { g.Expect(nginxConf).NotTo(ContainSubstring("ssl_prefer_server_ciphers")) }) }) + + t.Run("config hash annotation should be present in deployment and change when TLS config changes", func(t *testing.T) { + g := NewWithT(t) + t.Setenv("NETWORKING_CONSOLE_PLUGIN_IMAGE", "quay.io/openshift/networking-console-plugin:latest") + bootstrapResult := fakeBootstrapResult() + bootstrapResult.Infra.ConsolePluginCRDExists = true + bootstrapResult.TLSProfile = bootstrap.TLSProfile{ + Spec: configv1.TLSProfileSpec{ + MinTLSVersion: configv1.VersionTLS12, + Ciphers: []string{"ECDHE-RSA-AES128-GCM-SHA256"}, + }, + Adherence: configv1.TLSAdherencePolicyStrictAllComponents, + } + + objs, err := renderNetworkingConsolePlugin(manifestDir, bootstrapResult) + g.Expect(err).NotTo(HaveOccurred()) + + deploy := mustFindRenderedObj[*appsv1.Deployment](t, objs, "Deployment", "networking-console-plugin") + hash1, ok := deploy.Spec.Template.Annotations["network.operator.openshift.io/config-hash"] + g.Expect(ok).To(BeTrue(), "config-hash annotation should be present") + g.Expect(hash1).NotTo(BeEmpty(), "config-hash should not be empty") + + // Render with different TLS config + bootstrapResult.TLSProfile = bootstrap.TLSProfile{ + Spec: configv1.TLSProfileSpec{ + MinTLSVersion: configv1.VersionTLS13, + Ciphers: nil, + }, + Adherence: configv1.TLSAdherencePolicyStrictAllComponents, + } + objs2, err := renderNetworkingConsolePlugin(manifestDir, bootstrapResult) + g.Expect(err).NotTo(HaveOccurred()) + deploy2 := mustFindRenderedObj[*appsv1.Deployment](t, objs2, "Deployment", "networking-console-plugin") + hash2 := deploy2.Spec.Template.Annotations["network.operator.openshift.io/config-hash"] + + g.Expect(hash1).NotTo(Equal(hash2), "config-hash should change when TLS config changes") + }) }