Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 Reference Manual  /  ...  /  PAM Pluggable Authentication

8.4.1.5 PAM 插件式认证

Note

PAM插件式认证是MySQL企业版的一个扩展,一个商业产品。要了解更多关于商业产品的信息,请参阅https://www.mysql.com/products/

MySQL企业版支持一种认证方法,使得MySQL服务器可以使用PAM(可插拔认证模块)来认证MySQL用户。PAM使得系统能够通过标准接口访问各种类型的认证方法,如传统的Unix密码或LDAP目录。

PAM插件式认证提供以下功能:

  • 外部认证:PAM认证使得MySQL服务器可以接受来自于MySQL授权表之外用户的连接,这些用户使用PAM支持的方法进行认证。

  • 代理用户支持:PAM认证可以根据外部用户所属的PAM组和提供的认证字符串,将返回给MySQL一个与客户端程序传递的外部用户名不同的用户名。这样,插件就可以返回一个MySQL用户,这个用户定义了外部PAM认证用户应该拥有的权限。例如,操作系统用户joe可以连接,并拥有名为developer的MySQL用户的权限。

PAM插件式认证已在Linux和macOS上进行了测试;请注意,Windows不支持PAM。

以下是插件和库文件名。文件名后缀可能会根据您的系统不同而有所差异。这份文件必须位于由plugin_系统变量指定的目录中。有关安装信息,请参阅安装PAM插件式认证

表格 8.19 PAM认证的插件和库文件名

Plugin or File Plugin or File Name
服务器端插件 authentication_pam
客户端插件 mysql_clear_password
库文件 authentication_pam.so

与服务器端PAM插件通信的客户端mysql_clear_password清文本插件是libmysqlclient客户端库的一部分,并且在所有分发中都包含了它,包括社区分发。客户端插件在所有MySQL分发中都包含,使得来自任何分发的客户端程序能够连接到装载了服务器端PAM插件的服务器。

以下部分提供了特定于PAM插件式认证的安装和使用信息:

关于MySQL中的可插拔认证的总体信息,请参阅第8.2.17节,“可插拔认证”。关于mysql_clear_password插件,请参阅第8.4.1.4节,“客户端清文本可插拔认证”。关于代理用户的信息,请参阅第8.2.19节,“代理用户”

本节提供了MySQL和PAM如何协同工作以认证MySQL用户的概述。有关设置MySQL账户以使用特定PAM服务的示例,请参阅使用PAM插件式认证

  1. 客户端程序和服务器之间进行通信,客户端向服务器发送客户端用户名称(默认为操作系统用户名称)和密码:

    • 客户端用户名称是外部用户名称。

    • 对于使用PAM服务器端认证插件的账户,相应的客户端插件是mysql_清除_password。这个客户端插件不进行密码加密,因此客户端将密码发送给服务器作为明文。

  2. 服务器根据外部用户名称和客户端连接的主机找到一个匹配的MySQL账户。PAM插件使用MySQL Server提供的信息(如用户名称、主机名、密码和认证字符串)。当您为MySQL账户定义一个使用PAM进行认证时,认证字符串包含:

    • 一个PAM服务名称,这是系统管理员可以用来引用特定应用程序的认证方法的名称。同一数据库服务器实例可能与多个应用程序关联,因此选择服务名称由SQL应用程序开发者决定。

    • 如果需要使用代理,则还包含从PAM组映射到MySQL用户名称的映射。

  3. 插件使用认证字符串中指定的PAM服务来检查用户凭据,并返回'认证成功,用户名为user_name''认证失败'。密码必须适用于由PAM服务使用的密码存储器。示例:

    • 对于传统的Unix密码,服务查找/etc/shadow文件中存储的密码。

    • 对于LDAP,服务查找LDAP目录中的密码。

    如果凭据检查失败,服务器拒绝连接。

  4. 否则,认证字符串指示是否发生代理。如果字符串中没有PAM组映射,代理不发生。这种情况下,MySQL用户名称与外部用户名称相同。

  5. 否则,根据PAM组映射进行代理,以确定基于第一个匹配的组在映射列表中的MySQL用户名称。"PAM组"的含义取决于PAM服务。示例:

    • 对于传统的Unix密码,组是/etc/group文件中定义的Unix组,可能还包括在如/etc/security/group.conf这样的文件中的额外PAM信息。

    • 对于LDAP,组是LDAP目录中的LDAP组。

    如果代理用户(外部用户)具有对被代理MySQL用户名称的PROXY特权,代理发生,并且代理用户假设被代理用户的权限。

