文档首页
MySQL 9.0 参考手册
相关文档 下载此手册
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
手册页 (TGZ) - 258.2Kb
手册页 (Zip) - 365.3Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


MySQL 9.0 参考手册  /  ...  /  PAM 可插拔身份验证

8.4.1.4 PAM 可插拔身份验证

注意

PAM 可插拔身份验证是 MySQL 企业版(商业产品)中包含的扩展。要了解有关商业产品的更多信息,请参见 https://www.mysqlserver.cn/products/.

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

PAM 可插拔身份验证提供以下功能

  • 外部身份验证:PAM 身份验证使 MySQL 服务器能够接受来自在 MySQL 授权表之外定义的用户连接,这些用户使用 PAM 支持的方法进行身份验证。

  • 代理用户支持:PAM 身份验证可以根据外部用户所属的 PAM 组以及提供的身份验证字符串,将与客户端程序传递的外部用户名不同的用户名返回给 MySQL。这意味着插件可以返回定义外部 PAM 身份验证用户应拥有的特权的 MySQL 用户。例如,操作系统用户名为 joe 可以连接并拥有名为 developer 的 MySQL 用户的特权。

PAM 可插拔身份验证已在 Linux 和 macOS 上进行测试;请注意,Windows 不支持 PAM。

下表显示了插件和库文件名。文件名后缀可能在您的系统上有所不同。该文件必须位于由 plugin_dir 系统变量命名的目录中。有关安装信息,请参见 安装 PAM 可插拔身份验证

表 8.18 PAM 身份验证的插件和库名称

插件或文件 插件或文件名
服务器端插件 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.3 节,“客户端明文可插拔身份验证”。有关代理用户的信息,请参见 第 8.2.19 节,“代理用户”

PAM 身份验证 MySQL 用户的工作原理

本节概述了 MySQL 和 PAM 如何协同工作以验证 MySQL 用户。有关设置使用特定 PAM 服务的 MySQL 帐户的示例,请参见 使用 PAM 可插拔身份验证

  1. 客户端程序与服务器进行通信,客户端向服务器发送客户端用户名(默认情况下为操作系统用户名)和密码。

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

    • 对于使用 PAM 服务器端身份验证插件的帐户,相应的客户端插件是 mysql_clear_password。此客户端插件不执行任何密码哈希,因此客户端将密码以明文形式发送到服务器。

  2. 服务器根据外部用户名和客户端连接的主机查找匹配的 MySQL 帐户。PAM 插件使用 MySQL 服务器传递给它的信息(例如用户名、主机名、密码和身份验证字符串)。当您定义使用 PAM 身份验证的 MySQL 帐户时,身份验证字符串包含

    • PAM 服务名称,它是系统管理员可以用来引用特定应用程序的身份验证方法的名称。单个数据库服务器实例可以关联多个应用程序,因此服务名称的选择留给 SQL 应用程序开发人员。

    • 可选地,如果要使用代理,则将 PAM 组映射到 MySQL 用户名。

  3. 该插件使用身份验证字符串中命名的 PAM 服务来检查用户凭据,并返回 'Authentication succeeded, Username is user_name''Authentication failed'。密码必须适合 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.

要验证插件安装,请检查 Information Schema 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 可插拔身份验证 中所述。

要在 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 PAM 组中的操作系统用户分别映射到 developerdata_entry MySQL 用户,请使用以下语句

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

PAM 身份验证插件的身份验证字符串语法遵循以下规则

  • 该字符串由 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 来检查登录名和密码。每个允许连接到 MySQL 服务器的外部用户都应该具有一个匹配的 MySQL 帐户,该帐户被定义为使用 PAM 身份验证。(对于 MySQL 帐户 'user_name'@'host_name' 来匹配外部用户,user_name 必须是外部用户名,host_name 必须与客户端连接的主机匹配。)身份验证可以通过各种 PAM 支持的方法执行。后面的讨论将展示如何使用传统的 Unix 密码和 LDAP 中的密码来验证客户端凭据。

    PAM 身份验证在不通过代理用户或 PAM 组进行的情况下,要求 MySQL 用户名与操作系统用户名相同。MySQL 用户名限制为 32 个字符(请参阅 第 8.2.3 节,“Grant 表”),这将 PAM 非代理身份验证限制为名称不超过 32 个字符的 Unix 帐户。

  • 仅代理用户,使用 PAM 组映射。对于这种场景,请创建一个或多个定义不同权限集的 MySQL 帐户。(理想情况下,任何人都应该直接使用这些帐户进行连接。)然后,定义一个通过 PAM 进行身份验证的默认用户,该用户使用一些映射方案(通常基于用户所属的外部 PAM 组)将所有外部用户名映射到持有权限集的少数几个 MySQL 帐户。任何连接并指定外部用户名作为客户端用户名的客户端都会被映射到其中一个 MySQL 帐户,并使用其权限。讨论将展示如何使用传统的 Unix 密码来设置它,但也可以使用其他 PAM 方法(如 LDAP)。

这些场景可能有各种变体

  • 您可以允许某些用户直接登录(不使用代理),但要求其他用户通过代理帐户进行连接。

  • 您可以为某些用户使用一种 PAM 身份验证方法,而为其他用户使用另一种方法,方法是在您的 PAM 身份验证帐户中使用不同的 PAM 服务名称。例如,您可以对某些用户使用 mysql-unix PAM 服务,而对其他用户使用 mysql-ldap

