Skip to content

Commit

Permalink
PS-3829 : Innodb key rotation. ALPHA
Browse files Browse the repository at this point in the history
This PR implements Encryption threads for
encryption/re-encryption/decryption of
innodb tablespaces. It is based on MariaDB implementation ported from
Google's
patch. With this WL user can:

1) Change default KEYRING encryption key
2) Create a new table with KEYRING
3) Encrypt offline already existing tables with KEYRING (with alter)
4) Encrypt/re-encrypt online already existing tables with KEYRING (with
innodb_online_encryption, innodb_online_encryption_rotate_key_age
variables and innodb_online_encryption_threads) – including tables
already encrypted with Master Key encryption.
5) Re-encrypt online already encrypted tables with newer version of
encryption key (with variables innodb_online_encryption variable,
innodb_online_encryption_threads,
innodb_online_encryption_rotate_key_age).

This WL also fixed the following bugs reported to MariaDB:

(MDEV-17231) Encryption threads keep re-encrypting/encrypting corrupted
pages
(MDEV-17235) Data dictonary is not updated with encryption flags
(MDEV-17234) In memory crypt_data is updated before page0 is updated
(MDEV-17233) Page 0 is updated more than once when encryption completes
(MDEV-17230) encryption_key_id from alter is ignored by encryption
threads
(MDEV-17229) Encryption threads ignore innodb_default_encryption_key_id
  • Loading branch information
Robert Golebiowski committed Oct 30, 2018
1 parent 86bdf96 commit c7f44ee
Show file tree
Hide file tree
Showing 316 changed files with 37,635 additions and 1,154 deletions.
25 changes: 25 additions & 0 deletions include/create_info_encryption_key.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef create_info_encryption_key_h
#define create_info_encryption_key_h

//#ifndef UNIV_INNOCHECKSUM

struct CreateInfoEncryptionKeyId
{
CreateInfoEncryptionKeyId(bool was_encryption_key_id_set,
uint encryption_key_id)
: was_encryption_key_id_set(was_encryption_key_id_set)
, encryption_key_id(encryption_key_id)
{}

CreateInfoEncryptionKeyId()
: was_encryption_key_id_set(false)
, encryption_key_id(FIL_DEFAULT_ENCRYPTION_KEY)
{}

bool was_encryption_key_id_set;
uint encryption_key_id;
};

//#endif // UNIV_INNOCHECKSUM

#endif
3 changes: 3 additions & 0 deletions include/my_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,9 @@ is the global server default. */
/* Number of different errors */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)

#define HA_ERR_DECRYPTION_FAILED 500 /* Table encrypted but decypt failed */


/* Other constants */

#define HA_NAMELEN 64 /* Max length of saved filename */
Expand Down
5 changes: 3 additions & 2 deletions include/system_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@

C_MODE_START
#define PERCONA_BINLOG_KEY_NAME "percona_binlog"
extern const size_t valid_percona_system_keys_size;
extern const char* valid_percona_system_keys[];
#define PERCONA_INNODB_KEY_NAME "percona_innodb"

my_bool is_valid_percona_system_key(const char *key_name, size_t *key_length);

