Description\n-----------\n\nIn this article, we will walk through the configuration of PAM authentication using the pam authentication plugin and user and group mapping with the pam_user_map PAM module. The primary authentication will be handled by the pam_ldap PAM module, which performs LDAP authentication. We will also set up an OpenLDAP server.\n\nHypothetical Requirements\n\nIn this walkthrough, we are going to assume the following hypothetical requirements:\n\n The LDAP user foo should be mapped to the MariaDB user bar. (foo: bar)\n Any LDAP user in the LDAP group dba should be mapped to the MariaDB user dba. (@dba: dba)\n\nSetting up the OpenLDAP Server\n\nBefore we can use LDAP authentication, we first need to set up our OpenLDAP Server. This is usually done on a server that is completely separate from the database server.\n\nInstalling the OpenLDAP Server and Client Components\n\nOn the server acting as the OpenLDAP Server, first, we need to install the OpenLDAP components.\n\nOn RHEL, CentOS, and other similar Linux distributions that use RPM packages, that would go like this:\n\n``bash\nsudo yum install openldap openldap-servers openldap-clients nss-pam-ldapd\n`\n\nConfiguring the OpenLDAP Server\n\nNext, let's to configure the OpenLDAP Server. The easiest way to do that is to copy the template configuration file that is included with the installation. In many installations, that will be at /usr/share/openldap-servers/DB_CONFIG.example:\n\n`bash\nsudo cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG\nsudo chown ldap. /var/lib/ldap/DB_CONFIG\n`\n\nConfiguring the OpenLDAP Port\n\nSometimes it is useful to change the port used by OpenLDAP. For example, some cloud environments block well-known authentication services, so they block the default LDAP port.\n\nOn some systems, the port can be changed by setting SLAPD_URLS in /etc/sysconfig/slapd:\n\n`ini\nSLAPD_URLS="ldapi:/// ldap://0.0.0.0:3306/"\n`\n\nI used 3306 because that is the port that is usually used by mysqld, so I know that it is not blocked.\n\nStarting the OpenLDAP Server\n\nNext, let's start the OpenLDAP Server and configure it to start on reboot. On systemd systems, that would go like this:\n\n`bash\nsudo systemctl start slapd\nsudo systemctl enable slapd\n`\n\nInstalling the Standard LDAP objectClasses\n\nIn order to use LDAP for authentication, we also need to install some standard objectClasses, such as posixAccount and posixGroup. In LDAP, things like objectClasses are defined in LDIF files. In many installations, these specific objectClasses are defined in /etc/openldap/schema/nis.ldif. nis.ldif also depends on core.ldif and cosine.ldif. However, core.ldif is usually installed by default.\n\nWe can install them with ldapmodify:\n\n`bash\nsudo ldapmodify -a -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif\nsudo ldapmodify -a -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif\n`\n\nCreating the LDAP Directory Manager User\n\nNext, let’s create a directory manager user. We can do this by using OpenLDAP's olc configuration system to change the olcRootDN directive to the DN of the directory manager user, which means that the user will be a privileged LDAP user that is not subject to access controls. We will also set the root password for the user by changing the olcRootPW directive.\n\nWe will also set the DN suffix for our backend LDAP database by changing the olcSuffix directive.\n\nLet’s use the slappasswd utility to generate a password hash from a clear-text password. Simply execute:\n\n`bash\nslappasswd\n`\n\nThis utility provides a password hash that looks like this: {SSHA}AwT4jrvmokeCkbDrFAnGvzzjCMb7bvEl\n\nOpenLDAP's olc configuration system also uses LDIF files. Now that we have the password hash, let’s create an LDIF file to create the directory manager user:\n\n`bash\ntee ~/setupDirectoryManager.ldif <<EOF\ndn: olcDatabase={1}monitor,cn=config\nchangetype: modify\nreplace: olcAccess\nolcAccess: {0}to  \n    by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read \n    by dn.base="cn=Manager,dc=support,dc=mariadb,dc=com" read \n    by  none\n\ndn: olcDatabase={2}hdb,cn=config\nchangetype: modify\nreplace: olcSuffix\nolcSuffix: dc=support,dc=mariadb,dc=com\n\ndn: olcDatabase={2}hdb,cn=config\nchangetype: modify\nreplace: olcRootDN\nolcRootDN: cn=Manager,dc=support,dc=mariadb,dc=com\n\ndn: olcDatabase={2}hdb,cn=config\nchangetype: modify\nadd: olcRootPW\nolcRootPW: {SSHA}AwT4jrvmokeCkbDrFAnGvzzjCMb7bvEl\n\ndn: olcDatabase={2}hdb,cn=config\nchangetype: modify\nadd: olcAccess\nolcAccess: {0}to attrs=userPassword,shadowLastChange \n    by   dn="cn=Manager,dc=support,dc=mariadb,dc=com" write \n    by anonymous auth \n    by self write \n    by  none\nolcAccess: {1}to dn.base="" \n    by  read\nolcAccess: {2}to  \n    by dn="cn=Manager,dc=support,dc=mariadb,dc=com" write \n    by  read\nEOF\n`\n\nNote that this is using the dc=support,dc=mariadb,dc=com domain for the directory. You can change it to whatever is relevant to you.\n\nNow let’s run the ldif file with ldapmodify:\n\n`bash\nsudo ldapmodify -Y EXTERNAL -H ldapi:/// -f ~/setupDirectoryManager.ldif\n`\n\nWe will use the new directory manager user to make changes to the LDAP directory after this step.\n\nCreating the Structure of the Directory\n\nNext, let's create the structure of the directory by creating parts of our tree.\n\n`bash\ntee ~/setupDirectoryStructure.ldif <<EOF\ndn: dc=support,dc=mariadb,dc=com\nobjectClass: top\nobjectClass: dcObject\nobjectclass: organization\no: MariaDB Support Team\ndc: support\n\ndn: cn=Manager,dc=support,dc=mariadb,dc=com\nobjectClass: top\nobjectClass: organizationalRole\ncn: Manager\ndescription: Directory Manager\n\ndn: ou=People,dc=support,dc=mariadb,dc=com\nobjectClass: top\nobjectClass: organizationalUnit\nou: People\n\ndn: ou=Groups,dc=support,dc=mariadb,dc=com\nobjectClass: top\nobjectClass: organizationalUnit\nou: Groups\n\ndn: ou=System Users,dc=support,dc=mariadb,dc=com\nobjectClass: top\nobjectClass: organizationalUnit\nou: System Users\nEOF\n`\n\nNow, let’s use our new directory manager user and run the LDIF file with ldapmodify:\n\n`\nldapmodify -a -x -D cn=Manager,dc=support,dc=mariadb,dc=com -W -f ~/setupDirectoryStructure.ldif\n`\n\nCreating the LDAP Users and Groups\n\nLet's go ahead and create the LDAP users and groups that we are using for this scenario.\n\nFirst, let's create the foo user:\n\n`bash\ntee ~/createFooUser.ldif <<EOF\ndn: uid=foo,ou=People,dc=support,dc=mariadb,dc=com\nobjectClass: top\nobjectClass: account\nobjectClass: posixAccount\nobjectClass: shadowAccount\ncn: foo\nuid: foo\nuidNumber: 16859\ngidNumber: 100\nhomeDirectory: /home/foo\nloginShell: /bin/bash\ngecos: foo\nuserPassword: {crypt}x\nshadowLastChange: -1\nshadowMax: -1\nshadowWarning: 0\nEOF\nldapmodify -a -x -D cn=Manager,dc=support,dc=mariadb,dc=com -W -f ~/createFooUser.ldif\n`\n\nNext, let's create a couple of users to go into the dba group:\n\n`bash\ntee ~/createDbaUsers.ldif <<EOF\ndn: uid=gmontee,ou=People,dc=support,dc=mariadb,dc=com\nobjectClass: top\nobjectClass: account\nobjectClass: posixAccount\nobjectClass: shadowAccount\ncn: gmontee\nuid: gmontee\nuidNumber: 16860\ngidNumber: 100\nhomeDirectory: /home/gmontee\nloginShell: /bin/bash\ngecos: gmontee\nuserPassword: {crypt}x\nshadowLastChange: -1\nshadowMax: -1\nshadowWarning: 0\n\ndn: uid=bstillman,ou=People,dc=support,dc=mariadb,dc=com\nobjectClass: top\nobjectClass: account\nobjectClass: posixAccount\nobjectClass: shadowAccount\ncn: bstillman\nuid: bstillman\nuidNumber: 16861\ngidNumber: 100\nhomeDirectory: /home/bstillman\nloginShell: /bin/bash\ngecos: bstillman\nuserPassword: {crypt}x\nshadowLastChange: -1\nshadowMax: -1\nshadowWarning: 0\nEOF\nldapmodify -a -x -D cn=Manager,dc=support,dc=mariadb,dc=com -W -f ~/createDbaUsers.ldif\n`\n\nNote that each of these users needs a password, so we can set it for each user with ldappasswd:\n\n`\nldappasswd -x -D cn=Manager,dc=support,dc=mariadb,dc=com -W -S uid=foo,ou=People,dc=support,dc=mariadb,dc=com\nldappasswd -x -D cn=Manager,dc=support,dc=mariadb,dc=com -W -S uid=gmontee,ou=People,dc=support,dc=mariadb,dc=com\nldappasswd -x -D cn=Manager,dc=support,dc=mariadb,dc=com -W -S uid=bstillman,ou=People,dc=support,dc=mariadb,dc=com\n`\n\nNext, let's create our dba group:\n\n`bash\ntee ~/createDbaGroup.ldif <<EOF\ndn: cn=dba,ou=Groups,dc=support,dc=mariadb,dc=com\nobjectClass: top\nobjectClass: posixGroup\ngidNumber: 678\nEOF\nldapmodify -a -x -D cn=Manager,dc=support,dc=mariadb,dc=com -W -f ~/createDbaGroup.ldif\n`\n\nNext, let's add our two users to it:\n\n`bash\ntee ~/addUsersToDbaGroup.ldif <<EOF\ndn: cn=dba,ou=Groups,dc=support,dc=mariadb,dc=com\nchangetype: modify\nadd: memberuid\nmemberuid: gmontee\n\ndn: cn=dba,ou=Groups,dc=support,dc=mariadb,dc=com\nchangetype: modify\nadd: memberuid\nmemberuid: bstillman\nEOF\nldapmodify -a -x -D cn=Manager,dc=support,dc=mariadb,dc=com -W -f ~/addUsersToDbaGroup.ldif\n`\n\nWe also need to create LDAP users with the same name as the bar and dba MariaDB users. See here to read more about the reasons to do so. No one will be logging in as these users, so they do not need passwords. Instead of the People organizationalUnit, we create them in the System Users organizationalUnit.\n\n`bash\ntee ~/createSystemUsers.ldif <<EOF\ndn: uid=bar,ou=System Users,dc=support,dc=mariadb,dc=com\nobjectClass: top\nobjectClass: account\nobjectClass: posixAccount\nobjectClass: shadowAccount\ncn: bar\nuid: bar\nuidNumber: 16862\ngidNumber: 100\nhomeDirectory: /home/bar\nloginShell: /bin/bash\ngecos: bar\nuserPassword: {crypt}x\nshadowLastChange: -1\nshadowMax: -1\nshadowWarning: 0\n\ndn: uid=dba,ou=System Users,dc=support,dc=mariadb,dc=com\nobjectClass: top\nobjectClass: account\nobjectClass: posixAccount\nobjectClass: shadowAccount\ncn: dba\nuid: dba\nuidNumber: 16863\ngidNumber: 100\nhomeDirectory: /home/dba\nloginShell: /bin/bash\ngecos: dba\nuserPassword: {crypt}x\nshadowLastChange: -1\nshadowMax: -1\nshadowWarning: 0\nEOF\nldapmodify -a -x -D cn=Manager,dc=support,dc=mariadb,dc=com -W -f ~/createSystemUsers.ldif\n`\n\nSetting up the MariaDB Server\n\nAt this point, we can move on to setting up the MariaDB Server.\n\nInstalling LDAP and PAM Libraries\n\nFirst, we need to make sure that the LDAP and PAM libraries are installed.\n\nOn RHEL, CentOS, and other similar Linux distributions that use RPM packages, we need to install the following packages:\n\n`bash\nsudo yum install openldap-clients nss-pam-ldapd pam pam-devel\n`\n\nConfiguring LDAP\n\nNext, let's configure LDAP on the system. We can use authconfig for this:\n\n`bash\nsudo authconfig --enableldap \\\n   --enableldapauth \\\n   --ldapserver="ldap://172.30.0.238:3306" \\\n   --ldapbasedn="dc=support,dc=mariadb,dc=com" \\\n   --enablemkhomedir \\\n   --update\n`\n\nBe sure to replace -–ldapserver and -–ldapbasedn with values that are relevant for your environment.\n\nInstalling the pam_user_map PAM Module\n\nThe pam_user_map PAM module is included in the base install. No installation is needed.\n\nNext, let's install the pam_user_map PAM module.\n\nBefore the module can be compiled from source, we may need to install some dependencies.\n\nOn RHEL, CentOS, and other similar Linux distributions that use RPM packages, we need to install gcc and pam-devel:\n\n`bash\nsudo yum install gcc pam-devel\n`\n\nOn Debian, Ubuntu, and other similar Linux distributions that use DEB packages, we need to install gcc and libpam0g-dev:\n\n`bash\nsudo apt-get install gcc libpam0g-dev\n`\n\nAnd then we can build and install the library with the following:\n\n`bash\nwget https://raw.githubusercontent.com/MariaDB/server/10.4/plugin/auth_pam/mapper/pam_user_map.c \ngcc pam_user_map.c -shared -lpam -fPIC -o pam_user_map.so \nsudo install --mode=0755 pam_user_map.so /lib64/security/\n`\n\nConfiguring the pam_user_map PAM Module\n\nNext, let's configure the pam_user_map PAM module based on our hypothetical requirements.\n\nThe configuration file for the pam_user_map PAM module is /etc/security/user_map.conf. Based on our requirements, ours would look like:\n\n`\nfoo: bar\n@dba:dba\n`\n\nInstalling the PAM Authentication Plugin\n\nNext, let's install the pam authentication plugin.\n\nLog into the MariaDB Server and execute the following:\n\n`sql\nINSTALL SONAME 'auth_pam';\n`\n\nConfiguring the PAM Service\n\nFor modern Linux distributions (like RHEL 8 and newer) that use SSSD (System Security Services Daemon) to connect to an LDAP provider, the pam_sss.so module is the modern equivalent of pam_ldap.so. In such a configuration, pam_sss.so replaces pam_ldap.so. For more information, please see the Red Hat Enterprise Linux documentation.\n\nNext, let's configure the PAM service. We will call our service mariadb, so our PAM service configuration file will be located at /etc/pam.d/mariadb on most systems.\n\nConfiguring PAM to Allow Only LDAP Authentication\n\nSince we are only doing LDAP authentication with the pam_ldap PAM module and group mapping with the pam_user_map PAM module, our configuration file would look like this:\n\n`\nauth required pam_ldap.so\nauth required pam_user_map.so\naccount required pam_ldap.so\n`\n\nConfiguring PAM to Allow LDAP and Local Unix Authentication\n\nIf we want to allow authentication from LDAP users and from local Unix users through pam_unix, while giving priority to the local users, then we could do this instead:\n\n`\nauth [success=1 new_authtok_reqd=1 default=ignore] pam_unix.so audit\nauth required pam_ldap.so try_first_pass\nauth required pam_user_map.so\naccount sufficient pam_unix.so audit\naccount required pam_ldap.so\n`\n\nConfiguring the pam_unix PAM Module\n\nIf you also want to allow authentication from local Unix users, the pam_unix PAM module adds some additional configuration steps on a lot of systems. We basically have to give the user that runs mysqld access to /etc/shadow.\n\nIf the mysql user is running mysqld, then we can do that by executing the following:\n\n`bash\nsudo groupadd shadow\nsudo usermod -a -G shadow mysql\nsudo chown root:shadow /etc/shadow\nsudo chmod g+r /etc/shadow\n`\n\nThe server needs to be restarted for this change to take affect.\n\nCreating MariaDB Users\n\nNext, let's create the MariaDB users. Remember that our PAM service is called mariadb.\n\nFirst, let's create the MariaDB user for the user mapping: foo: bar\n\nThat means that we need to create a bar user:\n\n`sql\nCREATE USER 'bar'@'%' IDENTIFIED BY 'strongpassword';\nGRANT ALL PRIVILEGES ON . TO 'bar'@'%' ;\n`\n\nAnd then let's create the MariaDB user for the group mapping: @dba: dba\n\nThat means that we need to create a dba user:\n\n`sql\nCREATE USER 'dba'@'%' IDENTIFIED BY 'strongpassword';\nGRANT ALL PRIVILEGES ON . TO 'dba'@'%' ;\n`\n\nAnd then to allow for the user and group mapping, we need to create an anonymous user that authenticates with the pam authentication plugin that is also able to PROXY as the bar and dba users. Before we can create the proxy user, we might need to clean up some defaults:\n\n`sql\nDELETE FROM mysql.db WHERE User='' AND Host='%';\nFLUSH PRIVILEGES;\n`\n\nAnd then let's create the anonymous proxy user:\n\n`sql\nCREATE USER ''@'%' IDENTIFIED VIA pam USING 'mariadb';\nGRANT PROXY ON 'bar'@'%' TO ''@'%';\nGRANT PROXY ON 'dba'@'%' TO ''@'%';\n`\n\nTesting our Configuration\n\nNext, let's test our configuration by verifying that mapping\n\n[Truncated — full content at mariadb.com/docs]