安装PAM插件式认证

本节描述了如何安装服务器端的PAM认证插件。有关安装插件的一般信息,请参阅第7.6.1节,“安装和卸载插件”

为了使插件库文件可供服务器使用,该文件必须位于MySQL插件目录(由plugin_ dir系统变量指定的目录)中。如果必要,通过在服务器启动时设置plugin_ dir的值来配置插件目录位置。

插件库文件的基础名称为authentication_pam,通常以.so后缀编译。

要在服务器启动时加载插件,请使用--plugin-load-add选项来指定包含它的库文件。使用此插件加载方法,每次启动服务器时都必须给出该选项。例如,将这些行放在服务器my.cnf文件中:

[mysqld]
plugin-load-add=authentication_pam.so

修改my.cnf后,重启服务器以使新设置生效。

或者,要在运行时加载插件,请使用以下语句,根据需要调整.so后缀:

INSTALL PLUGIN authentication_pam SONAME 'authentication_pam.so';

INSTALL PLUGIN立即加载插件,并将其注册到mysql.plugins系统表中,以便服务器在没有--plugin-load-add的情况下也能自动加载它。

为了验证插件安装,检查信息架构中的PLUGINS表或使用SHOW PLUGINS语句(参见第7.6.2节,“获取服务器插件信息”)。例如:

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
       FROM INFORMATION_SCHEMA.PLUGINS
       WHERE PLUGIN_NAME LIKE '%pam%';
+--------------------+---------------+
| PLUGIN_NAME        | PLUGIN_STATUS |
+--------------------+---------------+
| authentication_pam | ACTIVE        |
+--------------------+---------------+

如果插件在初始化时失败,请检查服务器错误日志以查找诊断消息。

要将MySQL帐户与PAM插件关联,请参阅使用PAM可插拔认证

卸载PAM插件式认证

卸载PAM认证插件的方法取决于您如何安装它:

  • 如果使用--plugin-load-add选项在服务器启动时安装了插件,请在不带此选项的情况下重启服务器。

  • 如果使用INSTALL PLUGIN语句在运行时安装了插件,它将保持安装状态,即使服务器重启。要卸载它,请使用UNINSTALL PLUGIN

    UNINSTALL PLUGIN authentication_pam;
使用PAM插件式认证

本节描述了如何使用PAM认证插件从MySQL客户端程序连接到服务器。以下各节提供了在特定方式下使用PAM认证的说明。假设服务器正在以启用服务器侧PAM插件的形式运行,正如安装PAM可插拔认证中所述。

CREATE USER语句的IDENTIFIED WITH子句中引用PAM认证插件,请使用名称authentication_pam。例如:

CREATE USER user
  IDENTIFIED WITH authentication_pam
  AS 'auth_string';

认证字符串指定以下类型的信息:

  • PAM服务名称(参见如何对MySQL用户进行PAM认证)。以下讨论中的示例使用服务名称mysql-unix用于传统的Unix密码认证,以及mysql-ldap用于LDAP认证。

  • 对于代理支持,PAM提供了一种方式,让PAM模块返回给服务器一个与客户端程序连接到服务器时通过的外部用户名称不同的MySQL用户名称。使用认证字符串来控制从外部用户名称映射到MySQL用户名称的映射。如果您想要利用代理用户功能,该字符串必须包含这种类型的映射。

例如,如果帐户使用mysql-unix服务名称,并且应该将操作系统用户在PAM组rootusers中映射到MySQL用户developerdata_entry,请使用以下语句:

