diff --git a/build/pbm-entry.sh b/build/pbm-entry.sh index f4f7bd737a..e85e3eaef2 100755 --- a/build/pbm-entry.sh +++ b/build/pbm-entry.sh @@ -2,10 +2,12 @@ PBM_MONGODB_URI="mongodb://${PBM_AGENT_MONGODB_USERNAME}:${PBM_AGENT_MONGODB_PASSWORD}@localhost:${PBM_MONGODB_PORT}/?replicaSet=${PBM_MONGODB_REPLSET}" -MONGO_SSL_DIR=/etc/mongodb-ssl -if [[ -f "${MONGO_SSL_DIR}/tls.crt" ]] && [[ -f "${MONGO_SSL_DIR}/tls.key" ]]; then - PBM_MONGODB_URI="${PBM_MONGODB_URI}&tls=true&tlsCertificateKeyFile=%2Ftmp%2Ftls.pem&tlsCAFile=${MONGO_SSL_DIR}%2Fca.crt&tlsInsecure=true" - cat "${MONGO_SSL_DIR}/tls.key" "${MONGO_SSL_DIR}/tls.crt" > /tmp/tls.pem +if [[ -z ${PBM_AGENT_TLS_ENABLED} ]] || [[ ${PBM_AGENT_TLS_ENABLED} == "true" ]]; then + MONGO_SSL_DIR=/etc/mongodb-ssl + if [[ -f "${MONGO_SSL_DIR}/tls.crt" ]] && [[ -f "${MONGO_SSL_DIR}/tls.key" ]]; then + PBM_MONGODB_URI="${PBM_MONGODB_URI}&tls=true&tlsCertificateKeyFile=%2Ftmp%2Ftls.pem&tlsCAFile=${MONGO_SSL_DIR}%2Fca.crt&tlsInsecure=true" + cat "${MONGO_SSL_DIR}/tls.key" "${MONGO_SSL_DIR}/tls.crt" >/tmp/tls.pem + fi fi export PBM_MONGODB_URI diff --git a/build/ps-entry.sh b/build/ps-entry.sh index 22055ae66d..03ecfe2b7a 100755 --- a/build/ps-entry.sh +++ b/build/ps-entry.sh @@ -1,5 +1,6 @@ #!/bin/bash set -Eeuo pipefail +set -o xtrace if [ "${1:0:1}" = '-' ]; then set -- mongod "$@" @@ -68,9 +69,9 @@ _mongod_hack_have_arg() { local arg for arg; do case "$arg" in - "$checkArg" | "$checkArg"=*) - return 0 - ;; + "$checkArg" | "$checkArg"=*) + return 0 + ;; esac done return 1 @@ -83,14 +84,14 @@ _mongod_hack_get_arg_val() { local arg="$1" shift case "$arg" in - "$checkArg") - echo "$1" - return 0 - ;; - "$checkArg"=*) - echo "${arg#"$checkArg"=}" - return 0 - ;; + "$checkArg") + echo "$1" + return 0 + ;; + "$checkArg"=*) + echo "${arg#"$checkArg"=}" + return 0 + ;; esac done return 1 @@ -131,14 +132,14 @@ _mongod_hack_ensure_no_arg_val() { local arg="$1" shift case "$arg" in - "$ensureNoArg") - shift # also skip the value - continue - ;; - "$ensureNoArg"=*) - # value is already included - continue - ;; + "$ensureNoArg") + shift # also skip the value + continue + ;; + "$ensureNoArg"=*) + # value is already included + continue + ;; esac mongodHackedArgs+=("$arg") done @@ -282,10 +283,10 @@ if [ "$originalArgOne" = 'mongod' ]; then # if we've got any /docker-entrypoint-initdb.d/* files to parse later, we should initdb for f in /docker-entrypoint-initdb.d/*; do case "$f" in - *.sh | *.js) # this should match the set of files we check for below - shouldPerformInitdb="$f" - break - ;; + *.sh | *.js) # this should match the set of files we check for below + shouldPerformInitdb="$f" + break + ;; esac done fi @@ -321,20 +322,6 @@ if [ "$originalArgOne" = 'mongod' ]; then _mongod_hack_ensure_no_arg_val --replSet "${mongodHackedArgs[@]}" fi - # "BadValue: need sslPEMKeyFile when SSL is enabled" vs "BadValue: need to enable SSL via the sslMode flag when using SSL configuration parameters" - tlsMode='disabled' - if _mongod_hack_have_arg '--tlsCertificateKeyFile' "${mongodHackedArgs[@]}"; then - tlsMode='preferTLS' - elif _mongod_hack_have_arg '--sslPEMKeyFile' "${mongodHackedArgs[@]}"; then - tlsMode='preferSSL' - fi - # 4.2 switched all configuration/flag names from "SSL" to "TLS" - if [ "$tlsMode" = 'preferTLS' ] || mongod --help 2>&1 | grep -q -- ' --tlsMode '; then - _mongod_hack_ensure_arg_val --tlsMode "$tlsMode" "${mongodHackedArgs[@]}" - else - _mongod_hack_ensure_arg_val --sslMode "$tlsMode" "${mongodHackedArgs[@]}" - fi - if stat "/proc/$$/fd/1" >/dev/null && [ -w "/proc/$$/fd/1" ]; then # https://github.com/mongodb/mongo/blob/38c0eb538d0fd390c6cb9ce9ae9894153f6e8ef5/src/mongo/db/initialize_server_global_state.cpp#L237-L251 # https://github.com/docker-library/mongo/issues/164#issuecomment-293965668 @@ -396,17 +383,17 @@ if [ "$originalArgOne" = 'mongod' ]; then echo for f in /docker-entrypoint-initdb.d/*; do case "$f" in - *.sh) - echo "$0: running $f" - # shellcheck source=/dev/null - . "$f" - ;; - *.js) - echo "$0: running $f" - "${mongo[@]}" "$MONGO_INITDB_DATABASE" "$f" - echo - ;; - *) echo "$0: ignoring $f" ;; + *.sh) + echo "$0: running $f" + # shellcheck source=/dev/null + . "$f" + ;; + *.js) + echo "$0: running $f" + "${mongo[@]}" "$MONGO_INITDB_DATABASE" "$f" + echo + ;; + *) echo "$0: ignoring $f" ;; esac echo done @@ -422,76 +409,61 @@ fi if [[ $originalArgOne == mongo* ]]; then mongodHackedArgs=("$@") - MONGO_SSL_DIR=${MONGO_SSL_DIR:-/etc/mongodb-ssl} - CA=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt - if [ -f /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt ]; then - CA=/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt - fi - if [ -f "${MONGO_SSL_DIR}/ca.crt" ]; then - CA="${MONGO_SSL_DIR}/ca.crt" - fi - LDAP_SSL_DIR=${LDAP_SSL_DIR:-/etc/openldap/certs} - if [ -f "${LDAP_SSL_DIR}/ca.crt" ]; then - echo "TLS_CACERT ${LDAP_SSL_DIR}/ca.crt" >/etc/openldap/ldap.conf - fi - if [ -f "${MONGO_SSL_DIR}/tls.key" ] && [ -f "${MONGO_SSL_DIR}/tls.crt" ]; then - cat "${MONGO_SSL_DIR}/tls.key" "${MONGO_SSL_DIR}/tls.crt" >/tmp/tls.pem - _mongod_hack_ensure_arg_val --sslPEMKeyFile /tmp/tls.pem "${mongodHackedArgs[@]}" - if [ -f "${CA}" ]; then - _mongod_hack_ensure_arg_val --sslCAFile "${CA}" "${mongodHackedArgs[@]}" - fi - fi - MONGO_SSL_INTERNAL_DIR=${MONGO_SSL_INTERNAL_DIR:-/etc/mongodb-ssl-internal} - if [ -f "${MONGO_SSL_INTERNAL_DIR}/tls.key" ] && [ -f "${MONGO_SSL_INTERNAL_DIR}/tls.crt" ]; then - cat "${MONGO_SSL_INTERNAL_DIR}/tls.key" "${MONGO_SSL_INTERNAL_DIR}/tls.crt" >/tmp/tls-internal.pem - _mongod_hack_ensure_arg_val --sslClusterFile /tmp/tls-internal.pem "${mongodHackedArgs[@]}" - if [ -f "${MONGO_SSL_INTERNAL_DIR}/ca.crt" ]; then - _mongod_hack_ensure_arg_val --sslClusterCAFile "${MONGO_SSL_INTERNAL_DIR}/ca.crt" "${mongodHackedArgs[@]}" - fi + + # if --tlsMode arg is present, get it + tlsMode="$(_mongod_hack_get_arg_val --tlsMode "${mongodHackedArgs[@]}")" + + if [[ -z ${tlsMode} ]]; then + # if neither --tlsMode arg or net.tls.mode is present, set it to preferSSL + tlsMode="preferSSL" fi - # don't add --tlsMode if allowUnsafeConfigurations is true + # don't add --tlsMode if TLS is disabled if clusterAuthMode="$(_mongod_hack_get_arg_val --clusterAuthMode "${mongodHackedArgs[@]}")"; then if [[ ${clusterAuthMode} != "keyFile" ]]; then - tlsMode="preferSSL" - # if --config arg is present, try to get tlsMode from it - if _parse_config "${mongodHackedArgs[@]}"; then - tlsMode=$(jq -r '.net.tls.mode // "preferSSL"' "${jsonConfigFile}") - fi - _mongod_hack_ensure_arg_val --sslMode "${tlsMode}" "${mongodHackedArgs[@]}" + _mongod_hack_ensure_arg_val --tlsMode "${tlsMode}" "${mongodHackedArgs[@]}" + else + _mongod_hack_ensure_no_arg --sslAllowInvalidCertificates "${mongodHackedArgs[@]}" fi fi - if [ "$MONGODB_VERSION" != 'v4.0' ]; then - - _mongod_hack_rename_arg_save_val --sslMode --tlsMode "${mongodHackedArgs[@]}" - - if _mongod_hack_have_arg '--tlsMode' "${mongodHackedArgs[@]}"; then - tlsMode="none" - if _mongod_hack_have_arg 'allowSSL' "${mongodHackedArgs[@]}"; then - tlsMode='allowTLS' - elif _mongod_hack_have_arg 'preferSSL' "${mongodHackedArgs[@]}"; then - tlsMode='preferTLS' - elif _mongod_hack_have_arg 'requireSSL' "${mongodHackedArgs[@]}"; then - tlsMode='requireTLS' + if [[ ${tlsMode} != "disabled" ]]; then + MONGO_SSL_DIR=${MONGO_SSL_DIR:-/etc/mongodb-ssl} + CA=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + if [ -f /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt ]; then + CA=/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt + fi + if [ -f "${MONGO_SSL_DIR}/ca.crt" ]; then + CA="${MONGO_SSL_DIR}/ca.crt" + fi + if [ -f "${MONGO_SSL_DIR}/tls.key" ] && [ -f "${MONGO_SSL_DIR}/tls.crt" ]; then + cat "${MONGO_SSL_DIR}/tls.key" "${MONGO_SSL_DIR}/tls.crt" >/tmp/tls.pem + _mongod_hack_ensure_arg_val --sslPEMKeyFile /tmp/tls.pem "${mongodHackedArgs[@]}" + if [ -f "${CA}" ]; then + _mongod_hack_ensure_arg_val --sslCAFile "${CA}" "${mongodHackedArgs[@]}" fi - - if [ "$tlsMode" != "none" ]; then - _mongod_hack_ensure_no_arg_val --tlsMode "${mongodHackedArgs[@]}" - _mongod_hack_ensure_arg_val --tlsMode "$tlsMode" "${mongodHackedArgs[@]}" + fi + MONGO_SSL_INTERNAL_DIR=${MONGO_SSL_INTERNAL_DIR:-/etc/mongodb-ssl-internal} + if [ -f "${MONGO_SSL_INTERNAL_DIR}/tls.key" ] && [ -f "${MONGO_SSL_INTERNAL_DIR}/tls.crt" ]; then + cat "${MONGO_SSL_INTERNAL_DIR}/tls.key" "${MONGO_SSL_INTERNAL_DIR}/tls.crt" >/tmp/tls-internal.pem + _mongod_hack_ensure_arg_val --sslClusterFile /tmp/tls-internal.pem "${mongodHackedArgs[@]}" + if [ -f "${MONGO_SSL_INTERNAL_DIR}/ca.crt" ]; then + _mongod_hack_ensure_arg_val --sslClusterCAFile "${MONGO_SSL_INTERNAL_DIR}/ca.crt" "${mongodHackedArgs[@]}" fi fi - _mongod_hack_rename_arg_save_val --sslPEMKeyFile --tlsCertificateKeyFile "${mongodHackedArgs[@]}" - if ! _mongod_hack_have_arg '--tlsMode' "${mongodHackedArgs[@]}"; then - if _mongod_hack_have_arg '--tlsCertificateKeyFile' "${mongodHackedArgs[@]}"; then - _mongod_hack_ensure_arg_val --tlsMode "preferTLS" "${mongodHackedArgs[@]}" - fi + LDAP_SSL_DIR=${LDAP_SSL_DIR:-/etc/openldap/certs} + if [ -f "${LDAP_SSL_DIR}/ca.crt" ]; then + echo "TLS_CACERT ${LDAP_SSL_DIR}/ca.crt" >/etc/openldap/ldap.conf fi + fi + + if [ "$MONGODB_VERSION" != 'v4.0' ]; then _mongod_hack_rename_arg '--sslAllowInvalidCertificates' '--tlsAllowInvalidCertificates' "${mongodHackedArgs[@]}" _mongod_hack_rename_arg '--sslAllowInvalidHostnames' '--tlsAllowInvalidHostnames' "${mongodHackedArgs[@]}" _mongod_hack_rename_arg '--sslAllowConnectionsWithoutCertificates' '--tlsAllowConnectionsWithoutCertificates' "${mongodHackedArgs[@]}" _mongod_hack_rename_arg '--sslFIPSMode' '--tlsFIPSMode' "${mongodHackedArgs[@]}" + _mongod_hack_rename_arg '--sslMode' '--tlsMode' "${mongodHackedArgs[@]}" _mongod_hack_rename_arg_save_val --sslPEMKeyPassword --tlsCertificateKeyFilePassword "${mongodHackedArgs[@]}" _mongod_hack_rename_arg_save_val --sslClusterFile --tlsClusterFile "${mongodHackedArgs[@]}" diff --git a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml index 51b1add6f1..53e59385e8 100644 --- a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml +++ b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml @@ -17255,9 +17255,24 @@ spec: required: - name type: object + mode: + type: string type: object unmanaged: type: boolean + unsafeFlags: + properties: + backupIfUnhealthy: + type: boolean + mongosSize: + type: boolean + replsetSize: + type: boolean + terminationGracePeriod: + type: boolean + tls: + type: boolean + type: object updateStrategy: type: string upgradeOptions: diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index e9a090ada6..8a664c2efa 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -17894,9 +17894,24 @@ spec: required: - name type: object + mode: + type: string type: object unmanaged: type: boolean + unsafeFlags: + properties: + backupIfUnhealthy: + type: boolean + mongosSize: + type: boolean + replsetSize: + type: boolean + terminationGracePeriod: + type: boolean + tls: + type: boolean + type: object updateStrategy: type: string upgradeOptions: diff --git a/deploy/cr.yaml b/deploy/cr.yaml index 9ed131ec72..3821f4a04d 100644 --- a/deploy/cr.yaml +++ b/deploy/cr.yaml @@ -15,6 +15,7 @@ spec: image: perconalab/percona-server-mongodb-operator:main-mongod6.0 imagePullPolicy: Always # tls: +# mode: preferTLS # # 90 days in hours # certValidityDuration: 2160h # issuerConf: @@ -25,7 +26,12 @@ spec: # - name: private-registry-credentials # initImage: perconalab/percona-server-mongodb-operator:main # initContainerSecurityContext: {} - allowUnsafeConfigurations: false + unsafeFlags: + tls: false + replsetSize: false + mongosSize: false + terminationGracePeriod: false + backupIfUnhealthy: false updateStrategy: SmartUpdate # ignoreAnnotations: # - service.beta.kubernetes.io/aws-load-balancer-backend-protocol @@ -70,9 +76,6 @@ spec: # - host: 34.124.76.92 # # for more configuration fields refer to https://docs.mongodb.com/manual/reference/configuration-options/ # configuration: | -# net: -# tls: -# mode: preferTLS # operationProfiling: # mode: slowOp # systemLog: diff --git a/deploy/crd.yaml b/deploy/crd.yaml index d61aa73227..1c8272538d 100644 --- a/deploy/crd.yaml +++ b/deploy/crd.yaml @@ -17894,9 +17894,24 @@ spec: required: - name type: object + mode: + type: string type: object unmanaged: type: boolean + unsafeFlags: + properties: + backupIfUnhealthy: + type: boolean + mongosSize: + type: boolean + replsetSize: + type: boolean + terminationGracePeriod: + type: boolean + tls: + type: boolean + type: object updateStrategy: type: string upgradeOptions: diff --git a/deploy/cw-bundle.yaml b/deploy/cw-bundle.yaml index 0db56b97a2..edd2a8d1db 100644 --- a/deploy/cw-bundle.yaml +++ b/deploy/cw-bundle.yaml @@ -17894,9 +17894,24 @@ spec: required: - name type: object + mode: + type: string type: object unmanaged: type: boolean + unsafeFlags: + properties: + backupIfUnhealthy: + type: boolean + mongosSize: + type: boolean + replsetSize: + type: boolean + terminationGracePeriod: + type: boolean + tls: + type: boolean + type: object updateStrategy: type: string upgradeOptions: diff --git a/e2e-tests/version-service/conf/crd.yaml b/e2e-tests/version-service/conf/crd.yaml index d61aa73227..1c8272538d 100644 --- a/e2e-tests/version-service/conf/crd.yaml +++ b/e2e-tests/version-service/conf/crd.yaml @@ -17894,9 +17894,24 @@ spec: required: - name type: object + mode: + type: string type: object unmanaged: type: boolean + unsafeFlags: + properties: + backupIfUnhealthy: + type: boolean + mongosSize: + type: boolean + replsetSize: + type: boolean + terminationGracePeriod: + type: boolean + tls: + type: boolean + type: object updateStrategy: type: string upgradeOptions: diff --git a/pkg/apis/psmdb/v1/psmdb_defaults.go b/pkg/apis/psmdb/v1/psmdb_defaults.go index cb8a1f7a2d..593757d5aa 100644 --- a/pkg/apis/psmdb/v1/psmdb_defaults.go +++ b/pkg/apis/psmdb/v1/psmdb_defaults.go @@ -134,13 +134,16 @@ func (cr *PerconaServerMongoDB) CheckNSetDefaults(platform version.Platform, log return errors.New("mongos should be specified") } - if !cr.Spec.Pause && cr.DeletionTimestamp == nil { - if !cr.Spec.UnsafeConf && cr.Spec.Sharding.Mongos.Size < minSafeMongosSize { - log.Info("Safe config set, updating mongos size", - "oldSize", cr.Spec.Sharding.Mongos.Size, "newSize", minSafeMongosSize) - cr.Spec.Sharding.Mongos.Size = minSafeMongosSize + if cr.CompareVersion("1.16.0") < 0 { + if !cr.Spec.Pause && cr.DeletionTimestamp == nil { + if !cr.Spec.UnsafeConf && cr.Spec.Sharding.Mongos.Size < minSafeMongosSize { + log.Info("Safe config set, updating mongos size", + "oldSize", cr.Spec.Sharding.Mongos.Size, "newSize", minSafeMongosSize) + cr.Spec.Sharding.Mongos.Size = minSafeMongosSize + } } } + if cr.CompareVersion("1.15.0") >= 0 { var fsgroup *int64 if platform == version.PlatformKubernetes { @@ -191,8 +194,7 @@ func (cr *PerconaServerMongoDB) CheckNSetDefaults(platform version.Platform, log }, } - if (cr.CompareVersion("1.7.0") >= 0 && cr.CompareVersion("1.15.0") < 0) || - cr.CompareVersion("1.15.0") >= 0 && !cr.Spec.UnsafeConf { + if cr.TLSEnabled() { cr.Spec.Sharding.Mongos.LivenessProbe.Exec.Command = append(cr.Spec.Sharding.Mongos.LivenessProbe.Exec.Command, "--ssl", "--sslInsecure", "--sslCAFile", "/etc/mongodb-ssl/ca.crt", @@ -236,8 +238,7 @@ func (cr *PerconaServerMongoDB) CheckNSetDefaults(platform version.Platform, log }, } - if (cr.CompareVersion("1.7.0") >= 0 && cr.CompareVersion("1.15.0") < 0) || - cr.CompareVersion("1.15.0") >= 0 && !cr.Spec.UnsafeConf { + if cr.TLSEnabled() { cr.Spec.Sharding.Mongos.ReadinessProbe.Exec.Command = append(cr.Spec.Sharding.Mongos.ReadinessProbe.Exec.Command, "--ssl", "--sslInsecure", "--sslCAFile", "/etc/mongodb-ssl/ca.crt", @@ -271,7 +272,9 @@ func (cr *PerconaServerMongoDB) CheckNSetDefaults(platform version.Platform, log cr.Spec.Sharding.Mongos.ReadinessProbe.FailureThreshold = 3 } - cr.Spec.Sharding.Mongos.reconcileOpts(cr) + if err := cr.Spec.Sharding.Mongos.reconcileOpts(cr); err != nil { + return errors.Wrap(err, "reconcile mongos options") + } if err := cr.Spec.Sharding.Mongos.Configuration.SetDefaults(); err != nil { return errors.Wrap(err, "failed to set configuration defaults") @@ -364,15 +367,12 @@ func (cr *PerconaServerMongoDB) CheckNSetDefaults(platform version.Platform, log Command: []string{"mongodb-healthcheck", "k8s", "liveness"}, } - if cr.CompareVersion("1.6.0") >= 0 { - replset.LivenessProbe.Probe.Exec.Command[0] = "/data/db/mongodb-healthcheck" - if (cr.CompareVersion("1.7.0") >= 0 && cr.CompareVersion("1.15.0") < 0) || - cr.CompareVersion("1.15.0") >= 0 && !cr.Spec.UnsafeConf { - replset.LivenessProbe.Probe.Exec.Command = append(replset.LivenessProbe.Probe.Exec.Command, - "--ssl", "--sslInsecure", - "--sslCAFile", "/etc/mongodb-ssl/ca.crt", - "--sslPEMKeyFile", "/tmp/tls.pem") - } + replset.LivenessProbe.Probe.Exec.Command[0] = "/data/db/mongodb-healthcheck" + if cr.TLSEnabled() { + replset.LivenessProbe.Probe.Exec.Command = append(replset.LivenessProbe.Probe.Exec.Command, + "--ssl", "--sslInsecure", + "--sslCAFile", "/etc/mongodb-ssl/ca.crt", + "--sslPEMKeyFile", "/tmp/tls.pem") } if cr.CompareVersion("1.4.0") >= 0 && !replset.LivenessProbe.CommandHas(startupDelaySecondsFlag) { @@ -562,13 +562,23 @@ func (rs *ReplsetSpec) SetDefaults(platform version.Platform, cr *PerconaServerM rs.Expose.ExposeType = corev1.ServiceTypeClusterIP } - rs.MultiAZ.reconcileOpts(cr) + if err := rs.MultiAZ.reconcileOpts(cr); err != nil { + return errors.Wrapf(err, "reconcile multiAZ options for replset %s", rs.Name) + } if rs.Arbiter.Enabled { - rs.Arbiter.MultiAZ.reconcileOpts(cr) + if err := rs.Arbiter.MultiAZ.reconcileOpts(cr); err != nil { + return errors.Wrapf(err, "reconcile multiAZ options for arbiter in replset %s", rs.Name) + } } - if !cr.Spec.UnsafeConf && (cr.DeletionTimestamp == nil && !cr.Spec.Pause) { + if cr.CompareVersion("1.16.0") >= 0 { + if err := rs.checkSafeDefaults(cr.Spec.Unsafe); err != nil { + return errors.Wrap(err, "check safe defaults") + } + } + + if cr.CompareVersion("1.16.0") < 0 && !cr.Spec.UnsafeConf && (cr.DeletionTimestamp == nil && !cr.Spec.Pause) { rs.setSafeDefaults(log) } @@ -655,7 +665,7 @@ func (nv *NonVotingSpec) SetDefaults(cr *PerconaServerMongoDB, rs *ReplsetSpec) Command: []string{"/data/db/mongodb-healthcheck", "k8s", "liveness"}, } - if !cr.Spec.UnsafeConf || cr.CompareVersion("1.15.0") < 0 { + if cr.TLSEnabled() { nv.LivenessProbe.Probe.ProbeHandler.Exec.Command = append( nv.LivenessProbe.Probe.ProbeHandler.Exec.Command, "--ssl", "--sslInsecure", "--sslCAFile", "/etc/mongodb-ssl/ca.crt", "--sslPEMKeyFile", "/tmp/tls.pem", @@ -756,19 +766,68 @@ func (rs *ReplsetSpec) setSafeDefaults(log logr.Logger) { } } -func (m *MultiAZ) reconcileOpts(cr *PerconaServerMongoDB) { +func (rs *ReplsetSpec) checkSafeDefaults(unsafe UnsafeFlags) error { + if !unsafe.ReplsetSize { + if rs.Arbiter.Enabled { + if rs.Arbiter.Size != 1 { + return errors.New("arbiter size must be 1. Set spec.unsafeFlags.replsetSize to true to disable this check") + } + if rs.Size < minSafeReplicasetSizeWithArbiter { + return errors.Errorf("replset size must be at least %d with arbiter. Set spec.unsafeFlags.replsetSize to true to disable this check", minSafeReplicasetSizeWithArbiter) + } + if rs.Size%2 != 0 { + return errors.New("arbiter must disabled due to odd replset size. Set spec.unsafeFlags.replsetSize to true to disable this check") + } + } else { + if rs.Size < 2 { + return errors.Errorf("replset size must be at least %d. Set spec.unsafeFlags.replsetSize to true to disable this check", defaultMongodSize) + } + if rs.Size%2 == 0 { + return errors.New("replset size must be odd. Set spec.unsafeFlags.replsetSize to true to disable this check") + } + } + } + + if !unsafe.TLS { + tlsMode, err := rs.Configuration.GetTLSMode() + if err != nil { + return errors.Wrap(err, "get TLS mode") + } + + if tlsMode == TLSModeDisabled { + return errors.New("TLS must be enabled. Set spec.unsafeFlags.tls to true to disable this check") + } + } + + return nil +} + +func (m *MultiAZ) reconcileOpts(cr *PerconaServerMongoDB) error { m.reconcileAffinityOpts(cr) m.reconcileTopologySpreadConstraints(cr) if cr.CompareVersion("1.15.0") >= 0 { - if m.TerminationGracePeriodSeconds == nil || (!cr.Spec.UnsafeConf && *m.TerminationGracePeriodSeconds < 30) { + if m.TerminationGracePeriodSeconds == nil { + m.TerminationGracePeriodSeconds = new(int64) + *m.TerminationGracePeriodSeconds = 60 + } + } + if cr.CompareVersion("1.15.0") == 0 { + if !cr.Spec.UnsafeConf && *m.TerminationGracePeriodSeconds < 30 { m.TerminationGracePeriodSeconds = new(int64) *m.TerminationGracePeriodSeconds = 60 } } + if cr.CompareVersion("1.16.0") >= 0 { + if *m.TerminationGracePeriodSeconds < 30 && !cr.Spec.Unsafe.TerminationGracePeriod { + return errors.New("terminationGracePeriodSeconds must be at least 30 seconds for safe configuration. Set spec.unsafeFlags.terminationGracePeriod to true to disable this check") + } + } if m.PodDisruptionBudget == nil { defaultMaxUnavailable := intstr.FromInt(1) m.PodDisruptionBudget = &PodDisruptionBudgetSpec{MaxUnavailable: &defaultMaxUnavailable} } + + return nil } var affinityValidTopologyKeys = map[string]struct{}{ diff --git a/pkg/apis/psmdb/v1/psmdb_types.go b/pkg/apis/psmdb/v1/psmdb_types.go index 771d2402df..080805d990 100644 --- a/pkg/apis/psmdb/v1/psmdb_types.go +++ b/pkg/apis/psmdb/v1/psmdb_types.go @@ -3,6 +3,7 @@ package v1 import ( "fmt" "os" + "slices" "strconv" "strings" @@ -71,6 +72,7 @@ type PerconaServerMongoDBSpec struct { Image string `json:"image"` ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` UnsafeConf bool `json:"allowUnsafeConfigurations,omitempty"` + Unsafe UnsafeFlags `json:"unsafeFlags,omitempty"` IgnoreLabels []string `json:"ignoreLabels,omitempty"` IgnoreAnnotations []string `json:"ignoreAnnotations,omitempty"` Replsets []*ReplsetSpec `json:"replsets,omitempty"` @@ -90,7 +92,25 @@ type PerconaServerMongoDBSpec struct { TLS *TLSSpec `json:"tls,omitempty"` } +type UnsafeFlags struct { + TLS bool `json:"tls,omitempty"` + ReplsetSize bool `json:"replsetSize,omitempty"` + MongosSize bool `json:"mongosSize,omitempty"` + TerminationGracePeriod bool `json:"terminationGracePeriod,omitempty"` + BackupIfUnhealthy bool `json:"backupIfUnhealthy,omitempty"` +} + +type TLSMode string + +const ( + TLSModeDisabled TLSMode = "disabled" + TLSModeAllow TLSMode = "allowTLS" + TLSModePrefer TLSMode = "preferTLS" + TLSModeRequire TLSMode = "requireTLS" +) + type TLSSpec struct { + Mode TLSMode `json:"mode,omitempty"` CertValidityDuration metav1.Duration `json:"certValidityDuration,omitempty"` IssuerConf *cmmeta.ObjectReference `json:"issuerConf,omitempty"` } @@ -421,6 +441,39 @@ func (conf MongoConfiguration) GetOptions(name string) (map[interface{}]interfac return options, nil } +func (conf MongoConfiguration) GetTLSMode() (TLSMode, error) { + m, err := conf.GetOptions("net") + if err != nil || m == nil { + return TLSModePrefer, err + } + + tls, ok := m["tls"] + if !ok { + return TLSModePrefer, nil + } + + tlsMap, ok := tls.(map[any]any) + if !ok { + return TLSModePrefer, errors.New("tls configuration is invalid") + } + + tlsMode, ok := tlsMap["mode"] + if !ok { + return TLSModePrefer, nil + } + + mode, ok := tlsMode.(string) + if !ok { + return TLSModePrefer, errors.Errorf("can't cast %s to string", mode) + } + + if !slices.Contains([]TLSMode{TLSModeDisabled, TLSModeAllow, TLSModePrefer, TLSModeRequire}, TLSMode(mode)) { + return TLSModePrefer, errors.Errorf("net.tls.mode value is not valid: %s", mode) + } + + return TLSMode(mode), nil +} + // IsEncryptionEnabled returns nil if "enableEncryption" field is not specified or the pointer to the value of this field func (conf MongoConfiguration) IsEncryptionEnabled() (*bool, error) { m, err := conf.GetOptions("security") @@ -973,10 +1026,14 @@ func (cr *PerconaServerMongoDB) CanBackup() error { return nil } - if !cr.Spec.UnsafeConf { + if cr.CompareVersion("1.15.0") <= 0 && !cr.Spec.UnsafeConf { return errors.Errorf("allowUnsafeConfigurations must be true to run backup on cluster with status %s", cr.Status.State) } + if cr.CompareVersion("1.16.0") >= 0 && !cr.Spec.Unsafe.BackupIfUnhealthy { + return errors.Errorf("spec.unsafeFlags.backupIfUnhealthy must be true to run backup on cluster with status %s", cr.Status.State) + } + for rsName, rs := range cr.Status.Replsets { if rs.Ready < int32(1) { return errors.New(rsName + " has no ready nodes") @@ -1072,3 +1129,18 @@ func (cr *PerconaServerMongoDB) GetOrderedFinalizers() []string { } const AnnotationResyncPBM = "percona.com/resync-pbm" + +func (cr *PerconaServerMongoDB) TLSEnabled() bool { + if cr.CompareVersion("1.16.0") < 0 { + return !cr.Spec.UnsafeConf + } + + switch cr.Spec.TLS.Mode { + case TLSModeDisabled: + return !(cr.CompareVersion("1.16.0") >= 0 && cr.Spec.Unsafe.TLS) + case TLSModeAllow, TLSModePrefer, TLSModeRequire: + return true + default: + return true + } +} diff --git a/pkg/apis/psmdb/v1/zz_generated.deepcopy.go b/pkg/apis/psmdb/v1/zz_generated.deepcopy.go index 43a09059a7..dc73660d48 100644 --- a/pkg/apis/psmdb/v1/zz_generated.deepcopy.go +++ b/pkg/apis/psmdb/v1/zz_generated.deepcopy.go @@ -1123,6 +1123,7 @@ func (in *PerconaServerMongoDBSpec) DeepCopyInto(out *PerconaServerMongoDBSpec) *out = make([]corev1.LocalObjectReference, len(*in)) copy(*out, *in) } + out.Unsafe = in.Unsafe if in.IgnoreLabels != nil { in, out := &in.IgnoreLabels, &out.IgnoreLabels *out = make([]string, len(*in)) @@ -1484,6 +1485,21 @@ func (in *TLSSpec) DeepCopy() *TLSSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UnsafeFlags) DeepCopyInto(out *UnsafeFlags) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UnsafeFlags. +func (in *UnsafeFlags) DeepCopy() *UnsafeFlags { + if in == nil { + return nil + } + out := new(UnsafeFlags) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *UpgradeOptions) DeepCopyInto(out *UpgradeOptions) { *out = *in diff --git a/pkg/controller/perconaservermongodb/connections.go b/pkg/controller/perconaservermongodb/connections.go index 4522583a13..76d1d7d779 100644 --- a/pkg/controller/perconaservermongodb/connections.go +++ b/pkg/controller/perconaservermongodb/connections.go @@ -15,7 +15,7 @@ import ( type MongoClientProvider interface { Mongo(ctx context.Context, cr *api.PerconaServerMongoDB, rs api.ReplsetSpec, role api.UserRole) (mongo.Client, error) Mongos(ctx context.Context, cr *api.PerconaServerMongoDB, role api.UserRole) (mongo.Client, error) - Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.UserRole, host string) (mongo.Client, error) + Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.UserRole, host string, tlsEnabled bool) (mongo.Client, error) } func (r *ReconcilePerconaServerMongoDB) MongoClientProvider() MongoClientProvider { @@ -47,13 +47,13 @@ func (p *mongoClientProvider) Mongos(ctx context.Context, cr *api.PerconaServerM return psmdb.MongosClient(ctx, p.k8sclient, cr, c) } -func (p *mongoClientProvider) Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.UserRole, host string) (mongo.Client, error) { +func (p *mongoClientProvider) Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.UserRole, host string, tlsEnabled bool) (mongo.Client, error) { c, err := getInternalCredentials(ctx, p.k8sclient, cr, role) if err != nil { return nil, errors.Wrap(err, "failed to get credentials") } - return psmdb.StandaloneClient(ctx, p.k8sclient, cr, c, host) + return psmdb.StandaloneClient(ctx, p.k8sclient, cr, c, host, tlsEnabled) } func (r *ReconcilePerconaServerMongoDB) mongoClientWithRole(ctx context.Context, cr *api.PerconaServerMongoDB, rs api.ReplsetSpec, role api.UserRole) (mongo.Client, error) { @@ -69,5 +69,5 @@ func (r *ReconcilePerconaServerMongoDB) standaloneClientWithRole(ctx context.Con if err != nil { return nil, errors.Wrap(err, "failed to get mongo host") } - return r.MongoClientProvider().Standalone(ctx, cr, role, host) + return r.MongoClientProvider().Standalone(ctx, cr, role, host, cr.TLSEnabled()) } diff --git a/pkg/controller/perconaservermongodb/connections_test.go b/pkg/controller/perconaservermongodb/connections_test.go index 10ac5177dd..d5bfd60433 100644 --- a/pkg/controller/perconaservermongodb/connections_test.go +++ b/pkg/controller/perconaservermongodb/connections_test.go @@ -377,7 +377,7 @@ func (g *fakeMongoClientProvider) Mongos(ctx context.Context, cr *api.PerconaSer fakeClient := mongoFake.NewClient() return &fakeMongoClient{pods: g.pods, cr: g.cr, connectionCount: g.connectionCount, Client: fakeClient}, nil } -func (g *fakeMongoClientProvider) Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.UserRole, host string) (mongo.Client, error) { +func (g *fakeMongoClientProvider) Standalone(ctx context.Context, cr *api.PerconaServerMongoDB, role api.UserRole, host string, tlsEnabled bool) (mongo.Client, error) { *g.connectionCount++ fakeClient := mongoFake.NewClient() diff --git a/pkg/controller/perconaservermongodb/mgo.go b/pkg/controller/perconaservermongodb/mgo.go index f7ced795ba..9540a403a8 100644 --- a/pkg/controller/perconaservermongodb/mgo.go +++ b/pkg/controller/perconaservermongodb/mgo.go @@ -237,7 +237,13 @@ func (r *ReconcilePerconaServerMongoDB) reconcileCluster(ctx context.Context, cr func (r *ReconcilePerconaServerMongoDB) updateConfigMembers(ctx context.Context, cli mongo.Client, cr *api.PerconaServerMongoDB, rs *api.ReplsetSpec) (int, error) { log := logf.FromContext(ctx) // Primary with a Secondary and an Arbiter (PSA) - unsafePSA := cr.Spec.UnsafeConf && rs.Arbiter.Enabled && rs.Arbiter.Size == 1 && !rs.NonVoting.Enabled && rs.Size == 2 + unsafePSA := false + + if cr.CompareVersion("1.15.0") <= 0 { + unsafePSA = cr.Spec.UnsafeConf && rs.Arbiter.Enabled && rs.Arbiter.Size == 1 && !rs.NonVoting.Enabled && rs.Size == 2 + } else { + unsafePSA = cr.Spec.Unsafe.ReplsetSize && rs.Arbiter.Enabled && rs.Arbiter.Size == 1 && !rs.NonVoting.Enabled && rs.Size == 2 + } pods, err := psmdb.GetRSPods(ctx, r.client, cr, rs.Name) if err != nil { @@ -582,7 +588,7 @@ func (r *ReconcilePerconaServerMongoDB) handleReplsetInit(ctx context.Context, c mongoCmd = "mongo" } - if !cr.Spec.UnsafeConf { + if cr.TLSEnabled() { mongoCmd += " --tls --tlsCertificateKeyFile /tmp/tls.pem --tlsAllowInvalidCertificates --tlsCAFile /etc/mongodb-ssl/ca.crt" } diff --git a/pkg/controller/perconaservermongodb/psmdb_controller.go b/pkg/controller/perconaservermongodb/psmdb_controller.go index c3b7199854..22f4e7b36f 100644 --- a/pkg/controller/perconaservermongodb/psmdb_controller.go +++ b/pkg/controller/perconaservermongodb/psmdb_controller.go @@ -351,7 +351,7 @@ func (r *ReconcilePerconaServerMongoDB) Reconcile(ctx context.Context, request r } } - err = r.reconsileSSL(ctx, cr) + err = r.reconcileSSL(ctx, cr) if err != nil { err = errors.Errorf(`TLS secrets handler: "%v". Please create your TLS secret `+cr.Spec.Secrets.SSL+` manually or setup cert-manager correctly`, err) return reconcile.Result{}, err @@ -1179,16 +1179,18 @@ func (r *ReconcilePerconaServerMongoDB) reconcileMongosStatefulset(ctx context.C return errors.Wrapf(err, "create template spec for mongos") } - sslAnn, err := r.sslAnnotation(ctx, cr) - if err != nil { - return errors.Wrap(err, "failed to get ssl annotations") - } - if templateSpec.Annotations == nil { - templateSpec.Annotations = make(map[string]string) - } + if cr.TLSEnabled() { + sslAnn, err := r.sslAnnotation(ctx, cr) + if err != nil { + return errors.Wrap(err, "failed to get ssl annotations") + } + if templateSpec.Annotations == nil { + templateSpec.Annotations = make(map[string]string) + } - for k, v := range sslAnn { - templateSpec.Annotations[k] = v + for k, v := range sslAnn { + templateSpec.Annotations[k] = v + } } secret := new(corev1.Secret) diff --git a/pkg/controller/perconaservermongodb/ssl.go b/pkg/controller/perconaservermongodb/ssl.go index 3a647773ca..6232b85954 100644 --- a/pkg/controller/perconaservermongodb/ssl.go +++ b/pkg/controller/perconaservermongodb/ssl.go @@ -14,7 +14,11 @@ import ( "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/tls" ) -func (r *ReconcilePerconaServerMongoDB) reconsileSSL(ctx context.Context, cr *api.PerconaServerMongoDB) error { +func (r *ReconcilePerconaServerMongoDB) reconcileSSL(ctx context.Context, cr *api.PerconaServerMongoDB) error { + if !cr.TLSEnabled() { + return nil + } + secretObj := corev1.Secret{} secretInternalObj := corev1.Secret{} errSecret := r.client.Get(ctx, diff --git a/pkg/controller/perconaservermongodb/statefulset.go b/pkg/controller/perconaservermongodb/statefulset.go index 6aee61df2d..6dbefdb6da 100644 --- a/pkg/controller/perconaservermongodb/statefulset.go +++ b/pkg/controller/perconaservermongodb/statefulset.go @@ -116,12 +116,14 @@ func (r *ReconcilePerconaServerMongoDB) getStatefulsetFromReplset(ctx context.Co sfs.Labels = sfsSpec.Template.Labels sfs.Spec = sfsSpec - sslAnn, err := r.sslAnnotation(ctx, cr) - if err != nil { - return nil, errors.Wrap(err, "failed to get ssl annotations") - } - for k, v := range sslAnn { - sfsSpec.Template.Annotations[k] = v + if cr.TLSEnabled() { + sslAnn, err := r.sslAnnotation(ctx, cr) + if err != nil { + return nil, errors.Wrap(err, "failed to get ssl annotations") + } + for k, v := range sslAnn { + sfsSpec.Template.Annotations[k] = v + } } return sfs, nil diff --git a/pkg/psmdb/backup/backup.go b/pkg/psmdb/backup/backup.go index 9fd2618242..433faf34ec 100644 --- a/pkg/psmdb/backup/backup.go +++ b/pkg/psmdb/backup/backup.go @@ -2,6 +2,7 @@ package backup import ( "context" + "strings" "github.com/pkg/errors" client "sigs.k8s.io/controller-runtime/pkg/client" @@ -43,6 +44,10 @@ func NewRestoreJob(cr *api.PerconaServerMongoDBRestore) Job { return j } +func IsPBMNotConfiguredError(err error) bool { + return strings.Contains(err.Error(), "mongo: no documents in result") +} + // HasActiveJobs returns true if there are running backups or restores // in given cluster and namespace func HasActiveJobs(ctx context.Context, newPBMFunc NewPBMFunc, cl client.Client, cluster *api.PerconaServerMongoDB, current Job, allowLock ...LockHeaderPredicate) (bool, error) { @@ -96,6 +101,9 @@ func HasActiveJobs(ctx context.Context, newPBMFunc NewPBMFunc, cl client.Client, pbm, err := newPBMFunc(ctx, cl, cluster) if err != nil { + if IsPBMNotConfiguredError(err) { + return false, nil + } return false, errors.Wrap(err, "getting PBM object") } defer pbm.Close(ctx) diff --git a/pkg/psmdb/backup/pbm.go b/pkg/psmdb/backup/pbm.go index 4c24a87cbc..cfc9d6b8e1 100644 --- a/pkg/psmdb/backup/pbm.go +++ b/pkg/psmdb/backup/pbm.go @@ -81,7 +81,7 @@ type PBM interface { Node(ctx context.Context) (string, error) } -func getMongoUri(ctx context.Context, k8sclient client.Client, cr *api.PerconaServerMongoDB, addrs []string) (string, error) { +func getMongoUri(ctx context.Context, k8sclient client.Client, cr *api.PerconaServerMongoDB, addrs []string, tlsEnabled bool) (string, error) { usersSecretName := api.UserSecretName(cr) scr, err := getSecret(ctx, k8sclient, cr.Namespace, usersSecretName) if err != nil { @@ -94,6 +94,10 @@ func getMongoUri(ctx context.Context, k8sclient client.Client, cr *api.PerconaSe strings.Join(addrs, ","), ) + if !tlsEnabled { + return murl, nil + } + // PBM connection is opened from the operator pod. In order to use SSL // certificates of the cluster, we need to copy them to operator pod. // This is especially important if the user passes custom config to set @@ -156,7 +160,7 @@ func NewPBM(ctx context.Context, c client.Client, cluster *api.PerconaServerMong return nil, errors.Wrap(err, "get replset addrs") } - murl, err := getMongoUri(ctx, c, cluster, addrs) + murl, err := getMongoUri(ctx, c, cluster, addrs, cluster.TLSEnabled()) if err != nil { return nil, errors.Wrap(err, "get mongo uri") } @@ -224,7 +228,7 @@ func GetPriorities(ctx context.Context, k8sclient client.Client, cluster *api.Pe } for _, pod := range podList.Items { - host, err := psmdb.MongoHost(ctx, k8sclient, cluster, rs.Name, rs.Expose.Enabled, pod) + host, err := psmdb.MongoHost(ctx, k8sclient, cluster, cluster.Spec.ClusterServiceDNSMode, rs.Name, rs.Expose.Enabled, pod) if err != nil { return priorities, errors.Wrapf(err, "get mongo hostname for pod %s", pod.Name) } diff --git a/pkg/psmdb/client.go b/pkg/psmdb/client.go index 8e74d3a9f7..31b4959045 100644 --- a/pkg/psmdb/client.go +++ b/pkg/psmdb/client.go @@ -50,12 +50,14 @@ func MongoClient(ctx context.Context, k8sclient client.Client, cr *api.PerconaSe Password: c.Password, } - tlsCfg, err := tls.Config(ctx, k8sclient, cr) - if err != nil { - return nil, errors.Wrap(err, "failed to get TLS config") - } + if cr.TLSEnabled() { + tlsCfg, err := tls.Config(ctx, k8sclient, cr) + if err != nil { + return nil, errors.Wrap(err, "failed to get TLS config") + } - conf.TLSConf = &tlsCfg + conf.TLSConf = &tlsCfg + } return mongo.Dial(conf) } @@ -71,17 +73,19 @@ func MongosClient(ctx context.Context, k8sclient client.Client, cr *api.PerconaS Password: c.Password, } - tlsCfg, err := tls.Config(ctx, k8sclient, cr) - if err != nil { - return nil, errors.Wrap(err, "failed to get TLS config") - } + if cr.TLSEnabled() { + tlsCfg, err := tls.Config(ctx, k8sclient, cr) + if err != nil { + return nil, errors.Wrap(err, "failed to get TLS config") + } - conf.TLSConf = &tlsCfg + conf.TLSConf = &tlsCfg + } return mongo.Dial(&conf) } -func StandaloneClient(ctx context.Context, k8sclient client.Client, cr *api.PerconaServerMongoDB, c Credentials, host string) (mongo.Client, error) { +func StandaloneClient(ctx context.Context, k8sclient client.Client, cr *api.PerconaServerMongoDB, c Credentials, host string, tlsEnabled bool) (mongo.Client, error) { conf := mongo.Config{ Hosts: []string{host}, Username: c.Username, @@ -89,12 +93,14 @@ func StandaloneClient(ctx context.Context, k8sclient client.Client, cr *api.Perc Direct: true, } - tlsCfg, err := tls.Config(ctx, k8sclient, cr) - if err != nil { - return nil, errors.Wrap(err, "failed to get TLS config") - } + if tlsEnabled { + tlsCfg, err := tls.Config(ctx, k8sclient, cr) + if err != nil { + return nil, errors.Wrap(err, "failed to get TLS config") + } - conf.TLSConf = &tlsCfg + conf.TLSConf = &tlsCfg + } return mongo.Dial(&conf) } diff --git a/pkg/psmdb/container.go b/pkg/psmdb/container.go index 96bcc7c23e..9d788e8e83 100644 --- a/pkg/psmdb/container.go +++ b/pkg/psmdb/container.go @@ -181,8 +181,6 @@ func containerArgs(ctx context.Context, cr *api.PerconaServerMongoDB, replset *a "--replSet=" + replset.Name, "--storageEngine=" + string(replset.Storage.Engine), "--relaxPermChecks", - "--sslAllowInvalidCertificates", - "--clusterAuthMode=x509", } name, err := replset.CustomReplsetName() @@ -190,16 +188,25 @@ func containerArgs(ctx context.Context, cr *api.PerconaServerMongoDB, replset *a args[4] = "--replSet=" + name } - if cr.Spec.UnsafeConf { + if cr.TLSEnabled() { + args = append(args, "--sslAllowInvalidCertificates") + if cr.Spec.TLS.Mode == api.TLSModeAllow { + args = append(args, + "--clusterAuthMode=keyFile", + "--keyFile="+mongodSecretsDir+"/mongodb-key", + ) + } else { + args = append(args, "--clusterAuthMode=x509") + } + } else if (cr.CompareVersion("1.16.0") >= 0 && cr.Spec.Unsafe.TLS) || (cr.CompareVersion("1.16.0") < 0 && cr.Spec.UnsafeConf) { args = append(args, "--clusterAuthMode=keyFile", "--keyFile="+mongodSecretsDir+"/mongodb-key", ) - } else { - if cr.CompareVersion("1.12.0") <= 0 { - args = append(args, "--sslMode=preferSSL") - } - args = append(args, "--clusterAuthMode=x509") + } + + if cr.CompareVersion("1.16.0") >= 0 { + args = append(args, "--tlsMode="+string(cr.Spec.TLS.Mode)) } // sharding diff --git a/pkg/psmdb/mongos.go b/pkg/psmdb/mongos.go index 0164be0d3a..1d14110e4f 100644 --- a/pkg/psmdb/mongos.go +++ b/pkg/psmdb/mongos.go @@ -174,12 +174,7 @@ func mongosContainer(cr *api.PerconaServerMongoDB, useConfigFile bool, cfgInstan Name: "mongos", Image: cr.Spec.Image, ImagePullPolicy: cr.Spec.ImagePullPolicy, - Args: mongosContainerArgs( - cr, - cr.Spec.Sharding.Mongos.Resources, - useConfigFile, - cfgInstances, - ), + Args: mongosContainerArgs(cr, useConfigFile, cfgInstances), Ports: []corev1.ContainerPort{ { Name: mongosPortName, @@ -232,7 +227,7 @@ func mongosContainer(cr *api.PerconaServerMongoDB, useConfigFile bool, cfgInstan return container, nil } -func mongosContainerArgs(cr *api.PerconaServerMongoDB, resources corev1.ResourceRequirements, useConfigFile bool, cfgInstances []string) []string { +func mongosContainerArgs(cr *api.PerconaServerMongoDB, useConfigFile bool, cfgInstances []string) []string { msSpec := cr.Spec.Sharding.Mongos cfgRs := cr.Spec.Sharding.ConfigsvrReplSet @@ -249,10 +244,8 @@ func mongosContainerArgs(cr *api.PerconaServerMongoDB, resources corev1.Resource "mongos", "--bind_ip_all", "--port=" + strconv.Itoa(int(msSpec.Port)), - "--sslAllowInvalidCertificates", "--configdb", configDB, - "--clusterAuthMode=x509", } if cr.CompareVersion("1.7.0") >= 0 { args = append(args, @@ -260,8 +253,20 @@ func mongosContainerArgs(cr *api.PerconaServerMongoDB, resources corev1.Resource ) } - if cr.CompareVersion("1.12.0") <= 0 { - args = append(args, "--sslMode=preferSSL") + if cr.TLSEnabled() { + args = append(args, + "--sslAllowInvalidCertificates", + "--clusterAuthMode=x509", + ) + } else if (cr.CompareVersion("1.16.0") >= 0 && cr.Spec.Unsafe.TLS) || (cr.CompareVersion("1.16.0") < 0 && cr.Spec.UnsafeConf) { + args = append(args, + "--clusterAuthMode=keyFile", + "--keyFile="+mongodSecretsDir+"/mongodb-key", + ) + } + + if cr.CompareVersion("1.16.0") >= 0 { + args = append(args, "--tlsMode="+string(cr.Spec.TLS.Mode)) } if msSpec.SetParameter != nil { @@ -364,25 +369,29 @@ func volumes(cr *api.PerconaServerMongoDB, configSource VolumeSourceType) []core }) } - if cr.CompareVersion("1.16.0") >= 0 && cr.Spec.Secrets.LDAPSecret != "" { - volumes = append(volumes, []corev1.Volume{ - { - Name: LDAPTLSVolClaimName, - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: cr.Spec.Secrets.LDAPSecret, - Optional: &tvar, - DefaultMode: &secretFileMode, + if cr.CompareVersion("1.16.0") >= 0 { + if cr.Spec.Secrets.LDAPSecret != "" { + volumes = append(volumes, []corev1.Volume{ + { + Name: LDAPTLSVolClaimName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: cr.Spec.Secrets.LDAPSecret, + Optional: &tvar, + DefaultMode: &secretFileMode, + }, }, }, - }, - { - Name: LDAPConfVolClaimName, - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, + { + Name: LDAPConfVolClaimName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, }, - }, - }...) + }...) + } + + volumes[1].VolumeSource.Secret.Optional = &cr.Spec.Unsafe.TLS } return volumes diff --git a/pkg/psmdb/pmm.go b/pkg/psmdb/pmm.go index 36fda1f6f7..4f84761f54 100644 --- a/pkg/psmdb/pmm.go +++ b/pkg/psmdb/pmm.go @@ -293,6 +293,8 @@ func pmmAgentEnvs(spec api.PMMSpec, secret *corev1.Secret, customLogin bool, cus } func PMMAgentScript(cr *api.PerconaServerMongoDB) []corev1.EnvVar { + // handle disabled TLS + pmmServerArgs := "$(PMM_ADMIN_CUSTOM_PARAMS) --skip-connection-check --metrics-mode=push " pmmServerArgs += " --username=$(DB_USER) --password=$(DB_PASSWORD) --cluster=$(CLUSTER_NAME) " pmmServerArgs += "--service-name=$(PMM_AGENT_SETUP_NODE_NAME) --host=$(DB_HOST) --port=$(DB_PORT)" diff --git a/pkg/psmdb/statefulset.go b/pkg/psmdb/statefulset.go index 27c2306b5b..ab8fbc1072 100644 --- a/pkg/psmdb/statefulset.go +++ b/pkg/psmdb/statefulset.go @@ -169,19 +169,24 @@ func StatefulSpec(ctx context.Context, cr *api.PerconaServerMongoDB, replset *ap volumeClaimTemplates := []corev1.PersistentVolumeClaim{} + sslVolume := corev1.Volume{ + Name: "ssl", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: cr.Spec.Secrets.SSL, + Optional: &cr.Spec.UnsafeConf, + DefaultMode: &secretFileMode, + }, + }, + } + if cr.CompareVersion("1.16.0") >= 0 { + sslVolume.VolumeSource.Secret.Optional = &cr.Spec.Unsafe.TLS + } + // add TLS/SSL Volume t := true volumes = append(volumes, - corev1.Volume{ - Name: "ssl", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: cr.Spec.Secrets.SSL, - Optional: &cr.Spec.UnsafeConf, - DefaultMode: &secretFileMode, - }, - }, - }, + sslVolume, corev1.Volume{ Name: "ssl-internal", VolumeSource: corev1.VolumeSource{ @@ -253,7 +258,7 @@ func StatefulSpec(ctx context.Context, cr *api.PerconaServerMongoDB, replset *ap if name, err := replset.CustomReplsetName(); err == nil { rsName = name } - containers = append(containers, backupAgentContainer(cr, rsName)) + containers = append(containers, backupAgentContainer(cr, rsName, cr.TLSEnabled())) } pmmC := AddPMMContainer(ctx, cr, usersSecret, cr.Spec.PMM.MongodParams) @@ -319,7 +324,7 @@ func StatefulSpec(ctx context.Context, cr *api.PerconaServerMongoDB, replset *ap const agentContainerName = "backup-agent" // backupAgentContainer creates the container object for a backup agent -func backupAgentContainer(cr *api.PerconaServerMongoDB, replsetName string) corev1.Container { +func backupAgentContainer(cr *api.PerconaServerMongoDB, replsetName string, tlsEnabled bool) corev1.Container { fvar := false usersSecretName := api.UserSecretName(cr) @@ -424,6 +429,13 @@ func backupAgentContainer(cr *api.PerconaServerMongoDB, replsetName string) core }...) } + if cr.CompareVersion("1.16.0") >= 0 { + c.Env = append(c.Env, corev1.EnvVar{ + Name: "PBM_AGENT_TLS_ENABLED", + Value: strconv.FormatBool(tlsEnabled), + }) + } + return c }