diff --git a/docs/userguide/main.md b/docs/userguide/main.md index 7f55780e..9d9dce26 100644 --- a/docs/userguide/main.md +++ b/docs/userguide/main.md @@ -1221,14 +1221,14 @@ type: Opaque data: # admin username: YWRtaW4= - # admin123 - password: YWRtaW4xMjM= + # 0penS3@rch! + password: MHBlblMzQHJjaCE= ``` Then you have to create your own securityconfig and store it in a secret (`securityconfig-secret` in this example). You can take a look at [securityconfig-secret.yaml](../../opensearch-operator/examples/securityconfig-secret.yaml) for how such a secret should look like. Make sure that the password hash of the admin user corresponds to the password you stored in the `admin-credentials-secret`. -Notice that inside `securityconfig-secret` You must edit the `hash` of the admin user before creating the secret. if you have python 3.x installed on your machine you can use the following command to hash your password: `python -c 'import bcrypt; print(bcrypt.hashpw("admin123".encode("utf-8"), bcrypt.gensalt(12, prefix=b"2a")).decode("utf-8"))'` +Notice that inside `securityconfig-secret` You must edit the `hash` of the admin user before creating the secret. if you have python 3.x installed on your machine you can use the following command to hash your password: `python -c 'import bcrypt; print(bcrypt.hashpw("0penS3@rch!".encode("utf-8"), bcrypt.gensalt(12, prefix=b"2a")).decode("utf-8"))'` ```yaml internal_users.yml: |- diff --git a/opensearch-operator/pkg/builders/cluster.go b/opensearch-operator/pkg/builders/cluster.go index 760a498c..d475fb1e 100644 --- a/opensearch-operator/pkg/builders/cluster.go +++ b/opensearch-operator/pkg/builders/cluster.go @@ -30,13 +30,13 @@ const ( ) func NewSTSForNodePool( - username string, cr *opsterv1.OpenSearchCluster, node opsterv1.NodePool, configChecksum string, volumes []corev1.Volume, volumeMounts []corev1.VolumeMount, extraConfig map[string]string, + envVars []corev1.EnvVar, ) *appsv1.StatefulSet { // To make sure disksize is not passed as empty var disksize string @@ -466,41 +466,13 @@ func NewSTSForNodePool( Spec: corev1.PodSpec{ Containers: []corev1.Container{ { - Env: []corev1.EnvVar{ - { - Name: "cluster.initial_master_nodes", - Value: BootstrapPodName(cr), - }, - { - Name: "discovery.seed_hosts", - Value: DiscoveryServiceName(cr), - }, - { - Name: "cluster.name", - Value: cr.Name, - }, - { - Name: "network.bind_host", - Value: "0.0.0.0", - }, - { - // Make elasticsearch announce its hostname instead of IP so that certificates using the hostname can be verified - Name: "network.publish_host", - ValueFrom: &corev1.EnvVarSource{FieldRef: &corev1.ObjectFieldSelector{APIVersion: "v1", FieldPath: "metadata.name"}}, - }, - { - Name: "OPENSEARCH_JAVA_OPTS", - Value: jvm, - }, - { - Name: "node.roles", - Value: strings.Join(selectedRoles, ","), - }, - { - Name: "http.port", - Value: fmt.Sprint(cr.Spec.General.HttpPort), - }, - }, + Env: append(envVars, corev1.EnvVar{ + Name: "OPENSEARCH_JAVA_OPTS", + Value: jvm, + }, corev1.EnvVar{ + Name: "node.roles", + Value: strings.Join(selectedRoles, ","), + }), Name: "opensearch", Command: mainCommand, Image: image.GetImage(), @@ -757,6 +729,7 @@ func NewBootstrapPod( cr *opsterv1.OpenSearchCluster, volumes []corev1.Volume, volumeMounts []corev1.VolumeMount, + envVars []corev1.EnvVar, ) *corev1.Pod { labels := map[string]string{ helpers.ClusterLabel: cr.Name, @@ -798,41 +771,13 @@ func NewBootstrapPod( podSecurityContext := cr.Spec.General.PodSecurityContext securityContext := cr.Spec.General.SecurityContext - env := []corev1.EnvVar{ - { - Name: "cluster.initial_master_nodes", - Value: BootstrapPodName(cr), - }, - { - Name: "discovery.seed_hosts", - Value: DiscoveryServiceName(cr), - }, - { - Name: "cluster.name", - Value: cr.Name, - }, - { - Name: "network.bind_host", - Value: "0.0.0.0", - }, - { - // Make elasticsearch announce its hostname instead of IP so that certificates using the hostname can be verified - Name: "network.publish_host", - ValueFrom: &corev1.EnvVarSource{FieldRef: &corev1.ObjectFieldSelector{APIVersion: "v1", FieldPath: "metadata.name"}}, - }, - { - Name: "OPENSEARCH_JAVA_OPTS", - Value: jvm, - }, - { - Name: "node.roles", - Value: masterRole, - }, - { - Name: "http.port", - Value: fmt.Sprint(cr.Spec.General.HttpPort), - }, - } + env := append(envVars, corev1.EnvVar{ + Name: "OPENSEARCH_JAVA_OPTS", + Value: jvm, + }, corev1.EnvVar{ + Name: "node.roles", + Value: masterRole, + }) // Append additional config to env vars, use General.AdditionalConfig by default, overwrite with Bootstrap.AdditionalConfig extraConfig := cr.Spec.General.AdditionalConfig @@ -981,6 +926,47 @@ func STSInNodePools(sts appsv1.StatefulSet, nodepools []opsterv1.NodePool) bool return false } +func CommonEnvVars(cr *opsterv1.OpenSearchCluster, passwordSecretName string) []corev1.EnvVar { + return []corev1.EnvVar{ + { + Name: "cluster.initial_master_nodes", + Value: BootstrapPodName(cr), + }, + { + Name: "discovery.seed_hosts", + Value: DiscoveryServiceName(cr), + }, + { + Name: "cluster.name", + Value: cr.Name, + }, + { + Name: "network.bind_host", + Value: "0.0.0.0", + }, + { + // Make OpenSearch announce its hostname instead of IP so that certificates using the hostname can be verified + Name: "network.publish_host", + ValueFrom: &corev1.EnvVarSource{FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.name", + }}, + }, + { + Name: "OPENSEARCH_INITIAL_ADMIN_PASSWORD", + ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: passwordSecretName}, + Key: "password", + Optional: pointer.Bool(false), + }}, + }, + { + Name: "http.port", + Value: fmt.Sprint(cr.Spec.General.HttpPort), + }, + } +} + func NewSecurityconfigUpdateJob( instance *opsterv1.OpenSearchCluster, jobName string, diff --git a/opensearch-operator/pkg/builders/cluster_test.go b/opensearch-operator/pkg/builders/cluster_test.go index c7f22c53..2fb9414d 100644 --- a/opensearch-operator/pkg/builders/cluster_test.go +++ b/opensearch-operator/pkg/builders/cluster_test.go @@ -59,25 +59,25 @@ var _ = Describe("Builders", func() { When("Constructing a STS for a NodePool", func() { It("should include the init containers as SKIP_INIT_CONTAINER is not set", func() { clusterObject := ClusterDescWithVersion("2.2.1") - result := NewSTSForNodePool("foobar", &clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(len(result.Spec.Template.Spec.InitContainers)).To(Equal(1)) }) It("should skip the init container as SKIP_INIT_CONTAINER is set", func() { _ = os.Setenv(helpers.SkipInitContainerEnvVariable, "true") clusterObject := ClusterDescWithVersion("2.2.1") - result := NewSTSForNodePool("foobar", &clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(len(result.Spec.Template.Spec.InitContainers)).To(Equal(0)) _ = os.Unsetenv(helpers.SkipInitContainerEnvVariable) }) It("should include the init containers as SKIP_INIT_CONTAINER is not set", func() { clusterObject := ClusterDescWithVersion("2.2.1") - result := NewBootstrapPod(&clusterObject, nil, nil) + result := NewBootstrapPod(&clusterObject, nil, nil, []corev1.EnvVar{}) Expect(len(result.Spec.InitContainers)).To(Equal(1)) }) It("should skip the init container as SKIP_INIT_CONTAINER is set", func() { _ = os.Setenv(helpers.SkipInitContainerEnvVariable, "true") clusterObject := ClusterDescWithVersion("2.2.1") - result := NewBootstrapPod(&clusterObject, nil, nil) + result := NewBootstrapPod(&clusterObject, nil, nil, []corev1.EnvVar{}) Expect(len(result.Spec.InitContainers)).To(Equal(0)) _ = os.Unsetenv(helpers.SkipInitContainerEnvVariable) }) @@ -87,7 +87,7 @@ var _ = Describe("Builders", func() { Component: "masters", Roles: []string{"cluster_manager", "foobar", "ingest"}, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: "node.roles", Value: "cluster_manager,ingest", @@ -99,7 +99,7 @@ var _ = Describe("Builders", func() { Component: "masters", Roles: []string{"master"}, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: "node.roles", Value: "cluster_manager", @@ -111,7 +111,7 @@ var _ = Describe("Builders", func() { Component: "masters", Roles: []string{"cluster_manager"}, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: "node.roles", Value: "master", @@ -126,7 +126,7 @@ var _ = Describe("Builders", func() { "testAnnotationKey": "testAnnotationValue", }, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Annotations).To(Equal(map[string]string{ ConfigurationChecksumAnnotation: "foobar", "testAnnotationKey": "testAnnotationValue", @@ -141,7 +141,7 @@ var _ = Describe("Builders", func() { "testAnnotationKey": "testAnnotationValue", }, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Annotations).To(Equal(map[string]string{ ConfigurationChecksumAnnotation: "foobar", "testAnnotationKey": "testAnnotationValue", @@ -154,14 +154,14 @@ var _ = Describe("Builders", func() { Roles: []string{"cluster_manager"}, PriorityClassName: "default", } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.PriorityClassName).To(Equal("default")) }) It("should use General.DefaultRepo for the InitHelper image if configured", func() { clusterObject := ClusterDescWithVersion("2.2.1") customRepository := "mycustomrepo.cr" clusterObject.Spec.General.DefaultRepo = &customRepository - result := NewSTSForNodePool("foobar", &clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.InitContainers[0].Image).To(Equal("mycustomrepo.cr/busybox:latest")) }) It("should use InitHelper.Image as InitHelper image if configured", func() { @@ -172,12 +172,12 @@ var _ = Describe("Builders", func() { Image: &customImage, }, } - result := NewSTSForNodePool("foobar", &clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.InitContainers[0].Image).To(Equal("mycustomrepo.cr/custombusybox:1.2.3")) }) It("should use defaults when no custom image is configured for InitHelper image", func() { clusterObject := ClusterDescWithVersion("2.2.1") - result := NewSTSForNodePool("foobar", &clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.InitContainers[0].Image).To(Equal("docker.io/busybox:latest")) }) It("should use a custom dns name when env variable is set as cluster url", func() { @@ -205,7 +205,7 @@ var _ = Describe("Builders", func() { pluginB := "another-plugin" clusterObject.Spec.General.PluginsList = []string{pluginA, pluginB} - result := NewSTSForNodePool("foobar", &clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil, []corev1.EnvVar{}) installCmd := fmt.Sprintf( "./bin/opensearch-plugin install --batch '%s' '%s' && ./opensearch-docker-entrypoint.sh", @@ -230,7 +230,7 @@ var _ = Describe("Builders", func() { Component: "masters", Roles: []string{"search"}, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, CommonEnvVars(&clusterObject, "")) Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: "node.roles", Value: "search", @@ -248,7 +248,7 @@ var _ = Describe("Builders", func() { Component: "masters", Roles: []string{"search"}, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, CommonEnvVars(&clusterObject, "")) Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: "node.roles", Value: "search", @@ -280,7 +280,7 @@ var _ = Describe("Builders", func() { Roles: []string{"cluster_manager", "data"}, } clusterObject.Spec.NodePools = append(clusterObject.Spec.NodePools, nodePool) - result := NewSTSForNodePool("foobar", &clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.SecurityContext).To(Equal(podSecurityContext)) Expect(result.Spec.Template.Spec.Containers[0].SecurityContext).To(Equal(securityContext)) }) @@ -297,7 +297,7 @@ var _ = Describe("Builders", func() { }}, } clusterObject.Spec.NodePools = append(clusterObject.Spec.NodePools, nodePool) - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) var expected *string = nil actual := result.Spec.VolumeClaimTemplates[0].Spec.StorageClassName Expect(expected).To(Equal(actual)) @@ -311,7 +311,7 @@ var _ = Describe("Builders", func() { }, }, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: "OPENSEARCH_JAVA_OPTS", Value: "-Xmx1024M -Xms1024M -Dopensearch.transport.cname_in_publish_address=true", @@ -326,7 +326,7 @@ var _ = Describe("Builders", func() { }, }, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: "OPENSEARCH_JAVA_OPTS", Value: "-Xmx768M -Xms768M -Dopensearch.transport.cname_in_publish_address=true", @@ -342,7 +342,7 @@ var _ = Describe("Builders", func() { }, }, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: "OPENSEARCH_JAVA_OPTS", Value: "-Xmx953M -Xms953M -Dopensearch.transport.cname_in_publish_address=true", @@ -351,7 +351,7 @@ var _ = Describe("Builders", func() { It("should set jvm to default when memory request and jvm are not provided", func() { clusterObject := ClusterDescWithVersion("2.2.1") nodePool := opsterv1.NodePool{} - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: "OPENSEARCH_JAVA_OPTS", Value: "-Xmx512M -Xms512M -Dopensearch.transport.cname_in_publish_address=true", @@ -362,7 +362,7 @@ var _ = Describe("Builders", func() { nodePool := opsterv1.NodePool{ Jvm: "-Xmx1024M -Xms1024M", } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: "OPENSEARCH_JAVA_OPTS", Value: "-Xmx1024M -Xms1024M -Dopensearch.transport.cname_in_publish_address=true", @@ -378,7 +378,7 @@ var _ = Describe("Builders", func() { }, }, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: "OPENSEARCH_JAVA_OPTS", Value: "-Xmx1024M -Xms1024M -Dopensearch.transport.cname_in_publish_address=true", @@ -391,7 +391,7 @@ var _ = Describe("Builders", func() { clusterObject := ClusterDescWithVersion("2.2.1") customRepository := "mycustomrepo.cr" clusterObject.Spec.General.DefaultRepo = &customRepository - result := NewBootstrapPod(&clusterObject, nil, nil) + result := NewBootstrapPod(&clusterObject, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.InitContainers[0].Image).To(Equal("mycustomrepo.cr/busybox:latest")) }) @@ -402,7 +402,7 @@ var _ = Describe("Builders", func() { mockKey: "/opensearch-operated", } clusterObject := ClusterDescWithAdditionalConfigs(nil, mockConfig) - result := NewBootstrapPod(&clusterObject, nil, nil) + result := NewBootstrapPod(&clusterObject, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: mockKey, @@ -410,6 +410,28 @@ var _ = Describe("Builders", func() { })) }) + It("should include OPENSEARCH_INITIAL_ADMIN_PASSWORD env var pointing to the supplied secret name", func() { + mockKey := "server.basePath" + mockSecretName := "fake-secret" + + mockConfig := map[string]string{ + mockKey: "/opensearch-operated", + } + clusterObject := ClusterDescWithAdditionalConfigs(mockConfig, nil) + result := NewBootstrapPod(&clusterObject, nil, nil, CommonEnvVars(&clusterObject, mockSecretName)) + + Expect(result.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ + Name: "OPENSEARCH_INITIAL_ADMIN_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: mockSecretName}, + Key: "password", + Optional: pointer.Bool(false), + }, + }, + })) + }) + It("should apply the General.AdditionalConfig to the env variables if not overwritten", func() { mockKey := "server.basePath" @@ -417,7 +439,7 @@ var _ = Describe("Builders", func() { mockKey: "/opensearch-operated", } clusterObject := ClusterDescWithAdditionalConfigs(mockConfig, nil) - result := NewBootstrapPod(&clusterObject, nil, nil) + result := NewBootstrapPod(&clusterObject, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{ Name: mockKey, @@ -437,7 +459,7 @@ var _ = Describe("Builders", func() { } clusterObject := ClusterDescWithAdditionalConfigs(mockGeneralConfig, mockBootstrapConfig) - result := NewBootstrapPod(&clusterObject, nil, nil) + result := NewBootstrapPod(&clusterObject, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Containers[0].Env).NotTo(ContainElement(corev1.EnvVar{ Name: mockKey1, @@ -460,7 +482,7 @@ var _ = Describe("Builders", func() { Roles: []string{"cluster_manager", "foobar", "ingest"}, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.InitContainers[1].VolumeMounts).To(ContainElements([]corev1.VolumeMount{ { Name: "keystore", @@ -480,7 +502,7 @@ var _ = Describe("Builders", func() { Component: "masters", Roles: []string{"cluster_manager", "foobar", "ingest"}, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].VolumeMounts).To(ContainElement(corev1.VolumeMount{ Name: "keystore", MountPath: "/usr/share/opensearch/config/opensearch.keystore", @@ -501,7 +523,7 @@ var _ = Describe("Builders", func() { Component: "masters", Roles: []string{"cluster_manager", "foobar", "ingest"}, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.InitContainers[1].VolumeMounts).To(ContainElement(corev1.VolumeMount{ Name: "keystore-" + mockSecretName, MountPath: "/tmp/keystoreSecrets/" + mockSecretName + "/" + newKey, @@ -525,7 +547,7 @@ var _ = Describe("Builders", func() { } clusterObject.Spec.NodePools = append(clusterObject.Spec.NodePools, nodePool) - sts := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + sts := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) sts.Status.ReadyReplicas = 2 Expect(k8sClient.Create(context.Background(), sts)).To(Not(HaveOccurred())) result := AllMastersReady(context.Background(), k8sClient, &clusterObject) @@ -546,7 +568,7 @@ var _ = Describe("Builders", func() { } clusterObject.Spec.NodePools = append(clusterObject.Spec.NodePools, nodePool) - sts := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + sts := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) sts.Status.ReadyReplicas = 2 Expect(k8sClient.Create(context.Background(), sts)).To(Not(HaveOccurred())) result := AllMastersReady(context.Background(), k8sClient, &clusterObject) @@ -567,7 +589,7 @@ var _ = Describe("Builders", func() { } clusterObject.Spec.NodePools = append(clusterObject.Spec.NodePools, nodePool) - sts := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + sts := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) sts.Status.ReadyReplicas = 2 Expect(k8sClient.Create(context.Background(), sts)).To(Not(HaveOccurred())) result := AllMastersReady(context.Background(), k8sClient, &clusterObject) @@ -590,7 +612,7 @@ var _ = Describe("Builders", func() { } clusterObject.Spec.NodePools = append(clusterObject.Spec.NodePools, nodePool) - sts := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + sts := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(sts.Spec.Template.Spec.Containers[0].Command[2]).To(Equal(customCommand)) }) }) @@ -609,7 +631,7 @@ var _ = Describe("Builders", func() { } clusterObject.Spec.NodePools = append(clusterObject.Spec.NodePools, nodePool) - sts := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + sts := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(sts.Spec.Template.Spec.ServiceAccountName).To(Equal(serviceAccount)) job := NewSecurityconfigUpdateJob(&clusterObject, "foobar", "foobar", "foobar", "admin-cert", "cmd", nil, nil) @@ -675,7 +697,7 @@ var _ = Describe("Builders", func() { Component: "masters", Roles: []string{"search"}, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].LivenessProbe.InitialDelaySeconds).To(Equal(int32(10))) Expect(result.Spec.Template.Spec.Containers[0].LivenessProbe.TimeoutSeconds).To(Equal(int32(5))) Expect(result.Spec.Template.Spec.Containers[0].LivenessProbe.PeriodSeconds).To(Equal(int32(20))) @@ -711,7 +733,7 @@ var _ = Describe("Builders", func() { }, }, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].LivenessProbe.InitialDelaySeconds).To(Equal(int32(10))) Expect(result.Spec.Template.Spec.Containers[0].LivenessProbe.TimeoutSeconds).To(Equal(int32(5))) Expect(result.Spec.Template.Spec.Containers[0].LivenessProbe.PeriodSeconds).To(Equal(int32(20))) @@ -758,7 +780,7 @@ var _ = Describe("Builders", func() { }, }, } - result := NewSTSForNodePool("foobar", &clusterObject, nodePool, "foobar", nil, nil, nil) + result := NewSTSForNodePool(&clusterObject, nodePool, "foobar", nil, nil, nil, []corev1.EnvVar{}) Expect(result.Spec.Template.Spec.Containers[0].LivenessProbe.InitialDelaySeconds).To(Equal(int32(12))) Expect(result.Spec.Template.Spec.Containers[0].LivenessProbe.TimeoutSeconds).To(Equal(int32(6))) Expect(result.Spec.Template.Spec.Containers[0].LivenessProbe.PeriodSeconds).To(Equal(int32(25))) @@ -777,7 +799,7 @@ var _ = Describe("Builders", func() { Expect(result.Spec.Template.Spec.Containers[0].ReadinessProbe.FailureThreshold).To(Equal(int32(9))) }) }) - + When("Configuring InitHelper Resources", func() { It("should propagate Resources to all init containers", func() { clusterObject := ClusterDescWithVersion("2.2.1") @@ -793,11 +815,11 @@ var _ = Describe("Builders", func() { }, }, } - nodePoolSts := NewSTSForNodePool("foobar", &clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil) + nodePoolSts := NewSTSForNodePool(&clusterObject, opsterv1.NodePool{}, "foobar", nil, nil, nil, []corev1.EnvVar{}) for _, container := range nodePoolSts.Spec.Template.Spec.InitContainers { Expect(container.Resources).To(Equal(clusterObject.Spec.InitHelper.Resources)) } - bootstrapPod := NewBootstrapPod(&clusterObject, nil, nil) + bootstrapPod := NewBootstrapPod(&clusterObject, nil, nil, []corev1.EnvVar{}) for _, container := range bootstrapPod.Spec.InitContainers { Expect(container.Resources).To(Equal(clusterObject.Spec.InitHelper.Resources)) } diff --git a/opensearch-operator/pkg/builders/dashboards.go b/opensearch-operator/pkg/builders/dashboards.go index 94f2efd4..98190b69 100644 --- a/opensearch-operator/pkg/builders/dashboards.go +++ b/opensearch-operator/pkg/builders/dashboards.go @@ -15,7 +15,7 @@ import ( /// Package that declare and build all the resources that related to the OpenSearch-Dashboard /// -func NewDashboardsDeploymentForCR(cr *opsterv1.OpenSearchCluster, volumes []corev1.Volume, volumeMounts []corev1.VolumeMount, annotations map[string]string) *appsv1.Deployment { +func NewDashboardsDeploymentForCR(cr *opsterv1.OpenSearchCluster, volumes []corev1.Volume, volumeMounts []corev1.VolumeMount, annotations map[string]string, secretName string) *appsv1.Deployment { var replicas int32 = cr.Spec.Dashboards.Replicas var port int32 = 5601 var mode int32 = 420 @@ -62,8 +62,28 @@ func NewDashboardsDeploymentForCR(cr *opsterv1.OpenSearchCluster, volumes []core env = append(env, corev1.EnvVar{Name: "OPENSEARCH_PASSWORD", ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: cr.Spec.Dashboards.OpensearchCredentialsSecret, Key: "password"}}}) } else { // Default values from demo configuration - env = append(env, corev1.EnvVar{Name: "OPENSEARCH_USERNAME", Value: "admin"}) - env = append(env, corev1.EnvVar{Name: "OPENSEARCH_PASSWORD", Value: "admin"}) + env = append(env, corev1.EnvVar{ + Name: "OPENSEARCH_USERNAME", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: secretName, + }, + Key: "username", + }, + }, + }) + env = append(env, corev1.EnvVar{ + Name: "OPENSEARCH_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: secretName, + }, + Key: "password", + }, + }, + }) } labels := map[string]string{ diff --git a/opensearch-operator/pkg/builders/dashboards_test.go b/opensearch-operator/pkg/builders/dashboards_test.go index d7ce5dd9..01193608 100644 --- a/opensearch-operator/pkg/builders/dashboards_test.go +++ b/opensearch-operator/pkg/builders/dashboards_test.go @@ -29,7 +29,7 @@ var _ = Describe("Builders", func() { }, }, } - result := NewDashboardsDeploymentForCR(&spec, nil, nil, nil) + result := NewDashboardsDeploymentForCR(&spec, nil, nil, nil, "") Expect(result.Spec.Template.Annotations).To(Equal(map[string]string{ "testAnnotationKey": "testValue", "testAnnotationKey2": "testValue2", @@ -52,7 +52,7 @@ var _ = Describe("Builders", func() { }, }, } - result := NewDashboardsDeploymentForCR(&spec, nil, nil, nil) + result := NewDashboardsDeploymentForCR(&spec, nil, nil, nil, "") Expect(result.Spec.Template.Labels).To(Equal(map[string]string{ "opensearch.cluster.dashboards": clusterName, "testLabelKey": "testValue", @@ -108,7 +108,7 @@ var _ = Describe("Builders", func() { }, } - result := NewDashboardsDeploymentForCR(&spec, nil, nil, nil) + result := NewDashboardsDeploymentForCR(&spec, nil, nil, nil, "") installCmd := fmt.Sprintf( "./bin/opensearch-dashboards-plugin install '%s' && ./bin/opensearch-dashboards-plugin install '%s' && ./opensearch-dashboards-docker-entrypoint.sh", pluginA, @@ -148,7 +148,7 @@ var _ = Describe("Builders", func() { }, }, } - result := NewDashboardsDeploymentForCR(&spec, nil, nil, nil) + result := NewDashboardsDeploymentForCR(&spec, nil, nil, nil, "") Expect(result.Spec.Template.Spec.SecurityContext).To(Equal(podSecurityContext)) Expect(result.Spec.Template.Spec.Containers[0].SecurityContext).To(Equal(securityContext)) }) @@ -169,7 +169,7 @@ var _ = Describe("Builders", func() { }, }, } - result := NewDashboardsDeploymentForCR(&spec, nil, nil, nil) + result := NewDashboardsDeploymentForCR(&spec, nil, nil, nil, "") Expect(result.Spec.Template.Spec.ServiceAccountName).To(Equal(serviceAccountName)) }) }) diff --git a/opensearch-operator/pkg/helpers/helpers.go b/opensearch-operator/pkg/helpers/helpers.go index 7795f260..319e0929 100644 --- a/opensearch-operator/pkg/helpers/helpers.go +++ b/opensearch-operator/pkg/helpers/helpers.go @@ -112,7 +112,9 @@ func UsernameAndPassword(k8sClient k8s.K8sClient, cr *opsterv1.OpenSearchCluster return string(username), string(password), nil } else { // Use default demo credentials - return "admin", "admin", nil + // minimum 8 character password and must contain at least one uppercase letter, + // one lowercase letter, one digit, and one special character + return "admin", "0penS3@rch!", nil } } diff --git a/opensearch-operator/pkg/reconcilers/cluster.go b/opensearch-operator/pkg/reconcilers/cluster.go index 6cea13bf..dbcc2093 100644 --- a/opensearch-operator/pkg/reconcilers/cluster.go +++ b/opensearch-operator/pkg/reconcilers/cluster.go @@ -3,6 +3,7 @@ package reconcilers import ( "context" "fmt" + corev1 "k8s.io/api/core/v1" "strings" "github.com/Opster/opensearch-k8s-operator/opensearch-operator/pkg/reconcilers/k8s" @@ -95,7 +96,9 @@ func (r *ClusterReconciler) Reconcile() (ctrl.Result, error) { result.CombineErr(ctrl.SetControllerReference(r.instance, passwordSecret, r.client.Scheme())) result.Combine(r.client.ReconcileResource(passwordSecret, reconciler.StatePresent)) - bootstrapPod := builders.NewBootstrapPod(r.instance, r.reconcilerContext.Volumes, r.reconcilerContext.VolumeMounts) + commonEnvVars := builders.CommonEnvVars(r.instance, passwordSecret.Name) + + bootstrapPod := builders.NewBootstrapPod(r.instance, r.reconcilerContext.Volumes, r.reconcilerContext.VolumeMounts, commonEnvVars) result.CombineErr(ctrl.SetControllerReference(r.instance, bootstrapPod, r.client.Scheme())) if r.instance.Status.Initialized { result.Combine(r.client.ReconcileResource(bootstrapPod, reconciler.StateAbsent)) @@ -108,7 +111,7 @@ func (r *ClusterReconciler) Reconcile() (ctrl.Result, error) { result.CombineErr(ctrl.SetControllerReference(r.instance, headlessService, r.client.Scheme())) result.Combine(r.client.ReconcileResource(headlessService, reconciler.StatePresent)) - result.Combine(r.reconcileNodeStatefulSet(nodePool, username)) + result.Combine(r.reconcileNodeStatefulSet(nodePool, commonEnvVars)) } // if Version isn't set we set it now to check for upgrades later. @@ -130,7 +133,7 @@ func (r *ClusterReconciler) Reconcile() (ctrl.Result, error) { return result.Result, result.Err } -func (r *ClusterReconciler) reconcileNodeStatefulSet(nodePool opsterv1.NodePool, username string) (*ctrl.Result, error) { +func (r *ClusterReconciler) reconcileNodeStatefulSet(nodePool opsterv1.NodePool, envVars []corev1.EnvVar) (*ctrl.Result, error) { found, nodePoolConfig := r.reconcilerContext.fetchNodePoolHash(nodePool.Component) // If config hasn't been set up for the node pool requeue @@ -143,13 +146,13 @@ func (r *ClusterReconciler) reconcileNodeStatefulSet(nodePool opsterv1.NodePool, extraConfig := helpers.MergeConfigs(r.instance.Spec.General.AdditionalConfig, nodePool.AdditionalConfig) sts := builders.NewSTSForNodePool( - username, r.instance, nodePool, nodePoolConfig.ConfigHash, r.reconcilerContext.Volumes, r.reconcilerContext.VolumeMounts, extraConfig, + envVars, ) if err := ctrl.SetControllerReference(r.instance, sts, r.client.Scheme()); err != nil { return &ctrl.Result{}, err diff --git a/opensearch-operator/pkg/reconcilers/dashboards.go b/opensearch-operator/pkg/reconcilers/dashboards.go index 295aa843..5d5507a2 100644 --- a/opensearch-operator/pkg/reconcilers/dashboards.go +++ b/opensearch-operator/pkg/reconcilers/dashboards.go @@ -91,7 +91,12 @@ func (r *DashboardsReconciler) Reconcile() (ctrl.Result, error) { annotations[helpers.DashboardChecksumName] = sha1sum } - deployment := builders.NewDashboardsDeploymentForCR(r.instance, volumes, volumeMounts, annotations) + username, password, err := helpers.UsernameAndPassword(r.client, r.instance) + if err != nil { + return ctrl.Result{}, err + } + passwordSecret := builders.PasswordSecret(r.instance, username, password).Name + deployment := builders.NewDashboardsDeploymentForCR(r.instance, volumes, volumeMounts, annotations, passwordSecret) result.CombineErr(ctrl.SetControllerReference(r.instance, deployment, r.client.Scheme())) result.Combine(r.client.CreateDeployment(deployment))