CREATE USER user
  IDENTIFIED WITH authentication_pam
  AS 'mysql-unix, root=developer, users=data_entry';

PAM认证插件的认证字符串遵循以下规则:

  • 字符串由PAM服务名称组成,后面可选地跟随一个或多个关键字/值对,每个对指定了PAM组名称和MySQL用户名称:

    pam_service_name[,pam_group_name=mysql_user_name]...

    插件为每次使用该帐户的连接尝试解析认证字符串。为了减少开销,请尽可能缩短字符串长度。

  • 每个pam_group_name=mysql_user_name对必须以逗号开头。

  • 不在双引号内的前导和尾随空格被忽略。

  • 未加双引号的pam_service_namepam_group_namemysql_user_name值可以包含任何内容,除了等号、逗号或空格。

  • 如果pam_service_namepam_group_namemysql_user_name值被双引号括起来,双引号内的所有内容都是该值的一部分。这对于包含空格字符的情况是必要的。所有字符都允许,除了双引号和反斜杠(\)。要包括任何一个字符,请使用反斜杠。

如果插件成功验证外部用户名(由客户端传递),它会在认证字符串中查找PAM组映射列表,如果存在,它将根据外部用户所属的PAM组返回一个不同的MySQL用户名给MySQL服务器:

  • 如果认证字符串中没有包含PAM组映射列表,插件将返回外部名称。

  • 如果认证字符串确实包含了PAM组映射列表,插件会从左到右检查每个pam_group_name=mysql_user_name对,并尝试在非MySQL目录中找到匹配的pam_group_name值,属于已验证用户的组,并返回第一个匹配的mysql_user_name。如果插件找不到任何PAM组,它将返回外部名称。如果插件无法查找目录中的组,它将忽略PAM组映射列表并返回外部名称。

以下部分描述了如何设置几个使用PAM认证插件的认证场景:

这些场景有可能进行变体:

  • 您可以允许一些用户直接登录(无需代理)但要求其他用户通过代理账户连接。

  • 您可以使用不同的PAM认证方法对不同用户进行认证,通过在您的PAM-认证账户中使用不同的PAM服务名称。例如,您可以使用mysql- unix PAM服务对一些用户进行认证,而对于其他用户,则使用mysql-ldap

以下假设将被做出:您可能需要根据您的系统设置进行调整。

PAM认证插件在初始化时检查服务器启动环境中的AUTHENTICATION_PAM_LOG环境变量是否设置。如果是这样,插件将启用对标准输出的诊断消息记录。这些消息可能会出现在控制台或错误日志中。这些消息对于调试PAM相关的问题非常有帮助,这些问题发生在插件执行认证时。有关更多信息,请参阅PAM认证调试

PAM Unix密码认证(无代理用户)

此身份验证方案使用PAM来检查根据操作系统用户名和Unix密码定义的外部用户,无需代理。每个被允许连接到MySQL服务器的外部用户都应该有一个匹配的MySQL帐户,该帐户被定义为通过传统的Unix密码存储使用PAM身份验证。

注意

