Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  General-Purpose Keyring Key-Management Functions

8.4.4.15 通用密钥环密钥管理函数

MySQL 服务器支持密钥环服务,启用内部组件和插件安全地存储敏感信息以供后续检索。

MySQL 服务器还包括一个 SQL 接口用于密钥环密钥管理,实现为一组通用函数,访问内部密钥环服务提供的功能。这些函数包含在插件库文件中,该文件还包含一个 keyring_udf 插件,必须在函数调用之前启用。为了使用这些函数,必须启用密钥环插件,例如 keyring_filekeyring_okv

这里描述的函数是通用的,旨在与任何密钥环插件一起使用。特定的密钥环插件可能具有其自己的函数,仅供该插件使用;见 第 8.4.4.16 节,“插件特定密钥环密钥管理函数”

以下部分提供了密钥环函数的安装说明,并演示如何使用它们。有关密钥环服务函数的信息,请参阅 第 7.6.9.2 节,“密钥环服务”。有关一般密钥环信息,请参阅 第 8.4.4 节,“MySQL 密钥环”

安装或卸载通用密钥环函数

本节描述如何安装或卸载密钥环函数,这些函数实现在插件库文件中,该文件还包含一个 keyring_udf 插件。有关安装或卸载插件和可加载函数的常规信息,请参阅 第 7.6.1 节,“安装和卸载插件”第 7.7.1 节,“安装和卸载可加载函数”

密钥环函数启用密钥环密钥管理操作,但 keyring_udf 插件也必须安装,因为函数不能在没有它的情况下正确工作。尝试在没有 keyring_udf 插件的情况下使用函数将导致错误。

要使插件库文件可供服务器使用,必须将其位于 MySQL 插件目录中(由 plugin_dir 系统变量命名的目录)。如果必要,通过设置 plugin_dir 系统变量的值在服务器启动时配置插件目录的位置。

插件库文件的基本名称是 keyring_udf。文件名后缀因平台而异(例如,Unix 和 Unix-like 系统上的 .so,Windows 上的 .dll)。

要安装 keyring_udf 插件和密钥环函数,使用 INSTALL PLUGINCREATE FUNCTION 语句,根据平台调整 .so 后缀:

INSTALL PLUGIN keyring_udf SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_generate RETURNS INTEGER
  SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_fetch RETURNS STRING
  SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_length_fetch RETURNS INTEGER
  SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_type_fetch RETURNS STRING
  SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_store RETURNS INTEGER
  SONAME 'keyring_udf.so';
CREATE FUNCTION keyring_key_remove RETURNS INTEGER
  SONAME 'keyring_udf.so';

如果插件和函数在源复制服务器上使用,也请在所有副本上安装它们,以避免复制问题。

一旦安装,如上所述,插件和函数将保持安装状态,直到卸载。要删除它们,请使用 UNINSTALL PLUGINDROP FUNCTION 语句:

UNINSTALL PLUGIN keyring_udf;
DROP FUNCTION keyring_key_generate;
DROP FUNCTION keyring_key_fetch;
DROP FUNCTION keyring_key_length_fetch;
DROP FUNCTION keyring_key_type_fetch;
DROP FUNCTION keyring_key_store;
DROP FUNCTION keyring_key_remove;
使用通用密钥环函数

在使用通用密钥环函数之前,按照安装或卸载通用密钥环函数中的说明安装它们。

