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
權限,同時仍然允許使用者存取特定的金鑰管理操作,可以定義「wrapper」(包裝)儲存程式(本節稍後描述的技術)。特定使用者儲存在金鑰環中的金鑰,日後只能由同一使用者操作。也就是說,金鑰操作時的
CURRENT_USER()
函式的值,必須與金鑰儲存在金鑰環中時的值相同。(此限制排除了使用金鑰環函式來操作實例範圍的金鑰,例如InnoDB
為了支援資料表空間加密而建立的金鑰。)若要讓多個使用者能夠對同一個金鑰執行操作,可以定義「wrapper」(包裝)儲存程式(本節稍後描述的技術)。
金鑰環函式支援底層金鑰環外掛程式支援的金鑰類型和長度。有關特定金鑰環外掛程式的金鑰資訊,請參閱第 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
值等於金鑰擁有者的「wrapper」(包裝)儲存程式。授予應該能夠呼叫它們的個別使用者特定儲存程式的
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()
的說明。