传统的Unix密码使用/etc/shadow文件进行检查。有关此文件可能出现的问题的信息,请参阅PAM 身份验证访问 Unix 密码存储

  1. 验证Unix身份验证是否允许使用用户名antonio和密码antonio_password登录操作系统。

  2. 通过创建一个名为/etc/pam.d/mysql-unixmysql-unix PAM服务文件,设置PAM以使用传统的Unix密码验证MySQL连接。文件内容取决于系统,因此请检查/etc/pam.d目录中现有的与登录相关的文件,以了解它们的外观。在Linux上,mysql-unix文件可能如下所示:

    #%PAM-1.0
    auth            include         password-auth
    account         include         password-auth

    对于macOS,请使用login而不是password-auth

    在某些系统上,PAM文件格式可能有所不同。例如,在Ubuntu和其他基于Debian的系统上,请改用以下文件内容:

    @include common-auth
    @include common-account
    @include common-session-noninteractive
  3. 创建一个与操作系统用户名相同的MySQL帐户,并将其定义为使用PAM插件和mysql-unix PAM服务进行身份验证:

    CREATE USER 'antonio'@'localhost'
      IDENTIFIED WITH authentication_pam
      AS 'mysql-unix';
    GRANT ALL PRIVILEGES
      ON mydb.*
      TO 'antonio'@'localhost';

    在这里,身份验证字符串仅包含PAM服务名称mysql-unix,它用于验证Unix密码。

  4. 使用mysql命令行客户端以antonio身份连接到MySQL服务器。例如:

    $> mysql --user=antonio --password --enable-cleartext-plugin
    Enter password: antonio_password

    服务器应允许连接,以下查询返回如下所示的输出:

    mysql> SELECT USER(), CURRENT_USER(), @@proxy_user;
    +-------------------+-------------------+--------------+
    | USER()            | CURRENT_USER()    | @@proxy_user |
    +-------------------+-------------------+--------------+
    | antonio@localhost | antonio@localhost | NULL         |
    +-------------------+-------------------+--------------+

    这表明antonio操作系统用户已通过身份验证,拥有授予antonio MySQL用户的权限,并且没有发生代理。

注意

客户端mysql_clear_password身份验证插件不会更改密码,因此客户端程序会将其以明文形式发送到MySQL服务器。这使得密码可以按原样传递给PAM。明文密码对于使用服务器端PAM库是必需的,但在某些配置中可能会存在安全问题。以下措施可最大程度地降低风险:

PAM LDAP认证(无代理用户)

这项认证方案使用PAM来检查操作系统用户名和LDAP密码的外部用户,而不进行代理。每个允许连接到MySQL Server的这样的外部用户都应该有一个与之对应的MySQL账户,该账户定义为通过LDAP进行PAM认证。

为了在MySQL中使用PAM LDAP插件式认证,必须满足以下条件:

  • 必须有一个可供PAM LDAP服务通信的LDAP服务器。

  • 所有要由MySQL进行LDAP认证的LDAP用户都必须存在于由LDAP服务器管理的目录中。

Note

另一种使用LDAP为MySQL用户认证的方法是使用LDAP特定的认证插件。请参阅第8.4.1.7节,“LDAP Pluggable Authentication”

为MySQL配置PAM LDAP认证如下:

  1. 验证操作系统用户名为antonio,密码为antonio_密码的Unix认证是否允许登录。

  2. 创建一个名为/etc/pam.d/mysql-ldap的PAM服务文件来为MySQL连接使用LDAP进行认证。该文件内容取决于系统,因此请检查/etc/pam.d目录中的现有登录相关文件,以了解它们是什么样子。在Linux上,mysql-ldap文件可能看起来像这样:

    #%PAM-1.0
    auth        required    pam_ldap.so
    account     required    pam_ldap.so

    如果PAM对象文件的后缀与.so不同于您的系统,请替换正确的后缀。

    PAM文件格式可能在某些系统上有所不同。

  3. 使用与操作系统用户名相同的MySQL账户,并将其定义为使用PAM插件和mysql-ldapPAM服务进行身份验证:

    CREATE USER 'antonio'@'localhost'
      IDENTIFIED WITH authentication_pam
      AS 'mysql-ldap';
    GRANT ALL PRIVILEGES
      ON mydb.*
      TO 'antonio'@'localhost';

    这里,认证字符串仅包含PAM服务名称mysql-ldap,它使用LDAP进行身份验证。

  4. 连接到服务器与在PAM Unix Password Authentication without Proxy Users中描述的相同。

PAM Unix密码认证与代理用户和组映射

这里描述的认证方案使用代理和PAM组映射将通过PAM进行身份验证的MySQL用户映射到拥有不同权限集的其他MySQL账户。用户不直接连接到定义权限的账户,而是通过一个默认代理账户进行身份验证,这样所有外部用户都被映射到持有权限的MySQL账户。任何使用代理账户连接的用户都会被映射到这些MySQL账户,权限决定了对外部用户可执行的数据库操作。

