From 9ce021d235cc185de1e6ee9d4e97c7994a4037c5 Mon Sep 17 00:00:00 2001 From: Veronika Fisarova Date: Mon, 3 Aug 2026 10:38:19 +0200 Subject: [PATCH] Fernet RNG should not return empty string GenerateFernetKey logged RNG failure then returned "". Callers stored that into the Fernet/credential Secret. Change the API to (string, error). On rand.Read failure, return a wrapped error. ensureFernetKeys propagates it so reconcile fails and retries instead of writing bad secrets. Signed-off-by: Veronika Fisarova --- internal/controller/keystoneapi_controller.go | 33 +++++++++++++++---- internal/keystone/fernet.go | 10 +++--- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/internal/controller/keystoneapi_controller.go b/internal/controller/keystoneapi_controller.go index a0775e02..aeecc35e 100644 --- a/internal/controller/keystoneapi_controller.go +++ b/internal/controller/keystoneapi_controller.go @@ -1742,7 +1742,6 @@ func (r *KeystoneAPIReconciler) ensureFernetKeys( helper *helper.Helper, envVars *map[string]env.Setter, ) error { - logger := r.GetLogger(ctx) fernetAnnotation := labels.GetGroupLabel(keystone.ServiceName) + "/rotatedat" labels := labels.GetLabels(instance, labels.GetGroupLabel(keystone.ServiceName), map[string]string{}) now := time.Now().UTC() @@ -1763,13 +1762,25 @@ func (r *KeystoneAPIReconciler) ensureFernetKeys( if err != nil && !k8s_errors.IsNotFound(err) { return err } else if k8s_errors.IsNotFound(err) { + credentialKeys0, err := keystone.GenerateFernetKey() + if err != nil { + return err + } + credentialKeys1, err := keystone.GenerateFernetKey() + if err != nil { + return err + } fernetKeys := map[string]string{ - "CredentialKeys0": keystone.GenerateFernetKey(logger), - "CredentialKeys1": keystone.GenerateFernetKey(logger), + "CredentialKeys0": credentialKeys0, + "CredentialKeys1": credentialKeys1, } for i := 0; i < numberKeys; i++ { - fernetKeys[fmt.Sprintf("FernetKeys%d", i)] = keystone.GenerateFernetKey(logger) + fernetKey, err := keystone.GenerateFernetKey() + if err != nil { + return err + } + fernetKeys[fmt.Sprintf("FernetKeys%d", i)] = fernetKey } annotations := map[string]string{ @@ -1785,7 +1796,7 @@ func (r *KeystoneAPIReconciler) ensureFernetKeys( Annotations: annotations, }, } - err := oko_secret.EnsureSecrets(ctx, helper, instance, tmpl, envVars) + err = oko_secret.EnsureSecrets(ctx, helper, instance, tmpl, envVars) if err != nil { return err } @@ -1817,7 +1828,11 @@ func (r *KeystoneAPIReconciler) ensureFernetKeys( changedKeys = true } else if rotatedAt.AddDate(0, 0, duration).Before(now) { secret.Data[extraKey] = secret.Data["FernetKeys0"] - secret.Data["FernetKeys0"] = []byte(keystone.GenerateFernetKey(logger)) + fernetKey, err := keystone.GenerateFernetKey() + if err != nil { + return err + } + secret.Data["FernetKeys0"] = []byte(fernetKey) } // @@ -1854,7 +1869,11 @@ func (r *KeystoneAPIReconciler) ensureFernetKeys( } changedKeys = true i := 1 - nextKeyValue := []byte(keystone.GenerateFernetKey(logger)) + fernetKey, err := keystone.GenerateFernetKey() + if err != nil { + return err + } + nextKeyValue := []byte(fernetKey) for { key := fmt.Sprintf("FernetKeys%d", i) i++ diff --git a/internal/keystone/fernet.go b/internal/keystone/fernet.go index 2d670f48..574e9785 100644 --- a/internal/keystone/fernet.go +++ b/internal/keystone/fernet.go @@ -18,18 +18,16 @@ package keystone import ( "crypto/rand" "encoding/base64" - - "github.com/go-logr/logr" + "fmt" ) // GenerateFernetKey - returns a base64-encoded, 32-byte key using cryptographically secure random generation -func GenerateFernetKey(logger logr.Logger) string { +func GenerateFernetKey() (string, error) { data := make([]byte, 32) _, err := rand.Read(data) if err != nil { - logger.Error(err, "failed to read random bytes for Fernet key generation") - return "" + return "", fmt.Errorf("failed to read random bytes for Fernet key generation: %w", err) } - return base64.StdEncoding.EncodeToString(data) + return base64.StdEncoding.EncodeToString(data), nil }