Schedule Meeting

a

Enhancing MySQL Security: Data-at-Rest Encryption with the Keyring Plugin

by | Oct 31, 2024 | MySQL, MySQL InnoDB

Need Help?  Click Here for Expert Support

Data security has always been important for any organization handling sensitive information. Data-at-rest encryption is one of the key things used to protect stored data, ensuring that unauthorized users cannot access or read the data even if they gain access to the physical storage medium.

In this post, we’ll dive into how MySQL implements data-at-rest encryption, specifically highlighting the Keyring Plugin used for secure encryption key management. We’ll also explore why it’s vital to keep sensitive data encrypted by walking through practical, hands-on examples.

So what is Data-at-rest? It is data stored on persistent media, such as hard drives, and it is opposed to data over network transmission, called Data-in-transit. So encryption at rest means that data is encrypted while being stored, so that unauthorized users who got access to the storage device will not be able to read the data.

This post will provide practical examples and step-by-step guidelines for setting up encryption, managing encryption keys, and verifying encrypted data.

Test environment/data

My test environment is prepared in Docker, with two hosts: a source and a replica with MySQL Server Community Edition v.8.0.40 (the latest version).

$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0fbe03459348 mysql:8.0.40-debian "docker-entrypoint.s…" 15 seconds ago Up 3 seconds (health: starting) 33060/tcp, 0.0.0.0:3308->3306/tcp replica
b391109eafcc mysql:8.0.40-debian "docker-entrypoint.s…" 15 seconds ago Up 14 seconds (healthy) 33060/tcp, 0.0.0.0:3307->3306/tcp source

Encryption is enabled by default on both hosts, see Using the component_keyring_file File-Based Keyring Component.

--default-table-encryption=ON
--binlog_encryption=ON
--innodb_redo_log_encrypt=ON
--innodb_undo_log_encrypt=ON

Let’s verify that:

source> SELECT @@hostname, @@global.binlog_encryption, @@global.innodb_redo_log_encrypt, @@global.innodb_undo_log_encrypt, @@global.default_table_encryption\G
*************************** 1. row ***************************
@@hostname: source
@@global.binlog_encryption: 1
@@global.innodb_redo_log_encrypt: 1
@@global.innodb_undo_log_encrypt: 1
@@global.default_table_encryption: 1
1 row in set (0.00 sec)
replica> SELECT @@hostname, @@global.binlog_encryption, @@global.innodb_redo_log_encrypt, @@global.innodb_undo_log_encrypt, @@global.default_table_encryption\G
*************************** 1. row ***************************
@@hostname: replica
@@global.binlog_encryption: 1
@@global.innodb_redo_log_encrypt: 1
@@global.innodb_undo_log_encrypt: 1
@@global.default_table_encryption: 1
1 row in set (0.00 sec)

I’ve also prepared test data containing sensitive information across two tables, one with encryption enabled and the other without it.

-- Create and use the test database
USE testdb;

-- Create tables with sensitive data
DROP TABLE IF EXISTS tbl_encrypted;
CREATE TABLE IF NOT EXISTS tbl_encrypted (
id INT PRIMARY KEY,
email VARCHAR(100),
gov_id VARCHAR(20),
credit_card VARCHAR(20)
) ENGINE=InnoDB, ENCRYPTION='Y';

CREATE TABLE tbl_not_encrypted LIKE tbl_encrypted;
ALTER TABLE tbl_not_encrypted ENCRYPTION='N';

-- Insert some rows with fake sensitive data
INSERT INTO tbl_encrypted (id, email, gov_id, credit_card) VALUES
(1, 'johndoe\@example.com', 'ID123456789', '4111111111111111'),
(2, 'janedoe\@example.com', 'ID987654321', '5500000000000004'),
(3, 'bobsmith\@example.com', 'ID111222333', '340000000000009'),
(4, 'alicejones\@example.com', 'ID444555666', '30000000000004');

INSERT INTO tbl_not_encrypted SELECT * FROM tbl_encrypted;