这里使用的是Unix密码认证。如果要使用LDAP,请参阅PAM LDAP Authentication without Proxy Users的早期步骤。

Note

传统的Unix密码通过/etc/shadow文件进行检查。有关此文件可能遇到的问题,请参阅PAM Authentication Access to Unix Password Store

  1. 验证操作系统中用户名为antonio,密码为antonio_password的登录是否被允许。

  2. 验证antonio是PAM组rootusers的成员。

  3. 将PAM配置为通过操作系统用户认证mysql-unixPAM服务,创建名为/etc/pam.d/mysql-unix的文件。该文件内容因系统而异,因此请查看/etc/pam.d目录中的登录相关文件以了解其格式。在Linux上,mysql-unix文件可能看起来像这样:

    #%PAM-1.0
    auth            include         password-auth
    account         include         password-auth

    在macOS上,请使用login而不是password-auth

    PAM文件格式可能在某些系统上有所不同。例如,在Ubuntu和其他基于Debian的系统上,使用以下内容代替:

    @include common-auth
    @include common-account
    @include common-session-noninteractive
  4. 创建一个默认代理用户(''@''),将外部PAM用户映射到代理账户:

    CREATE USER ''@''
      IDENTIFIED WITH authentication_pam
      AS 'mysql-unix, root=developer, users=data_entry';

    这里,认证字符串包含PAM服务名称mysql-unix,它使用Unix密码进行身份验证。认证字符串还将rootusersPAM组的外部用户映射到MySQL账户developerdata_entry,分别。

    在设置代理用户时,PAM组映射列表是必需的。否则,插件无法确定如何将外部用户名映射到适当的代理MySQL用户名。

    Note

    如果MySQL安装中有匿名用户,它们可能与默认代理用户冲突。有关此问题以及解决方案,请参阅Default Proxy User and Anonymous User Conflicts

  5. 创建代理账户并为每个账户授予其应有的权限:

    CREATE USER 'developer'@'localhost'
      IDENTIFIED WITH mysql_no_login;
    CREATE USER 'data_entry'@'localhost'
      IDENTIFIED WITH mysql_no_login;
    
    GRANT ALL PRIVILEGES
      ON mydevdb.*
      TO 'developer'@'localhost';
    GRANT ALL PRIVILEGES
      ON mydb.*
      TO 'data_entry'@'localhost';

    代理账户使用mysql_no_login认证插件来防止客户端直接使用这些账户登录到MySQL服务器。相反,通过PAM进行身份验证的用户被期望使用developerdata_entry账户作为代理,以基于其PAM组的方式。(假设插件已安装。有关说明,请参阅Section 8.4.1.9, “No-Login Pluggable Authentication”。)为了防止代理账户直接使用的替代方法,请参阅Preventing Direct Login to Proxied Accounts

  6. 为每个代理账户授予PROXY权限:

    GRANT PROXY
      ON 'developer'@'localhost'
      TO ''@'';
    GRANT PROXY
      ON 'data_entry'@'localhost'
      TO ''@'';
  7. 使用mysql命令行客户端连接到MySQL服务器作为antonio

    $> mysql --user=antonio --password --enable-cleartext-plugin
    Enter password: antonio_password

    服务器使用默认的 ''@'' 代理账户来验证连接。对于 antonio,其权限取决于它是哪些 PAM 组的成员。如果 antonioroot PAM 组的成员,PAM 插件将 root 映射到 MySQL 用户名 developer 并将该名称返回给服务器。服务器验证 ''@''developerPROXY 权限,并允许连接。以下查询返回显示如下:

    mysql> SELECT USER(), CURRENT_USER(), @@proxy_user;
    +-------------------+---------------------+--------------+
    | USER()            | CURRENT_USER()      | @@proxy_user |
    +-------------------+---------------------+--------------+
    | antonio@localhost | developer@localhost | ''@''        |
    +-------------------+---------------------+--------------+

    这表明操作系统用户 antonio 已经被授权拥有 developer MySQL 用户的权限,并且通过默认代理账户进行了代理。

    如果 antonio 不是 root PAM 组的成员但是在 users PAM 组中,类似的过程会发生,但插件将 user PAM 组成员资格映射到 MySQL 用户名 data_entry 并返回该名称给服务器:

    mysql> SELECT USER(), CURRENT_USER(), @@proxy_user;
    +-------------------+----------------------+--------------+
    | USER()            | CURRENT_USER()       | @@proxy_user |
    +-------------------+----------------------+--------------+
    | antonio@localhost | data_entry@localhost | ''@''        |
    +-------------------+----------------------+--------------+

    这表明操作系统用户 antonio 已经被授权拥有 data_entry MySQL 用户的权限,并且通过默认代理账户进行了代理。