/**
A convenience function that extracts key's data and key's version from system key.
Expand Down
19 changes: 15 additions & 4 deletions mysql-test/include/search_pattern_in_file.inc
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,12 @@
#

perl;

use strict;
die "SEARCH_FILE not set" unless $ENV{'SEARCH_FILE'};
my $print_search_result= $ENV{PRINT_SEARCH_RESULT} or 0;
my $abort_on= $ENV{ABORT_ON} or "NOT_FOUND";
#my $abort_on_found= $ENV{ABORT_ON_FOUND} or 0;
my @search_files= glob($ENV{'SEARCH_FILE'});
my $search_pattern= $ENV{'SEARCH_PATTERN'} or die "SEARCH_PATTERN not set";
my $file_content= "";
Expand All @@ -76,12 +79,20 @@ perl;
}
close(FILE);
}
if ( $print_search_result ) {

if ( $print_search_result == 0 ) {
if ( $abort_on eq "NOT_FOUND" and $found == 0 ) {
die ("# ERROR: Non of the files do not contain the expected pattern $search_pattern\n");
}
if ( $abort_on eq "FOUND" and $found ) {
die ("# ERROR: Some of the files contain pattern that we expected not to find $search_pattern\n");
}
} else {
my $res=$found ? "FOUND" : "NOT FOUND";
$ENV{SEARCH_FILE} =~ s{^.*?([^/\\]+)$}{$1};
print "$res /$search_pattern/ in $ENV{SEARCH_FILE}\n";
}
elsif ( $found == 0 ) {
die("# ERROR: Non of the files do not contain the expected pattern $search_pattern\n");
}
#elsif ( $found == 0 and $abort_on_found eq "Disabled" ) {
#die("# ERROR: Non of the files do not contain the expected pattern $search_pattern\n");
#}
EOF
50 changes: 50 additions & 0 deletions mysql-test/include/table_encrypt_1_small.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# InnoDB transparent tablespace data encryption
# This test case will test basic encryption support features.

--source include/no_valgrind_without_big.inc
--source include/have_innodb.inc
--source include/not_embedded.inc
--source include/have_innodb_max_16k.inc
--source include/have_debug.inc

# Create a table with encryption, should fail since keyring is not
# loaded
call mtr.add_suppression("\\[Error\\] InnoDB: Encryption can't find master key, please check the keyring plugin is loaded.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Failed to find tablespace for table `\.\.*`\.`\.\.*` in the cache.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Operating system error number 2 in a file operation.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: The error means the system cannot find the path specified.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Could not find a valid tablespace file for");
call mtr.add_suppression("ibd can't be decrypted , please confirm the keyfile is match and keyring plugin is loaded.");
call mtr.add_suppression("\\[Warning\\] InnoDB: Ignoring tablespace .* because it could not be opened");
call mtr.add_suppression("\\[ERROR\\] InnoDB: If you are installing InnoDB, remember that you must create directories yourself, InnoDB does not create them.");

--let $restart_parameters="$KEYRING_RESTART_PARAM"
--let $restart_hide_args= 1
--source include/restart_mysqld.inc

--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings

let $innodb_file_per_table = `SELECT @@innodb_file_per_table`;
SET GLOBAL innodb_file_per_table=ON;

eval CREATE TABLE t1 (id int unsigned NOT NULL auto_increment PRIMARY KEY, val varchar(20) NOT NULL) ENCRYPTION="$encryption_type" ENGINE=InnoDB;

INSERT INTO t1 (val) VALUES ('Sydney'), ('Melbourne'), ('Brisbane'), ('Perth'), ('Adelaide');

#ALTER TABLE t1 ENCRYPTION = "KEYRING";
#ALTER TABLE t1 ENCRYPTION = 'Y';

#ALTER TABLE t1 ADD COLUMN is_capital char(1) NOT NULL DEFAULT 'N' AFTER val;
#SHOW CREATE TABLE t1;

LET $MYSQLD_DATADIR = `select @@datadir`;
let SEARCH_FILE = $MYSQLD_DATADIR/test/t1.ibd;
let SEARCH_PATTERN=Sydney;
# The string should not be found, since it's encrypted.
--source include/search_pattern.inc

# Cleanup
eval SET GLOBAL innodb_file_per_table=$innodb_file_per_table;
DROP TABLE t1;
8 changes: 4 additions & 4 deletions mysql-test/include/table_encrypt_2.inc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# InnoDB transparent tablespace data encryption
# This test case will test basic encryption support features.

CREATE TABLE t1(c1 int) ENGINE=InnoDB ENCRYPTION="Y";
eval CREATE TABLE t1(c1 int) ENGINE=InnoDB ENCRYPTION="$encryption_type";

DROP TABLE t1;

Expand All @@ -20,7 +20,7 @@ SET GLOBAL innodb_file_per_table = 1;
SELECT @@innodb_file_per_table;

# Create a table with encryption
CREATE TABLE t1(c1 INT, c2 char(20)) ENCRYPTION="Y" ENGINE = InnoDB;
eval CREATE TABLE t1(c1 INT, c2 char(20)) ENCRYPTION="$encryption_type" ENGINE = InnoDB;

SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES(0, "aaaaa");
Expand Down Expand Up @@ -55,7 +55,7 @@ ALTER INSTANCE ROTATE INNODB MASTER KEY;
DROP TABLE t1;

# Crash/recovery test.
CREATE TABLE t1(c1 INT, c2 char(20)) ENCRYPTION="Y" ENGINE = InnoDB;
eval CREATE TABLE t1(c1 INT, c2 char(20)) ENCRYPTION="$encryption_type" ENGINE = InnoDB;

INSERT INTO t1 VALUES(0, "aaaaa");
INSERT INTO t1 VALUES(1, "bbbbb");
Expand Down Expand Up @@ -86,7 +86,7 @@ SET block_encryption_mode = 'aes-256-cbc';
--disable_warnings
DROP DATABASE IF EXISTS tde_db;
CREATE DATABASE tde_db;
CREATE TABLE tde_db.t1(c1 INT PRIMARY KEY, c2 char(50)) ENCRYPTION = 'Y' ENGINE = InnoDB;
eval CREATE TABLE tde_db.t1(c1 INT PRIMARY KEY, c2 char(50)) ENCRYPTION = '$encryption_type' ENGINE = InnoDB;
--enable_warnings
#
INSERT INTO tde_db.t1 VALUES(0, 'abc');
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/mysql-test-run.pl
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ END

# If you add a new suite, please check TEST_DIRS in Makefile.am.
#
my $DEFAULT_SUITES= "main,sys_vars,binlog,binlog_encryption,rpl_encryption,"
my $DEFAULT_SUITES= "main,sys_vars,binlog,binlog_encryption,rpl_encryption,encryption,"
."federated,gis,rpl,innodb,innodb_gis,"
."innodb_fts,innodb_zip,innodb_undo,innodb_stress,perfschema,funcs_1,"
."funcs_2,opt_trace,parts,auth_sec,query_rewrite_plugins,gcol,sysschema,"
Expand Down
14 changes: 8 additions & 6 deletions mysql-test/r/mysqlshow.result
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Database: information_schema
| INNODB_CMP_RESET |
| INNODB_SYS_DATAFILES |
| XTRADB_READ_VIEW |
| INNODB_SYS_VIRTUAL |
| INNODB_SYS_TABLESTATS |
| XTRADB_RSEG |
| INNODB_BUFFER_PAGE |
| INNODB_TRX |
Expand All @@ -131,7 +131,7 @@ Database: information_schema
| INNODB_LOCKS |
| INNODB_LOCK_WAITS |
| XTRADB_INTERNAL_HASH_TABLES |
| INNODB_SYS_INDEXES |
| INNODB_TABLESPACES_ENCRYPTION |
| INNODB_CMPMEM_RESET |
| INNODB_SYS_FIELDS |
| XTRADB_ZIP_DICT |
Expand All @@ -152,7 +152,8 @@ Database: information_schema
| INNODB_SYS_COLUMNS |
| INNODB_FT_CONFIG |
| XTRADB_ZIP_DICT_COLS |
| INNODB_SYS_TABLESTATS |
| INNODB_SYS_INDEXES |
| INNODB_SYS_VIRTUAL |
+---------------------------------------+
Database: INFORMATION_SCHEMA
+---------------------------------------+
Expand Down Expand Up @@ -200,7 +201,7 @@ Database: INFORMATION_SCHEMA
| INNODB_CMP_RESET |
| INNODB_SYS_DATAFILES |
| XTRADB_READ_VIEW |
| INNODB_SYS_VIRTUAL |
| INNODB_SYS_TABLESTATS |
| XTRADB_RSEG |
| INNODB_BUFFER_PAGE |
| INNODB_TRX |
Expand All @@ -210,7 +211,7 @@ Database: INFORMATION_SCHEMA
| INNODB_LOCKS |
| INNODB_LOCK_WAITS |
| XTRADB_INTERNAL_HASH_TABLES |
| INNODB_SYS_INDEXES |
| INNODB_TABLESPACES_ENCRYPTION |
| INNODB_CMPMEM_RESET |
| INNODB_SYS_FIELDS |
| XTRADB_ZIP_DICT |
Expand All @@ -231,7 +232,8 @@ Database: INFORMATION_SCHEMA
| INNODB_SYS_COLUMNS |
| INNODB_FT_CONFIG |
| XTRADB_ZIP_DICT_COLS |
| INNODB_SYS_TABLESTATS |
| INNODB_SYS_INDEXES |
| INNODB_SYS_VIRTUAL |
+---------------------------------------+
Wildcard: inf_rmation_schema
+--------------------+
Expand Down
16 changes: 8 additions & 8 deletions mysql-test/r/opt_hints_pfs.result
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ SELECT * FROM t1;
SELECT /*+ */ * FROM t1;
SELECT digest, digest_text FROM performance_schema.events_statements_history ORDER BY timer_start DESC LIMIT 2;
digest digest_text
7813b9aec0c09117f127053b466bb3e0 SELECT * FROM `t1`
7813b9aec0c09117f127053b466bb3e0 SELECT * FROM `t1`
008e63017f2468d2f16f5172af64a001 SELECT * FROM `t1`
008e63017f2468d2f16f5172af64a001 SELECT * FROM `t1`
# Digests should be different:
SELECT * FROM t1, t2;
SELECT /*+
Expand All @@ -33,19 +33,19 @@ SUBQUERY(t1)
*/ * FROM t1, t2;
SELECT digest, digest_text FROM performance_schema.events_statements_history ORDER BY timer_start DESC LIMIT 2;
digest digest_text
5873dbf27c6f838d5ce06c692ee7f2b1 SELECT /*+ BKA ( `t1`@`qb1` ) BNL ( @`qb1` `t1` ) DUPSWEEDOUT FIRSTMATCH INTOEXISTS LOOSESCAN MATERIALIZATION MRR ( `t1` ) NO_BKA ( `t2` ) NO_BNL ( `t2` ) NO_ICP ( `t2` ) NO_MRR ( `t2` ) NO_RANGE_OPTIMIZATION ( `t2` ) NO_SEMIJOIN ( `t2` ) QB_NAME ( `qb1` ) SEMIJOIN ( `t1` ) SUBQUERY ( `t1` ) */ * FROM `t1` , `t2`
c2eecd9ef952755ec648eb7406354e72 SELECT * FROM `t1` , `t2`
e6bab229a5969540cf7c80f2192ecfbc SELECT /*+ BKA ( `t1`@`qb1` ) BNL ( @`qb1` `t1` ) DUPSWEEDOUT FIRSTMATCH INTOEXISTS LOOSESCAN MATERIALIZATION MRR ( `t1` ) NO_BKA ( `t2` ) NO_BNL ( `t2` ) NO_ICP ( `t2` ) NO_MRR ( `t2` ) NO_RANGE_OPTIMIZATION ( `t2` ) NO_SEMIJOIN ( `t2` ) QB_NAME ( `qb1` ) SEMIJOIN ( `t1` ) SUBQUERY ( `t1` ) */ * FROM `t1` , `t2`
7f97a4520a86d2261d6a0e49902d1081 SELECT * FROM `t1` , `t2`
SELECT * FROM t2, t1;
SELECT /*+ MAX_EXECUTION_TIME(10) */ * FROM t2, t1;
SELECT digest, digest_text FROM performance_schema.events_statements_history ORDER BY timer_start DESC LIMIT 2;
digest digest_text
c58f25464cd266d708f88b7a3c48a166 SELECT /*+ MAX_EXECUTION_TIME (?) */ * FROM `t2` , `t1`
531f2cca2dc0bca50a1208c81e130676 SELECT * FROM `t2` , `t1`
0537c682529951572f816ad552e388d4 SELECT /*+ MAX_EXECUTION_TIME (?) */ * FROM `t2` , `t1`
d0802028ada67e69fdff6375d47d0614 SELECT * FROM `t2` , `t1`
SELECT 1;
SELECT /*+ bad_hint_also_goes_to_digest */ 1;
SELECT digest, digest_text FROM performance_schema.events_statements_history ORDER BY timer_start DESC LIMIT 2;
digest digest_text
9c363c2243b369eb9d9d8130a7b278d9 SELECT /*+ `bad_hint_also_goes_to_digest` */ ?
24e5a8c19fe8009f403640dabf2a9e0f SELECT ?
e5c09badfc97b3ffaf95c0dfdeae496c SELECT /*+ `bad_hint_also_goes_to_digest` */ ?
3fff4c5a5ca5e1e484663cab257efd1e SELECT ?
DROP TABLE t1, t2;
#
Binary file added mysql-test/std_data/keys2.txt
Binary file not shown.
Binary file added mysql-test/std_data/keys3.txt
Binary file not shown.
22 changes: 22 additions & 0 deletions mysql-test/suite/encryption/r/create_or_replace.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
SET default_storage_engine = InnoDB;
CREATE TABLE t1 (pk INT PRIMARY KEY, c VARCHAR(256));
CREATE TABLE t2 AS SELECT * FROM t1;
drop table t1,t2;
SET GLOBAL innodb_encryption_threads = 0;
SET GLOBAL innodb_encryption_threads = 4;
CREATE TABLE `table10_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int, key (`col_int_key` ),primary key (pk)) engine=innodb;
INSERT /*! IGNORE */ INTO table10_int_autoinc VALUES (NULL, NULL, -474021888) , (1, NULL, NULL) , (1141047296, NULL, NULL) , (NULL, NULL, NULL) , (NULL, NULL, 1) , (NULL, NULL, 9) , (0, NULL, 1225785344) , (NULL, NULL, 1574174720) , (2, NULL, NULL) , (6, NULL, 3);
CREATE TABLE `table1_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int,key (`col_int_key` ), primary key (pk)) engine=innodb;
CREATE TABLE `table0_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int, key (`col_int_key` ),primary key (pk)) engine=innodb;
INSERT /*! IGNORE */ INTO table1_int_autoinc VALUES (4, NULL, NULL);
INSERT IGNORE INTO `table0_int_autoinc` ( `col_int_key` ) VALUES ( 1 ), ( 3 ), ( 4 ), ( 1 );
INSERT IGNORE INTO `table1_int_autoinc` ( `col_int` ) VALUES ( 1 ), ( 0 ), ( 7 ), ( 9 );
INSERT IGNORE INTO `table10_int_autoinc` ( `col_int` ) VALUES ( 6 ), ( 2 ), ( 3 ), ( 6 );
drop table if exists create_or_replace_t, table1_int_autoinc, table0_int_autoinc, table10_int_autoinc;
SET GLOBAL innodb_encrypt_tables = ONLINE_FROM_KEYRING_TO_UNENCRYPTED;
SET GLOBAL innodb_encryption_threads = 4;
# Wait max 10 min for key encryption threads to decrypt all spaces
# Success!
SET GLOBAL innodb_encryption_threads = 0;
SET GLOBAL innodb_encrypt_tables = ONLINE_FROM_KEYRING_TO_UNENCRYPTED;
# restart
Loading

0 comments on commit c7f44ee

Please sign in to comment.