密钥环函数受以下约束:

  • 要使用任何密钥环函数,keyring_udf插件必须启用。否则,将发生错误:

    ERROR 1123 (HY000): Can't initialize function 'keyring_key_generate';
    This function requires keyring_udf plugin which is not installed.
    Please install

    要安装keyring_udf插件,请参阅安装或卸载通用密钥环函数

  • 密钥环函数调用密钥服务函数(见第 7.6.9.2 节,“密钥服务”)。服务函数随后使用安装的密钥插件(例如,keyring_filekeyring_okv)。因此,要使用任何密钥环函数,必须启用某个基础密钥插件。否则,将发生错误:

    ERROR 3188 (HY000): Function 'keyring_key_generate' failed because
    underlying keyring service returned an error. Please check if a
    keyring plugin is installed and that provided arguments are valid
    for the keyring you are using.

    要安装密钥插件,请参阅第 8.4.4.3 节,“密钥插件安装”

  • 用户必须拥有全局EXECUTE特权,以使用任何密钥环函数。否则,将发生错误:

    ERROR 1123 (HY000): Can't initialize function 'keyring_key_generate';
    The user is not privileged to execute this function. User needs to
    have EXECUTE

    要授予用户全局EXECUTE特权,请使用以下语句:

    GRANT EXECUTE ON *.* TO user;

    或者,如果您想避免授予全局EXECUTE特权,同时仍允许用户访问特定的密钥管理操作,可以定义“包装器”存储程序(在本节后面将描述这种技术)。

  • 用户存储在密钥环中的密钥只能由同一个用户后续操作。也就是说,在密钥操作时CURRENT_USER()函数的值必须与存储密钥时相同的值。(这条约束排除了使用密钥环函数来操作实例范围的密钥,例如InnoDB用于表空间加密创建的密钥。)

    要启用多个用户对同一个密钥进行操作,可以定义“包装器”存储程序(在本节后面将描述这种技术)。

  • 密钥环函数支持基础密钥插件支持的密钥类型和长度。有关特定密钥插件的密钥信息,请参阅第 8.4.4.13 节,“支持的密钥环密钥类型和长度”

要创建新的随机密钥并将其存储在密钥环中,请调用keyring_key_generate(),将密钥 ID、密钥类型(加密方法)和密钥长度(以字节为单位)传递给它。以下调用创建了一个 2048 位 DSA 加密密钥,名为 MyKey

mysql> SELECT keyring_key_generate('MyKey', 'DSA', 256);
+-------------------------------------------+
| keyring_key_generate('MyKey', 'DSA', 256) |
+-------------------------------------------+
|                                         1 |
+-------------------------------------------+

返回值为 1 表示成功。如果密钥无法创建,返回值为 NULL,并发生错误。可能的原因是基础密钥插件不支持指定的密钥类型和密钥长度组合;请参阅第 8.4.4.13 节,“支持的密钥环密钥类型和长度”

要无论是否发生错误都可以检查返回类型,请使用 SELECT ... INTO @var_name 并测试变量值:

mysql> SELECT keyring_key_generate('', '', -1) INTO @x;
ERROR 3188 (HY000): Function 'keyring_key_generate' failed because
underlying keyring service returned an error. Please check if a
keyring plugin is installed and that provided arguments are valid
for the keyring you are using.
mysql> SELECT @x;
+------+
| @x   |
+------+
| NULL |
+------+
mysql> SELECT keyring_key_generate('x', 'AES', 16) INTO @x;
mysql> SELECT @x;
+------+
| @x   |
+------+
|    1 |
+------+

这种技术也适用于其他密钥环函数,它们在失败时返回值和错误。

传递给 keyring_key_generate() 的 ID 提供了一种方式,以便在后续函数调用中引用密钥。例如,使用密钥 ID 来检索其类型作为字符串或其长度作为整数:

mysql> SELECT keyring_key_type_fetch('MyKey');
+---------------------------------+
| keyring_key_type_fetch('MyKey') |
+---------------------------------+
| DSA                             |
+---------------------------------+
mysql> SELECT keyring_key_length_fetch('MyKey');
+-----------------------------------+
| keyring_key_length_fetch('MyKey') |
+-----------------------------------+
|                               256 |
+-----------------------------------+

要检索密钥值,请将密钥 ID 传递给 keyring_key_fetch()。以下示例使用 HEX() 显示密钥值,因为它可能包含不可打印的字符。该示例还使用了一个短密钥以简洁,但请注意,较长的密钥提供了更好的安全性:

mysql> SELECT keyring_key_generate('MyShortKey', 'DSA', 8);
+----------------------------------------------+
| keyring_key_generate('MyShortKey', 'DSA', 8) |
+----------------------------------------------+
|                                            1 |
+----------------------------------------------+
mysql> SELECT HEX(keyring_key_fetch('MyShortKey'));
+--------------------------------------+
| HEX(keyring_key_fetch('MyShortKey')) |
+--------------------------------------+
| 1DB3B0FC3328A24C                     |
+--------------------------------------+

