This blog post will discuss the issues and solutions for MySQL Data at Rest encryption. There is an update, too, by my colleague Ceri Williams – you can check it out here.
Data at Rest Encryption is not only a good-to-have feature, but it is also a requirement for HIPAA, PCI, and other regulations.
There are three major ways to solve data encryption at rest:
I consider full disk encryption to be the weakest method, as it only protects from someone physically removing the disks from the server. Application-level encryption, on the other hand, is the best: it is the most flexible method with almost no overhead, and it also solves data in-flight encryption. Unfortunately, it is not always possible to change the application code to support application-level encryption so database-level encryption can be a valuable alternative.
Sergei Golubchik, Chief Architect at MariaDB, outlined the pluses and minuses of database level encryption during his session at Percona Live Amsterdam:
Currently, there are two options for data at rest encryption at the database level:
MariaDB’s implementation is different from MySQL 5.7.11. MySQL 5.7.11 only encrypts InnoDB tablespace(s), while MariaDB has an option to encrypt undo/redo logs, binary logs/relay logs, etc. However, there are some limitations (especially together with Galera Cluster):
Database level encryption also has its weakness:
To enable the full level encryption we can add the following options to my.cnf:
|
1 |
[mysqld]<br>plugin-load-add=file_key_management.so<br>file_key_management_filekey = FILE:/mount/keys/mysql.key<br>file-key-management-filename = /mount/keys/mysql.enc<br>innodb-encrypt-tables = ON<br>innodb-encrypt-log = 1<br>innodb-encryption-threads=1<br>encrypt-tmp-disk-tables=1<br>encrypt-tmp-files=1 <br>encrypt-binlog=1<br>file_key_management_encryption_algorithm = AES_CTR |
After starting MariaDB with those settings, it will start encrypting the database in the background. The file_key_management plugin is used; unfortunately, it does not support key rotation. The actual keys are encrypted with:
|
1 |
# openssl enc -aes-256-cbc -md sha1 -k <key> -in keys.txt -out mysql.enc |
The encryption <key> is placed in /mount/keys/mysql.key.
After starting MySQL, we can unmount the “/mount/key” partition. In this case, the key will not be available and a potential hacker will not be able to restart MySQL with “–skip-grant-tables” option (without passwords). However, it also prevents normal restarts, especially SSTs (cluster full sync).
Additional notes:
|
1 |
select * from information_schema.INNODB_TABLESPACES_ENCRYPTION where ENCRYPTION_SCHEME=1 |
To enable encryption, add the following option to my.cnf:
|
1 |
[mysqld]<br>early-plugin-load=keyring_file.so<br>keyring_file_data=/mount/mysql-keyring/keyring |
Again, after starting MySQL we can unmount the “/mount/mysql-keyring/” partition.
To start encrypting the tables, we will need to run alter table table_name encryption='Y' , as MySQL will not encrypt tables by default.
The latest Percona Xtrabackup also supports encryption, and can backup encrypted tables.
To find all encrypted tablespaces in MySQL/Percona Server 5.7.11, we can use information_schema.INNODB_SYS_TABLESPACES and the flag field. For example, to find normally encrypted tables, use the following query:
|
1 |
mysql> select * from information_schema.INNODB_SYS_TABLESPACES where flag = 8225G<br>*************************** 1. row ***************************<br> SPACE: 4688<br> NAME: test/t1<br> FLAG: 8225<br> FILE_FORMAT: Barracuda<br> ROW_FORMAT: Dynamic<br> PAGE_SIZE: 16384<br> ZIP_PAGE_SIZE: 0<br> SPACE_TYPE: Single<br> FS_BLOCK_SIZE: 4096<br> FILE_SIZE: 98304<br>ALLOCATED_SIZE: 98304<br>*************************** 2. row ***************************<br> SPACE: 4697<br> NAME: sbtest/sbtest1_enc<br> FLAG: 8225<br> FILE_FORMAT: Barracuda<br> ROW_FORMAT: Dynamic<br> PAGE_SIZE: 16384<br> ZIP_PAGE_SIZE: 0<br> SPACE_TYPE: Single<br> FS_BLOCK_SIZE: 4096<br> FILE_SIZE: 255852544<br>ALLOCATED_SIZE: 255856640<br>2 rows in set (0.00 sec) |
You can also use this query instead: select * from information_schema.tables where CREATE_OPTIONS like '%ENCRYPTION="Y"%';.
Performance overhead
This is a debatable topic, especially for the MariaDB implementation when everything is configured to be encrypted. During my tests, I’ve seen ~10% of overhead for the standalone MySQL instance, and ~20% with Galera Cluster.
The MySQL 5.7/Percona Server 5.7 tablespace-level encryption shows an extremely low overhead, however, that needs to be tested in different conditions.
Conclusion
Even with all the above limitations, database-level encryption can be a better option than the filesystem-level encryption if the application can not be changed. However, it is a new feature (especially MySQL 5.7.11 version) and I expect a number of bugs here.
Resources
RELATED POSTS