diff --git a/internal/resource/configmap.go b/internal/resource/configmap.go index b05e2d832..710e7f5dd 100644 --- a/internal/resource/configmap.go +++ b/internal/resource/configmap.go @@ -101,6 +101,26 @@ func (builder *ServerConfigMapBuilder) Update(object client.Object) error { return err } + rmqProperties := builder.Instance.Spec.Rabbitmq + authMechsConfigured, err := areAuthMechanismsConfigued(rmqProperties.AdditionalConfig) + if err != nil { + return err + } + // By default, RabbitMQ configures the following SASL mechanisms: + // auth_mechanisms.1 = PLAIN + // auth_mechanisms.2 = AMQPLAIN + // auth_mechanisms.3 = ANONYMOUS + if !authMechsConfigured { + // Since the user didn't explicitly configure auth mechanisms, we disable + // ANONYMOUS logins because they should be disabled in production. + if _, err := defaultSection.NewKey("auth_mechanisms.1", "PLAIN"); err != nil { + return err + } + if _, err := defaultSection.NewKey("auth_mechanisms.2", "AMQPLAIN"); err != nil { + return err + } + } + userConfiguration := ini.Empty() userConfigurationSection := userConfiguration.Section("") @@ -231,7 +251,6 @@ func (builder *ServerConfigMapBuilder) Update(object client.Object) error { rmqConfBuffer.Reset() - rmqProperties := builder.Instance.Spec.Rabbitmq if err := userConfiguration.Append([]byte(rmqProperties.AdditionalConfig)); err != nil { return fmt.Errorf("failed to append spec.rabbitmq.additionalConfig: %w", err) } @@ -307,3 +326,18 @@ func removeHeadroom(memLimit int64) int64 { } return memLimit - memLimit/5 } + +func areAuthMechanismsConfigued(additionalConfig string) (bool, error) { + iniFile, err := ini.Load([]byte(additionalConfig)) + if err != nil { + return false, fmt.Errorf("failed to load spec.rabbitmq.additionalConfig: %w", err) + } + + section := iniFile.Section("") + for _, key := range section.KeyStrings() { + if strings.HasPrefix(key, "auth_mechanisms") { + return true, nil + } + } + return false, nil +} diff --git a/internal/resource/configmap_test.go b/internal/resource/configmap_test.go index fb537f1f1..dffc2edec 100644 --- a/internal/resource/configmap_test.go +++ b/internal/resource/configmap_test.go @@ -36,7 +36,10 @@ cluster_formation.peer_discovery_backend = rabbit_peer_discovery_k8s cluster_formation.k8s.host = kubernetes.default cluster_formation.k8s.address_type = hostname cluster_formation.target_cluster_size_hint = 1 -cluster_name = ` + instanceName) +cluster_name = ` + instanceName + ` +auth_mechanisms.1 = PLAIN +auth_mechanisms.2 = AMQPLAIN +`) } var _ = Describe("GenerateServerConfigMap", func() { @@ -168,6 +171,22 @@ var _ = Describe("GenerateServerConfigMap", func() { Expect(configMapBuilder.Update(configMap)).To(Succeed()) Expect(configMap.Data).To(HaveKeyWithValue("userDefinedConfiguration.conf", expectedConfiguration)) }) + + When("user restricts SSL mechanisms to EXTERNAL", func() { + It("adds only EXTERNAL", func() { + userDefinedConfiguration := "auth_mechanisms.1 = EXTERNAL" + instance.Spec.Rabbitmq.AdditionalConfig = userDefinedConfiguration + expectedConfiguration := iniString(userDefinedConfiguration) + + Expect(configMapBuilder.Update(configMap)).To(Succeed()) + Expect(configMap.Data).To(HaveKeyWithValue("userDefinedConfiguration.conf", expectedConfiguration)) + Expect(configMap.Data).To(HaveKey("operatorDefaults.conf")) + operatorDefaults := configMap.Data["operatorDefaults.conf"] + Expect(operatorDefaults).NotTo(ContainSubstring("auth_mechanisms")) + Expect(operatorDefaults).NotTo(ContainSubstring("PLAIN")) + Expect(operatorDefaults).NotTo(ContainSubstring("ANONYMOUS")) + }) + }) }) When("invalid userDefinedConfiguration is provided", func() {