From 94adba15c6379e090533f733d3cb95fde6f2b16d Mon Sep 17 00:00:00 2001 From: Brendan Shephard Date: Thu, 3 Oct 2024 10:45:06 +1000 Subject: [PATCH 1/3] Validate AuthEncryptionKey length If a user provides a AuthEncryptionKey less than 32 characters, the Heat service will fail to start and pods will CrashLoopBackOff. This change validates the length of the provided value to ensure we can return an error early rather than waiting until the service is trying to initialize. Jira: https://issues.redhat.com/browse/OSPRH-10507 Signed-off-by: Brendan Shephard --- controllers/heat_controller.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/controllers/heat_controller.go b/controllers/heat_controller.go index 58898658..e3a87271 100644 --- a/controllers/heat_controller.go +++ b/controllers/heat_controller.go @@ -952,7 +952,10 @@ func (r *HeatReconciler) generateServiceSecrets( return err } password := strings.TrimSuffix(string(ospSecret.Data[instance.Spec.PasswordSelectors.Service]), "\n") - authEncryptionKey := strings.TrimSuffix(string(ospSecret.Data[instance.Spec.PasswordSelectors.AuthEncryptionKey]), "\n") + authEncryptionKey, err := validateAuthEncryptionKey(instance, ospSecret) + if err != nil { + return err + } transportURLSecret, _, err := oko_secret.GetSecret(ctx, h, instance.Status.TransportURLSecret, instance.Namespace) if err != nil { @@ -1347,3 +1350,18 @@ func renderVhost(instance *heatv1beta1.Heat, endpt service.Endpoint, serviceName return httpdVhostConfig } + +// validateAuthEncryptionKey - the heat_auth_encrption_key needs to be 32 characters long. This function validates +// the length of the user provided key and returns an error if it isn't long enough. +func validateAuthEncryptionKey(instance *heatv1beta1.Heat, ospSecret *corev1.Secret) (string, error) { + const HeatAuthEncKeyLen int = 32 + + heatAuthEncKey := strings.TrimSuffix(string(ospSecret.Data[instance.Spec.PasswordSelectors.AuthEncryptionKey]), "\n") + + if len(heatAuthEncKey) < HeatAuthEncKeyLen { + return "", fmt.Errorf("AuthEncryptionKey must be at least %d characters", HeatAuthEncKeyLen) + } + + return heatAuthEncKey, nil + +} From df97dc57b8dc86b53d3ec7c40732d081e8109473 Mon Sep 17 00:00:00 2001 From: Brendan Shephard Date: Thu, 3 Oct 2024 11:07:26 +1000 Subject: [PATCH 2/3] Adjust tests for HeatAuthEncryptionKey length This change adjusts the tests for the HeatAuthEncryptionKey length validation. It also changes the name of the Key in the map to reflect documented recommendations. Jira: https://issues.redhat.com/browse/OSPRH-10508 Signed-off-by: Brendan Shephard --- tests/functional/base_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/functional/base_test.go b/tests/functional/base_test.go index 859db43b..311efd9c 100644 --- a/tests/functional/base_test.go +++ b/tests/functional/base_test.go @@ -34,6 +34,9 @@ func GetDefaultHeatSpec() map[string]interface{} { "heatEngine": GetDefaultHeatEngineSpec(), "heatAPI": GetDefaultHeatAPISpec(), "heatCfnAPI": GetDefaultHeatCFNAPISpec(), + "passwordSelectors": map[string]interface{}{ + "AuthEncryptionKey": "HeatAuthEncryptionKey", + }, } } @@ -75,8 +78,8 @@ func CreateHeatSecret(namespace string, name string) *corev1.Secret { return th.CreateSecret( types.NamespacedName{Namespace: namespace, Name: name}, map[string][]byte{ - "HeatPassword": []byte("12345678"), - "AuthEncryptionKey": []byte("1234567812345678123456781212345678345678"), + "HeatPassword": []byte("12345678"), + "HeatAuthEncryptionKey": []byte("1234567812345678123456781212345678345678"), }, ) } From e48838a6830da122492e25bb899bc7d84253b72c Mon Sep 17 00:00:00 2001 From: Brendan Shephard Date: Thu, 3 Oct 2024 13:57:27 +1000 Subject: [PATCH 3/3] Add test for invalid AuthEncryptionKey length Jira: https://issues.redhat.com/browse/OSPRH-10509 Signed-off-by: Brendan Shephard --- tests/functional/heat_controller_test.go | 55 ++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/functional/heat_controller_test.go b/tests/functional/heat_controller_test.go index cf745924..e77da21c 100644 --- a/tests/functional/heat_controller_test.go +++ b/tests/functional/heat_controller_test.go @@ -644,4 +644,59 @@ var _ = Describe("Heat controller", func() { return GetEnvVarValue(deployment.Spec.Template.Spec.Containers[0].Env, "CONFIG_HASH", "") })*/ + When("HeatAuthEncryptionKey is too short", func() { + + BeforeEach(func() { + DeferCleanup(th.DeleteInstance, CreateHeat(heatName, GetDefaultHeatSpec())) + DeferCleanup( + k8sClient.Delete, ctx, CreateHeatSecret(namespace, SecretName)) + DeferCleanup(infra.DeleteMemcached, infra.CreateMemcached(namespace, "memcached", memcachedSpec)) + infra.SimulateMemcachedReady(types.NamespacedName{ + Name: "memcached", + Namespace: namespace, + }) + DeferCleanup( + k8sClient.Delete, ctx, CreateHeatMessageBusSecret(namespace, HeatMessageBusSecretName)) + infra.SimulateTransportURLReady(heatTransportURLName) + keystoneAPI := keystone.CreateKeystoneAPI(namespace) + DeferCleanup(keystone.DeleteKeystoneAPI, keystoneAPI) + DeferCleanup( + mariadb.DeleteDBService, + mariadb.CreateDBService( + namespace, + GetHeat(heatName).Spec.DatabaseInstance, + corev1.ServiceSpec{ + Ports: []corev1.ServicePort{{Port: 3306}}, + }, + ), + ) + mariadb.SimulateMariaDBAccountCompleted(types.NamespacedName{Namespace: namespace, Name: GetHeat(heatName).Spec.DatabaseAccount}) + mariadb.SimulateMariaDBDatabaseCompleted(types.NamespacedName{Namespace: namespace, Name: heat.DatabaseCRName}) + dbSyncJobName := types.NamespacedName{ + Name: "heat-db-sync", + Namespace: namespace, + } + th.SimulateJobSuccess(dbSyncJobName) + + }) + + It("Should complain about the Key length", func() { + Eventually(func(g Gomega) { + heat := GetHeat(heatName) + heat.Spec.PasswordSelectors.AuthEncryptionKey = "TooShortAuthEncKey" + g.Expect(th.K8sClient.Update(ctx, heat)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + + th.ExpectCondition( + heatName, + ConditionGetterFunc(HeatConditionGetter), + condition.ServiceConfigReadyCondition, + corev1.ConditionFalse, + ) + + conditions := HeatConditionGetter(heatName) + message := &conditions.Get(condition.ServiceConfigReadyCondition).Message + Expect(*message).Should(ContainSubstring("AuthEncryptionKey must be at least 32 characters")) + }) + }) })