diff --git a/Makefile b/Makefile index dfd36866a4..43ea1f62ac 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ endef CONTROLLER_GEN = $(shell pwd)/bin/controller-gen controller-gen: ## Download controller-gen locally if necessary. - $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.1) + $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0) KUSTOMIZE = $(shell pwd)/bin/kustomize kustomize: ## Download kustomize locally if necessary. diff --git a/build/ps-entry.sh b/build/ps-entry.sh index b680571aa9..22055ae66d 100755 --- a/build/ps-entry.sh +++ b/build/ps-entry.sh @@ -430,6 +430,10 @@ if [[ $originalArgOne == mongo* ]]; then 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[@]}" diff --git a/config/crd/bases/psmdb.percona.com_perconaservermongodbbackups.yaml b/config/crd/bases/psmdb.percona.com_perconaservermongodbbackups.yaml index 85ca23d728..cd0c6dfa42 100644 --- a/config/crd/bases/psmdb.percona.com_perconaservermongodbbackups.yaml +++ b/config/crd/bases/psmdb.percona.com_perconaservermongodbbackups.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbbackups.psmdb.percona.com spec: group: psmdb.percona.com diff --git a/config/crd/bases/psmdb.percona.com_perconaservermongodbrestores.yaml b/config/crd/bases/psmdb.percona.com_perconaservermongodbrestores.yaml index 6c59246c50..81125b26f3 100644 --- a/config/crd/bases/psmdb.percona.com_perconaservermongodbrestores.yaml +++ b/config/crd/bases/psmdb.percona.com_perconaservermongodbrestores.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbrestores.psmdb.percona.com spec: group: psmdb.percona.com diff --git a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml index 918f581321..3233b54f47 100644 --- a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml +++ b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbs.psmdb.percona.com spec: group: psmdb.percona.com @@ -7636,6 +7635,8 @@ spec: properties: encryptionKey: type: string + ldapSecret: + type: string ssl: type: string sslInternal: diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index 9ac7d78cb8..4b2def980b 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -2,8 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbbackups.psmdb.percona.com spec: group: psmdb.percona.com @@ -160,8 +159,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbrestores.psmdb.percona.com spec: group: psmdb.percona.com @@ -319,8 +317,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbs.psmdb.percona.com spec: group: psmdb.percona.com @@ -8271,6 +8268,8 @@ spec: properties: encryptionKey: type: string + ldapSecret: + type: string ssl: type: string sslInternal: diff --git a/deploy/cr.yaml b/deploy/cr.yaml index 8915d0c248..c22bcce0f2 100644 --- a/deploy/cr.yaml +++ b/deploy/cr.yaml @@ -43,6 +43,7 @@ spec: users: my-cluster-name-secrets encryptionKey: my-cluster-name-mongodb-encryption-key # vault: my-cluster-name-vault +# ldapSecret: my-ldap-secret pmm: enabled: false image: perconalab/pmm-client:dev-latest diff --git a/deploy/crd.yaml b/deploy/crd.yaml index 5cc785b425..ba39be88ff 100644 --- a/deploy/crd.yaml +++ b/deploy/crd.yaml @@ -2,8 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbbackups.psmdb.percona.com spec: group: psmdb.percona.com @@ -160,8 +159,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbrestores.psmdb.percona.com spec: group: psmdb.percona.com @@ -319,8 +317,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbs.psmdb.percona.com spec: group: psmdb.percona.com @@ -8271,6 +8268,8 @@ spec: properties: encryptionKey: type: string + ldapSecret: + type: string ssl: type: string sslInternal: diff --git a/deploy/cw-bundle.yaml b/deploy/cw-bundle.yaml index 560b81170a..25659cc0ea 100644 --- a/deploy/cw-bundle.yaml +++ b/deploy/cw-bundle.yaml @@ -2,8 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbbackups.psmdb.percona.com spec: group: psmdb.percona.com @@ -160,8 +159,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbrestores.psmdb.percona.com spec: group: psmdb.percona.com @@ -319,8 +317,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbs.psmdb.percona.com spec: group: psmdb.percona.com @@ -8271,6 +8268,8 @@ spec: properties: encryptionKey: type: string + ldapSecret: + type: string ssl: type: string sslInternal: diff --git a/e2e-tests/arbiter/run b/e2e-tests/arbiter/run index 0fc53be9a2..2721feae74 100755 --- a/e2e-tests/arbiter/run +++ b/e2e-tests/arbiter/run @@ -70,8 +70,8 @@ check_cr_config() { } main() { - deploy_cert_manager create_infra $namespace + deploy_cert_manager desc 'create secrets and start client' kubectl_bin apply \ diff --git a/e2e-tests/data-sharded/run b/e2e-tests/data-sharded/run index c37339d9c3..d400055a23 100755 --- a/e2e-tests/data-sharded/run +++ b/e2e-tests/data-sharded/run @@ -35,8 +35,8 @@ main() { MONGO_VER=$(echo -n "${IMAGE_MONGOD}" | $sed -r 's/.*:([0-9]+\.[0-9]+).*$/\1/') fi - deploy_cert_manager create_infra "$namespace" + deploy_cert_manager desc 'create secrets and start client' kubectl_bin apply -f "$conf_dir/secrets.yml" diff --git a/e2e-tests/init-deploy/compare/clusterMonitor-50.json b/e2e-tests/init-deploy/compare/clusterMonitor-50.json index 9a1e7eb308..5ceb48eb9c 100644 --- a/e2e-tests/init-deploy/compare/clusterMonitor-50.json +++ b/e2e-tests/init-deploy/compare/clusterMonitor-50.json @@ -50,6 +50,15 @@ "indexStats" ] }, + { + "resource": { + "db": "admin", + "collection": "system.version" + }, + "actions": [ + "find" + ] + }, { "resource": { "db": "config", diff --git a/e2e-tests/init-deploy/compare/clusterMonitor-60.json b/e2e-tests/init-deploy/compare/clusterMonitor-60.json index c5dae81e27..dff1c0b0b8 100644 --- a/e2e-tests/init-deploy/compare/clusterMonitor-60.json +++ b/e2e-tests/init-deploy/compare/clusterMonitor-60.json @@ -50,6 +50,15 @@ "indexStats" ] }, + { + "resource": { + "db": "admin", + "collection": "system.version" + }, + "actions": [ + "find" + ] + }, { "resource": { "db": "config", diff --git a/e2e-tests/init-deploy/compare/clusterMonitor.json b/e2e-tests/init-deploy/compare/clusterMonitor.json index 1f8281d83e..759a48df5a 100644 --- a/e2e-tests/init-deploy/compare/clusterMonitor.json +++ b/e2e-tests/init-deploy/compare/clusterMonitor.json @@ -34,6 +34,15 @@ "find" ] }, + { + "resource": { + "db": "admin", + "collection": "system.version" + }, + "actions": [ + "find" + ] + }, { "resource": { "db": "config", diff --git a/e2e-tests/ldap-tls/compare/authInfo.json b/e2e-tests/ldap-tls/compare/authInfo.json new file mode 100644 index 0000000000..af2d0eae53 --- /dev/null +++ b/e2e-tests/ldap-tls/compare/authInfo.json @@ -0,0 +1,38 @@ +{ + "authenticatedUsers": [ + { + "user": "percona", + "db": "$external" + } + ], + "authenticatedUserRoles": [ + { + "role": "backup", + "db": "admin" + }, + { + "role": "clusterMonitor", + "db": "admin" + }, + { + "role": "cn=admin,ou=perconadba,dc=ldap,dc=local", + "db": "admin" + }, + { + "role": "dbAdminAnyDatabase", + "db": "admin" + }, + { + "role": "readAnyDatabase", + "db": "admin" + }, + { + "role": "readWriteAnyDatabase", + "db": "admin" + }, + { + "role": "restore", + "db": "admin" + } + ] +} diff --git a/e2e-tests/ldap-tls/conf/mongod.conf b/e2e-tests/ldap-tls/conf/mongod.conf new file mode 100644 index 0000000000..c3afb1b270 --- /dev/null +++ b/e2e-tests/ldap-tls/conf/mongod.conf @@ -0,0 +1,13 @@ +security: + authorization: enabled + ldap: + authz: + queryTemplate: dc=ldap,dc=local??sub?(&(objectClass=groupOfUniqueNames)(uniqueMember={USER})) + bind: + queryUser: "cn=readonly,dc=ldap,dc=local" + queryPassword: "readonlypass" + servers: servers + transportSecurity: tls + userToDNMapping: '[{"match":"(.+)","ldapQuery":"OU=perconadba,DC=ldap,DC=local??sub?(uid={0})"}]' +setParameter: + authenticationMechanisms: PLAIN,SCRAM-SHA-1 diff --git a/e2e-tests/ldap-tls/conf/mongos.conf b/e2e-tests/ldap-tls/conf/mongos.conf new file mode 100644 index 0000000000..502c113062 --- /dev/null +++ b/e2e-tests/ldap-tls/conf/mongos.conf @@ -0,0 +1,10 @@ +security: + ldap: + bind: + queryUser: "cn=readonly,dc=ldap,dc=local" + queryPassword: "readonlypass" + servers: servers + transportSecurity: tls + userToDNMapping: '[{"match":"(.+)","ldapQuery":"OU=perconadba,DC=ldap,DC=local??sub?(uid={0})"}]' +setParameter: + authenticationMechanisms: PLAIN,SCRAM-SHA-1 diff --git a/e2e-tests/ldap-tls/conf/openldap.yaml b/e2e-tests/ldap-tls/conf/openldap.yaml new file mode 100644 index 0000000000..a5b4f9879b --- /dev/null +++ b/e2e-tests/ldap-tls/conf/openldap.yaml @@ -0,0 +1,154 @@ +apiVersion: v1 +kind: Secret +metadata: + name: openldap +type: Opaque +stringData: + adminpassword: adminpassword +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: ldap-issuer +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: ldap-ca +spec: + isCA: true + commonName: openldap + secretName: ldap-ca + issuerRef: + name: ldap-issuer + kind: Issuer + group: cert-manager.io +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: percona-ldif +data: + 0-base.ldif: |- + dn: dc=ldap,dc=local + objectClass: top + objectClass: dcObject + objectClass: organization + o: ldap.local + dc: ldap + 1-percona-ous.ldif: |- + dn: ou=perconadba,dc=ldap,dc=local + objectClass: organizationalUnit + ou: perconadba + 2-percona-users.ldif: |- + dn: uid=percona,ou=perconadba,dc=ldap,dc=local + objectClass: top + objectClass: account + objectClass: posixAccount + objectClass: shadowAccount + cn: percona + uid: percona + uidNumber: 1100 + gidNumber: 100 + homeDirectory: /home/percona + loginShell: /bin/bash + gecos: percona + userPassword: password + shadowLastChange: -1 + shadowMax: -1 + #userPassword: {crypt}x + #shadowWarning: -1 + 3-group-cn.ldif: |- + dn: cn=admin,ou=perconadba,dc=ldap,dc=local + cn: admin + objectClass: groupOfUniqueNames + objectClass: top + ou: perconadba + uniqueMember: uid=percona,ou=perconadba,dc=ldap,dc=local + 4-readonly-user.ldif: |- + dn: cn=readonly,dc=ldap,dc=local + objectClass: top + objectClass: person + objectClass: organizationalPerson + objectClass: inetOrgPerson + cn: readonly + sn: readonly + userPassword: readonlypass + description: Read-only user for database-issued user lookups +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: openldap + labels: + app.kubernetes.io/name: openldap +spec: + selector: + matchLabels: + app.kubernetes.io/name: openldap + replicas: 1 + template: + metadata: + labels: + app.kubernetes.io/name: openldap + spec: + containers: + - name: openldap + image: docker.io/bitnami/openldap:latest + imagePullPolicy: "Always" + env: + - name: LDAP_ENABLE_TLS + value: "yes" + - name: LDAP_REQUIRE_TLS + value: "yes" + - name: LDAP_TLS_CERT_FILE + value: "/opt/bitnami/openldap/certs/tls.crt" + - name: LDAP_TLS_KEY_FILE + value: "/opt/bitnami/openldap/certs/tls.key" + - name: LDAP_TLS_CA_FILE + value: "/opt/bitnami/openldap/certs/ca.crt" + - name: LDAP_ROOT + value: "dc=ldap,dc=local" + - name: LDAP_ADMIN_USERNAME + value: "admin" + - name: LDAP_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: adminpassword + name: openldap + - name: LDAP_LOGLEVEL + value: "64" + - name: BITNAMI_DEBUG + value: "true" + ports: + - name: tls-ldap + containerPort: 1636 + volumeMounts: + - name: custom-ldif + mountPath: /ldifs + - name: ldap-ca + mountPath: /opt/bitnami/openldap/certs + volumes: + - name: custom-ldif + configMap: + name: percona-ldif + - name: ldap-ca + secret: + secretName: ldap-ca +--- +apiVersion: v1 +kind: Service +metadata: + name: openldap + labels: + app.kubernetes.io/name: openldap +spec: + type: ClusterIP + ports: + - name: tls-ldap + port: 1636 + targetPort: tls-ldap + selector: + app.kubernetes.io/name: openldap diff --git a/e2e-tests/ldap-tls/conf/some-name-sharded.yml b/e2e-tests/ldap-tls/conf/some-name-sharded.yml new file mode 100644 index 0000000000..05b9500b4d --- /dev/null +++ b/e2e-tests/ldap-tls/conf/some-name-sharded.yml @@ -0,0 +1,52 @@ +apiVersion: psmdb.percona.com/v1 +kind: PerconaServerMongoDB +metadata: + name: some-name-sharded +spec: + #platform: openshift + image: + imagePullPolicy: Always + backup: + enabled: false + sharding: + enabled: true + configsvrReplSet: + size: 3 + volumeSpec: + persistentVolumeClaim: + resources: + requests: + storage: 1Gi + expose: + enabled: false + + mongos: + size: 3 + configuration: | + replication: + localPingThresholdMs: 15 + expose: + exposeType: ClusterIP + + replsets: + - name: rs0 + affinity: + antiAffinityTopologyKey: none + expose: + enabled: false + resources: + limits: + cpu: 500m + memory: 1G + requests: + cpu: 100m + memory: 0.1G + volumeSpec: + persistentVolumeClaim: + resources: + requests: + storage: 1Gi + size: 3 + secrets: + users: some-users + ldapSecret: ldap-ca diff --git a/e2e-tests/ldap-tls/conf/some-name.yml b/e2e-tests/ldap-tls/conf/some-name.yml new file mode 100644 index 0000000000..28943342f3 --- /dev/null +++ b/e2e-tests/ldap-tls/conf/some-name.yml @@ -0,0 +1,30 @@ +apiVersion: psmdb.percona.com/v1 +kind: PerconaServerMongoDB +metadata: + name: some-name +spec: + #platform: openshift + image: + imagePullPolicy: Always + backup: + enabled: false + replsets: + - name: rs0 + resources: + limits: + cpu: 500m + memory: 1G + requests: + cpu: 100m + memory: 0.1G + volumeSpec: + persistentVolumeClaim: + resources: + requests: + storage: 1Gi + expose: + enabled: false + size: 3 + secrets: + users: some-users + ldapSecret: ldap-ca diff --git a/e2e-tests/ldap-tls/run b/e2e-tests/ldap-tls/run new file mode 100755 index 0000000000..cd476d5d50 --- /dev/null +++ b/e2e-tests/ldap-tls/run @@ -0,0 +1,161 @@ +#!/bin/bash + +set -o errexit + +test_dir=$(realpath "$(dirname "$0")") +. "${test_dir}/../functions" +set_debug + +deploy_openldap() { + yq "$test_dir/conf/openldap.yaml" \ + | yq "select(.metadata.name == \"ldap-ca\").spec.dnsNames[0]=\"openldap.$namespace.svc.cluster.local\"" \ + | kubectl_bin apply -f - + + kubectl rollout status deployment/openldap --timeout=120s +} + +test_mongod_openldap() { + cluster="some-name" + + kubectl_bin create secret generic $cluster-rs0-mongod --from-literal=mongod.conf="$(yq "$test_dir/conf/mongod.conf" \ + | yq ".security.ldap.servers=\"openldap.$namespace.svc.cluster.local:1636\"")" + + desc "create first PSMDB cluster $cluster" + apply_cluster "$test_dir/conf/$cluster.yml" + + desc 'check if all 3 Pods started' + wait_for_running $cluster-rs0 3 + + run_mongo \ + 'db.getSiblingDB("admin").createRole( +{ + role: "cn=admin,ou=perconadba,dc=ldap,dc=local", + privileges: [], + roles : [ + { + "role" : "readAnyDatabase", + "db" : "admin" + }, + { + "role" : "dbAdminAnyDatabase", + "db" : "admin" + }, + { + "role" : "clusterMonitor", + "db" : "admin" + }, + { + "role" : "readWriteAnyDatabase", + "db" : "admin" + }, + { + "role" : "restore", + "db" : "admin" + }, + { + "role" : "backup", + "db" : "admin" + } + ]})' \ + "userAdmin:userAdmin123456@$cluster-rs0.$namespace" + + run_mongo 'JSON.stringify(db.runCommand({connectionStatus:1}))' \ + "percona:password@$cluster-rs0.$namespace" "" "" \ + "--authenticationMechanism 'PLAIN' --authenticationDatabase '\$external'" \ + | grep -E -v "Percona Server for MongoDB|connecting to:|Implicit session:|versions do not match|Error saving history file:|bye" \ + | jq '.authInfo' \ + | jq '.authenticatedUserRoles |= sort_by(.role)' >"$tmp_dir/$cluster-$namespace-authInfo.json" + + diff "${test_dir}/compare/authInfo.json" "$tmp_dir/$cluster-$namespace-authInfo.json" + + kubectl_bin delete psmdb $cluster + kubectl_bin delete pvc --all +} + +test_sharded_openldap() { + cluster="some-name-sharded" + + kubectl_bin create secret generic $cluster-mongos --from-literal=mongos.conf="$(yq "$test_dir/conf/mongos.conf" \ + | yq ".security.ldap.servers=\"openldap.$namespace.svc.cluster.local:1636\"")" + + kubectl_bin create secret generic $cluster-cfg-mongod --from-literal=mongod.conf="$(yq "$test_dir/conf/mongod.conf" \ + | yq ".security.ldap.servers=\"openldap.$namespace.svc.cluster.local:1636\"")" + + desc "create first PSMDB cluster $cluster" + + apply_cluster "$test_dir/conf/$cluster.yml" + + desc 'check if all 3 Pods started' + wait_for_running $cluster-rs0 3 + wait_for_running $cluster-cfg 3 "false" + wait_for_running $cluster-mongos 3 + wait_cluster_consistency $cluster + + run_mongos \ + 'db.getSiblingDB("admin").createRole( +{ + role: "cn=admin,ou=perconadba,dc=ldap,dc=local", + privileges: [], + roles : [ + { + "role" : "readAnyDatabase", + "db" : "admin" + }, + { + "role" : "dbAdminAnyDatabase", + "db" : "admin" + }, + { + "role" : "clusterMonitor", + "db" : "admin" + }, + { + "role" : "readWriteAnyDatabase", + "db" : "admin" + }, + { + "role" : "restore", + "db" : "admin" + }, + { + "role" : "backup", + "db" : "admin" + } + ]})' \ + "userAdmin:userAdmin123456@$cluster-mongos.$namespace" + + run_mongos 'JSON.stringify(db.runCommand({connectionStatus:1}))' \ + "percona:password@$cluster-mongos.$namespace" "" "" \ + "--authenticationMechanism 'PLAIN' --authenticationDatabase '\$external'" \ + | grep -E -v "Percona Server for MongoDB|connecting to:|Implicit session:|versions do not match|Error saving history file:|bye" \ + | jq '.authInfo' \ + | jq '.authenticatedUserRoles |= sort_by(.role)' >"$tmp_dir/$cluster-$namespace-authInfo.json" + + diff "${test_dir}/compare/authInfo.json" "$tmp_dir/$cluster-$namespace-authInfo.json" + + kubectl_bin delete psmdb $cluster + kubectl_bin delete pvc --all +} + +main() { + create_infra "$namespace" + + deploy_cert_manager + + deploy_openldap + + desc 'create secrets and start client' + cluster="some-name" + kubectl_bin apply \ + -f "$conf_dir/secrets.yml" \ + -f "$conf_dir/client.yml" + + test_mongod_openldap + test_sharded_openldap + + destroy "$namespace" + + desc 'test passed' +} + +main diff --git a/e2e-tests/ldap/compare/authInfo.json b/e2e-tests/ldap/compare/authInfo.json new file mode 100644 index 0000000000..af2d0eae53 --- /dev/null +++ b/e2e-tests/ldap/compare/authInfo.json @@ -0,0 +1,38 @@ +{ + "authenticatedUsers": [ + { + "user": "percona", + "db": "$external" + } + ], + "authenticatedUserRoles": [ + { + "role": "backup", + "db": "admin" + }, + { + "role": "clusterMonitor", + "db": "admin" + }, + { + "role": "cn=admin,ou=perconadba,dc=ldap,dc=local", + "db": "admin" + }, + { + "role": "dbAdminAnyDatabase", + "db": "admin" + }, + { + "role": "readAnyDatabase", + "db": "admin" + }, + { + "role": "readWriteAnyDatabase", + "db": "admin" + }, + { + "role": "restore", + "db": "admin" + } + ] +} diff --git a/e2e-tests/ldap/conf/mongod.conf b/e2e-tests/ldap/conf/mongod.conf new file mode 100644 index 0000000000..fbfccc1efc --- /dev/null +++ b/e2e-tests/ldap/conf/mongod.conf @@ -0,0 +1,13 @@ +security: + authorization: enabled + ldap: + authz: + queryTemplate: dc=ldap,dc=local??sub?(&(objectClass=groupOfUniqueNames)(uniqueMember={USER})) + bind: + queryUser: "cn=readonly,dc=ldap,dc=local" + queryPassword: "readonlypass" + servers: servers + transportSecurity: none + userToDNMapping: '[{"match":"(.+)","ldapQuery":"OU=perconadba,DC=ldap,DC=local??sub?(uid={0})"}]' +setParameter: + authenticationMechanisms: PLAIN,SCRAM-SHA-1 diff --git a/e2e-tests/ldap/conf/mongos.conf b/e2e-tests/ldap/conf/mongos.conf new file mode 100644 index 0000000000..810af4bb8f --- /dev/null +++ b/e2e-tests/ldap/conf/mongos.conf @@ -0,0 +1,12 @@ +replication: + localPingThresholdMs: 15 +security: + ldap: + bind: + queryUser: "cn=readonly,dc=ldap,dc=local" + queryPassword: "readonlypass" + servers: servers + transportSecurity: none + userToDNMapping: '[{"match":"(.+)","ldapQuery":"OU=perconadba,DC=ldap,DC=local??sub?(uid={0})"}]' +setParameter: + authenticationMechanisms: PLAIN,SCRAM-SHA-1 diff --git a/e2e-tests/ldap/conf/openldap.yaml b/e2e-tests/ldap/conf/openldap.yaml new file mode 100644 index 0000000000..b6a840d3ad --- /dev/null +++ b/e2e-tests/ldap/conf/openldap.yaml @@ -0,0 +1,119 @@ +apiVersion: v1 +kind: Secret +metadata: + name: openldap +type: Opaque +stringData: + adminpassword: adminpassword +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: percona-ldif +data: + 0-base.ldif: |- + dn: dc=ldap,dc=local + objectClass: top + objectClass: dcObject + objectClass: organization + o: ldap.local + dc: ldap + 1-percona-ous.ldif: |- + dn: ou=perconadba,dc=ldap,dc=local + objectClass: organizationalUnit + ou: perconadba + 2-percona-users.ldif: |- + dn: uid=percona,ou=perconadba,dc=ldap,dc=local + objectClass: top + objectClass: account + objectClass: posixAccount + objectClass: shadowAccount + cn: percona + uid: percona + uidNumber: 1100 + gidNumber: 100 + homeDirectory: /home/percona + loginShell: /bin/bash + gecos: percona + userPassword: password + shadowLastChange: -1 + shadowMax: -1 + #userPassword: {crypt}x + #shadowWarning: -1 + 3-group-cn.ldif: |- + dn: cn=admin,ou=perconadba,dc=ldap,dc=local + cn: admin + objectClass: groupOfUniqueNames + objectClass: top + ou: perconadba + uniqueMember: uid=percona,ou=perconadba,dc=ldap,dc=local + 4-readonly-user.ldif: |- + dn: cn=readonly,dc=ldap,dc=local + objectClass: top + objectClass: person + objectClass: organizationalPerson + objectClass: inetOrgPerson + cn: readonly + sn: readonly + userPassword: readonlypass + description: Read-only user for database-issued user lookups +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: openldap + labels: + app.kubernetes.io/name: openldap +spec: + selector: + matchLabels: + app.kubernetes.io/name: openldap + replicas: 1 + template: + metadata: + labels: + app.kubernetes.io/name: openldap + spec: + containers: + - name: openldap + image: docker.io/bitnami/openldap:latest + imagePullPolicy: "Always" + env: + - name: LDAP_ROOT + value: "dc=ldap,dc=local" + - name: LDAP_ADMIN_USERNAME + value: "admin" + - name: LDAP_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: adminpassword + name: openldap + - name: LDAP_LOGLEVEL + value: "64" + - name: BITNAMI_DEBUG + value: "true" + ports: + - name: tcp-ldap + containerPort: 1389 + volumeMounts: + - name: custom-ldif + mountPath: /ldifs + volumes: + - name: custom-ldif + configMap: + name: percona-ldif +--- +apiVersion: v1 +kind: Service +metadata: + name: openldap + labels: + app.kubernetes.io/name: openldap +spec: + type: ClusterIP + ports: + - name: tcp-ldap + port: 1389 + targetPort: tcp-ldap + selector: + app.kubernetes.io/name: openldap diff --git a/e2e-tests/ldap/conf/some-name-sharded.yml b/e2e-tests/ldap/conf/some-name-sharded.yml new file mode 100644 index 0000000000..b3d1677810 --- /dev/null +++ b/e2e-tests/ldap/conf/some-name-sharded.yml @@ -0,0 +1,51 @@ +apiVersion: psmdb.percona.com/v1 +kind: PerconaServerMongoDB +metadata: + name: some-name-sharded +spec: + #platform: openshift + image: + imagePullPolicy: Always + backup: + enabled: false + sharding: + enabled: true + configsvrReplSet: + size: 3 + volumeSpec: + persistentVolumeClaim: + resources: + requests: + storage: 1Gi + expose: + enabled: false + + mongos: + size: 3 + configuration: | + replication: + localPingThresholdMs: 15 + expose: + exposeType: ClusterIP + + replsets: + - name: rs0 + affinity: + antiAffinityTopologyKey: none + expose: + enabled: false + resources: + limits: + cpu: 500m + memory: 1G + requests: + cpu: 100m + memory: 0.1G + volumeSpec: + persistentVolumeClaim: + resources: + requests: + storage: 1Gi + size: 3 + secrets: + users: some-users diff --git a/e2e-tests/ldap/conf/some-name.yml b/e2e-tests/ldap/conf/some-name.yml new file mode 100644 index 0000000000..35b9ef4e03 --- /dev/null +++ b/e2e-tests/ldap/conf/some-name.yml @@ -0,0 +1,29 @@ +apiVersion: psmdb.percona.com/v1 +kind: PerconaServerMongoDB +metadata: + name: some-name +spec: + #platform: openshift + image: + imagePullPolicy: Always + backup: + enabled: false + replsets: + - name: rs0 + resources: + limits: + cpu: 500m + memory: 1G + requests: + cpu: 100m + memory: 0.1G + volumeSpec: + persistentVolumeClaim: + resources: + requests: + storage: 1Gi + expose: + enabled: false + size: 3 + secrets: + users: some-users diff --git a/e2e-tests/ldap/run b/e2e-tests/ldap/run new file mode 100755 index 0000000000..b1e91089ec --- /dev/null +++ b/e2e-tests/ldap/run @@ -0,0 +1,157 @@ +#!/bin/bash + +set -o errexit + +test_dir=$(realpath "$(dirname "$0")") +. "${test_dir}/../functions" +set_debug + +deploy_openldap() { + kubectl_bin apply -f "$test_dir/conf/openldap.yaml" + + kubectl rollout status deployment/openldap --timeout=120s +} + +test_mongod_openldap() { + cluster="some-name" + + kubectl_bin create secret generic $cluster-rs0-mongod --from-literal=mongod.conf="$(yq "$test_dir/conf/mongod.conf" \ + | yq ".security.ldap.servers=\"openldap.$namespace.svc.cluster.local:1389\"")" + + desc "create first PSMDB cluster $cluster" + apply_cluster "$test_dir/conf/$cluster.yml" + + desc 'check if all 3 Pods started' + wait_for_running $cluster-rs0 3 + + run_mongo \ + 'db.getSiblingDB("admin").createRole( +{ + role: "cn=admin,ou=perconadba,dc=ldap,dc=local", + privileges: [], + roles : [ + { + "role" : "readAnyDatabase", + "db" : "admin" + }, + { + "role" : "dbAdminAnyDatabase", + "db" : "admin" + }, + { + "role" : "clusterMonitor", + "db" : "admin" + }, + { + "role" : "readWriteAnyDatabase", + "db" : "admin" + }, + { + "role" : "restore", + "db" : "admin" + }, + { + "role" : "backup", + "db" : "admin" + } + ]})' \ + "userAdmin:userAdmin123456@$cluster-rs0.$namespace" + + run_mongo 'JSON.stringify(db.runCommand({connectionStatus:1}))' \ + "percona:password@$cluster-rs0.$namespace" "" "" \ + "--authenticationMechanism 'PLAIN' --authenticationDatabase '\$external'" \ + | grep -E -v "Percona Server for MongoDB|connecting to:|Implicit session:|versions do not match|Error saving history file:|bye" \ + | jq '.authInfo' \ + | jq '.authenticatedUserRoles |= sort_by(.role)' >"$tmp_dir/$cluster-$namespace-authInfo.json" + + diff "${test_dir}/compare/authInfo.json" "$tmp_dir/$cluster-$namespace-authInfo.json" + + kubectl_bin delete psmdb $cluster + kubectl_bin delete pvc --all +} + +test_sharded_openldap() { + cluster="some-name-sharded" + + kubectl_bin create secret generic $cluster-mongos --from-literal=mongos.conf="$(yq "$test_dir/conf/mongos.conf" \ + | yq ".security.ldap.servers=\"openldap.$namespace.svc.cluster.local:1389\"")" + + kubectl_bin create secret generic $cluster-cfg-mongod --from-literal=mongod.conf="$(yq "$test_dir/conf/mongod.conf" \ + | yq ".security.ldap.servers=\"openldap.$namespace.svc.cluster.local:1389\"")" + + desc "create first PSMDB cluster $cluster" + + apply_cluster "$test_dir/conf/$cluster.yml" + + desc 'check if all 3 Pods started' + wait_for_running $cluster-rs0 3 + wait_for_running $cluster-cfg 3 "false" + wait_for_running $cluster-mongos 3 + wait_cluster_consistency $cluster + + run_mongos \ + 'db.getSiblingDB("admin").createRole( +{ + role: "cn=admin,ou=perconadba,dc=ldap,dc=local", + privileges: [], + roles : [ + { + "role" : "readAnyDatabase", + "db" : "admin" + }, + { + "role" : "dbAdminAnyDatabase", + "db" : "admin" + }, + { + "role" : "clusterMonitor", + "db" : "admin" + }, + { + "role" : "readWriteAnyDatabase", + "db" : "admin" + }, + { + "role" : "restore", + "db" : "admin" + }, + { + "role" : "backup", + "db" : "admin" + } + ]})' \ + "userAdmin:userAdmin123456@$cluster-mongos.$namespace" + + run_mongos 'JSON.stringify(db.runCommand({connectionStatus:1}))' \ + "percona:password@$cluster-mongos.$namespace" "" "" \ + "--authenticationMechanism 'PLAIN' --authenticationDatabase '\$external'" \ + | grep -E -v "Percona Server for MongoDB|connecting to:|Implicit session:|versions do not match|Error saving history file:|bye" \ + | jq '.authInfo' \ + | jq '.authenticatedUserRoles |= sort_by(.role)' >"$tmp_dir/$cluster-$namespace-authInfo.json" + + diff "${test_dir}/compare/authInfo.json" "$tmp_dir/$cluster-$namespace-authInfo.json" + + kubectl_bin delete psmdb $cluster + kubectl_bin delete pvc --all +} + +main() { + create_infra "$namespace" + + deploy_openldap + + desc 'create secrets and start client' + cluster="some-name" + kubectl_bin apply \ + -f "$conf_dir/secrets.yml" \ + -f "$conf_dir/client.yml" + + test_mongod_openldap + test_sharded_openldap + + destroy "$namespace" + + desc 'test passed' +} + +main diff --git a/e2e-tests/monitoring-2-0/run b/e2e-tests/monitoring-2-0/run index 3d448e47ad..d535a2a446 100755 --- a/e2e-tests/monitoring-2-0/run +++ b/e2e-tests/monitoring-2-0/run @@ -25,8 +25,8 @@ does_node_id_exists() { echo "${nodeList_from_pmm[@]}" } -deploy_cert_manager create_infra $namespace +deploy_cert_manager desc 'install PMM Server' diff --git a/e2e-tests/non-voting/run b/e2e-tests/non-voting/run index 0d33f5b72f..088df33f7c 100755 --- a/e2e-tests/non-voting/run +++ b/e2e-tests/non-voting/run @@ -35,8 +35,8 @@ spinup_psmdb() { main() { local cluster="nonvoting-rs0" - deploy_cert_manager create_infra $namespace + deploy_cert_manager desc 'create secrets and start client' kubectl_bin apply \ diff --git a/e2e-tests/run-distro.csv b/e2e-tests/run-distro.csv index 3ecee26709..b8574a0074 100644 --- a/e2e-tests/run-distro.csv +++ b/e2e-tests/run-distro.csv @@ -9,6 +9,8 @@ demand-backup-physical demand-backup-physical-sharded demand-backup-sharded init-deploy +ldap +ldap-tls mongod-major-upgrade mongod-major-upgrade-sharded monitoring-2-0 diff --git a/e2e-tests/run-minikube.csv b/e2e-tests/run-minikube.csv index 1da7bc8190..c6f303109e 100644 --- a/e2e-tests/run-minikube.csv +++ b/e2e-tests/run-minikube.csv @@ -2,6 +2,8 @@ arbiter default-cr demand-backup demand-backup-physical +ldap +ldap-tls limits liveness mongod-major-upgrade diff --git a/e2e-tests/run-pr.csv b/e2e-tests/run-pr.csv index 08aeef9436..5fcff3e9e9 100644 --- a/e2e-tests/run-pr.csv +++ b/e2e-tests/run-pr.csv @@ -13,6 +13,8 @@ expose-sharded ignore-labels-annotations init-deploy finalizer +ldap +ldap-tls limits liveness mongod-major-upgrade diff --git a/e2e-tests/run-release.csv b/e2e-tests/run-release.csv index c96dcd7973..ac49b0fb6c 100644 --- a/e2e-tests/run-release.csv +++ b/e2e-tests/run-release.csv @@ -14,6 +14,8 @@ expose-sharded ignore-labels-annotations init-deploy finalizer +ldap +ldap-tls limits liveness mongod-major-upgrade diff --git a/e2e-tests/service-per-pod/run b/e2e-tests/service-per-pod/run index 12156dd9b0..e3d2131d1b 100755 --- a/e2e-tests/service-per-pod/run +++ b/e2e-tests/service-per-pod/run @@ -75,8 +75,8 @@ check_cr_config() { } main() { - deploy_cert_manager create_infra $namespace + deploy_cert_manager desc 'create secrets and start client' kubectl_bin apply \ diff --git a/e2e-tests/storage/run b/e2e-tests/storage/run index 340844fab4..4dff4779f6 100755 --- a/e2e-tests/storage/run +++ b/e2e-tests/storage/run @@ -43,8 +43,8 @@ check_cr_config() { } main() { - deploy_cert_manager create_infra $namespace + deploy_cert_manager desc 'create secrets and start client' kubectl_bin apply \ diff --git a/e2e-tests/upgrade-sharded/run b/e2e-tests/upgrade-sharded/run index 5f8b141520..08db6b2323 100755 --- a/e2e-tests/upgrade-sharded/run +++ b/e2e-tests/upgrade-sharded/run @@ -161,8 +161,8 @@ function main() { if [ -n "$OPERATOR_NS" ]; then rbac="cw-rbac" fi - deploy_cert_manager create_infra_gh "${namespace}" "${GIT_TAG}" + deploy_cert_manager apply_s3_storage_secrets deploy_minio diff --git a/e2e-tests/version-service/conf/crd.yaml b/e2e-tests/version-service/conf/crd.yaml index 5cc785b425..ba39be88ff 100644 --- a/e2e-tests/version-service/conf/crd.yaml +++ b/e2e-tests/version-service/conf/crd.yaml @@ -2,8 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbbackups.psmdb.percona.com spec: group: psmdb.percona.com @@ -160,8 +159,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbrestores.psmdb.percona.com spec: group: psmdb.percona.com @@ -319,8 +317,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.11.1 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.14.0 name: perconaservermongodbs.psmdb.percona.com spec: group: psmdb.percona.com @@ -8271,6 +8268,8 @@ spec: properties: encryptionKey: type: string + ldapSecret: + type: string ssl: type: string sslInternal: diff --git a/pkg/apis/psmdb/v1/psmdb_defaults.go b/pkg/apis/psmdb/v1/psmdb_defaults.go index 8112b5dcdc..cbd0412a4c 100644 --- a/pkg/apis/psmdb/v1/psmdb_defaults.go +++ b/pkg/apis/psmdb/v1/psmdb_defaults.go @@ -193,11 +193,10 @@ 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 { - cr.Spec.Sharding.Mongos.LivenessProbe.Exec.Command = - append(cr.Spec.Sharding.Mongos.LivenessProbe.Exec.Command, - "--ssl", "--sslInsecure", - "--sslCAFile", "/etc/mongodb-ssl/ca.crt", - "--sslPEMKeyFile", "/tmp/tls.pem") + cr.Spec.Sharding.Mongos.LivenessProbe.Exec.Command = append(cr.Spec.Sharding.Mongos.LivenessProbe.Exec.Command, + "--ssl", "--sslInsecure", + "--sslCAFile", "/etc/mongodb-ssl/ca.crt", + "--sslPEMKeyFile", "/tmp/tls.pem") } if cr.CompareVersion("1.11.0") >= 0 && !cr.Spec.Sharding.Mongos.LivenessProbe.CommandHas(startupDelaySecondsFlag) { @@ -239,11 +238,10 @@ 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 { - cr.Spec.Sharding.Mongos.ReadinessProbe.Exec.Command = - append(cr.Spec.Sharding.Mongos.ReadinessProbe.Exec.Command, - "--ssl", "--sslInsecure", - "--sslCAFile", "/etc/mongodb-ssl/ca.crt", - "--sslPEMKeyFile", "/tmp/tls.pem") + cr.Spec.Sharding.Mongos.ReadinessProbe.Exec.Command = append(cr.Spec.Sharding.Mongos.ReadinessProbe.Exec.Command, + "--ssl", "--sslInsecure", + "--sslCAFile", "/etc/mongodb-ssl/ca.crt", + "--sslPEMKeyFile", "/tmp/tls.pem") } if cr.CompareVersion("1.14.0") >= 0 { @@ -370,11 +368,10 @@ func (cr *PerconaServerMongoDB) CheckNSetDefaults(platform version.Platform, log 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 = append(replset.LivenessProbe.Probe.Exec.Command, + "--ssl", "--sslInsecure", + "--sslCAFile", "/etc/mongodb-ssl/ca.crt", + "--sslPEMKeyFile", "/tmp/tls.pem") } } diff --git a/pkg/apis/psmdb/v1/psmdb_types.go b/pkg/apis/psmdb/v1/psmdb_types.go index 5f92cdf82d..6a214e3869 100644 --- a/pkg/apis/psmdb/v1/psmdb_types.go +++ b/pkg/apis/psmdb/v1/psmdb_types.go @@ -599,6 +599,7 @@ type SecretsSpec struct { SSLInternal string `json:"sslInternal,omitempty"` EncryptionKey string `json:"encryptionKey,omitempty"` Vault string `json:"vault,omitempty"` + LDAPSecret string `json:"ldapSecret,omitempty"` } type MongosSpec struct { diff --git a/pkg/apis/psmdb/v1/zz_generated.deepcopy.go b/pkg/apis/psmdb/v1/zz_generated.deepcopy.go index 833470601b..0a098eb1d0 100644 --- a/pkg/apis/psmdb/v1/zz_generated.deepcopy.go +++ b/pkg/apis/psmdb/v1/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated // Code generated by controller-gen. DO NOT EDIT. @@ -268,7 +267,8 @@ func (in HorizonsSpec) DeepCopyInto(out *HorizonsSpec) { if val == nil { (*out)[key] = nil } else { - in, out := &val, &outVal + inVal := (*in)[key] + in, out := &inVal, &outVal *out = make(map[string]string, len(*in)) for key, val := range *in { (*out)[key] = val @@ -1334,7 +1334,8 @@ func (in *ReplsetSpec) DeepCopyInto(out *ReplsetSpec) { if val == nil { (*out)[key] = nil } else { - in, out := &val, &outVal + inVal := (*in)[key] + in, out := &inVal, &outVal *out = make(map[string]string, len(*in)) for key, val := range *in { (*out)[key] = val diff --git a/pkg/controller/perconaservermongodb/mgo.go b/pkg/controller/perconaservermongodb/mgo.go index 04d55594cd..f7ced795ba 100644 --- a/pkg/controller/perconaservermongodb/mgo.go +++ b/pkg/controller/perconaservermongodb/mgo.go @@ -24,7 +24,8 @@ import ( var errReplsetLimit = fmt.Errorf("maximum replset member (%d) count reached", mongo.MaxMembers) func (r *ReconcilePerconaServerMongoDB) reconcileCluster(ctx context.Context, cr *api.PerconaServerMongoDB, replset *api.ReplsetSpec, - mongosPods []corev1.Pod) (api.AppState, error) { + mongosPods []corev1.Pod, +) (api.AppState, error) { log := logf.FromContext(ctx) replsetSize := replset.Size @@ -505,7 +506,8 @@ func (r *ReconcilePerconaServerMongoDB) removeRSFromShard(ctx context.Context, c } func (r *ReconcilePerconaServerMongoDB) handleRsAddToShard(ctx context.Context, cr *api.PerconaServerMongoDB, replset *api.ReplsetSpec, rspod corev1.Pod, - mongosPod corev1.Pod) error { + mongosPod corev1.Pod, +) error { if !isContainerAndPodRunning(rspod, "mongod") || !isPodReady(rspod) { return errors.Errorf("rsPod %s is not ready", rspod.Name) } @@ -796,6 +798,17 @@ func (r *ReconcilePerconaServerMongoDB) createOrUpdateSystemUsers(ctx context.Co }, } } + if cr.CompareVersion("1.16.0") >= 0 { + privileges = append(privileges, mongo.RolePrivilege{ + Resource: map[string]interface{}{ + "db": "admin", + "collection": "system.version", + }, + Actions: []string{ + "find", + }, + }) + } err = r.createOrUpdateSystemRoles(ctx, cli, "explainRole", privileges) if err != nil { diff --git a/pkg/controller/perconaservermongodb/psmdb_controller.go b/pkg/controller/perconaservermongodb/psmdb_controller.go index eb741bf70b..1ae4fd6b41 100644 --- a/pkg/controller/perconaservermongodb/psmdb_controller.go +++ b/pkg/controller/perconaservermongodb/psmdb_controller.go @@ -1537,6 +1537,26 @@ func (r *ReconcilePerconaServerMongoDB) reconcileStatefulSet( }, }) } + if cr.CompareVersion("1.16.0") >= 0 && cr.Spec.Secrets.LDAPSecret != "" { + sfsSpec.Template.Spec.Volumes = append(sfsSpec.Template.Spec.Volumes, + corev1.Volume{ + Name: psmdb.LDAPTLSVolClaimName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: cr.Spec.Secrets.LDAPSecret, + Optional: &t, + DefaultMode: &secretFileMode, + }, + }, + }, + corev1.Volume{ + Name: psmdb.LDAPConfVolClaimName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + ) + } secret := new(corev1.Secret) err = r.client.Get(ctx, types.NamespacedName{Name: api.UserSecretName(cr), Namespace: cr.Namespace}, secret) if client.IgnoreNotFound(err) != nil { diff --git a/pkg/controller/perconaservermongodb/users.go b/pkg/controller/perconaservermongodb/users.go index 6bf8db5a3e..99953d40f2 100644 --- a/pkg/controller/perconaservermongodb/users.go +++ b/pkg/controller/perconaservermongodb/users.go @@ -158,7 +158,6 @@ func (r *ReconcilePerconaServerMongoDB) killcontainer(ctx context.Context, pods return nil }) - if err != nil { return errors.Wrap(err, "failed to restart container") } @@ -212,7 +211,8 @@ func (su *systemUsers) len() int { } func (r *ReconcilePerconaServerMongoDB) updateSysUsers(ctx context.Context, cr *api.PerconaServerMongoDB, newUsersSec, currUsersSec *corev1.Secret, - repls []*api.ReplsetSpec) ([]string, error) { + repls []*api.ReplsetSpec, +) ([]string, error) { su := systemUsers{ currData: currUsersSec.Data, newData: newUsersSec.Data, diff --git a/pkg/psmdb/const.go b/pkg/psmdb/const.go index f9dc089144..ba9beb3f68 100644 --- a/pkg/psmdb/const.go +++ b/pkg/psmdb/const.go @@ -23,6 +23,11 @@ const ( BinVolumeName = "bin" BinMountPath = "/opt/percona" + LDAPConfVolClaimName = "ldap" + ldapConfDir = "/etc/openldap" + LDAPTLSVolClaimName = "ldap-tls" + ldapTLSDir = "/etc/openldap/certs" + SSLDir = "/etc/mongodb-ssl" sslInternalDir = "/etc/mongodb-ssl-internal" vaultDir = "/etc/mongodb-vault" @@ -130,7 +135,7 @@ func (s *hashableSecret) GetHashHex() (string, error) { } func getCustomConfigHashHex(strData map[string]string, binData map[string][]byte) (string, error) { - var content = struct { + content := struct { StrData map[string]string `json:"str_data,omitempty"` BinData map[string][]byte `json:"bin_data,omitempty"` }{ diff --git a/pkg/psmdb/container.go b/pkg/psmdb/container.go index c28b75c4a3..9552300232 100644 --- a/pkg/psmdb/container.go +++ b/pkg/psmdb/container.go @@ -14,7 +14,8 @@ import ( func container(ctx context.Context, cr *api.PerconaServerMongoDB, replset *api.ReplsetSpec, name string, resources corev1.ResourceRequirements, ikeyName string, useConfigFile bool, livenessProbe *api.LivenessProbeExtended, readinessProbe *corev1.Probe, - containerSecurityContext *corev1.SecurityContext) (corev1.Container, error) { + containerSecurityContext *corev1.SecurityContext, +) (corev1.Container, error) { fvar := false volumes := []corev1.VolumeMount{ @@ -50,6 +51,20 @@ func container(ctx context.Context, cr *api.PerconaServerMongoDB, replset *api.R volumes = append(volumes, corev1.VolumeMount{Name: BinVolumeName, MountPath: BinMountPath}) } + if cr.CompareVersion("1.16.0") >= 0 && cr.Spec.Secrets.LDAPSecret != "" { + volumes = append(volumes, []corev1.VolumeMount{ + { + Name: LDAPTLSVolClaimName, + MountPath: ldapTLSDir, + ReadOnly: true, + }, + { + Name: LDAPConfVolClaimName, + MountPath: ldapConfDir, + }, + }...) + } + encryptionEnabled, err := isEncryptionEnabled(cr, replset) if err != nil { return corev1.Container{}, err diff --git a/pkg/psmdb/mongo/fake/client.go b/pkg/psmdb/mongo/fake/client.go index b3507936a8..3f05527fe1 100644 --- a/pkg/psmdb/mongo/fake/client.go +++ b/pkg/psmdb/mongo/fake/client.go @@ -11,8 +11,7 @@ import ( "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/mongo" ) -type fakeMongoClient struct { -} +type fakeMongoClient struct{} func NewClient() mongo.Client { return &fakeMongoClient{} @@ -22,8 +21,7 @@ func (c *fakeMongoClient) Disconnect(ctx context.Context) error { return nil } -type fakeMongoClientDatabase struct { -} +type fakeMongoClientDatabase struct{} func (c *fakeMongoClientDatabase) RunCommand(ctx context.Context, runCommand interface{}, opts ...*options.RunCmdOptions) *mgo.SingleResult { return singleResult(mongo.OKResponse{ diff --git a/pkg/psmdb/mongos.go b/pkg/psmdb/mongos.go index 9e27a9d929..f29303dfb6 100644 --- a/pkg/psmdb/mongos.go +++ b/pkg/psmdb/mongos.go @@ -186,6 +186,20 @@ func mongosContainer(cr *api.PerconaServerMongoDB, useConfigFile bool, cfgInstan volumes = append(volumes, corev1.VolumeMount{Name: BinVolumeName, MountPath: BinMountPath}) } + if cr.CompareVersion("1.16.0") >= 0 && cr.Spec.Secrets.LDAPSecret != "" { + volumes = append(volumes, []corev1.VolumeMount{ + { + Name: LDAPTLSVolClaimName, + MountPath: ldapTLSDir, + ReadOnly: true, + }, + { + Name: LDAPConfVolClaimName, + MountPath: ldapConfDir, + }, + }...) + } + container := corev1.Container{ Name: "mongos", Image: cr.Spec.Image, @@ -387,6 +401,27 @@ 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, + }, + }, + }, + { + Name: LDAPConfVolClaimName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + }...) + } + return volumes }