diff --git a/api/common_types.go b/api/common_types.go index ae4f5aa6a..a1cc66db5 100644 --- a/api/common_types.go +++ b/api/common_types.go @@ -8,14 +8,14 @@ import ( // KubernetesConfig will be the JSON struct for Basic Redis Config // +k8s:deepcopy-gen=true type KubernetesConfig struct { - Image string `json:"image"` - ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` - Resources *corev1.ResourceRequirements `json:"resources,omitempty"` - ExistingPasswordSecret *ExistingPasswordSecret `json:"redisSecret,omitempty"` - ImagePullSecrets *[]corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` - UpdateStrategy appsv1.StatefulSetUpdateStrategy `json:"updateStrategy,omitempty"` - Service *ServiceConfig `json:"service,omitempty"` - IgnoreAnnotations []string `json:"ignoreAnnotations,omitempty"` + Image string `json:"image"` + ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` + Resources *corev1.ResourceRequirements `json:"resources,omitempty"` + ExistingAuthSecret *ExistingAuthSecret `json:"redisSecret,omitempty"` + ImagePullSecrets *[]corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` + UpdateStrategy appsv1.StatefulSetUpdateStrategy `json:"updateStrategy,omitempty"` + Service *ServiceConfig `json:"service,omitempty"` + IgnoreAnnotations []string `json:"ignoreAnnotations,omitempty"` } // ServiceConfig define the type of service to be created and its annotations @@ -26,11 +26,12 @@ type ServiceConfig struct { ServiceAnnotations map[string]string `json:"annotations,omitempty"` } -// ExistingPasswordSecret is the struct to access the existing secret +// ExistingAuthSecret is the struct to access the existing secret // +k8s:deepcopy-gen=true -type ExistingPasswordSecret struct { - Name *string `json:"name,omitempty"` - Key *string `json:"key,omitempty"` +type ExistingAuthSecret struct { + Name *string `json:"name,omitempty"` + UsernameKey *string `json:"username,omitempty"` + PasswordKey *string `json:"password,omitempty"` } // RedisExporter interface will have the information for redis exporter related stuff diff --git a/api/v1beta2/common_types.go b/api/v1beta2/common_types.go index 76a3adcd0..9f564bad5 100644 --- a/api/v1beta2/common_types.go +++ b/api/v1beta2/common_types.go @@ -38,10 +38,11 @@ type RedisConfig struct { common.RedisConfig `json:",inline"` } -// ExistingPasswordSecret is the struct to access the existing secret -type ExistingPasswordSecret struct { - Name *string `json:"name,omitempty"` - Key *string `json:"key,omitempty"` +// ExistingAuthSecret is the struct to access the existing secret +type ExistingAuthSecret struct { + Name *string `json:"name,omitempty"` + UsernameKey *string `json:"username,omitempty"` + PasswordKey *string `json:"password,omitempty"` } // Storage is the inteface to add pvc and pv support in redis @@ -71,7 +72,7 @@ type ACLConfig struct { Secret *corev1.SecretVolumeSource `json:"secret,omitempty"` } -// Probe is a interface for ReadinessProbe and LivenessProbe +// Probe is an interface for ReadinessProbe and LivenessProbe type Probe struct { common.Probe `json:",inline"` } diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index 6fc14b16b..0b6da6647 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -65,26 +65,31 @@ func (in *ClusterStorage) DeepCopy() *ClusterStorage { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExistingPasswordSecret) DeepCopyInto(out *ExistingPasswordSecret) { +func (in *ExistingAuthSecret) DeepCopyInto(out *ExistingAuthSecret) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name *out = new(string) **out = **in } - if in.Key != nil { - in, out := &in.Key, &out.Key + if in.UsernameKey != nil { + in, out := &in.UsernameKey, &out.UsernameKey + *out = new(string) + **out = **in + } + if in.PasswordKey != nil { + in, out := &in.PasswordKey, &out.PasswordKey *out = new(string) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExistingPasswordSecret. -func (in *ExistingPasswordSecret) DeepCopy() *ExistingPasswordSecret { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExistingAuthSecret. +func (in *ExistingAuthSecret) DeepCopy() *ExistingAuthSecret { if in == nil { return nil } - out := new(ExistingPasswordSecret) + out := new(ExistingAuthSecret) in.DeepCopyInto(out) return out } diff --git a/api/zz_generated.deepcopy.go b/api/zz_generated.deepcopy.go index 975b24a1b..fd1070838 100644 --- a/api/zz_generated.deepcopy.go +++ b/api/zz_generated.deepcopy.go @@ -55,26 +55,31 @@ func (in *AdditionalVolume) DeepCopy() *AdditionalVolume { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExistingPasswordSecret) DeepCopyInto(out *ExistingPasswordSecret) { +func (in *ExistingAuthSecret) DeepCopyInto(out *ExistingAuthSecret) { *out = *in if in.Name != nil { in, out := &in.Name, &out.Name *out = new(string) **out = **in } - if in.Key != nil { - in, out := &in.Key, &out.Key + if in.UsernameKey != nil { + in, out := &in.UsernameKey, &out.UsernameKey + *out = new(string) + **out = **in + } + if in.PasswordKey != nil { + in, out := &in.PasswordKey, &out.PasswordKey *out = new(string) **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExistingPasswordSecret. -func (in *ExistingPasswordSecret) DeepCopy() *ExistingPasswordSecret { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExistingAuthSecret. +func (in *ExistingAuthSecret) DeepCopy() *ExistingAuthSecret { if in == nil { return nil } - out := new(ExistingPasswordSecret) + out := new(ExistingAuthSecret) in.DeepCopyInto(out) return out } @@ -87,9 +92,9 @@ func (in *KubernetesConfig) DeepCopyInto(out *KubernetesConfig) { *out = new(v1.ResourceRequirements) (*in).DeepCopyInto(*out) } - if in.ExistingPasswordSecret != nil { - in, out := &in.ExistingPasswordSecret, &out.ExistingPasswordSecret - *out = new(ExistingPasswordSecret) + if in.ExistingAuthSecret != nil { + in, out := &in.ExistingAuthSecret, &out.ExistingAuthSecret + *out = new(ExistingAuthSecret) (*in).DeepCopyInto(*out) } if in.ImagePullSecrets != nil { diff --git a/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml b/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml index 396696ccd..d7ccbcbc0 100644 --- a/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml +++ b/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml @@ -954,13 +954,15 @@ spec: type: object type: array redisSecret: - description: ExistingPasswordSecret is the struct to access the - existing secret + description: ExistingAuthSecret is the struct to access the existing + secret properties: - key: - type: string name: type: string + password: + type: string + username: + type: string type: object resources: description: ResourceRequirements describes the compute resource @@ -5131,13 +5133,15 @@ spec: type: object type: array redisSecret: - description: ExistingPasswordSecret is the struct to access the - existing secret + description: ExistingAuthSecret is the struct to access the existing + secret properties: - key: - type: string name: type: string + password: + type: string + username: + type: string type: object resources: description: ResourceRequirements describes the compute resource diff --git a/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml b/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml index b781c15ef..edb0aef2a 100644 --- a/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml +++ b/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml @@ -160,13 +160,15 @@ spec: type: object type: array redisSecret: - description: ExistingPasswordSecret is the struct to access the - existing secret + description: ExistingAuthSecret is the struct to access the existing + secret properties: - key: - type: string name: type: string + password: + type: string + username: + type: string type: object resources: description: ResourceRequirements describes the compute resource @@ -5511,13 +5513,15 @@ spec: type: object type: array redisSecret: - description: ExistingPasswordSecret is the struct to access the - existing secret + description: ExistingAuthSecret is the struct to access the existing + secret properties: - key: - type: string name: type: string + password: + type: string + username: + type: string type: object resources: description: ResourceRequirements describes the compute resource diff --git a/config/crd/bases/redis.redis.opstreelabs.in_redisreplications.yaml b/config/crd/bases/redis.redis.opstreelabs.in_redisreplications.yaml index c52f9a10a..44ba0ebf5 100644 --- a/config/crd/bases/redis.redis.opstreelabs.in_redisreplications.yaml +++ b/config/crd/bases/redis.redis.opstreelabs.in_redisreplications.yaml @@ -956,13 +956,15 @@ spec: type: object type: array redisSecret: - description: ExistingPasswordSecret is the struct to access the - existing secret + description: ExistingAuthSecret is the struct to access the existing + secret properties: - key: - type: string name: type: string + password: + type: string + username: + type: string type: object resources: description: ResourceRequirements describes the compute resource @@ -5136,13 +5138,15 @@ spec: type: object type: array redisSecret: - description: ExistingPasswordSecret is the struct to access the - existing secret + description: ExistingAuthSecret is the struct to access the existing + secret properties: - key: - type: string name: type: string + password: + type: string + username: + type: string type: object resources: description: ResourceRequirements describes the compute resource diff --git a/config/crd/bases/redis.redis.opstreelabs.in_redissentinels.yaml b/config/crd/bases/redis.redis.opstreelabs.in_redissentinels.yaml index d0ce64fbe..76677541f 100644 --- a/config/crd/bases/redis.redis.opstreelabs.in_redissentinels.yaml +++ b/config/crd/bases/redis.redis.opstreelabs.in_redissentinels.yaml @@ -957,13 +957,15 @@ spec: type: object type: array redisSecret: - description: ExistingPasswordSecret is the struct to access the - existing secret + description: ExistingAuthSecret is the struct to access the existing + secret properties: - key: - type: string name: type: string + password: + type: string + username: + type: string type: object resources: description: ResourceRequirements describes the compute resource @@ -2901,13 +2903,15 @@ spec: type: object type: array redisSecret: - description: ExistingPasswordSecret is the struct to access the - existing secret + description: ExistingAuthSecret is the struct to access the existing + secret properties: - key: - type: string name: type: string + password: + type: string + username: + type: string type: object resources: description: ResourceRequirements describes the compute resource diff --git a/example/v1beta2/backup_restore/backup/env-secrets.yaml b/example/v1beta2/backup_restore/backup/env-secrets.yaml index 84e1be7e9..bd36ed28c 100644 --- a/example/v1beta2/backup_restore/backup/env-secrets.yaml +++ b/example/v1beta2/backup_restore/backup/env-secrets.yaml @@ -11,6 +11,7 @@ stringData: RESTIC_PASSWORD: abc@123 RESTIC_CACHE_DIR: "/tmp/restic_cache" REDIS_PORT: "6379" + REDIS_USERNAME: "default" REDIS_PASSWORD: "" BACKUP_DESTINATION: AWS_S3 AWS_S3_BUCKET: shubham-redis diff --git a/k8sutils/cluster-scaling.go b/k8sutils/cluster-scaling.go index 6699a5a75..601c3c545 100644 --- a/k8sutils/cluster-scaling.go +++ b/k8sutils/cluster-scaling.go @@ -38,8 +38,17 @@ func ReshardRedisCluster(client kubernetes.Interface, logger logr.Logger, cr *re cmd = append(cmd, getRedisServerAddress(client, logger, transferPOD, *cr.Spec.Port)) } - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + username, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey) + if err != nil { + logger.Error(err, "Error in getting redis username") + } + if username != "" { + cmd = append(cmd, "--user") + cmd = append(cmd, username) + } + + pass, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey) if err != nil { logger.Error(err, "Error in getting redis password") } @@ -146,7 +155,7 @@ func getRedisNodeID(ctx context.Context, client kubernetes.Interface, logger log // Rebalance the Redis CLuster using the Empty Master Nodes func RebalanceRedisClusterEmptyMasters(client kubernetes.Interface, logger logr.Logger, cr *redisv1beta2.RedisCluster) { - // cmd = redis-cli --cluster rebalance : --cluster-use-empty-masters -a + // cmd = redis-cli --cluster rebalance : --cluster-use-empty-masters --user -a var cmd []string pod := RedisDetails{ PodName: cr.ObjectMeta.Name + "-leader-1", @@ -162,8 +171,17 @@ func RebalanceRedisClusterEmptyMasters(client kubernetes.Interface, logger logr. cmd = append(cmd, "--cluster-use-empty-masters") - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + username, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey) + if err != nil { + logger.Error(err, "Error in getting redis username") + } + if username != "" { + cmd = append(cmd, "--user") + cmd = append(cmd, username) + } + + pass, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey) if err != nil { logger.Error(err, "Error in getting redis password") } @@ -212,8 +230,17 @@ func RebalanceRedisCluster(client kubernetes.Interface, logger logr.Logger, cr * cmd = append(cmd, getRedisServerAddress(client, logger, pod, *cr.Spec.Port)) } - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + username, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey) + if err != nil { + logger.Error(err, "Error in getting redis username") + } + if username != "" { + cmd = append(cmd, "--user") + cmd = append(cmd, username) + } + + pass, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey) if err != nil { logger.Error(err, "Error in getting redis password") } @@ -251,8 +278,17 @@ func AddRedisNodeToCluster(ctx context.Context, client kubernetes.Interface, log cmd = append(cmd, getRedisServerAddress(client, logger, existingPod, *cr.Spec.Port)) } - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + username, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey) + if err != nil { + logger.Error(err, "Error in getting redis username") + } + if username != "" { + cmd = append(cmd, "--user") + cmd = append(cmd, username) + } + + pass, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey) if err != nil { logger.Error(err, "Error in getting redis password") } @@ -309,8 +345,17 @@ func RemoveRedisFollowerNodesFromCluster(ctx context.Context, client kubernetes. cmd = []string{"redis-cli"} - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + username, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey) + if err != nil { + logger.Error(err, "Error in getting redis username") + } + if username != "" { + cmd = append(cmd, "--user") + cmd = append(cmd, username) + } + + pass, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey) if err != nil { logger.Error(err, "Error in getting redis password") } @@ -362,8 +407,17 @@ func RemoveRedisNodeFromCluster(ctx context.Context, client kubernetes.Interface removePodNodeID := getRedisNodeID(ctx, client, logger, cr, removePod) cmd = append(cmd, removePodNodeID) - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + username, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey) + if err != nil { + logger.Error(err, "Error in getting redis username") + } + if username != "" { + cmd = append(cmd, "--user") + cmd = append(cmd, username) + } + + pass, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey) if err != nil { logger.Error(err, "Error in getting redis password") } @@ -420,8 +474,17 @@ func ClusterFailover(ctx context.Context, client kubernetes.Interface, logger lo cmd = append(cmd, getRedisServerAddress(client, logger, pod, *cr.Spec.Port)) } - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + username, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey) + if err != nil { + logger.Error(err, "Error in getting redis username") + } + if username != "" { + cmd = append(cmd, "--user") + cmd = append(cmd, username) + } + + pass, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey) if err != nil { logger.Error(err, "Error in getting redis password") } diff --git a/k8sutils/redis-cluster.go b/k8sutils/redis-cluster.go index aae4cf5bf..4b39e4f17 100644 --- a/k8sutils/redis-cluster.go +++ b/k8sutils/redis-cluster.go @@ -164,12 +164,13 @@ func generateRedisClusterContainerParams(cl kubernetes.Interface, logger logr.Lo containerProp.AdditionalVolume = cr.Spec.Storage.VolumeMount.Volume containerProp.AdditionalMountPath = cr.Spec.Storage.VolumeMount.MountPath } - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - containerProp.EnabledPassword = &trueProperty - containerProp.SecretName = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name - containerProp.SecretKey = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + containerProp.EnableAuth = &trueProperty + containerProp.SecretName = cr.Spec.KubernetesConfig.ExistingAuthSecret.Name + containerProp.SecretUsernameKey = cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey + containerProp.SecretPasswordKey = cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey } else { - containerProp.EnabledPassword = &falseProperty + containerProp.EnableAuth = &falseProperty } if cr.Spec.RedisExporter != nil { containerProp.RedisExporterImage = cr.Spec.RedisExporter.Image diff --git a/k8sutils/redis-cluster_test.go b/k8sutils/redis-cluster_test.go index ff7e83672..3e7900518 100644 --- a/k8sutils/redis-cluster_test.go +++ b/k8sutils/redis-cluster_test.go @@ -248,17 +248,29 @@ func Test_generateRedisClusterContainerParams(t *testing.T) { ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ - Name: "mysecret", + Name: "redis-secret", }, Key: "username", }, }, }, + { + Name: "SECRET_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "redis-secret", + }, + Key: "password", + }, + }, + }, }, Role: "cluster", - EnabledPassword: pointer.Bool(true), + EnableAuth: pointer.Bool(true), SecretName: pointer.String("redis-secret"), - SecretKey: pointer.String("password"), + SecretUsernameKey: pointer.String("username"), + SecretPasswordKey: pointer.String("password"), PersistenceEnabled: pointer.Bool(true), TLSConfig: &redisv1beta2.TLSConfig{ TLSConfig: common.TLSConfig{ @@ -361,17 +373,29 @@ func Test_generateRedisClusterContainerParams(t *testing.T) { ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ - Name: "mysecret", + Name: "redis-secret", }, Key: "username", }, }, }, + { + Name: "SECRET_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "redis-secret", + }, + Key: "password", + }, + }, + }, }, Role: "cluster", - EnabledPassword: pointer.Bool(true), + EnableAuth: pointer.Bool(true), SecretName: pointer.String("redis-secret"), - SecretKey: pointer.String("password"), + SecretUsernameKey: pointer.String("username"), + SecretPasswordKey: pointer.String("password"), PersistenceEnabled: pointer.Bool(true), TLSConfig: &redisv1beta2.TLSConfig{ TLSConfig: common.TLSConfig{ diff --git a/k8sutils/redis-replication.go b/k8sutils/redis-replication.go index 9f47f85dd..c7987899e 100644 --- a/k8sutils/redis-replication.go +++ b/k8sutils/redis-replication.go @@ -133,12 +133,13 @@ func generateRedisReplicationContainerParams(cr *redisv1beta2.RedisReplication) containerProp.AdditionalMountPath = cr.Spec.Storage.VolumeMount.MountPath } - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - containerProp.EnabledPassword = &trueProperty - containerProp.SecretName = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name - containerProp.SecretKey = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + containerProp.EnableAuth = &trueProperty + containerProp.SecretName = cr.Spec.KubernetesConfig.ExistingAuthSecret.Name + containerProp.SecretUsernameKey = cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey + containerProp.SecretPasswordKey = cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey } else { - containerProp.EnabledPassword = &falseProperty + containerProp.EnableAuth = &falseProperty } if cr.Spec.RedisExporter != nil { containerProp.RedisExporterImage = cr.Spec.RedisExporter.Image diff --git a/k8sutils/redis-replication_test.go b/k8sutils/redis-replication_test.go index 57765acba..e10e539a2 100644 --- a/k8sutils/redis-replication_test.go +++ b/k8sutils/redis-replication_test.go @@ -150,17 +150,29 @@ func Test_generateRedisReplicationContainerParams(t *testing.T) { ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ - Name: "mysecret", + Name: "redis-secret", }, Key: "username", }, }, }, + { + Name: "SECRET_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "redis-secret", + }, + Key: "password", + }, + }, + }, }, Role: "replication", - EnabledPassword: pointer.Bool(true), + EnableAuth: pointer.Bool(true), SecretName: pointer.String("redis-secret"), - SecretKey: pointer.String("password"), + SecretUsernameKey: pointer.String("username"), + SecretPasswordKey: pointer.String("password"), PersistenceEnabled: pointer.Bool(true), TLSConfig: &redisv1beta2.TLSConfig{ TLSConfig: common.TLSConfig{ diff --git a/k8sutils/redis-sentinel.go b/k8sutils/redis-sentinel.go index ad0c754b6..5c12d8fbb 100644 --- a/k8sutils/redis-sentinel.go +++ b/k8sutils/redis-sentinel.go @@ -152,12 +152,13 @@ func generateRedisSentinelContainerParams(ctx context.Context, client kubernetes if cr.Spec.EnvVars != nil { containerProp.EnvVars = cr.Spec.EnvVars } - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - containerProp.EnabledPassword = &trueProperty - containerProp.SecretName = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name - containerProp.SecretKey = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + containerProp.EnableAuth = &trueProperty + containerProp.SecretName = cr.Spec.KubernetesConfig.ExistingAuthSecret.Name + containerProp.SecretUsernameKey = cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey + containerProp.SecretPasswordKey = cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey } else { - containerProp.EnabledPassword = &falseProperty + containerProp.EnableAuth = &falseProperty } if cr.Spec.RedisExporter != nil { containerProp.RedisExporterImage = cr.Spec.RedisExporter.Image diff --git a/k8sutils/redis-sentinel_test.go b/k8sutils/redis-sentinel_test.go index 98cee4ee9..d7ed30149 100644 --- a/k8sutils/redis-sentinel_test.go +++ b/k8sutils/redis-sentinel_test.go @@ -143,17 +143,29 @@ func Test_generateRedisSentinelContainerParams(t *testing.T) { ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ - Name: "mysecret", + Name: "redis-secret", }, Key: "username", }, }, }, + { + Name: "SECRET_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "redis-secret", + }, + Key: "password", + }, + }, + }, }, - Role: "sentinel", - EnabledPassword: pointer.Bool(true), - SecretName: pointer.String("redis-secret"), - SecretKey: pointer.String("password"), + Role: "sentinel", + EnableAuth: pointer.Bool(true), + SecretName: pointer.String("redis-secret"), + SecretUsernameKey: pointer.String("username"), + SecretPasswordKey: pointer.String("password"), TLSConfig: &redisv1beta2.TLSConfig{ TLSConfig: common.TLSConfig{ CaKeyFile: "ca.key", diff --git a/k8sutils/redis-standalone.go b/k8sutils/redis-standalone.go index a99a45b92..6c70e9496 100644 --- a/k8sutils/redis-standalone.go +++ b/k8sutils/redis-standalone.go @@ -134,12 +134,13 @@ func generateRedisStandaloneContainerParams(cr *redisv1beta2.Redis) containerPar containerProp.AdditionalMountPath = cr.Spec.Storage.VolumeMount.MountPath } - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - containerProp.EnabledPassword = &trueProperty - containerProp.SecretName = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name - containerProp.SecretKey = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + containerProp.EnableAuth = &trueProperty + containerProp.SecretName = cr.Spec.KubernetesConfig.ExistingAuthSecret.Name + containerProp.SecretUsernameKey = cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey + containerProp.SecretPasswordKey = cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey } else { - containerProp.EnabledPassword = &falseProperty + containerProp.EnableAuth = &falseProperty } if cr.Spec.RedisExporter != nil { containerProp.RedisExporterImage = cr.Spec.RedisExporter.Image diff --git a/k8sutils/redis-standalone_test.go b/k8sutils/redis-standalone_test.go index e7eebe882..2d3264666 100644 --- a/k8sutils/redis-standalone_test.go +++ b/k8sutils/redis-standalone_test.go @@ -158,17 +158,29 @@ func Test_generateRedisStandaloneContainerParams(t *testing.T) { ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ - Name: "mysecret", + Name: "redis-secret", }, Key: "username", }, }, }, + { + Name: "SECRET_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "redis-secret", + }, + Key: "password", + }, + }, + }, }, Role: "standalone", - EnabledPassword: pointer.Bool(true), + EnableAuth: pointer.Bool(true), SecretName: pointer.String("redis-secret"), - SecretKey: pointer.String("password"), + SecretUsernameKey: pointer.String("username"), + SecretPasswordKey: pointer.String("password"), PersistenceEnabled: pointer.Bool(true), TLSConfig: &redisv1beta2.TLSConfig{ TLSConfig: common.TLSConfig{ diff --git a/k8sutils/redis.go b/k8sutils/redis.go index ee0db0a17..5d105c0b6 100644 --- a/k8sutils/redis.go +++ b/k8sutils/redis.go @@ -121,8 +121,17 @@ func ExecuteRedisClusterCommand(ctx context.Context, client kubernetes.Interface cmd = CreateMultipleLeaderRedisCommand(client, logger, cr) } - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + username, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey) + if err != nil { + logger.Error(err, "Error in getting redis username") + } + if username != "" { + cmd = append(cmd, "--user") + cmd = append(cmd, username) + } + + pass, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey) if err != nil { logger.Error(err, "Error in getting redis password") } @@ -161,10 +170,19 @@ func createRedisReplicationCommand(client kubernetes.Interface, logger logr.Logg cmd = append(cmd, followerAddress, leaderAddress, "--cluster-slave") - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + username, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey) if err != nil { - logger.Error(err, "Failed to retrieve Redis password", "Secret", *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name) + logger.Error(err, "Error in getting redis username") + } + if username != "" { + cmd = append(cmd, "--user") + cmd = append(cmd, username) + } + + pass, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey) + if err != nil { + logger.Error(err, "Failed to retrieve Redis password", "Secret", *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name) } cmd = append(cmd, "-a", pass) } @@ -345,13 +363,22 @@ func configureRedisClient(client kubernetes.Interface, logger logr.Logger, cr *r } var redisClient *redis.Client - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + username, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey) + if err != nil { + logger.Error(err, "Error in getting redis username") + } + if username == "" { + username = "default" + } + + pass, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey) if err != nil { logger.Error(err, "Error in getting redis password") } redisClient = redis.NewClient(&redis.Options{ - Addr: getRedisServerAddress(client, logger, redisInfo, *cr.Spec.Port), + Addr: getRedisServerIP(client, logger, redisInfo) + fmt.Sprintf(":%d", *cr.Spec.Port), + Username: username, Password: pass, DB: 0, TLSConfig: getRedisTLSConfig(client, logger, cr, redisInfo), @@ -464,13 +491,22 @@ func configureRedisReplicationClient(client kubernetes.Interface, logger logr.Lo } var redisClient *redis.Client - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistingAuthSecret != nil { + username, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.UsernameKey) + if err != nil { + logger.Error(err, "Error in getting redis username") + } + if username == "" { + username = "default" + } + + pass, err := getKVFromSecret(client, logger, cr.Namespace, *cr.Spec.KubernetesConfig.ExistingAuthSecret.Name, *cr.Spec.KubernetesConfig.ExistingAuthSecret.PasswordKey) if err != nil { logger.Error(err, "Error in getting redis password") } redisClient = redis.NewClient(&redis.Options{ - Addr: getRedisServerAddress(client, logger, redisInfo, 6379), + Addr: getRedisServerIP(client, logger, redisInfo) + ":6379", + Username: username, Password: pass, DB: 0, TLSConfig: getRedisReplicationTLSConfig(client, logger, cr, redisInfo), diff --git a/k8sutils/secrets.go b/k8sutils/secrets.go index 40f3853fe..22b28c9b3 100644 --- a/k8sutils/secrets.go +++ b/k8sutils/secrets.go @@ -16,8 +16,8 @@ import ( var log = logf.Log.WithName("controller_redis") -// getRedisPassword method will return the redis password from the secret -func getRedisPassword(client kubernetes.Interface, logger logr.Logger, namespace, name, secretKey string) (string, error) { +// getKVFromSecret method will return the KV for from the secret +func getKVFromSecret(client kubernetes.Interface, logger logr.Logger, namespace, name, secretKey string) (string, error) { secretName, err := client.CoreV1().Secrets(namespace).Get(context.TODO(), name, metav1.GetOptions{}) if err != nil { logger.Error(err, "Failed in getting existing secret for redis") diff --git a/k8sutils/secrets_test.go b/k8sutils/secrets_test.go index e8ae83fe3..760e897de 100644 --- a/k8sutils/secrets_test.go +++ b/k8sutils/secrets_test.go @@ -15,7 +15,7 @@ import ( k8sClientFake "k8s.io/client-go/kubernetes/fake" ) -func Test_getRedisPassword(t *testing.T) { +func TestGetRedisKVFromSecret(t *testing.T) { tests := []struct { name string setup func() *k8sClientFake.Clientset @@ -26,11 +26,11 @@ func Test_getRedisPassword(t *testing.T) { expectedErr bool }{ { - name: "successful retrieval", + name: "successful retrieval password", setup: func() *k8sClientFake.Clientset { secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: "redis-secret", + Name: "mysecret", Namespace: "default", }, Data: map[string][]byte{ @@ -41,11 +41,32 @@ func Test_getRedisPassword(t *testing.T) { return client }, namespace: "default", - secretName: "redis-secret", + secretName: "mysecret", secretKey: "password", expected: "secret-password", expectedErr: false, }, + { + name: "successful retrieval username", + setup: func() *k8sClientFake.Clientset { + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mysecret", + Namespace: "default", + }, + Data: map[string][]byte{ + "username": []byte("secret-username"), + }, + } + client := k8sClientFake.NewSimpleClientset(secret.DeepCopyObject()) + return client + }, + namespace: "default", + secretName: "mysecret", + secretKey: "username", + expected: "secret-username", + expectedErr: false, + }, { name: "secret not found", setup: func() *k8sClientFake.Clientset { @@ -85,7 +106,7 @@ func Test_getRedisPassword(t *testing.T) { t.Run(tt.name, func(t *testing.T) { client := tt.setup() logger := testr.New(t) - got, err := getRedisPassword(client, logger, tt.namespace, tt.secretName, tt.secretKey) + got, err := getKVFromSecret(client, logger, tt.namespace, tt.secretName, tt.secretKey) if tt.expectedErr { require.Error(t, err, "Expected an error but didn't get one") diff --git a/k8sutils/statefulset.go b/k8sutils/statefulset.go index b732a3afc..1fdc4cf16 100644 --- a/k8sutils/statefulset.go +++ b/k8sutils/statefulset.go @@ -65,9 +65,10 @@ type containerParameters struct { RedisExporterEnv *[]corev1.EnvVar RedisExporterPort *int Role string - EnabledPassword *bool + EnableAuth *bool SecretName *string - SecretKey *string + SecretUsernameKey *string + SecretPasswordKey *string PersistenceEnabled *bool TLSConfig *redisv1beta2.TLSConfig ACLConfig *redisv1beta2.ACLConfig @@ -354,9 +355,10 @@ func generateContainerDef(name string, containerParams containerParameters, clus SecurityContext: containerParams.SecurityContext, Env: getEnvironmentVariables( containerParams.Role, - containerParams.EnabledPassword, + containerParams.EnableAuth, containerParams.SecretName, - containerParams.SecretKey, + containerParams.SecretUsernameKey, + containerParams.SecretPasswordKey, containerParams.PersistenceEnabled, containerParams.TLSConfig, containerParams.ACLConfig, @@ -522,7 +524,20 @@ func getExporterEnvironmentVariables(params containerParameters) []corev1.EnvVar Value: fmt.Sprintf("redis://localhost:%d", *params.Port), }) } - if params.EnabledPassword != nil && *params.EnabledPassword { + if params.EnableAuth != nil && *params.EnableAuth { + envVars = append(envVars, corev1.EnvVar{ + Name: "REDIS_USERNAME", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: *params.SecretName, + }, + Key: *params.SecretUsernameKey, + }, + }, + }) + } + if params.EnableAuth != nil && *params.EnableAuth { envVars = append(envVars, corev1.EnvVar{ Name: "REDIS_PASSWORD", ValueFrom: &corev1.EnvVarSource{ @@ -530,7 +545,7 @@ func getExporterEnvironmentVariables(params containerParameters) []corev1.EnvVar LocalObjectReference: corev1.LocalObjectReference{ Name: *params.SecretName, }, - Key: *params.SecretKey, + Key: *params.SecretPasswordKey, }, }, }) @@ -611,8 +626,8 @@ func getProbeInfo(probe *commonapi.Probe) *corev1.Probe { } // getEnvironmentVariables returns all the required Environment Variables -func getEnvironmentVariables(role string, enabledPassword *bool, secretName *string, - secretKey *string, persistenceEnabled *bool, tlsConfig *redisv1beta2.TLSConfig, +func getEnvironmentVariables(role string, enableAuth *bool, secretName *string, + secretUsernameKey *string, secretPasswordKey *string, persistenceEnabled *bool, tlsConfig *redisv1beta2.TLSConfig, aclConfig *redisv1beta2.ACLConfig, envVar *[]corev1.EnvVar, port *int, clusterVersion *string, ) []corev1.EnvVar { envVars := []corev1.EnvVar{ @@ -659,8 +674,20 @@ func getEnvironmentVariables(role string, enabledPassword *bool, secretName *str Name: "REDIS_ADDR", Value: redisHost, }) - - if enabledPassword != nil && *enabledPassword { + if enableAuth != nil && *enableAuth && secretUsernameKey != nil { + envVars = append(envVars, corev1.EnvVar{ + Name: "REDIS_USERNAME", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: *secretName, + }, + Key: *secretUsernameKey, + }, + }, + }) + } + if enableAuth != nil && *enableAuth && secretPasswordKey != nil { envVars = append(envVars, corev1.EnvVar{ Name: "REDIS_PASSWORD", ValueFrom: &corev1.EnvVarSource{ @@ -668,7 +695,7 @@ func getEnvironmentVariables(role string, enabledPassword *bool, secretName *str LocalObjectReference: corev1.LocalObjectReference{ Name: *secretName, }, - Key: *secretKey, + Key: *secretPasswordKey, }, }, }) diff --git a/k8sutils/statefulset_test.go b/k8sutils/statefulset_test.go index 879c3242e..6837695b5 100644 --- a/k8sutils/statefulset_test.go +++ b/k8sutils/statefulset_test.go @@ -222,9 +222,10 @@ func TestGetEnvironmentVariables(t *testing.T) { tests := []struct { name string role string - enabledPassword *bool + enableAuth *bool secretName *string - secretKey *string + secretUsernameKey *string + secretPasswordKey *string persistenceEnabled *bool tlsConfig *redisv1beta2.TLSConfig aclConfig *redisv1beta2.ACLConfig @@ -234,11 +235,12 @@ func TestGetEnvironmentVariables(t *testing.T) { expectedEnvironment []corev1.EnvVar }{ { - name: "Test with role sentinel, metrics true, password true, persistence true, exporter env, tls enabled, acl enabled and env var", + name: "Test with role sentinel, metrics true, auth true, username true, password true, persistence true, exporter env, tls enabled, acl enabled and env var", role: "sentinel", - enabledPassword: pointer.Bool(true), + enableAuth: pointer.Bool(true), secretName: pointer.String("test-secret"), - secretKey: pointer.String("test-key"), + secretUsernameKey: pointer.String("test-username-key"), + secretPasswordKey: pointer.String("test-password-key"), persistenceEnabled: pointer.Bool(true), tlsConfig: &redisv1beta2.TLSConfig{ TLSConfig: common.TLSConfig{ @@ -267,12 +269,20 @@ func TestGetEnvironmentVariables(t *testing.T) { {Name: "REDIS_TLS_CA_KEY", Value: path.Join("/tls/", "test_ca.crt")}, {Name: "REDIS_TLS_CERT", Value: path.Join("/tls/", "test_tls.crt")}, {Name: "REDIS_TLS_CERT_KEY", Value: path.Join("/tls/", "test_tls.key")}, + {Name: "REDIS_USERNAME", ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "test-secret", + }, + Key: "test-username-key", + }, + }}, {Name: "REDIS_PASSWORD", ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ Name: "test-secret", }, - Key: "test-key", + Key: "test-password-key", }, }}, {Name: "SERVER_MODE", Value: "sentinel"}, @@ -282,11 +292,12 @@ func TestGetEnvironmentVariables(t *testing.T) { }, }, { - name: "Test with role redis, metrics false, password nil, persistence nil, exporter nil, tls nil, acl nil and nil env var", + name: "Test with role redis, metrics false, username nil, password nil, persistence nil, exporter nil, tls nil, acl nil and nil env var", role: "redis", - enabledPassword: nil, + enableAuth: nil, secretName: nil, - secretKey: nil, + secretUsernameKey: nil, + secretPasswordKey: nil, persistenceEnabled: nil, tlsConfig: nil, aclConfig: nil, @@ -300,11 +311,12 @@ func TestGetEnvironmentVariables(t *testing.T) { }, }, { - name: "Test with role redis, metrics false, password nil, persistence false, exporter nil, tls nil, acl nil and nil env var", + name: "Test with role redis, metrics false, username nil, password nil, persistence false, exporter nil, tls nil, acl nil and nil env var", role: "sentinel", - enabledPassword: nil, + enableAuth: nil, secretName: nil, - secretKey: nil, + secretUsernameKey: nil, + secretPasswordKey: nil, persistenceEnabled: pointer.Bool(false), tlsConfig: nil, aclConfig: nil, @@ -316,11 +328,12 @@ func TestGetEnvironmentVariables(t *testing.T) { }, }, { - name: "Test with role cluster, metrics true, password true, persistence true, exporter env, tls nil, acl enabled and env var", + name: "Test with role cluster, metrics true, auth true, username nil, password true, persistence true, exporter env, tls nil, acl enabled and env var", role: "cluster", - enabledPassword: pointer.Bool(true), + enableAuth: pointer.Bool(true), secretName: pointer.String("test-secret"), - secretKey: pointer.String("test-key"), + secretUsernameKey: nil, + secretPasswordKey: pointer.String("test-password-key"), persistenceEnabled: pointer.Bool(true), tlsConfig: nil, aclConfig: &redisv1beta2.ACLConfig{}, @@ -337,7 +350,7 @@ func TestGetEnvironmentVariables(t *testing.T) { LocalObjectReference: corev1.LocalObjectReference{ Name: "test-secret", }, - Key: "test-key", + Key: "test-password-key", }, }}, {Name: "SERVER_MODE", Value: "cluster"}, @@ -349,9 +362,10 @@ func TestGetEnvironmentVariables(t *testing.T) { { name: "Test with cluster role and only metrics enabled", role: "cluster", - enabledPassword: nil, + enableAuth: nil, secretName: nil, - secretKey: nil, + secretUsernameKey: nil, + secretPasswordKey: nil, persistenceEnabled: nil, tlsConfig: nil, aclConfig: nil, @@ -362,12 +376,37 @@ func TestGetEnvironmentVariables(t *testing.T) { {Name: "SETUP_MODE", Value: "cluster"}, }, }, + { + name: "Test with role redis, metrics false, auth true, username true, password nil, persistence false, exporter nil, tls nil, acl nil and nil env var", + role: "sentinel", + enableAuth: pointer.Bool(true), + secretName: pointer.String("test-secret"), + secretUsernameKey: pointer.String("test-username-key"), + secretPasswordKey: nil, + persistenceEnabled: pointer.Bool(false), + tlsConfig: nil, + aclConfig: nil, + envVar: nil, + expectedEnvironment: []corev1.EnvVar{ + {Name: "REDIS_ADDR", Value: "redis://localhost:26379"}, + {Name: "SERVER_MODE", Value: "sentinel"}, + {Name: "REDIS_USERNAME", ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "test-secret", + }, + Key: "test-username-key", + }, + }}, + {Name: "SETUP_MODE", Value: "sentinel"}, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - actualEnvironment := getEnvironmentVariables(tt.role, tt.enabledPassword, tt.secretName, - tt.secretKey, tt.persistenceEnabled, tt.tlsConfig, tt.aclConfig, tt.envVar, tt.port, tt.clusterVersion) + actualEnvironment := getEnvironmentVariables(tt.role, tt.enableAuth, tt.secretName, + tt.secretUsernameKey, tt.secretPasswordKey, tt.persistenceEnabled, tt.tlsConfig, tt.aclConfig, tt.envVar, tt.port, tt.clusterVersion) assert.ElementsMatch(t, tt.expectedEnvironment, actualEnvironment) }) diff --git a/scripts/backup/backup-user.bash b/scripts/backup/backup-user.bash index 4fb946d07..80d909e47 100644 --- a/scripts/backup/backup-user.bash +++ b/scripts/backup/backup-user.bash @@ -6,6 +6,7 @@ set -e # Exit on error DEFAULT_CLUSTER_NAME="redis-cluster" DEFAULT_CLUSTER_NAMESPACE="default" DEFAULT_REDIS_PORT="6379" +DEFAULT_REDIS_USERNAME="default" DEFAULT_REDIS_PASSWORD="" # Prompt the user for input or use default values @@ -18,6 +19,9 @@ CLUSTER_NAMESPACE=${CLUSTER_NAMESPACE:-$DEFAULT_CLUSTER_NAMESPACE} read -p "Enter Redis port [$DEFAULT_REDIS_PORT]: " REDIS_PORT REDIS_PORT=${REDIS_PORT:-$DEFAULT_REDIS_PORT} +read -p "Enter Redis username [DEFAULT_REDIS_USERNAME]: " REDIS_USERNAME +REDIS_USERNAME=${REDIS_USERNAME:-DEFAULT_REDIS_USERNAME} + read -p "Enter Redis password [$DEFAULT_REDIS_PASSWORD]: " REDIS_PASSWORD REDIS_PASSWORD=${REDIS_PASSWORD:-$DEFAULT_REDIS_PASSWORD} @@ -59,7 +63,7 @@ REDIS_HOST="${CLUSTER_NAME}-leader-0.${CLUSTER_NAME}-leader-headless.${CLUSTER_N # Check the Total Leader Present in Redis Cluster using cr and redis-cli TOTAL_LEADERS=$(kubectl get redisclusters.redis.redis.opstreelabs.in "${CLUSTER_NAME}" -n "${CLUSTER_NAMESPACE}" -o jsonpath='{.spec.redisLeader.replicas}') -MASTERS_IP=($(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_PASSWORD" --no-auth-warning cluster nodes | grep "master" | awk '{print $2}' | cut -d "@" -f1)) +MASTERS_IP=($(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" --username "$REDIS_USERNAME" -a "$REDIS_PASSWORD" --no-auth-warning cluster nodes | grep "master" | awk '{print $2}' | cut -d "@" -f1)) check_total_leaders_from_cr() { if [[ -z "$TOTAL_LEADERS" || "$TOTAL_LEADERS" == 0 ]]; then @@ -108,7 +112,7 @@ perform_redis_backup(){ echo "Performing backup on Redis instance at $IP:$PORT" # Copy the file from the Redis instance to a local file - redis-cli -h "$IP" -p "$PORT" -a "$REDIS_PASSWORD" --rdb "/tmp/${POD}.rdb" + redis-cli -h "$IP" -p "$PORT" --username "$REDIS_USERNAME" -a "$REDIS_PASSWORD" --rdb "/tmp/${POD}.rdb" # Upload the file to the selected backup destination using restic restic -r "$RESTIC_REPOSITORY" backup "/tmp/${POD}.rdb" --host "${CLUSTER_NAME}_${CLUSTER_NAMESPACE}" --tag "${POD}" --tag "redis" diff --git a/scripts/backup/backup-v0.15.1.bash b/scripts/backup/backup-v0.15.1.bash index 6d9ac4954..097c99eac 100644 --- a/scripts/backup/backup-v0.15.1.bash +++ b/scripts/backup/backup-v0.15.1.bash @@ -23,7 +23,7 @@ REDIS_HOST="${CLUSTER_NAME}-leader-0.${CLUSTER_NAME}-leader-headless.${CLUSTER_N # Check the Total Leader Present in Redis Cluster using cr and redis-cli TOTAL_LEADERS=$(kubectl get redisclusters.redis.redis.opstreelabs.in "${CLUSTER_NAME}" -n "${CLUSTER_NAMESPACE}" -o jsonpath='{.spec.redisLeader.replicas}') -MASTERS_IP=($(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_PASSWORD" --no-auth-warning cluster nodes | grep "master" | awk '{print $2}' | cut -d "@" -f1)) +MASTERS_IP=($(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" --username "$REDIS_USERNAME" -a "$REDIS_PASSWORD" --no-auth-warning cluster nodes | grep "master" | awk '{print $2}' | cut -d "@" -f1)) check_total_leaders_from_cr() { if [[ -z "$TOTAL_LEADERS" || "$TOTAL_LEADERS" == 0 ]]; then @@ -73,7 +73,7 @@ perform_redis_backup(){ echo "Performing backup on Redis instance at $IP:$PORT" # Copy the file from the Redis instance to a local file - redis-cli -h "$IP" -p "$PORT" -a "$REDIS_PASSWORD" --rdb "/tmp/${POD}.rdb" + redis-cli -h "$IP" -p "$PORT" --username "$REDIS_USERNAME" -a "$REDIS_PASSWORD" --rdb "/tmp/${POD}.rdb" # Upload the file to the selected backup destination using restic restic -r "$RESTIC_REPOSITORY" backup "/tmp/${POD}.rdb" --host "${CLUSTER_NAME}_${CLUSTER_NAMESPACE}" --tag "${POD}" --tag "redis" diff --git a/scripts/backup/backup.bash b/scripts/backup/backup.bash index 5e70ddc7e..f49d51e1c 100644 --- a/scripts/backup/backup.bash +++ b/scripts/backup/backup.bash @@ -23,7 +23,7 @@ REDIS_HOST="${CLUSTER_NAME}-leader-0.${CLUSTER_NAME}-leader-headless.${CLUSTER_N # Check the Total Leader Present in Redis Cluster using cr and redis-cli TOTAL_LEADERS=$(kubectl get redisclusters.redis.redis.opstreelabs.in "${CLUSTER_NAME}" -n "${CLUSTER_NAMESPACE}" -o jsonpath='{.spec.redisLeader.replicas}') -MASTERS_IP=($(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_PASSWORD" --no-auth-warning cluster nodes | grep "master" | awk '{print $2}' | cut -d "@" -f1)) +MASTERS_IP=($(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" --username "$REDIS_USERNAME" -a "$REDIS_PASSWORD" --no-auth-warning cluster nodes | grep "master" | awk '{print $2}' | cut -d "@" -f1)) check_total_leaders_from_cr() { # Check if TOTAL_LEADERS is 0 or nil @@ -73,7 +73,7 @@ perform_redis_backup(){ echo "Performing backup on Redis instance at $IP:$PORT" # Copy the file from the Redis instance to a local file - redis-cli -h "$IP" -p "$PORT" -a "$REDIS_PASSWORD" --rdb "/tmp/${POD}.rdb" + redis-cli -h "$IP" -p "$PORT" --username "$REDIS_USERNAME" -a "$REDIS_PASSWORD" --rdb "/tmp/${POD}.rdb" # Upload the file to the selected backup destination using restic restic -r "$RESTIC_REPOSITORY" backup "/tmp/${POD}.rdb" --host "${CLUSTER_NAME}_${CLUSTER_NAMESPACE}" --tag "${POD}" --tag "redis" diff --git a/scripts/backup/env_vars.env b/scripts/backup/env_vars.env index 110f775f7..c061cfc45 100644 --- a/scripts/backup/env_vars.env +++ b/scripts/backup/env_vars.env @@ -11,6 +11,7 @@ export RESTIC_CACHE_DIR=/tmp/restic_cache # Redis export DEFAULT_REDIS_PORT="6379" +export DEFAULT_REDIS_USERNAME="default" export DEFAULT_REDIS_PASSWORD="" # Backup destination diff --git a/scripts/env_vars.env b/scripts/env_vars.env index 237ef020c..da689264b 100644 --- a/scripts/env_vars.env +++ b/scripts/env_vars.env @@ -12,6 +12,7 @@ export RESTIC_CACHE_DIR=/tmp/restic_cache # Redis export DEFAULT_REDIS_HOST="redis-cluster-leader-0" export DEFAULT_REDIS_PORT="6379" +export DEFAULT_REDIS_USERNAME="default" export DEFAULT_REDIS_PASSWORD="" # Backup destination diff --git a/scripts/restore/env_vars.env b/scripts/restore/env_vars.env index 2234e1f14..c061cfc45 100644 --- a/scripts/restore/env_vars.env +++ b/scripts/restore/env_vars.env @@ -11,10 +11,10 @@ export RESTIC_CACHE_DIR=/tmp/restic_cache # Redis export DEFAULT_REDIS_PORT="6379" +export DEFAULT_REDIS_USERNAME="default" export DEFAULT_REDIS_PASSWORD="" # Backup destination - export BACKUP_DESTINATION=AWS_S3 # AWS diff --git a/tests/testdata/redis-cluster.yaml b/tests/testdata/redis-cluster.yaml index b107d6508..46b837068 100644 --- a/tests/testdata/redis-cluster.yaml +++ b/tests/testdata/redis-cluster.yaml @@ -24,7 +24,8 @@ spec: memory: 128Mi redisSecret: name: redis-secret - key: password + username: username + password: password ignoreAnnotations: - "opstreelabs.in/ignore" podSecurityContext: @@ -108,8 +109,13 @@ spec: - name: SECRET_USERNAME valueFrom: secretKeyRef: - name: mysecret + name: redis-secret key: username + - name: SECRET_PASSWORD + valueFrom: + secretKeyRef: + name: redis-secret + key: password persistenceEnabled: true storage: nodeConfVolume: true diff --git a/tests/testdata/redis-replication.yaml b/tests/testdata/redis-replication.yaml index 2f695bfe1..913de5895 100644 --- a/tests/testdata/redis-replication.yaml +++ b/tests/testdata/redis-replication.yaml @@ -21,8 +21,8 @@ spec: runAsNonRoot: true readOnlyRootFilesystem: true capabilities: - drop: ["ALL"] - add: ["NET_BIND_SERVICE"] + drop: [ "ALL" ] + add: [ "NET_BIND_SERVICE" ] kubernetesConfig: image: quay.io/opstree/redis:v7.0.12 imagePullPolicy: IfNotPresent @@ -37,7 +37,8 @@ spec: memory: 128Mi redisSecret: name: redis-secret - key: password + username: username + password: password ignoreAnnotations: - "opstreelabs.in/ignore" redisExporter: @@ -62,13 +63,18 @@ spec: - name: SECRET_USERNAME valueFrom: secretKeyRef: - name: mysecret + name: redis-secret key: username + - name: SECRET_PASSWORD + valueFrom: + secretKeyRef: + name: redis-secret + key: password storage: volumeClaimTemplate: spec: storageClassName: standard - accessModes: ["ReadWriteOnce"] + accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 1Gi @@ -119,8 +125,8 @@ spec: enabled: true image: quay.io/opstree/redis-operator-restore:latest imagePullPolicy: Always - command: ["/bin/bash", "-c", "/app/restore.bash"] - args: ["--restore-from", "redis-replication-restore"] + command: [ "/bin/bash", "-c", "/app/restore.bash" ] + args: [ "--restore-from", "redis-replication-restore" ] resources: requests: cpu: 100m diff --git a/tests/testdata/redis-sentinel.yaml b/tests/testdata/redis-sentinel.yaml index 40bf80154..59cdbecae 100644 --- a/tests/testdata/redis-sentinel.yaml +++ b/tests/testdata/redis-sentinel.yaml @@ -35,7 +35,8 @@ spec: memory: 128Mi redisSecret: name: redis-secret - key: password + username: username + password: password ignoreAnnotations: - "opstreelabs.in/ignore" redisExporter: @@ -60,8 +61,13 @@ spec: - name: SECRET_USERNAME valueFrom: secretKeyRef: - name: mysecret - key: username + name: redis-secret + key: "username" + - name: SECRET_PASSWORD + valueFrom: + secretKeyRef: + name: redis-secret + key: "password" nodeSelector: node-role.kubernetes.io/infra: worker priorityClassName: high-priority diff --git a/tests/testdata/redis-standalone.yaml b/tests/testdata/redis-standalone.yaml index a3b351259..843ec1ad1 100644 --- a/tests/testdata/redis-standalone.yaml +++ b/tests/testdata/redis-standalone.yaml @@ -20,8 +20,8 @@ spec: runAsNonRoot: true readOnlyRootFilesystem: true capabilities: - drop: ["ALL"] - add: ["NET_BIND_SERVICE"] + drop: [ "ALL" ] + add: [ "NET_BIND_SERVICE" ] kubernetesConfig: image: quay.io/opstree/redis:v7.0.12 imagePullPolicy: IfNotPresent @@ -36,7 +36,8 @@ spec: memory: 128Mi redisSecret: name: redis-secret - key: password + username: username + password: password ignoreAnnotations: - "opstreelabs.in/ignore" redisExporter: @@ -61,13 +62,18 @@ spec: - name: SECRET_USERNAME valueFrom: secretKeyRef: - name: mysecret + name: redis-secret key: username + - name: SECRET_PASSWORD + valueFrom: + secretKeyRef: + name: redis-secret + key: password storage: volumeClaimTemplate: spec: storageClassName: standard - accessModes: ["ReadWriteOnce"] + accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 1Gi @@ -118,8 +124,8 @@ spec: enabled: true image: quay.io/opstree/redis-operator-restore:latest imagePullPolicy: Always - command: ["/bin/bash", "-c", "/app/restore.bash"] - args: ["--restore-from", "redis-standalone-restore"] + command: [ "/bin/bash", "-c", "/app/restore.bash" ] + args: [ "--restore-from", "redis-standalone-restore" ] resources: requests: cpu: 100m