以下示例基于以下假设。如果您的系统设置不同,您可能需要进行一些调整。

  • 登录名和密码分别是 antonioantonio_password。将这些更改为与您要验证的用户相对应。

  • PAM 配置目录为 /etc/pam.d

  • PAM 服务名称对应于身份验证方法(在本讨论中为 mysql-unixmysql-ldap)。要使用给定的 PAM 服务,您必须在 PAM 配置目录中设置一个同名 PAM 文件(如果文件不存在则创建)。此外,您必须在任何使用该 PAM 服务进行身份验证的帐户的 CREATE USER 语句的身份验证字符串中命名 PAM 服务。

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 服务器的此类外部用户都应该有一个匹配的 MySQL 帐户,该帐户被定义为通过 LDAP 使用 PAM 身份验证。

要对 MySQL 使用 PAM LDAP 可插拔身份验证,必须满足以下先决条件

  • PAM LDAP 服务必须能够与之通信的 LDAP 服务器必须可用。

  • 每个要由 MySQL 验证的 LDAP 用户都必须存在于 LDAP 服务器管理的目录中。

注意

使用 LDAP 对 MySQL 用户进行身份验证的另一种方法是使用特定于 LDAP 的身份验证插件。请参见 第 8.4.1.6 节,“LDAP 可插拔身份验证”

按如下方式配置 MySQL 以使用 PAM LDAP 身份验证

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

  2. 通过创建名为 /etc/pam.d/mysql-ldapmysql-ldap PAM 服务文件,设置 PAM 以使用 LDAP 对 MySQL 连接进行身份验证。文件内容依赖于系统,因此请检查 /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-ldap PAM 服务进行身份验证

    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 密码身份验证 中描述的相同。

使用代理用户和组映射的 PAM Unix 密码身份验证

此处描述的身份验证方案使用代理和 PAM 组映射,将使用 PAM 进行身份验证的连接 MySQL 用户映射到定义不同权限集的其他 MySQL 帐户。用户不会直接通过定义权限的帐户进行连接。相反,他们通过使用 PAM 进行身份验证的默认代理帐户进行连接,以便所有外部用户都映射到拥有权限的 MySQL 帐户。任何使用代理帐户进行连接的用户都将映射到其中一个 MySQL 帐户,其权限决定了允许外部用户执行的数据库操作。

此处显示的过程使用 Unix 密码身份验证。要改用 LDAP,请参见 无代理用户的 PAM LDAP 身份验证 的早期步骤。

注意

传统的 Unix 密码使用 /etc/shadow 文件进行检查。有关与该文件相关的可能问题的详细信息,请参见 PAM 身份验证访问 Unix 密码存储

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

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

  3. 通过创建名为 /etc/pam.d/mysql-unix 的文件,设置 PAM 以通过操作系统用户对 mysql-unix PAM 服务进行身份验证。文件内容依赖于系统,因此请检查 /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 密码。身份验证字符串还将 rootusers PAM 组中的外部用户分别映射到 developerdata_entry MySQL 用户名。

    在设置代理用户时,需要 PAM 服务名称后面的 PAM 组映射列表。否则,插件无法知道如何从外部用户名映射到正确的代理 MySQL 用户名。

    注意

    如果您的 MySQL 安装有匿名用户,他们可能会与默认代理用户冲突。有关此问题的更多信息以及解决方法,请参见 默认代理用户和匿名用户冲突

  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 组。(这假设插件已安装。有关说明,请参见 第 8.4.1.8 节,“无登录可插拔身份验证”。)有关保护代理帐户免受直接使用的方法,请参见 阻止直接登录代理帐户

  6. 为代理帐户授予每个代理帐户的 PROXY 权限

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

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

    服务器使用默认的 ''@'' 代理帐户验证连接。antonio 的结果权限取决于 antonio 是哪个 PAM 组的成员。如果 antonioroot PAM 组的成员,则 PAM 插件会将 root 映射到 developer MySQL 用户名,并将该用户名返回给服务器。服务器会验证 ''@'' 是否对 developer 拥有 PROXY 权限,并允许连接。以下查询将返回如下所示的输出

    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 组成员资格映射到 data_entry MySQL 用户名,并将该用户名返回给服务器

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

    这表明 antonio 操作系统用户被验证为拥有授予 data_entry MySQL 用户的权限,并且代理通过默认代理帐户进行。

注意

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

PAM 身份验证访问 Unix 密码存储

在某些系统上,Unix 身份验证使用密码存储,例如 /etc/shadow,这是一个通常具有受限访问权限的文件。这会导致 MySQL 基于 PAM 的身份验证失败。不幸的是,PAM 实现不允许区分 无法检查密码(例如,由于无法读取 /etc/shadow)和 密码不匹配。如果您对 PAM 身份验证使用 Unix 密码存储,则可以使用以下方法之一启用 MySQL 从中访问密码存储

  • 假设 MySQL 服务器从 mysql 操作系统帐户运行,将该帐户放入具有 /etc/shadow 访问权限的 shadow 组。

    1. /etc/group 中创建一个 shadow 组。

    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 身份验证调试

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-password PAM 服务的帐户。

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

mysql-any-password 服务文件会导致任何身份验证尝试都返回 true,即使密码不正确也是如此。如果身份验证尝试失败,则表明配置问题出在 MySQL 端。否则,问题出在操作系统/PAM 端。要查看可能发生的情况,请检查系统日志文件,例如 /var/log/secure/var/log/audit.log/var/log/syslog/var/log/messages

在确定问题后,删除 mysql-any-password PAM 服务文件以禁用任何密码访问。