diff --git a/bundle/manifests/runtime-component.clusterserviceversion.yaml b/bundle/manifests/runtime-component.clusterserviceversion.yaml index e75f09e8..dba1871c 100644 --- a/bundle/manifests/runtime-component.clusterserviceversion.yaml +++ b/bundle/manifests/runtime-component.clusterserviceversion.yaml @@ -71,7 +71,7 @@ metadata: categories: Application Runtime certified: "true" containerImage: icr.io/appcafe/runtime-component-operator:daily - createdAt: "2025-12-08T16:01:38Z" + createdAt: "2026-02-06T16:39:18Z" description: Deploys any runtime component with dynamic and auto-tuning configuration features.operators.openshift.io/disconnected: "true" features.operators.openshift.io/fips-compliant: "true" diff --git a/go.mod b/go.mod index 013529a3..1c03cd14 100644 --- a/go.mod +++ b/go.mod @@ -40,6 +40,7 @@ require ( github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/moby/spdystream v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -72,6 +73,7 @@ require ( k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect knative.dev/networking v0.0.0-20250716125000-edb1a4a0c863 // indirect + lukechampine.com/blake3 v1.4.1 sigs.k8s.io/gateway-api v1.1.0 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/go.sum b/go.sum index ca5c8833..7f7dd884 100644 --- a/go.sum +++ b/go.sum @@ -62,6 +62,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -212,6 +214,8 @@ knative.dev/pkg v0.0.0-20250817152444-53ed1d53d232 h1:DqXSNueFZ28EAoU4wrPu8nsFBN knative.dev/pkg v0.0.0-20250817152444-53ed1d53d232/go.mod h1:ZIbXYkQ/A4WeXhPyeZ9OtEuW4RTkpxeYNByJeC0h6Zs= knative.dev/serving v0.46.1 h1:nkbZMcu5r1c+hZhOSW3MIh/7mJp/WLQ4j89PHknDXyU= knative.dev/serving v0.46.1/go.mod h1:NHcCSU65kUFC8rmvxoa+v3HEqWsahTBWsobGvqp3Dd0= +lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= +lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= sigs.k8s.io/controller-runtime v0.19.7 h1:DLABZfMr20A+AwCZOHhcbcu+TqBXnJZaVBri9K3EO48= sigs.k8s.io/controller-runtime v0.19.7/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/gateway-api v1.1.0 h1:DsLDXCi6jR+Xz8/xd0Z1PYl2Pn0TyaFMOPPZIj4inDM= diff --git a/utils/hash.go b/utils/hash.go new file mode 100644 index 00000000..e8b9ed57 --- /dev/null +++ b/utils/hash.go @@ -0,0 +1,35 @@ +package utils + +import ( + "bytes" + "encoding/hex" + "io" + "sort" + + "lukechampine.com/blake3" +) + +func HashData(data map[string][]byte) string { + hasher := blake3.New(32, nil) + io.Copy(hasher, bytes.NewReader(serializeSecretData(data))) + hash := hasher.Sum(nil) + return hex.EncodeToString(hash) +} + +func serializeSecretData(data map[string][]byte) []byte { + // sort data keys + dataKeys := []string{} + for k := range data { + dataKeys = append(dataKeys, k) + } + sort.Strings(dataKeys) + // load dataBuffer delimited by a null character for every key-value pair \0\0 + dataBuffer := []byte{} + for _, k := range dataKeys { + dataBuffer = append(dataBuffer, []byte(k)...) + dataBuffer = append(dataBuffer, '\000') + dataBuffer = append(dataBuffer, data[k]...) + dataBuffer = append(dataBuffer, '\000') + } + return dataBuffer +} diff --git a/utils/hash_test.go b/utils/hash_test.go new file mode 100644 index 00000000..a3f63263 --- /dev/null +++ b/utils/hash_test.go @@ -0,0 +1,22 @@ +package utils + +import ( + "testing" + + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" +) + +func TestHashData(t *testing.T) { + logger := zap.New() + logf.SetLogger(logger) + + data := map[string][]byte{} + data["xyz"] = []byte("contentforxyz") + data["abc"] = []byte("1Ag@aZ821Sd1asd1231nkgrniekghis168adf") + testGHFD := []Test{ + {"Serialize sample data", []byte("abc\0001Ag@aZ821Sd1asd1231nkgrniekghis168adf\000xyz\000contentforxyz\000"), serializeSecretData(data)}, + {"Get hash from serialized data", "2d0b4d0adc4124bdfb959cb8b584473b5392cf2287b69a11663b288c90cfa010", HashData(data)}, + } + verifyTests(testGHFD, t) +} diff --git a/utils/utils.go b/utils/utils.go index 3d016372..1e3b9d5b 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1752,27 +1752,28 @@ func AddOCPCertAnnotation(ba common.BaseComponent, svc *corev1.Service) { } func CustomizePodWithSVCCertificate(pts *corev1.PodTemplateSpec, ba common.BaseComponent, client client.Client) error { - if ba.GetManageTLS() == nil || *ba.GetManageTLS() || ba.GetService().GetCertificateSecretRef() != nil { obj := ba.(metav1.Object) secretName := ba.GetStatus().GetReferences()[common.StatusReferenceCertSecretName] if secretName != "" { - return addSecretResourceVersionAsEnvVar(pts, obj, client, secretName, "SERVICE_CERT") + return addSecretHashAsAnnotation(pts, obj, client, secretName, ba.GetGroupName()) } else { return errors.New("Service certifcate secret name must not be empty") } } return nil } -func addSecretResourceVersionAsEnvVar(pts *corev1.PodTemplateSpec, object metav1.Object, client client.Client, secretName string, envNamePrefix string) error { + +func addSecretHashAsAnnotation(pts *corev1.PodTemplateSpec, object metav1.Object, client client.Client, secretName string, groupName string) error { secret := &corev1.Secret{} err := client.Get(context.Background(), types.NamespacedName{Name: secretName, Namespace: object.GetNamespace()}, secret) if err != nil { return fmt.Errorf("Secret %q was not found in namespace %q, %w", secretName, object.GetNamespace(), err) } - pts.Spec.Containers[0].Env = append(pts.Spec.Containers[0].Env, corev1.EnvVar{ - Name: envNamePrefix + "_SECRET_RESOURCE_VERSION", - Value: secret.ResourceVersion}) + if pts.ObjectMeta.Annotations == nil { + pts.ObjectMeta.Annotations = make(map[string]string) + } + pts.ObjectMeta.Annotations[groupName+"/secret-"+secretName] = HashData(secret.Data) return nil } @@ -1856,7 +1857,7 @@ func GetIssuerResourceVersion(client client.Client, certificate *certmanagerv1.C if err != nil { return "", err } else { - return issuer.ResourceVersion + "," + caSecret.ResourceVersion, nil + return issuer.ResourceVersion + "," + HashData(caSecret.Data), nil } } else { return issuer.ResourceVersion, nil