MySQL 服务器支持密钥环服务,使内部组件和插件能够安全地存储敏感信息以供以后检索。
MySQL Server 还包括用于密钥环密钥管理的 SQL 接口,实现为一组通用函数,可访问内部密钥环服务提供的功能。密钥环函数包含在一个插件库文件中,该文件还包含一个keyring_udf
必须在调用函数之前启用的插件。要使用这些功能,
必须启用
keyring_file
或
之类的密钥环插件。keyring_okv
此处描述的功能是通用的,旨在与任何密钥环插件一起使用。一个给定的密钥环插件可能有它自己的功能,这些功能只能与该插件一起使用;请参阅 第 6.4.4.16 节,“插件特定的密钥环密钥管理功能”。
以下部分提供密钥环功能的安装说明并演示如何使用它们。有关这些函数调用的密钥环服务函数的信息,请参阅第 5.6.9.2 节,“密钥环服务”。有关一般密钥环信息,请参阅第 6.4.4 节,“MySQL 密钥环”。
本节介绍如何安装或卸载密钥环功能,这些功能在也包含插件的插件库文件中实现keyring_udf
。有关安装或卸载插件和可加载函数的一般信息,请参阅第 5.6.1 节,“安装和卸载插件”和第 5.7.1 节,“安装和卸载可加载函数”。
密钥环功能启用密钥环密钥管理操作,但keyring_udf
还必须安装插件,因为没有它这些功能将无法正常工作。尝试在没有
keyring_udf
插件的情况下使用这些功能会导致错误。
为了被服务器使用,插件库文件必须位于MySQL插件目录(由plugin_dir
系统变量命名的目录)中。plugin_dir
如有必要,通过在服务器启动时
设置值来配置插件目录位置
。
插件库文件的基本名称是
keyring_udf
. 文件名后缀因平台而异(例如,.so
对于 Unix 和类 Unix 系统,.dll
对于 Windows)。
要安装keyring_udf
插件和密钥环功能,请使用INSTALL
PLUGIN
andCREATE
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
and
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
插件,请参阅 安装或卸载通用密钥环功能。密钥环函数调用密钥环服务函数(参见第 5.6.9.2 节,“密钥环服务”)。服务功能依次使用安装的任何密钥环插件(例如,
keyring_file
或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.
要安装密钥环插件,请参阅 第 6.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
支持表空间加密而创建的密钥。)为了使多个用户能够对同一个键执行操作,可以定义 “包装器”存储程序(本节稍后介绍的技术)。
密钥环函数支持底层密钥环插件支持的密钥类型和长度。有关特定密钥环插件的特定密钥的信息,请参阅第 6.4.4.13 节,“支持的密钥环密钥类型和长度”。
要创建一个新的随机密钥并将其存储在密钥环中,请调用
keyring_key_generate()
,将密钥的 ID 以及密钥类型(加密方法)及其长度(以字节为单位)传递给它。以下调用创建一个名为 的 2,048 位 DSA 加密密钥MyKey
:
mysql> SELECT keyring_key_generate('MyKey', 'DSA', 256);
+-------------------------------------------+
| keyring_key_generate('MyKey', 'DSA', 256) |
+-------------------------------------------+
| 1 |
+-------------------------------------------+
返回值为 1 表示成功。如果无法创建密钥,则返回值为NULL
并发生错误。原因之一可能是底层密钥环插件不支持指定的密钥类型和密钥长度组合;请参阅
第 6.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 |
+------+
此技术还适用于其他密钥环函数,这些函数在失败时会返回一个值和一个错误。
传递给的 ID
keyring_key_generate()
提供了一种在后续函数调用中引用键的方法。例如,使用密钥 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、类型和值视为二进制字符串,因此比较区分大小写。例如,IDMyKey
和mykey
引用不同的密钥。
要删除密钥,请将密钥 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 提供更细粒度的控制,以控制谁可以使用密钥做什么,而无需授予全局权限。
以下示例显示如何设置一个名为
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 |
+----------------------------------+
对于每个通用密钥环函数,本节描述其用途、调用顺序和返回值。有关可以调用这些函数的条件的信息,请参阅使用通用密钥环函数。
给定密钥 ID,反混淆并返回密钥值。
参数:
key_id
:指定密钥 ID 的字符串。
返回值:
如果成功则返回键值作为字符串,
NULL
如果键不存在,或者NULL
失败则返回错误。笔记使用检索的密钥值 受第 6.4.4.13 节“支持的密钥环密钥类型和长度”
keyring_key_fetch()
中描述的一般密钥环功能限制的约束。可以使用密钥环服务函数(参见第 5.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、类型和长度的新随机密钥,并将其存储在密钥环中。类型和长度值必须与底层密钥环插件支持的值一致。请参阅 第 6.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()
。从密钥环中删除具有给定 ID 的密钥。
参数:
key_id
:指定密钥 ID 的字符串。
返回值:
成功返回 1,
NULL
失败返回 1。例子:
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()
。