diff --git a/docs/ldap.md b/docs/ldap.md index 7e6f97a8..3b6c2d44 100644 --- a/docs/ldap.md +++ b/docs/ldap.md @@ -1,400 +1,420 @@ # How to integrate Percona Operator for MongoDB with OpenLDAP -LDAP services provided by software like OpenLDAP, Microsoft Active Directory, etc. are widely used by enterprises to control information about users, systems, networks, services and applications and the corresponding access rights for the authentication/authorization process in a centralized way. - -The following guide covers a simple integration of the already-installed OpenLDAP server with Percona Distribution for MongoDB and the Operator. You can know more about LDAP concepts and [LDIF :octicons-link-external-16:](https://en.wikipedia.org/wiki/LDAP_Data_Interchange_Format) files used to configure it, and find how to install and configure OpenLDAP in the official [OpenLDAP :octicons-link-external-16:](https://www.openldap.org/doc/admin26/) and [Percona Server for MongoDB :octicons-link-external-16:](https://docs.percona.com/percona-server-for-mongodb/latest/authentication.html) documentation. - -## The OpenLDAP side - -You can add needed OpenLDAP settings will the following [LDIF :octicons-link-external-16:](https://en.wikipedia.org/wiki/LDAP_Data_Interchange_Format) portions: - -```yaml -0-percona-ous.ldif: |- - dn: ou=perconadba,dc=ldap,dc=local - objectClass: organizationalUnit - ou: perconadba -1-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: {crypt}x - shadowLastChange: -1 - shadowMax: -1 - shadowWarning: -1 -2-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 -``` - -Also a read-only user should be created for the database-issued user lookups. If everything is done correctly, the following command should work, resetting the percona user password: - -```bash -ldappasswd -s percona -D "cn=admin,dc=ldap,dc=local" -w password -x "uid=percona,ou=perconadba,dc=ldap,dc=local" -``` -!!! note +Enterprises use LDAP services provided by software like OpenLDAP, Microsoft Active Directory, etc. to control information about users, systems, networks, services and applications and manage corresponding access rights for the authentication/authorization process in a centralized way. - If you are not sure about the approach to make references between user and group objects, [OpenDAP overlays :octicons-link-external-16:](https://www.openldap.org/doc/admin24/overlays.html) provide one of the possible ways to go. +The following guide describes the integration of OpenLDAP with Percona Server for MongoDB managed by the Operator. We assume your OpenLDAP server is already installed and running. -## The MongoDB and Operator side +To help you understand and perform the integration of OpenLDAP with Percona Server for MongoDB and the Operator, refer to the following resources: -The following steps will look different depending on whether sharding is on (the default behavior) or off. +- Learn about LDAP concepts and [LDIF :octicons-link-external-16:](https://en.wikipedia.org/wiki/LDAP_Data_Interchange_Format) files, which are used for configuration. +- Follow the official [OpenLDAP documentation :octicons-link-external-16:](https://www.openldap.org/doc/admin26/) for detailed instructions on how to install and configure OpenLDAP. +- Review the [Percona Server for MongoDB documentation :octicons-link-external-16:](https://docs.percona.com/percona-server-for-mongodb/latest/authentication.html) for guidance on configuring MongoDB to work with LDAP. -### If sharding is off +## Configure the OpenLDAP server -In order to get MongoDB connected with OpenLDAP in case of a a non-sharded (ReplicaSet) MongoDB cluster we need to configure two things: +Add users to your LDAP directory. To do that, use [LDIF :octicons-link-external-16:](https://en.wikipedia.org/wiki/LDAP_Data_Interchange_Format) (LDAP Data Interchange Format) files. LDIF is a standard plain-text format for representing LDAP entries and operations. You create LDIF files to define new users, groups, or other LDAP directory entries, and then apply them to your directory using LDAP utilities like `ldapadd`. LDIF can describe any LDAP entry or modification, making it essential for managing your LDAP Data Information Tree (DIT). -* Mongod -* Internal mongodb role +1. Add the following LDIF portions to your OpenLDAP server. -Create configuration Secrets for mongod: + ```yaml + 0-percona-ous.ldif: |- + dn: ou=perconadba,dc=ldap,dc=local + objectClass: organizationalUnit + ou: perconadba + 1-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: {crypt}x + shadowLastChange: -1 + shadowMax: -1 + shadowWarning: -1 + 2-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 + ``` -``` yaml title="my_mongod.conf" -security: - authorization: "enabled" - ldap: - authz: - queryTemplate: '{USER}?memberOf?base' - servers: "openldap" - transportSecurity: none - bind: - queryUser: "cn=readonly,dc=ldap,dc=local" - queryPassword: "password" - userToDNMapping: - '[ - { - match : "(.+)", - ldapQuery: "OU=perconadba,DC=ldap,DC=local??sub?(uid={0})" - } - ]' -setParameter: - authenticationMechanisms: 'PLAIN,SCRAM-SHA-1' -``` +2. Create a read-only user for the database-issued user lookups. Use the following command, resetting the percona user password: + + ```bash + ldappasswd -s percona -D "cn=admin,dc=ldap,dc=local" -w password -x "uid=percona,ou=perconadba,dc=ldap,dc=local" + ``` !!! note - This fragment provides mongod with LDAP-specific parameters, such as FQDN of the LDAP server (`server`), explicit lookup user, domain rules, etc. - -Put the snippet on you local machine and create a Kubernetes Secret object named based on [your MongoDB cluster name](operator.md#metadata): - -```bash -kubectl create secret generic -rs0-mongod --from-file=mongod.conf=my_mongod.conf -``` - -Next step is to start the MongoDB cluster up as it’s described in [Install Percona server for MongoDB on Kubernetes](kubernetes.md). On successful completion of the steps from this doc, we are to proceed with setting the roles for the ‘external’ (managed by LDAP) user inside the MongoDB. For this, log into MongoDB as administrator: - -```bash -mongo "mongodb+srv://userAdmin:@-rs0..svc.cluster.local/admin?replicaSet=rs0&ssl=false" -``` - -When logged in, execute the following: - -``` {.json data-prompt="mongos>" } -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" - } - ], -} -) -``` + If you are not sure about the approach to make references between user and group objects, [OpenLDAP overlays :octicons-link-external-16:](https://www.openldap.org/doc/admin24/overlays.html) provide one of the possible ways to go. + +## Configure the Operator and Percona Server for MongoDB + +The following steps will look different depending on your MongoDB topology. + +### Replica set + +To connect MongoDB to OpenLDAP in a non-sharded (replica set) cluster, you need to configure both: + +* `mongod` +* An internal MongoDB role + +The steps are the following: + +1. Create a configuration Secret for mongod. This fragment provides `mongod` configuration with LDAP-specific parameters, such as the FQDN of the LDAP server (`servers`), the explicit lookup user, domain rules, and more. + + ``` yaml title="my_mongod.conf" + security: + authorization: "enabled" + ldap: + authz: + queryTemplate: '{USER}?memberOf?base' + servers: "openldap" + transportSecurity: none + bind: + queryUser: "cn=readonly,dc=ldap,dc=local" + queryPassword: "password" + userToDNMapping: + '[ + { + match : "(.+)", + ldapQuery: "OU=perconadba,DC=ldap,DC=local??sub?(uid={0})" + } + ]' + setParameter: + authenticationMechanisms: 'PLAIN,SCRAM-SHA-256' + ``` + +2. Put the snippet on your local machine and create a Kubernetes Secret object named `--mongod`. Find the cluster name in the `metadata.name` field and the replica set name in the `spec.replsets.name` field of your Custom Resource. The following command creates a Secret for the cluster named `my-cluster-name` and `rs0` replica set: + + ```bash + kubectl create secret generic my-cluster-name-rs0-mongod --from-file=mongod.conf=my_mongod.conf + ``` + +3. Apply the configuration to create or update the database: + + ```bash + kubectl apply -f deploy/cr.yaml + ``` + + +4. Create roles for the ‘external’ user inside the MongoDB. This user is managed by LDAP. For this, log into MongoDB as administrator: + + ```bash + mongo "mongodb+srv://userAdmin:@-rs0..svc.cluster.local/admin?replicaSet=rs0&ssl=false" + ``` + + When logged in, execute the following: + + ``` {.javascript data-prompt="admin>"} + admin> 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" + } + ], + } + ) + ``` !!! note Extra roles listed in the above example are just to show more than one possible variant. -Now the new `percona` user created inside OpenLDAP is able to login to MongoDB as administrator. Verify whether the user role has been identified correctly with the following command: - -```bash -mongo --username percona --password 'percona' --authenticationMechanism 'PLAIN' --authenticationDatabase '$external' --host --port 27017 -``` - -When logged in, execute the following: - -``` {.json data-prompt="mongos>" } -mongos> db.runCommand({connectionStatus:1}) -``` - -The output should be like follows: - -``` {.json data-prompt="mongos>" } -{ - "authInfo" : { - "authenticatedUsers" : [ - { - "user" : "percona", - "db" : "$external" - } - ], - "authenticatedUserRoles" : [ - { - "role" : "restore", - "db" : "admin" - }, - { - "role" : "readAnyDatabase", - "db" : "admin" - }, - { - "role" : "clusterMonitor", - "db" : "admin" - }, - { - "role" : "dbAdminAnyDatabase", - "db" : "admin" - }, - { - "role" : "backup", - "db" : "admin" - }, - { - "role" : "cn=admin,ou=perconadba,dc=ldap,dc=local", - "db" : "admin" - }, - { - "role" : "readWriteAnyDatabase", - "db" : "admin" - } - ] - }, - "ok" : 1, - "$clusterTime" : { - "clusterTime" : Timestamp(1663067287, 4), - "signature" : { - "hash" : BinData(0,"ZaLGSVj4ZwZrngXZSOqXB5rx+oo="), - "keyId" : NumberLong("7142816031004688408") - } - }, - "operationTime" : Timestamp(1663067287, 4) -} -mongos> -``` - -### If sharding is on - -In order to get MongoDB connected with OpenLDAP in this case we need to configure three things: - -* Mongod -* Internal mongodb role -* Mongos - -Both the routing interface (mongos) and the configuration ReplicaSet (mongod) have to be configured to make the LDAP server a part of the Authentication/Authorization chain. +5. Now the new `percona` user created inside OpenLDAP is able to login to MongoDB as administrator. Verify whether the user role has been identified correctly with the following command: -!!! note + ```bash + mongo --username percona --password 'percona' --authenticationMechanism 'PLAIN' --authenticationDatabase '$external' --host --port 27017 + ``` + + When logged in, execute the following: + + ``` {.javascript data-prompt="admin>"} + admin> db.runCommand({connectionStatus:1}) + ``` - mongos is just a router between shards and underlying database instances, and configuration ReplicaSet is responsible for keeping information about database users and roles. Thus, the router can perform only authentication, while authorization is the responsibility of the configuration ReplicaSet. - -Create configuration Secrets for the router and the configuration ReplicaSet respectively. - -Secret for the router should look as follows: - -```yaml title="my_mongos.conf" -security: - ldap: - servers: "openldap" - transportSecurity: none - bind: - queryUser: "cn=readonly,dc=ldap,dc=local" - queryPassword: "password" - userToDNMapping: - '[ - { - match : "(.+)", - ldapQuery: "OU=perconadba,DC=ldap,DC=local??sub?(uid={0})" + ??? example "Sample output" + + ```json + { + "authInfo" : { + "authenticatedUsers" : [ + { + "user" : "percona", + "db" : "$external" + } + ], + "authenticatedUserRoles" : [ + { + "role" : "restore", + "db" : "admin" + }, + { + "role" : "readAnyDatabase", + "db" : "admin" + }, + { + "role" : "clusterMonitor", + "db" : "admin" + }, + { + "role" : "dbAdminAnyDatabase", + "db" : "admin" + }, + { + "role" : "backup", + "db" : "admin" + }, + { + "role" : "cn=admin,ou=perconadba,dc=ldap,dc=local", + "db" : "admin" + }, + { + "role" : "readWriteAnyDatabase", + "db" : "admin" + } + ] + }, + "ok" : 1, + "$clusterTime" : { + "clusterTime" : Timestamp(1663067287, 4), + "signature" : { + "hash" : BinData(0,"ZaLGSVj4ZwZrngXZSOqXB5rx+oo="), + "keyId" : NumberLong("7142816031004688408") } - ]' -setParameter: - authenticationMechanisms: 'PLAIN,SCRAM-SHA-1' -``` - -Put the snippet on you local machine and create a Kubernetes Secret object named based on [your MongoDB cluster name](operator.md#metadata): - -```bash -kubectl create secret generic -mongos --from-file=mongos.conf=my_mongos.conf -``` - -Secret for the configuration ReplicaSet should look as follows: - -```yaml title="my_mongod.conf" -security: - authorization: "enabled" - ldap: - authz: - queryTemplate: '{USER}?memberOf?base' - servers: "openldap" - transportSecurity: none - bind: - queryUser: "cn=readonly,dc=ldap,dc=local" - queryPassword: "password" - userToDNMapping: - '[ - { - match : "(.+)", - ldapQuery: "OU=perconadba,DC=ldap,DC=local??sub?(uid={0})" + }, + "operationTime" : Timestamp(1663067287, 4) + } + ``` + +### Sharded cluster + +To connect MongoDB to OpenLDAP in a sharded cluster, you need to configure the following components: + +* `mongod` +* An internal MongoDB role +* `mongos` + +You must configure both `mongos` and the configuration server replica set (`mongod`) to make the LDAP server a part of the Authentication/Authorization chain. + +`mongos` is a router between shards and underlying database instances, while configuration server replica set is responsible for keeping information about database users and roles. Thus, the router can perform only authentication, while authorization is the responsibility of the configuration server replica set. + +1. Create configuration Secrets for the `mongos` and the configuration server replica set respectively. + + Example Secret for `mongos`: + + ```yaml title="my_mongos.conf" + security: + ldap: + servers: "openldap" + transportSecurity: none + bind: + queryUser: "cn=readonly,dc=ldap,dc=local" + queryPassword: "password" + userToDNMapping: + '[ + { + match : "(.+)", + ldapQuery: "OU=perconadba,DC=ldap,DC=local??sub?(uid={0})" + } + ]' + setParameter: + authenticationMechanisms: 'PLAIN,SCRAM-SHA-256' + ``` + + Example Secret for the configuration server replica set: + + ```yaml title="my_mongod.conf" + security: + authorization: "enabled" + ldap: + authz: + queryTemplate: '{USER}?memberOf?base' + servers: "openldap" + transportSecurity: none + bind: + queryUser: "cn=readonly,dc=ldap,dc=local" + queryPassword: "password" + userToDNMapping: + '[ + { + match : "(.+)", + ldapQuery: "OU=perconadba,DC=ldap,DC=local??sub?(uid={0})" + } + ]' + setParameter: + authenticationMechanisms: 'PLAIN,SCRAM-SHA-256' + ``` + + Both files are pretty much the same except the `authz` subsection, which is only present for the configuration server replica set. + +2. Put the snippets on your local machine and create Kubernetes Secret objects. The Secret for `mongos` is named `-mongos`. The Secret for the configuration server replica set is named `-cfg-mongod`. + +Find the cluster name in the `metadata.name` field of your Custom Resource. The following commands create Secrets for the cluster named `my-cluster-name`: + + ```bash + kubectl create secret generic my-cluster-name-mongos --from-file=mongos.conf=my_mongos.conf + kubectl create secret generic my-cluster-name-cfg-mongod --from-file=mongod.conf=my_mongod.conf + ``` + +3. Apply the configuration to create or update the database cluster: + + ```bash + kubectl apply -f deploy/cr.yaml + ``` + +4. Create roles for the ‘external’ user inside the MongoDB. This user is managed by LDAP. For this, log into MongoDB as administrator: + + ```bash + mongo "mongodb://userAdmin:@-mongos..svc.cluster.local/admin?ssl=false" + ``` + + When logged in, execute the following: + + ``` {.javascript data-prompt="mongos>" } + 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" + } + ], + } + ) + ``` + + !!! note + + Extra roles listed in the above example are just to show more than one possible variant. + +5. Now the new `percona` user created inside OpenLDAP is able to login to MongoDB as administrator. Verify whether the user role has been identified correctly with the following command: + + ```bash + mongo --username percona --password 'percona' --authenticationMechanism 'PLAIN' --authenticationDatabase '$external' --host -mongos --port 27017 + ``` + + When logged in, execute the following: + + ``` {.javascript data-prompt="mongos>" } + mongos> db.runCommand({connectionStatus:1}) + ``` + + ??? example "Sample output" + + ``` {.json data-prompt="mongos>" } + { + "authInfo" : { + "authenticatedUsers" : [ + { + "user" : "percona", + "db" : "$external" + } + ], + "authenticatedUserRoles" : [ + { + "role" : "restore", + "db" : "admin" + }, + { + "role" : "readAnyDatabase", + "db" : "admin" + }, + { + "role" : "clusterMonitor", + "db" : "admin" + }, + { + "role" : "dbAdminAnyDatabase", + "db" : "admin" + }, + { + "role" : "backup", + "db" : "admin" + }, + { + "role" : "cn=admin,ou=perconadba,dc=ldap,dc=local", + "db" : "admin" + }, + { + "role" : "readWriteAnyDatabase", + "db" : "admin" + } + ] + }, + "ok" : 1, + "$clusterTime" : { + "clusterTime" : Timestamp(1663067287, 4), + "signature" : { + "hash" : BinData(0,"ZaLGSVj4ZwZrngXZSOqXB5rx+oo="), + "keyId" : NumberLong("7142816031004688408") } - ]' -setParameter: - authenticationMechanisms: 'PLAIN,SCRAM-SHA-1' -``` - -Put the snippet on you local machine and create a Kubernetes Secret object named based on [your MongoDB cluster name](operator.md#metadata): - -```bash -kubectl create secret generic -cfg-mongod --from-file=mongod.conf=my_mongod.conf -``` - -Both files are pretty much the same except the `authz` subsection, which is only present for the configuration ReplicaSet. - -Next step is to start the MongoDB cluster up as it’s described in [Install Percona server for MongoDB on Kubernetes](kubernetes.md). On successful completion of the steps from this doc, we are to proceed with setting the roles for the ‘external’ (managed by LDAP) user inside the MongoDB. For this, log into MongoDB as administrator: - -```bash -mongo "mongodb://userAdmin:@-mongos..svc.cluster.local/admin?ssl=false" -``` - -When logged in, execute the following: - -``` {.json data-prompt="mongos>" } -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" - } - ], -} -) -``` + }, + "operationTime" : Timestamp(1663067287, 4) + } + mongos> + ``` -!!! note +### OIDC authentication and LDAP authorization - Extra roles listed in the above example are just to show more than one possible variant. +A configuration file provided via a Secret takes precedence over Custom Resource settings (`spec.configuration`). -Now the new `percona` user created inside OpenLDAP is able to login to MongoDB as administrator. Verify whether the user role has been identified correctly with the following command: - -```bash -mongo --username percona --password 'percona' --authenticationMechanism 'PLAIN' --authenticationDatabase '$external' --host -mongos --port 27017 -``` - -When logged in, execute the following: - -``` {.json data-prompt="mongos>" } -mongos> db.runCommand({connectionStatus:1}) -``` - -The output should be like follows: - -``` {.json data-prompt="mongos>" } -{ - "authInfo" : { - "authenticatedUsers" : [ - { - "user" : "percona", - "db" : "$external" - } - ], - "authenticatedUserRoles" : [ - { - "role" : "restore", - "db" : "admin" - }, - { - "role" : "readAnyDatabase", - "db" : "admin" - }, - { - "role" : "clusterMonitor", - "db" : "admin" - }, - { - "role" : "dbAdminAnyDatabase", - "db" : "admin" - }, - { - "role" : "backup", - "db" : "admin" - }, - { - "role" : "cn=admin,ou=perconadba,dc=ldap,dc=local", - "db" : "admin" - }, - { - "role" : "readWriteAnyDatabase", - "db" : "admin" - } - ] - }, - "ok" : 1, - "$clusterTime" : { - "clusterTime" : Timestamp(1663067287, 4), - "signature" : { - "hash" : BinData(0,"ZaLGSVj4ZwZrngXZSOqXB5rx+oo="), - "keyId" : NumberLong("7142816031004688408") - } - }, - "operationTime" : Timestamp(1663067287, 4) -} -mongos> -``` +If you use [OIDC authentication](oidc.md) with LDAP authorization, merge both setups in one place — either in the Secret or in the Custom Resource — so one configuration does not overwrite the other. In this case, also update the authentication mechanisms to include `MONGODB-OIDC`. ## Using LDAP over TLS connection @@ -440,7 +460,7 @@ Changed mongod configuration should look as follows: } ]' setParameter: - authenticationMechanisms: 'PLAIN,SCRAM-SHA-1' + authenticationMechanisms: 'PLAIN,SCRAM-SHA-256' ``` If **sharding is on**, you will also need to change mongos configuration: @@ -461,6 +481,6 @@ Changed mongod configuration should look as follows: } ]' setParameter: - authenticationMechanisms: 'PLAIN,SCRAM-SHA-1' + authenticationMechanisms: 'PLAIN,SCRAM-SHA-256' ```