diff --git a/pkg/controller/common/password/password.go b/pkg/controller/common/password/password.go index 86a0071592..12ee29ae95 100644 --- a/pkg/controller/common/password/password.go +++ b/pkg/controller/common/password/password.go @@ -24,14 +24,15 @@ const ( // Digits is the list of permitted digits. Digits = "0123456789" - - // Symbols is the list of symbols. - Symbols = "~!@#$%^&*()_+`-={}|[]\\:\"<>?,./" ) var ( - defaultCharacterSet = strings.Join([]string{LowerLetters, UpperLetters, Digits, Symbols}, "") characterSetWithoutSymbols = strings.Join([]string{LowerLetters, UpperLetters, Digits}, "") + + // defaultCharacterSet is the default character set used for generating passwords. + // It includes lowercase letters, uppercase letters and digits, but excludes symbols. + // This is to ensure compatibility with configurations which do not offer a way to escape symbols. + defaultCharacterSet = characterSetWithoutSymbols ) // RandomGenerator is an interface for generating random passwords. @@ -63,7 +64,7 @@ func (r *randomPasswordGenerator) Generate(ctx context.Context) ([]byte, error) } // NewGenerator returns a password generator with the specified length. -// All character types (lowercase, uppercase, digits, symbols) are always used. +// All character types (lowercase, uppercase, digits) except symbols are used. func NewGenerator( client k8s.Client, passwordLength int, diff --git a/pkg/controller/common/stackmon/config.go b/pkg/controller/common/stackmon/config.go index a5fa19a620..f7708371ce 100644 --- a/pkg/controller/common/stackmon/config.go +++ b/pkg/controller/common/stackmon/config.go @@ -7,6 +7,7 @@ package stackmon import ( "bytes" "context" + "encoding/json" "fmt" "hash" "hash/fnv" @@ -203,6 +204,13 @@ func TemplateFuncs( version semver.Version, ) template.FuncMap { return template.FuncMap{ + "sanitizeJSON": func(v any) (string, error) { + b, err := json.Marshal(v) + if err != nil { + return "", fmt.Errorf("json marshal failed: %w", err) + } + return string(b), nil + }, "isVersionGTE": func(minAllowedVersion string) (bool, error) { minAllowedSemver, err := semver.Parse(minAllowedVersion) if err != nil { diff --git a/pkg/controller/elasticsearch/stackmon/__snapshots__/sidecar_test.snap b/pkg/controller/elasticsearch/stackmon/__snapshots__/sidecar_test.snap index c83f4c0eda..dd0b79a61d 100755 --- a/pkg/controller/elasticsearch/stackmon/__snapshots__/sidecar_test.snap +++ b/pkg/controller/elasticsearch/stackmon/__snapshots__/sidecar_test.snap @@ -20,7 +20,7 @@ metricbeat.modules: xpack.enabled: true hosts: ["https://localhost:9200"] username: elastic - password: secret + password: "secret" ssl.enabled: true # The ssl verification_mode is set to `certificate` in the config template to verify that the certificate is signed by a trusted authority, # but does not perform any hostname verification. This is used when SSL is enabled with or without CA, to support self-signed certificate @@ -57,7 +57,7 @@ metricbeat.modules: xpack.enabled: true hosts: ["https://localhost:9200"] username: elastic - password: secret + password: "secret" ssl.enabled: true # The ssl verification_mode is set to `certificate` in the config template to verify that the certificate is signed by a trusted authority, # but does not perform any hostname verification. This is used when SSL is enabled with or without CA, to support self-signed certificate @@ -94,7 +94,7 @@ metricbeat.modules: xpack.enabled: true hosts: ["https://localhost:9200"] username: elastic - password: secret + password: "secret" ssl.enabled: true # The ssl verification_mode is set to `certificate` in the config template to verify that the certificate is signed by a trusted authority, # but does not perform any hostname verification. This is used when SSL is enabled with or without CA, to support self-signed certificate @@ -133,7 +133,7 @@ metricbeat.modules: xpack.enabled: true hosts: ["https://localhost:9200"] username: elastic - password: secret + password: "secret" ssl.enabled: false # The ssl verification_mode is set to `certificate` in the config template to verify that the certificate is signed by a trusted authority, # but does not perform any hostname verification. This is used when SSL is enabled with or without CA, to support self-signed certificate @@ -170,7 +170,7 @@ metricbeat.modules: xpack.enabled: true hosts: ["https://localhost:9200"] username: elastic - password: secret + password: "secret" ssl.enabled: true # The ssl verification_mode is set to `certificate` in the config template to verify that the certificate is signed by a trusted authority, # but does not perform any hostname verification. This is used when SSL is enabled with or without CA, to support self-signed certificate @@ -207,7 +207,7 @@ setup.template.settings: { "metadata": { "annotations": { - "elasticsearch.k8s.elastic.co/monitoring-config-hash": "421654492" + "elasticsearch.k8s.elastic.co/monitoring-config-hash": "3826168075" } }, "spec": { @@ -471,7 +471,7 @@ setup.template.settings: { "metadata": { "annotations": { - "elasticsearch.k8s.elastic.co/monitoring-config-hash": "1805099278" + "elasticsearch.k8s.elastic.co/monitoring-config-hash": "3784706159" } }, "spec": { @@ -707,7 +707,7 @@ setup.template.settings: { "metadata": { "annotations": { - "elasticsearch.k8s.elastic.co/monitoring-config-hash": "1086800329" + "elasticsearch.k8s.elastic.co/monitoring-config-hash": "3685568186" } }, "spec": { diff --git a/pkg/controller/elasticsearch/stackmon/metricbeat.tpl.yml b/pkg/controller/elasticsearch/stackmon/metricbeat.tpl.yml index 8a34c8bf5c..31fda7108e 100644 --- a/pkg/controller/elasticsearch/stackmon/metricbeat.tpl.yml +++ b/pkg/controller/elasticsearch/stackmon/metricbeat.tpl.yml @@ -21,7 +21,7 @@ metricbeat.modules: xpack.enabled: true hosts: ["{{ .URL }}"] username: {{ .Username }} - password: {{ .Password }} + password: {{ sanitizeJSON .Password }} ssl.enabled: {{ .IsSSL }} # The ssl verification_mode is set to `certificate` in the config template to verify that the certificate is signed by a trusted authority, # but does not perform any hostname verification. This is used when SSL is enabled with or without CA, to support self-signed certificate diff --git a/pkg/controller/enterprisesearch/config.go b/pkg/controller/enterprisesearch/config.go index 6174976547..d443b03cd7 100644 --- a/pkg/controller/enterprisesearch/config.go +++ b/pkg/controller/enterprisesearch/config.go @@ -118,15 +118,15 @@ func readinessProbeScript(ent entv1.EnterpriseSearch, config *settings.Canonical } basicAuthArgs := "" // no credentials: no basic auth if esAuth.Elasticsearch.Username != "" { - basicAuthArgs = fmt.Sprintf("-u %s:%s", esAuth.Elasticsearch.Username, esAuth.Elasticsearch.Password) + basicAuthArgs = fmt.Sprintf("-u %s:'%s'", esAuth.Elasticsearch.Username, esAuth.Elasticsearch.Password) } return []byte(`#!/usr/bin/env bash # fail should be called as a last resort to help the user to understand why the probe failed function fail { - timestamp=$(date --iso-8601=seconds) - echo "{\"timestamp\": \"${timestamp}\", \"message\": \"readiness probe failed\", "$1"}" | tee /proc/1/fd/2 2> /dev/null + timestamp=$(date +%Y-%m-%dT%H:%M:%S%z) + echo '{"timestamp": "'"${timestamp}"'", "message": "readiness probe failed", '"${1}"'}'| tee /proc/1/fd/2 2> /dev/null exit 1 } @@ -134,7 +134,7 @@ func readinessProbeScript(ent entv1.EnterpriseSearch, config *settings.Canonical READINESS_PROBE_TIMEOUT=${READINESS_PROBE_TIMEOUT:=` + fmt.Sprintf("%d", ReadinessProbeTimeoutSec) + `} # request the health endpoint and expect http status code 200. Turning globbing off for unescaped IPv6 addresses - status=$(curl -g -o /dev/null -w "%{http_code}" ` + url + ` ` + basicAuthArgs + ` -k -s --max-time ${READINESS_PROBE_TIMEOUT}) + status=$(curl -g -o /dev/null -w "%{http_code}" ` + url + ` ` + basicAuthArgs + ` -k -s --max-time "${READINESS_PROBE_TIMEOUT}") curl_rc=$? if [[ ${curl_rc} -ne 0 ]]; then @@ -144,7 +144,7 @@ func readinessProbeScript(ent entv1.EnterpriseSearch, config *settings.Canonical if [[ ${status} == "200" ]]; then exit 0 else - fail " \"status\": \"${status}\", \"version\":\"${version}\" " + fail " \"status\": \"${status}\" " fi `), nil } diff --git a/pkg/controller/enterprisesearch/config_test.go b/pkg/controller/enterprisesearch/config_test.go index 1bd25de9e6..b833ed689e 100644 --- a/pkg/controller/enterprisesearch/config_test.go +++ b/pkg/controller/enterprisesearch/config_test.go @@ -790,7 +790,7 @@ func TestReconcileConfig_ReadinessProbe(t *testing.T) { }, }, ipFamily: corev1.IPv4Protocol, - wantCmd: `curl -g -o /dev/null -w "%{http_code}" https://127.0.0.1:3002/api/ent/v1/internal/health -k -s --max-time ${READINESS_PROBE_TIMEOUT}`, // no ES basic auth + wantCmd: `curl -g -o /dev/null -w "%{http_code}" https://127.0.0.1:3002/api/ent/v1/internal/health -k -s --max-time "${READINESS_PROBE_TIMEOUT}"`, // no ES basic auth }, { name: "create default readiness probe script (no es association, IPv6)", @@ -805,7 +805,7 @@ func TestReconcileConfig_ReadinessProbe(t *testing.T) { }, }, ipFamily: corev1.IPv6Protocol, - wantCmd: `curl -g -o /dev/null -w "%{http_code}" https://[::1]:3002/api/ent/v1/internal/health -k -s --max-time ${READINESS_PROBE_TIMEOUT}`, // no ES basic auth + wantCmd: `curl -g -o /dev/null -w "%{http_code}" https://[::1]:3002/api/ent/v1/internal/health -k -s --max-time "${READINESS_PROBE_TIMEOUT}"`, // no ES basic auth }, { name: "update existing readiness probe script if different", @@ -830,7 +830,7 @@ func TestReconcileConfig_ReadinessProbe(t *testing.T) { }, }, ipFamily: corev1.IPv4Protocol, - wantCmd: `curl -g -o /dev/null -w "%{http_code}" https://127.0.0.1:3002/api/ent/v1/internal/health -k -s --max-time ${READINESS_PROBE_TIMEOUT}`, // no ES basic auth + wantCmd: `curl -g -o /dev/null -w "%{http_code}" https://127.0.0.1:3002/api/ent/v1/internal/health -k -s --max-time "${READINESS_PROBE_TIMEOUT}"`, // no ES basic auth }, { name: "with ES association: use ES user credentials", @@ -853,7 +853,7 @@ func TestReconcileConfig_ReadinessProbe(t *testing.T) { }, }, ipFamily: corev1.IPv4Protocol, - wantCmd: `curl -g -o /dev/null -w "%{http_code}" https://127.0.0.1:3002/api/ent/v1/internal/health -u ns-sample-ent-user:password -k -s --max-time ${READINESS_PROBE_TIMEOUT}`, + wantCmd: `curl -g -o /dev/null -w "%{http_code}" https://127.0.0.1:3002/api/ent/v1/internal/health -u ns-sample-ent-user:'password' -k -s --max-time "${READINESS_PROBE_TIMEOUT}"`, }, { name: "with es credentials in a user-provided config secret", @@ -881,7 +881,7 @@ func TestReconcileConfig_ReadinessProbe(t *testing.T) { }, }, ipFamily: corev1.IPv4Protocol, - wantCmd: `curl -g -o /dev/null -w "%{http_code}" https://127.0.0.1:3002/api/ent/v1/internal/health -u myusername:mypassword -k -s --max-time ${READINESS_PROBE_TIMEOUT}`, + wantCmd: `curl -g -o /dev/null -w "%{http_code}" https://127.0.0.1:3002/api/ent/v1/internal/health -u myusername:'mypassword' -k -s --max-time "${READINESS_PROBE_TIMEOUT}"`, }, } for _, tt := range tests {