MySQL 服务器支持一个密钥环服务,该服务使内部组件和插件能够安全地存储敏感信息以供将来检索。
MySQL 服务器还包括一个用于密钥环密钥管理的 SQL 接口,它被实现为一组通用函数,这些函数访问内部密钥环服务提供的功能。密钥环函数包含在一个插件库文件中,该文件还包含一个 keyring_udf
插件,该插件必须在调用函数之前启用。要使用这些函数,必须启用一个密钥环插件,例如 keyring_okv
。
此处描述的函数是通用的,旨在与任何密钥环插件一起使用。给定的密钥环插件可能拥有专供该插件使用的函数;请参阅 第 8.4.4.13 节,“特定于插件的密钥环密钥管理函数”。
以下部分提供了密钥环函数的安装说明,并演示了如何使用它们。有关一般密钥环信息,请参阅 第 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 系统为 .so
,Windows 为 .dll
)。
要安装 keyring_udf
插件和密钥环函数,请使用 INSTALL PLUGIN
和 CREATE 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 PLUGIN
和 DROP 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_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.10 节,“支持的密钥环密钥类型和长度”。
要创建新的随机密钥并将其存储在密钥环中,请调用 keyring_key_generate()
,并将密钥的 ID、密钥类型(加密方法)及其以字节为单位的长度传递给它。以下调用将创建一个名为 MyKey
的 2,048 位 DSA 加密密钥
mysql> SELECT keyring_key_generate('MyKey', 'DSA', 256);
+-------------------------------------------+
| keyring_key_generate('MyKey', 'DSA', 256) |
+-------------------------------------------+
| 1 |
+-------------------------------------------+
返回值 1 表示成功。如果无法创建密钥,则返回值为 NULL
,并且会发生错误。导致这种情况的一个原因可能是底层密钥环插件不支持指定的密钥类型和密钥长度组合;请参阅 第 8.4.4.10 节,“支持的密钥环密钥类型和长度”。
为了能够在发生错误时检查返回类型,请使用 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、类型和值视为二进制字符串,因此比较区分大小写。例如,MyKey
和 mykey
的 ID 指的是不同的密钥。
要删除密钥,请将密钥 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
权限或可能不是密钥 “所有者” 的用户进行密钥操作,请使用以下技术
定义 “包装器” 存储程序,这些程序封装了必需的密钥操作,并且具有与密钥所有者相等的
DEFINER
值。授予特定存储程序的
EXECUTE
权限,以便应该能够调用这些程序的各个用户。如果包装器存储程序实现的操作不包括密钥创建,请使用在存储程序定义中作为
DEFINER
命名的帐户提前创建所有必需的密钥。
此技术允许在用户之间共享密钥,并为 DBA 提供更细粒度的控制,让他们可以控制谁可以对密钥执行哪些操作,而无需授予全局权限。
以下示例展示了如何设置一个由 DBA 拥有的名为 SharedKey
的共享密钥,以及一个 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'
从管理帐户为 key_user
授予存储函数的 EXECUTE
权限
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 |
+----------------------------------+
对于每个通用密钥环功能,本节将描述其用途、调用序列和返回值。有关调用这些函数的条件的信息,请参阅 使用通用密钥环功能。
给定一个密钥 ID,取消混淆并返回密钥值。
参数
key_id
: 指定密钥 ID 的字符串。
返回值
对于成功,返回密钥值作为字符串,对于密钥不存在,返回
NULL
,对于失败,返回NULL
和一个错误。注意使用
keyring_key_fetch()
检索的密钥值受 第 8.4.4.10 节,“支持的密钥环密钥类型和长度” 中描述的通用密钥环功能限制。可以使用密钥环服务函数存储比该长度更长的密钥值(参见 第 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.10 节,“支持的密钥环密钥类型和长度”。
参数
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()
的描述。从密钥环中删除具有给定 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()
的描述。