密钥环函数将密钥 ID、类型和值视为二进制字符串,因此比较是区分大小写的。例如,ID MyKeymykey 引用不同的密钥。

要删除密钥,请将密钥 ID 传递给 keyring_key_remove()

mysql> SELECT keyring_key_remove('MyKey');
+-----------------------------+
| keyring_key_remove('MyKey') |
+-----------------------------+
|                           1 |
+-----------------------------+

要混淆并存储您提供的密钥,请将密钥 ID、类型和值传递给 keyring_key_store()

mysql> SELECT keyring_key_store('AES_key', 'AES', 'Secret string');
+------------------------------------------------------+
| keyring_key_store('AES_key', 'AES', 'Secret string') |
+------------------------------------------------------+
|                                                    1 |
+------------------------------------------------------+

如前所述,用户必须拥有全局 EXECUTE 权限以调用密钥函数,并且最初存储密钥的用户必须是同一个用户,以后对密钥执行操作,根据每个函数调用的 CURRENT_USER() 值确定。要允许没有全局 EXECUTE 权限或不是密钥 “所有者”的用户执行密钥操作,请使用以下技术:

  1. 定义 wrapper 存储程序,以封装所需的密钥操作,并将 DEFINER 值设置为密钥所有者。

  2. 授予特定存储程序的 EXECUTE 权限给个别用户,以便他们可以调用这些程序。

  3. 如果 wrapper 存储程序不包括密钥创建,请提前创建必要的密钥,使用存储程序定义中的 DEFINER 帐户名。

这种技术使密钥可以在用户之间共享,并为 DBA 提供了更细粒度的控制,以确定谁可以对密钥执行什么操作,而不需要授予全局权限。

以下示例显示如何设置共享密钥 SharedKey,该密钥由 DBA 拥有,并创建一个 get_shared_key() 存储函数,以提供对当前密钥值的访问。任何拥有该函数 EXECUTE 权限的用户都可以检索该值,该函数是在 key_schema 架构中创建的。

从 MySQL 管理帐户 ('root'@'localhost' 在本示例中),创建管理架构和访问密钥的存储函数:

mysql> CREATE SCHEMA key_schema;

mysql> CREATE DEFINER = 'root'@'localhost'
       FUNCTION key_schema.get_shared_key()
       RETURNS BLOB READS SQL DATA
       RETURN keyring_key_fetch('SharedKey');

从管理帐户,确保共享密钥存在:

mysql> SELECT keyring_key_generate('SharedKey', 'DSA', 8);
+---------------------------------------------+
| keyring_key_generate('SharedKey', 'DSA', 8) |
+---------------------------------------------+
|                                           1 |
+---------------------------------------------+

从管理帐户,创建一个普通用户帐户,以授予密钥访问权限:

mysql> CREATE USER 'key_user'@'localhost'
       IDENTIFIED BY 'key_user_pwd';

key_user 帐户,验证在没有适当 EXECUTE 权限的情况下,新帐户无法访问共享密钥:

mysql> SELECT HEX(key_schema.get_shared_key());
ERROR 1370 (42000): execute command denied to user 'key_user'@'localhost'
for routine 'key_schema.get_shared_key'

从管理帐户,授予 EXECUTE 权限给 key_user,以便其可以访问存储函数:

mysql> GRANT EXECUTE ON FUNCTION key_schema.get_shared_key
       TO 'key_user'@'localhost';

key_user 帐户,验证密钥现在是可访问的:

mysql> SELECT HEX(key_schema.get_shared_key());
+----------------------------------+
| HEX(key_schema.get_shared_key()) |
+----------------------------------+
| 9BAFB9E75CEEB013                 |
+----------------------------------+
通用密钥环函数参考

对于每个通用密钥环函数,本节描述其目的、调用序列和返回值。有关这些函数可以被调用的条件,请参阅 使用通用密钥环函数

  • keyring_key_fetch(key_id)

    给定密钥 ID,解混淆并返回密钥值。

    参数:

    • key_id: 一个字符串,指定密钥 ID。

    返回值:

    成功时返回密钥值字符串,密钥不存在时返回 NULL,或失败时返回 NULL 和错误。

    Note

    使用 keyring_key_fetch() 检索的密钥值受通用密钥环函数限制,如 第 8.4.4.13 节,“支持的密钥环密钥类型和长度” 所述。使用密钥服务函数(见 第 7.6.9.2 节,“密钥环服务”)可以存储长于该限制的密钥值,但如果使用 keyring_key_fetch() 检索,则将被截断到通用密钥环函数限制。

    示例:

    mysql> SELECT keyring_key_generate('RSA_key', 'RSA', 16);
    +--------------------------------------------+
    | keyring_key_generate('RSA_key', 'RSA', 16) |
    +--------------------------------------------+
    |                                          1 |
    +--------------------------------------------+
    mysql> SELECT HEX(keyring_key_fetch('RSA_key'));
    +-----------------------------------+
    | HEX(keyring_key_fetch('RSA_key')) |
    +-----------------------------------+
    | 91C2253B696064D3556984B6630F891A  |
    +-----------------------------------+
    mysql> SELECT keyring_key_type_fetch('RSA_key');
    +-----------------------------------+
    | keyring_key_type_fetch('RSA_key') |
    +-----------------------------------+
    | RSA                               |
    +-----------------------------------+
    mysql> SELECT keyring_key_length_fetch('RSA_key');
    +-------------------------------------+
    | keyring_key_length_fetch('RSA_key') |
    +-------------------------------------+
    |                                  16 |
    +-------------------------------------+

    示例使用 HEX() 显示密钥值,因为它可能包含不可打印的字符。示例还使用了一个短密钥以简洁,但请注意,较长的密钥提供了更好的安全性。

  • keyring_key_generate(key_id, key_type, key_length)

    生成一个新的随机密钥,具有给定的 ID、类型和长度,并将其存储在密钥环中。类型和长度值必须与底层密钥环插件支持的值一致。见 第 8.4.4.13 节,“支持的密钥环密钥类型和长度”

    参数:

    • key_id:指定密钥 ID 的字符串。

    • key_type:指定密钥类型的字符串。

    • key_length:指定密钥长度(以字节为单位)的整数。

    返回值:

    成功时返回 1,否则返回 NULL 和错误。

    示例:

    mysql> SELECT keyring_key_generate('RSA_key', 'RSA', 384);
    +---------------------------------------------+
    | keyring_key_generate('RSA_key', 'RSA', 384) |
    +---------------------------------------------+
    |                                           1 |
    +---------------------------------------------+
  • keyring_key_length_fetch(key_id)

    给定密钥 ID,返回密钥长度。

    参数:

    • key_id:指定密钥 ID 的字符串。

    返回值:

    成功时返回密钥长度(以字节为单位)作为整数,否则返回 NULL 如果密钥不存在,或者返回 NULL 和错误。

    示例:

    keyring_key_fetch() 的描述。

  • keyring_key_remove(key_id)

    从密钥环中删除具有给定 ID 的密钥。

    参数:

    • key_id:指定密钥 ID 的字符串。

    返回值:

    成功时返回 1,否则返回 NULL

    示例:

    mysql> SELECT keyring_key_remove('AES_key');
    +-------------------------------+
    | keyring_key_remove('AES_key') |
    +-------------------------------+
    |                             1 |
    +-------------------------------+
  • keyring_key_store(key_id, key_type, key)

    对密钥进行混淆并将其存储在密钥环中。

    参数:

    • key_id:指定密钥 ID 的字符串。

    • key_type:指定密钥类型的字符串。

    • key:指定密钥值的字符串。

    返回值:

    成功时返回 1,否则返回 NULL 和错误。

    示例:

    mysql> SELECT keyring_key_store('new key', 'DSA', 'My key value');
    +-----------------------------------------------------+
    | keyring_key_store('new key', 'DSA', 'My key value') |
    +-----------------------------------------------------+
    |                                                   1 |
    +-----------------------------------------------------+
  • keyring_key_type_fetch(key_id)

    给定密钥 ID,返回密钥类型。

    参数:

    • key_id:指定密钥 ID 的字符串。

    返回值:

    成功时返回密钥类型作为字符串,否则返回 NULL 如果密钥不存在,或者返回 NULL 和错误。

    示例:

    keyring_key_fetch() 的描述。