Note

客户端的 mysql_ clear_password 认证插件不改变密码,因此客户端程序将其作为明文发送给 MySQL 服务器。这使得可以将密码直接传递给 PAM。虽然明文密码对于使用服务器端 PAM 库是必需的,但在某些配置中可能会造成安全问题。这些措施最小化了风险:

在某些系统上,Unix 认证使用一个密码存储,如 /etc/shadow,一个通常具有受限访问权限的文件。这可能导致 MySQL PAM 基于认证失败。遗憾的是,PAM 实现不允许区分 "密码无法验证””(例如,由于无法读取 /etc/shadow)和 "密码不匹配。””” 如果您正在使用 Unix 密码存储进行 PAM 认证,您可能可以通过以下方法为 MySQL 使用它:

  • 假设 MySQL 服务器是由 mysql 操作系统账户运行的,将该账户添加到拥有 /etc/shadow 访问权限的 shadow 组中:

    1. 创建一个 shadow 组并将其添加到 /etc/group 中。

    2. /etc/group 中将 mysql 操作系统账户添加到 shadow 组中。

    3. /etc/group 分配 shadow 组的读权限:

      chgrp shadow /etc/shadow
      chmod g+r /etc/shadow
    4. 重启 MySQL 服务器。

  • 如果您正在使用 pam_unix 模块和 unix_ chkpwd 工具,调整密码存储访问权限如下:

    chmod u-s /usr/sbin/unix_chkpwd
    setcap cap_dac_read_search+ep /usr/sbin/unix_chkpwd

    根据您的平台调整 unix_ chkpwd 的路径。

PAM 认证插件在初始化时检查环境变量 AUTHENTICATION_ PAM_LOG 是否设置。如果是这样,插件将启用对标准输出的诊断消息日志记录。这些消息可能有助于调试与 PAM 相关的问题。

设置 AUTHENTICATION_ PAM_LOG=1(或其他任意值)不会包含任何密码。如果您希望在这些消息中包括密码,请设置 AUTHENTICATION_ PAM_LOG=PAM_ LOG_ WITH_SECRET_INFO

一些消息引用 PAM 插件的源文件和行号,这使得插件操作与代码中的位置更紧密地关联。

另一种用于调试连接失败和在连接尝试期间确定发生了什么的技术是配置PAM认证以允许所有连接,然后检查系统日志文件。这一技术应仅在临时基础上使用,并不应在生产服务器上使用。

创建一个名为/etc/pam.d/mysql-any-password的PAM服务文件,内容如下(格式可能在某些系统上有所不同):

#%PAM-1.0
auth        required    pam_permit.so
account     required    pam_permit.so

创建一个使用PAM插件的账户,并将其命名为mysql-any-passwordPAM服务:

CREATE USER 'testuser'@'localhost'
  IDENTIFIED WITH authentication_pam
  AS 'mysql-any-password';

mysql-any-password服务文件会导致任何认证尝试都返回真值,即使是错误的密码。如果认证尝试失败,那么问题就出在MySQL侧;否则,问题就在操作系统/PAM侧。要查看可能发生的情况,请检查系统日志文件,如/var/log/secure/var/log/audit.log/var/log/syslog/var/log/messages

一旦确定问题所在,请删除mysql-any-passwordPAM服务文件以禁用任何密码访问。