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 提供更精細的控制,以控制誰可以使用金鑰執行哪些操作,而無需授予全域權限。
以下範例顯示如何設定名為 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
和錯誤。注意使用
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()
的說明。