MDEV-14180 Automatically disable key rotation checks for file_key_managment plugin

Problem:
=======
- InnoDB iterates the fil_system space list to encrypt the
tablespace in case of key rotation. But it is not
necessary for any encryption plugin which doesn't do
key version rotation.

Solution:
=========
- Introduce a new variable called srv_encrypt_rotate to
indicate whether encryption plugin does key rotation

fil_space_crypt_t::key_get_latest_version(): Enable the
srv_encrypt_rotate only once if current key version is
higher than innodb_encyrption_rotate_key_age

fil_crypt_must_default_encrypt(): Default encryption tables
should be added to default_encryp_tables list if
innodb_encyrption_rotate_key_age is zero and encryption
plugin doesn't do key version rotation

fil_space_create(): Add the newly created space to
default_encrypt_tables list if
fil_crypt_must_default_encrypt() returns true

Removed the nondeterministic select from
innodb-key-rotation-disable test. By default,
InnoDB adds the tablespace to the rotation list and
background crypt thread does encryption of tablespace.
So these select doesn't give reliable results.
parent 7d2c338c
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
NAME
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0;
NAME
create database enctests;
use enctests;
create table t1(a int not null primary key, b char(200)) engine=innodb;
......
create table t1(f1 int not null)engine=innodb;
create table t2(f1 int not null)engine=innodb;
insert into t1 select * from seq_1_to_100;
insert into t2 select * from seq_1_to_100;
# Enable encryption
set global innodb_encrypt_tables=ON;
# Create a new table and it is added to rotation list
create table t3(f1 int not null)engine=innodb;
insert into t3 select * from seq_1_to_100;
# Increase the version and it should set rotation
# variable for the encryption plugin
set global debug_key_management_version=10;
select @@debug_key_management_version;
@@debug_key_management_version
10
# Decrease the key version and Disable the encryption
set global debug_key_management_version=1;
set global innodb_encrypt_tables=off;
DROP TABLE t1, t2, t3;
......@@ -3,9 +3,6 @@
# not embedded because of restarts
-- source include/not_embedded.inc
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0;
--disable_query_log
--disable_warnings
let $encryption = `SELECT @@innodb_encrypt_tables`;
......
--innodb-tablespaces-encryption
--plugin-load-add=$DEBUG_KEY_MANAGEMENT_SO
--source include/have_innodb.inc
--source include/have_debug.inc
--source include/have_sequence.inc
create table t1(f1 int not null)engine=innodb;
create table t2(f1 int not null)engine=innodb;
insert into t1 select * from seq_1_to_100;
insert into t2 select * from seq_1_to_100;
let $restart_parameters=--innodb_encrypt_tables=0 --innodb_encryption_threads=1 --innodb_encryption_rotate_key_age=9;
--source include/restart_mysqld.inc
--echo # Enable encryption
set global innodb_encrypt_tables=ON;
--let $tables_count= `select count(*) from information_schema.tables where engine = 'InnoDB'`
--let $wait_timeout= 600
--let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
--source include/wait_condition.inc
--echo # Create a new table and it is added to rotation list
create table t3(f1 int not null)engine=innodb;
insert into t3 select * from seq_1_to_100;
--echo # Increase the version and it should set rotation
--echo # variable for the encryption plugin
set global debug_key_management_version=10;
select @@debug_key_management_version;
--let $tables_count= `select count(*) from information_schema.tables where engine = 'InnoDB'`
--let $wait_timeout= 600
--let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
--source include/wait_condition.inc
--echo # Decrease the key version and Disable the encryption
set global debug_key_management_version=1;
set global innodb_encrypt_tables=off;
--let $wait_timeout= 600
--let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0;
--source include/wait_condition.inc
DROP TABLE t1, t2, t3;
......@@ -55,6 +55,9 @@ UNIV_INTERN uint srv_n_fil_crypt_threads_started = 0;
/** At this age or older a space/page will be rotated */
UNIV_INTERN uint srv_fil_crypt_rotate_key_age;
/** Whether the encryption plugin does key rotation */
static bool srv_encrypt_rotate;
/** Event to signal FROM the key rotation threads. */
static os_event_t fil_crypt_event;
......@@ -136,6 +139,14 @@ fil_space_crypt_t::key_get_latest_version(void)
if (is_key_found()) {
key_version = encryption_key_get_latest_version(key_id);
/* InnoDB does dirty read of srv_fil_crypt_rotate_key_age.
It doesn't matter because srv_encrypt_rotate
can be set to true only once */
if (!srv_encrypt_rotate
&& key_version > srv_fil_crypt_rotate_key_age) {
srv_encrypt_rotate = true;
}
srv_stats.n_key_requests.inc();
key_found = key_version;
}
......@@ -1380,6 +1391,11 @@ fil_crypt_return_iops(
fil_crypt_update_total_stat(state);
}
bool fil_crypt_must_default_encrypt()
{
return !srv_fil_crypt_rotate_key_age || !srv_encrypt_rotate;
}
/** Return the next tablespace from default_encrypt_tables.
@param space previous tablespace (NULL to start from the start)
@param recheck whether the removal condition needs to be rechecked after
......@@ -1455,7 +1471,7 @@ static fil_space_t *fil_space_next(fil_space_t *space, bool recheck,
mutex_enter(&fil_system->mutex);
ut_ad(!space || space->n_pending_ops);
if (!srv_fil_crypt_rotate_key_age)
if (fil_crypt_must_default_encrypt())
space= fil_system->default_encrypt_next(space, recheck, encrypt);
else if (!space)
{
......@@ -2448,7 +2464,7 @@ fil_crypt_set_encrypt_tables(
srv_encrypt_tables = val;
if (srv_fil_crypt_rotate_key_age == 0) {
if (fil_crypt_must_default_encrypt()) {
fil_crypt_default_encrypt_tables_fill();
}
......
......@@ -1464,22 +1464,28 @@ fil_space_create(
fil_system->max_assigned_id = id;
}
const bool rotate =
(purpose == FIL_TYPE_TABLESPACE
&& (mode == FIL_ENCRYPTION_ON
|| mode == FIL_ENCRYPTION_OFF || srv_encrypt_tables)
&& fil_crypt_must_default_encrypt());
/* Inform key rotation that there could be something
to do */
if (purpose == FIL_TYPE_TABLESPACE
&& !srv_fil_crypt_rotate_key_age && fil_crypt_threads_event &&
(mode == FIL_ENCRYPTION_ON || mode == FIL_ENCRYPTION_OFF ||
srv_encrypt_tables)) {
if (rotate) {
/* Key rotation is not enabled, need to inform background
encryption threads. */
fil_system->default_encrypt_tables.push_back(*space);
space->is_in_default_encrypt = true;
mutex_exit(&fil_system->mutex);
} else {
mutex_exit(&fil_system->mutex);
}
if (rotate && srv_n_fil_crypt_threads_started) {
mutex_enter(&fil_crypt_threads_mutex);
os_event_set(fil_crypt_threads_event);
mutex_exit(&fil_crypt_threads_mutex);
} else {
mutex_exit(&fil_system->mutex);
}
return(space);
......
......@@ -499,4 +499,10 @@ bool
fil_space_verify_crypt_checksum(const byte* page, const page_size_t& page_size)
MY_ATTRIBUTE((warn_unused_result));
/** Add the tablespace to the rotation list if
innodb_encrypt_rotate_key_age is 0 or encryption plugin does
not do key version rotation
@return whether the tablespace should be added to rotation list */
bool fil_crypt_must_default_encrypt();
#endif /* fil0crypt_h */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment