6.4.4.8 通用密钥环密钥 Management 功能

MySQL Server 支持密钥环服务,该服务使内部服务器组件和插件能够安全地存储敏感信息,以便以后检索。

从 MySQL 5.7.13 开始,MySQL Server 包含一个用于密钥环密钥 Management 的 SQL 接口,该接口实现为一组通用的用户定义函数(UDF),用于访问内部密钥环服务提供的功能。密钥环 UDF 包含在插件库文件中,该文件还包含一个keyring_udf插件,必须在 UDF 调用之前将其启用。要使用这些 UDF,必须启用keyring_filekeyring_okv之类的密钥环插件。

这里描述的 UDF 是通用的,旨在与任何密钥环插件一起使用。给定的密钥环插件可能具有其自己的 UDF,这些 UDF 仅可用于该插件。参见第 6.4.4.9 节“特定于插件的密钥环密钥 Management 功能”

以下各节提供了密钥环 UDF 的安装说明,并演示了如何使用它们。有关 UDF 调用的密钥环服务功能的信息,请参见第 28.3.2 节“密钥环服务”。有关常规密钥环的信息,请参见第 6.4.4 节“ MySQL 密钥环”

安装或卸载通用密钥环功能

本节介绍如何安装或卸载密钥环用户定义功能(UDF),这些功能在也包含keyring_udf插件的插件库文件中实现。有关安装或卸载插件和 UDF 的一般信息,请参见第 5.5.1 节“安装和卸载插件”第 5.6.2 节“安装和卸载用户定义的函数”

密钥环 UDF 启用密钥环密钥 Management 操作,但是还必须安装keyring_udf插件,因为如果没有它,UDF 将无法正常工作。尝试使用没有keyring_udf插件的 UDF 会导致错误。

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

插件库文件的基本名称为keyring_udf。每个平台的文件名后缀都不同(例如,对于 Unix 和类 Unix 系统,为.so,对于 Windows 为.dll)。

要安装keyring_udf插件和 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';

如果插件和 UDF 在主复制服务器上使用,请在所有从属服务器上也安装它们,以避免复制问题。

如前所述,一旦安装,插件和 UDF 将保持安装状态,直到被卸载。要删除它们,请使用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;
使用通用密钥环功能

在使用密钥环用户定义功能(UDF)之前,请根据安装或卸载通用密钥环功能中提供的说明安装它们。

密钥环 UDF 受到以下约束:

  • 要使用任何密钥环 UDF,必须启用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插件,请参见安装或卸载通用密钥环功能

  • 密钥环 UDF 调用密钥环服务功能(请参阅第 28.3.2 节“密钥环服务”)。服务功能依次使用已安装的任何密钥环插件(例如keyring_filekeyring_okv)。因此,要使用任何密钥环 UDF,必须启用某些基础密钥环插件。否则,将发生错误:
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.

要安装钥匙圈插件,请参阅第 6.4.4.1 节“安装 Keyring 插件”

  • 要使用任何密钥环 UDF,用户必须拥有全局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特权的同时仍允许用户访问特定的密钥 Management 操作,则可以定义“包装器”存储的程序(本节稍后介绍的一种技术)。

  • 给定用户存储在密钥环中的密钥以后只能由同一用户操作。即,在进行键操作时,CURRENT_USER()函数的值必须与将键存储在键环中时的值相同。 (此约束排除了使用密钥环 UDF 来处理实例范围的密钥,例如InnoDB为支持 table 空间加密而创建的密钥)。

为了使多个用户可以对同一键执行操作,可以定义“包装”存储的程序(本节稍后介绍的一种技术)。

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

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

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

为了能够检查返回类型,而不管是否发生错误,请使用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 |
+------+

此技术还适用于其他密钥环 UDF,这些密钥环 UDF 对于失败将返回一个值和一个错误。

传递给keyring_key_generate()的 ID 提供了一种在后续的 UDF 调用中引用密钥的方法。例如,使用密钥 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                     |
+--------------------------------------+

密钥环 UDF 将密钥 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特权才能调用密钥环 UDF,并且根据有效的CURRENT_USER()值确定,最初在密钥环中存储密钥的用户必须是稍后对该密钥执行后续操作的用户。对于每个 UDF 调用。要允许对没有全局EXECUTE特权或可能不是密钥“所有者”的用户进行密钥操作,请使用以下技术:

  • 定义“包装程序”存储的程序,该程序封装所需的键操作,并且其DEFINER值等于键所有者。

  • 将特定存储程序的EXECUTE特权授予应该可以调用它们的单个用户。

  • 如果包装器存储程序执行的操作不包括密钥创建,请使用存储程序定义中名为DEFINER的帐户预先创建任何必需的密钥。

这种技术使密钥可以在用户之间共享,并为 DBA 提供了更细粒度的控制,使其可以在无需授予全局特权的情况下对谁可以使用密钥进行操作。

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

从一个 MySQLManagement 帐户(在此示例中为'root'@'localhost'),创建 Management 模式和存储的函数以访问密钥:

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');

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

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

从 Management 帐户中,创建要授予密钥访问权限的普通用户帐户:

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'

在 Management 帐户中,将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                 |
+----------------------------------+
通用密钥环功能参考

对于每个通用密钥环用户定义函数(UDF),本节描述其用途,调用 Sequences 和返回值。有关可以调用这些 UDF 的条件的信息,请参见使用通用密钥环功能

给定密钥 ID,对密钥进行反模糊处理并返回。

Arguments:

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

Return value:

返回键值作为成功的字符串;如果键不存在则返回NULL;如果失败则返回NULL和错误。

Note

使用keyring_key_fetch()检索的键值必须遵守第 6.4.4.6 节“支持的密钥环密钥类型和长度”中所述的通用密钥环 UDF 限制。可以使用密钥环服务功能(请参见第 28.3.2 节“密钥环服务”)来存储长于该长度的密钥值,但是如果使用keyring_key_fetch()进行检索,则会将其截断为通用密钥环 UDF 限制。

Example:

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()来显示键值,因为它可能包含不可打印的字符。为了简洁起见,该示例还使用了一个短键,但请注意,较长的键可提供更好的安全性。

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

Arguments:

    • key_id *:指定密钥 ID 的字符串。
      • key_type *:指定密钥类型的字符串。
      • key_length *:一个整数,以字节为单位指定密钥长度。

Return value:

返回 1table 示成功,返回NULLtable 示失败。

Example:

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

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

Arguments:

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

Return value:

返回密钥长度(以字节为单位),以整数形式 table 示成功;如果密钥不存在,则返回NULL;如果失败则返回NULL和错误。

Example:

请参阅keyring_key_fetch()的说明。

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

Arguments:

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

Return value:

返回 1table 示成功,或NULLtable 示失败。

Example:

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

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

Arguments:

    • key_id *:指定密钥 ID 的字符串。
      • key_type *:指定密钥类型的字符串。
      • key *:指定键值的字符串。

Return value:

返回 1table 示成功,返回NULLtable 示失败。

Example:

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

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

Arguments:

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

Return value:

返回密钥类型为成功的字符串;如果密钥不存在,则返回NULL;如果失败则返回NULL和错误。

Example:

请参阅keyring_key_fetch()的说明。