Read tablespace

Imagine you’ve performed binary backup and decided to store the files in some external location away from the database host. Now, let’s compare two tablespaces and make an attempt to read information from them using the following command:

strings /var/lib/mysql/testdb/tbl_encrypted.ibd | head -c 128

Encrypted

root@replica:/# strings /var/lib/mysql/testdb/tbl_encrypted.ibd | head -c 128
2b2b54e7-96f2-11ef-8a6c-0242ac14010c
nm8o
L5Z`
TZOh
xoU{
/l+#<8
F.'
~2Q[
J?$f
^cnE|x
dh[?
TDY2
8T"s
L)n5
JK~lF0
g(r,\
=g8&
2h L

Not Encrypted

root@replica:/# strings /var/lib/mysql/testdb/tbl_not_encrypted.ibd 
Einfimum
supremum
cd[o.
>*qS
nOnf}t
*T/#
"Z<D
Sn\1
H^O=F'
J@EVW
W='O
*]I=Q
vAU'
5p10
/^L
KYqa
0c<`
nM{n
,8kX'
/J;LA
?\h' 5
>p~(
infimum
supremum
johndoe\@example.comID1234567894111111111111111
janedoe\@example.comID9876543215500000000000004
*bobsmith\@example.comID111222333340000000000009
7alicejones\@example.comID44455566630000000000004

Summary of Reading Encrypted vs. Non-Encrypted Tablespaces

In contrast to the encrypted tablespace, reading from the non-encrypted one reveals plaintext data, including identifiable information such as emails and IDs. This demonstrates the risks of storing sensitive information without encryption, as it remains accessible to anyone with access to the storage location.

What about Binary Logs?

Now, let’s discuss binary logs. These logs can also be stored externally, offering a valuable means for analyzing and auditing database changes, as well as supporting point-in-time recovery. Here is the list of binary logs from our replica:

source> show binary logs\G
*************************** 1. row ***************************
Log_name: source-bin.000001
File_size: 692
Encrypted: Yes
*************************** 2. row ***************************
Log_name: source-bin.000002
File_size: 2942090
Encrypted: Yes
*************************** 3. row ***************************
Log_name: source-bin.000003
File_size: 709
Encrypted: Yes
3 rows in set (0.00 sec)
As you can see, all three binary logs have been encrypted.

The binary log source-bin.000002 contains more than 14K events.

source> \P grep -E "[0-9]+ rows"
PAGER set to 'grep -E "[0-9]+ rows"'
source> SHOW BINLOG EVENTS IN 'source-bin.000002';
14192 rows in set (0.04 sec)
 Let’s attempt to read one of them using the mysqlbinlog utility.
root@source:/# mysqlbinlog --base64-output=DECODE-ROWS --verbose /var/lib/mysql/source-bin.000002 
# The proper term is pseudo_replica_mode, but we use this compatibility alias
# to make the statement usable on server versions 8.0.24 and older.
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
ERROR: Reading encrypted log files directly is not supported.
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

This demonstrates that reading an encrypted binary log isn’t straightforward.

Why encrypting binary logs on all hosts is important?

Let’s disable binary logs encryption on our replica.

replica> set global binlog_encryption=0;
Query OK, 0 rows affected (0.06 sec)

replica> select @@global.binlog_encryption;
+----------------------------+
| @@global.binlog_encryption |
+----------------------------+
| 0 |
+----------------------------+
1 row in set (0.00 sec)

replica> flush logs;
Query OK, 0 rows affected (0.03 sec)

And insert more data on our source.

source> INSERT INTO testdb.tbl_encrypted (id, email, gov_id, credit_card) VALUES
-> (5, 'michaelwhite\@example.com', 'ID555666777', '6011111111111117'),
-> (6, 'sarahbrown\@example.com', 'ID888999000', '3530111333300000');
Query OK, 2 rows affected (0.03 sec)
Records: 2 Duplicates: 0 Warnings: 0

Let’s check binary logs on our replica and read the events from the non-encrypted one.

replica> SHOW BINARY LOGS\G
*************************** 1. row ***************************
Log_name: replica-bin.000001
File_size: 692
Encrypted: Yes
*************************** 2. row ***************************
Log_name: replica-bin.000002
File_size: 2940072
Encrypted: Yes
*************************** 3. row ***************************
Log_name: replica-bin.000003
File_size: 2942244
Encrypted: Yes
*************************** 4. row ***************************
Log_name: replica-bin.000004
File_size: 286
Encrypted: No
*************************** 5. row ***************************
Log_name: replica-bin.000005
File_size: 654
Encrypted: No
5 rows in set (0.01 sec)

Let’s read events:

replica> SHOW BINLOG EVENTS IN 'replica-bin.000005'\G
...
*************************** 5. row ***************************
Log_name: replica-bin.000005
Pos: 395
Event_type: Table_map
Server_id: 1
End_log_pos: 470
Info: table_id: 92 (testdb.tbl_encrypted)
*************************** 6. row ***************************
Log_name: replica-bin.000005
Pos: 470
Event_type: Write_rows
Server_id: 1
End_log_pos: 623
Info: table_id: 92 flags: STMT_END_F
...

Now, let’s attempt to read the binary log file directly:

root@replica:/# mysqlbinlog --base64-output=DECODE-ROWS --verbose /var/lib/mysql/replica-bin.000005 | grep -A5 INSERT
### INSERT INTO `testdb`.`tbl_encrypted`
### SET
### @1=5
### @2='michaelwhite\@example.com'
### @3='ID555666777'
### @4='6011111111111117'
### INSERT INTO `testdb`.`tbl_encrypted`
### SET
### @1=6
### @2='sarahbrown\@example.com'
### @3='ID888999000'
### @4='3530111333300000'

As shown, the binary log on the replica is readable.

Summary

Unencrypted tablespaces and binary logs leave sensitive data vulnerable, as they can expose details like emails, IDs to anyone with access to storage files. Encrypting both tablespaces and logs is essential to protect them against unauthorized access, ensuring that data remains secure and compliant with privacy regulations, even when backups or logs are stored externally. Prioritizing encryption helps safeguard critical information and strengthens your organization’s data security posture.

P.S.

We’ll also be hosting a free webinar on MySQL encryption at 4 PM GMT November, 27, please join us to learn more!

All content in this blog is distributed under the CreativeCommons Attribution-ShareAlike 4.0 International license. You can use it for your needs and even modify it, but please refer to Vettabase and the author of the original post. Read more about the terms and conditions: https://creativecommons.org/licenses/by-sa/4.0/

About Mike Rykmas
Mike Rykmas is a skilled software engineer with years of expertise in database administration, cloud computing, and IT infrastructure. Thanks to his strong background in data management and performance optimization, Mike has successfully led and implemented scalable solutions, managing petabytes of data to meet diverse business needs.

Recent Posts

The Mystery of ProxySQL Galera Writer Switchover!

The Mystery of ProxySQL Galera Writer Switchover!

Writer switchover issues with ProxySQL and Galera can feel like an unsolved puzzle. Recently, I encountered two strange behaviors that revealed underlying issues in how ProxySQL interacts with Galera clusters. In this post, I’ll walk through the unexpected behaviors I...

Getting Started with MindsDB and MySQL

Getting Started with MindsDB and MySQL

If you have not already heard, Vettabase is now a partner of MindsDB, working on improving MySQL compatibility. In this post we shall take a look at getting started with MindsDB by connecting to MySQL and some of the improvements to date. We have a ready to go example...

MariaDB/MySQL: working with storage engines

MariaDB/MySQL: working with storage engines

MariaDB and MySQL support several storage engines. See MariaDB and MySQL storage engines: an overview for a discussion about existing MariaDB and MySQL storage engines. Here we'll see how to work with them. We'll see how to obtain information about storage engines,...

Services

Need Help?  Click Here for Expert Support

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *