{"id":1423,"date":"2019-09-24T18:18:29","date_gmt":"2019-09-24T12:48:29","guid":{"rendered":"https:\/\/opstree.com\/blog\/\/?p=1423"},"modified":"2019-09-27T16:34:34","modified_gmt":"2019-09-27T11:04:34","slug":"mysql-data-at-rest-encryption","status":"publish","type":"post","link":"https:\/\/opstree.com\/blog\/2019\/09\/24\/mysql-data-at-rest-encryption\/","title":{"rendered":"The Concept Of Data At Rest Encryption In MySql"},"content":{"rendered":"\n<p>Word \u201cdata\u201d is very crucial since early 2000 and within a span of these 2 decades is it becoming more crucial. According to Forbes Google believe that in future every organisation will lead to becoming a data company. Well, when it comes to data, security is one of the major concerns that we have to face.&nbsp;<\/p>\n\n\n\n<p>We have several common techniques to store data in today&#8217;s environment like MySql, Oracle, MsSql, Cassandra, Mongo etc and these techs will keep on changing in future. But according to <a href=\"https:\/\/www.datanyze.com\/market-share\/databases\/mysql-vs-microsoft-sql-server\" target=\"_blank\" rel=\"noopener\">DataAnyz<\/a>, MySql Still has a 33% share of the market. So here we are with a technique to secure our MySQL data.<\/p>\n\n\n\n<p>Before getting more into this article, let us know what are possible combined approaches to secure MySQL data&nbsp;<\/p>\n\n\n\n<ol><li>Mysql Server hardening<\/li><li>Mysql Application-level hardening<\/li><li>Mysql data encryption at transit<\/li><li><strong>Mysql data at rest encryption<\/strong><\/li><li>Mysql Disk Encryption<\/li><\/ol>\n\n\n\n<p>You may explore all the approaches but in this article, we will understand the concept of <strong>Mysql data at encryption<\/strong> and hands-on too.<\/p>\n\n\n\n<p>The concept of&nbsp; \u201cData at Rest Encryption\u201d&nbsp; in MySQL was introduced in Mysql 5.7 with the initial support of InnoDB storage engine only and with the period it has evolved significantly. So let&#8217;s understand about \u201cData at Rest Encryption\u201d in MySQL&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is \u201cData at Rest Encryption\u201d&nbsp; in MySql?<\/h3>\n\n\n\n<p>The concept of&nbsp; \u201cdata at rest encryption\u201d uses two-tier encryption key architecture, which used below two keys&nbsp;<\/p>\n\n\n\n<ol><li><strong>Tablespace keys:<\/strong> This is an encrypted key which is stored&nbsp; in the tablespace header&nbsp;<\/li><li><strong>Master Key:<\/strong>&nbsp;the Master key is used to decrypt the tablespace keys<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/UaG1mjQ12iVQ4NAMptY80K18MqPMZk7Ki6ijxPdeivUjLxIHKmGbOj5zEeEf_MthUpyV2Wd48UyFnAfb_6at4XNIo70DqscRt_Rqsy5mutXkIWHIxy6_EjM1lVNx5gd7S_wJOipw\" alt=\"\" \/><\/figure>\n\n\n\n<p><h4>So let&#8217;s Understand its working<\/h4><\/p>\n\n\n\n<p>Let&#8217;s say we have a running MySQL with InnoDB storage engine and tablespace is encrypted using a key, referred as table space key. This key is then encrypted using a master key and stored in the tablespace header&nbsp;<\/p>\n\n\n\n<p>Now when a request is made to access MySQL data, InnoDB use master key to decrypt tablespace key present tablespace header.&nbsp;After getting decrypted tablespace key, the tablespace is decrypted and make is available to perform read\/write operations<\/p>\n\n\n\n<p><em><span style=\"text-decoration:underline;\"><strong>Note: <\/strong>The decrypted version of a tablespace key never changes, but the master key can be rotated.<\/span><\/em><\/p>\n\n\n\n<p>Data at rest encryption implemented using keyring file plugin to manage and encrypt the master key<\/p>\n\n\n\n<p>After understanding the concept of encryption and decryption below are few Pros and Cons for using&nbsp; <strong>DRE<\/strong><\/p>\n\n\n\n<p><h3><span style=\"text-decoration:underline;\"><strong>Pros:<\/strong><\/span><\/h3><\/p>\n\n\n\n<ul><li>A strong Encryption of AES 256 is used to encrypt the <em>InnoDB<\/em> tables<\/li><li>It is transparent to all applications as we don&#8217;t need any application code, schema, or data type changes<\/li><li>Key management is not done by DBA.<\/li><li>Keys can be securely stored away from the data and key rotation is very simple.<\/li><\/ul>\n\n\n\n<p><h3><span style=\"text-decoration:underline;\"><strong>Cons:<\/strong><\/span><\/h3><\/p>\n\n\n\n<ul><li>Encrypts only&nbsp; InnoDB tables<\/li><li>Can\u2019t encrypt&nbsp; binary logs, redo logs, relay logs on unencrypted slaves, slow log, error log, general log, and audit log<\/li><\/ul>\n\n\n\n<p>Though we can&#8217;t encrypt binary logs, redo logs, relay logs on Mysql 5.7 but MariaDB has implemented this with a mechanism to encrypt undo\/redo logs, binary logs\/relay logs, etc.\u00a0 by enabling few flags in MariaDB Config File<\/p>\r\n<pre><span style=\"font-weight:400;\">innodb_sys_tablespace_encrypt=ON<\/span><br \/><span style=\"font-weight:400;\">innodb_temp_tablespace_encrypt=ON<\/span><br \/><span style=\"font-weight:400;\">innodb_parallel_dblwr_encrypt=ON<\/span><br \/><span style=\"font-weight:400;\">innodb_encrypt_online_alter_logs=ON<\/span><br \/><span style=\"font-weight:400;\">innodb_encrypt_tables=FORCE<\/span><br \/><span style=\"font-weight:400;\">encrypt_binlog=ON<\/span><br \/><span style=\"font-weight:400;\">encrypt_tmp_files=ON<\/span><\/pre>\r\n<p>However, there are some limitations\u00a0<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<h5>Let&#8217;s Discuss its problem\/solutions and few solutions to them<\/h5>\r\n<p>\n\n\n\n<\/p>\r\n<ol>\r\n<li>Running MySQL on a host will have access from root user and the MySQL user and both of them may access key file(keyring file) present on the same system.\u00a0For this problem, we may have our keys on mount\/unmount drive which can be unmounted after restarting MySQL.<\/li>\r\n<li>Data will not be in encrypted form when it will get loaded onto the RAM and can be dumped and read<\/li>\r\n<li>If MySQL is restarted with<a href=\"http:\/\/dev.mysql.com\/doc\/refman\/5.7\/en\/resetting-permissions.html\" target=\"_blank\" rel=\"noopener\"> skip-grant-tables<\/a> then again it&#8217;s havoc but this can be eliminated using an unmounted drive for keyring<\/li>\r\n<li>\u00a0As tablespace key remains the same so our security relies on Master key rotation which can be used\u00a0 to save our master key\u00a0<\/li>\r\n<\/ol>\r\n<p>\n\n\n\n<\/p>\r\n<p><em><span style=\"text-decoration:underline;\"><strong>NOTE<\/strong>: Do not to lose the master key file, as we cant decrypt data and will suffer data loss<\/span><\/em><\/p>\r\n<p>\n\n\n\n<\/p>\r\n<h3>Doing Is Learning, so let&#8217;s try\u00a0<\/h3>\r\n<p>\n\n\n\n<\/p>\r\n<p>As a prerequisite, we need a machine with MySQL server up and running Now for data at rest encryption to work we need to enable\u00a0<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\r\n<div class=\"wp-block-group__inner-container\">\r\n<p>Enable file per table on with the help of the configuration file.\u00a0\u00a0<\/p>\r\n<\/div>\r\n<\/div>\r\n<div>\u00a0<\/div>\r\n<div>\r\n<pre>[root@mysql ~]#\u00a0 vim \/etc\/my.cnf<br \/>[mysqld]<br \/><br \/><strong>innodb_file_per_table=ON<\/strong><\/pre>\r\n<\/div><\/div>\r\n<p>\n\n\n\n<\/p>\r\n<p>Along with the above parameter, enable keyring plugin and keyring path. This parameter should always be on the top in configuration so that it will get load initially when MySQL starts up. Keyring plugin is already installed in MySQL server we just need to enable it.\u00a0<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre>[root@mysql ~]#\u00a0 vim \/etc\/my.cnf<br \/>[mysqld]<br \/><strong>early-plugin-load=keyring_file.so<\/strong><br \/><strong>keyring_file_data=\/var\/lib\/mysql\/keyring-data\/keyring<\/strong><br \/>innodb_file_per_table=ON<\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<p>And save the file with a restart to MySQL<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre>[root@mysql ~]#\u00a0 systemctl restart mysql<\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<p>We can check for the enabled plugin and verify our configuration.<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre>mysql&gt; SELECT plugin_name, plugin_status FROM INFORMATION_SCHEMA.PLUGINS WHERE plugin_name LIKE 'keyring%';<br \/>+--------------+---------------+<br \/>| plugin_name\u00a0 | plugin_status |<br \/>+--------------+---------------+<br \/>| keyring_file | ACTIVE\u00a0 \u00a0 \u00a0\u00a0\u00a0 |<br \/>+--------------+---------------+<br \/>1 rows in set (0.00 sec)<br \/><br \/><br \/><\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<p>verify that we have a running keyring plugin and its location<\/p>\r\n<pre>mysql&gt;\u00a0 show global variables like '%keyring%';<br \/>+--------------------+-------------------------------------+<br \/>| Variable_name\u00a0 \u00a0 \u00a0 | Value \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 |<br \/>+--------------------+-------------------------------------+<br \/>| keyring_file_data\u00a0 | \/var\/lib\/mysql\/keyring-data\/keyring |<br \/>| keyring_operations | ON\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 |<br \/>+--------------------+-------------------------------------+<br \/>2 rows in set (0.00 sec)<\/pre>\r\n<p>Verify that we have enabled file per table\u00a0<\/p>\r\n<pre>MariaDB [(none)]&gt; show global variables like 'innodb_file_per_table';<br \/>+-----------------------+-------+<br \/>| Variable_name \u00a0 \u00a0 \u00a0\u00a0\u00a0 | Value |<br \/>+-----------------------+-------+<br \/>| innodb_file_per_table | ON \u00a0 |<br \/>+-----------------------+-------+<br \/>1 row in set (0.33 sec)<\/pre>\r\n<p>Now we will test our set up by creating a test DB with a table and insert some value to the table using below commands\u00a0<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre>mysql&gt; CREATE DATABASE test_db;<br \/>mysql&gt; CREATE TABLE test_db.test_db_table (id int primary key auto_increment, payload varchar(256)) engine=innodb;<br \/>mysql&gt; INSERT INTO test_db.test_db_table(payload) VALUES('Confidential Data');<\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<p>After successful test data creation, run below command from the Linux shell to check whether you&#8217;re able to read InnoDB file for your created table i.e. Before encryption<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<p>Along with that, we see that our keyring file is also empty before encryption is enabled<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre>[root@mysql ~]#\u00a0 strings \/var\/lib\/mysql\/test_db\/test_db_table.ibd<br \/>infimum<br \/>supremum<br \/>Confidential DATA<\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<p>&nbsp;<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<p>At this point of time if we try to check our keyring file we will not find anything<\/p>\r\n<pre>[root@mysql ~]#\u00a0 cat \/var\/lib\/mysql\/keyring<br \/>[root@mysql ~]#\u00a0<\/pre>\r\n<p>Now let\u2019s encrypt our table with below command and check our InnoDB file and keyring file content.<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre>mysql&gt; ALTER TABLE test_db.test_db_table encryption='Y';<br \/>[root@mysql ~] strings \/var\/lib\/mysql\/test_db\/test_db_table.ibd<br \/>0094ca6d-7ba9-11e9-b0d0-0800275716d42QMw<\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<p>The above content clear that file data is not readable and table space is encrypted. As previously oy keyring file data was absent\/empty, so now it must be having some data.<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<p><span style=\"text-decoration:underline;\"><em><strong>\u00a0Note:<\/strong> Please look\u00a0 master Key and time stamp(we will implement key rotation )<\/em><\/span><\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre>[root@mysql ~] \u00a0cat \/var\/lib\/mysql\/keyring-data\/keyring<br \/>Keyring file version:1.0?0 INNODBKey-0094ca6d-7ba9-11e9-b0d0-0800275716d4-2AES???_gd?7m&gt;0??nz??8M??7Y\u02b9:ll8@?0 INNODBKey-0094ca6d-7ba9-11e9-b0d0-0800275716d4-1AES}??x?$F?z??$???:??k?6y?YEOF<br \/>[root@mysql ~] ls -ltr \/var\/lib\/mysql\/keyring-data\/keyring<br \/>-rw-r----- 1 mysql mysql 283 Sep 18 16:48 \/var\/lib\/mysql\/keyring-data\/keyring<\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<p>With known security concern for the compromised master key, we may use the<strong> master key rotation technique<\/strong> from time to time to save our key.<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre>mysql&gt; alter instance rotate innodb master key;<br \/>Query OK, 0 rows affected (0.00 sec)<\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<p>After this command, we realise that our key timestamp is changed now and we have a new key.\u00a0<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre>[root@mysql ~] ls -ltr \/var\/lib\/mysql\/keyring-data\/keyring<br \/>-rw-r----- 1 mysql mysql 411 Sep 18 18:17 \/var\/lib\/mysql\/keyring-data\/keyring<\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<h3>Some Useful Commands<\/h3>\r\n<p>Below are some helpful commands we may use in an encrypted system\u00a0<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<p>1. List All the tables with encryption enabled\u00a0<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre>mysql&gt; SELECT * FROM information_schema.tables WHERE create_options LIKE '%ENCRYPTION=\"Y\"%' \\G;<br \/>*************************** 1. row ***************************<br \/>TABLE_CATALOG: def<br \/>TABLE_SCHEMA: sample_db<br \/>TABLE_NAME: test_db_table<br \/>TABLE_TYPE: BASE TABLE<br \/>ENGINE: InnoDB<br \/>VERSION: 10<br \/>ROW_FORMAT: Dynamic<br \/>TABLE_ROWS: 0<br \/>AVG_ROW_LENGTH: 0<br \/>DATA_LENGTH: 16384<br \/>MAX_DATA_LENGTH: 0<br \/>INDEX_LENGTH: 0<br \/>DATA_FREE: 0<br \/>AUTO_INCREMENT: 2<br \/>CREATE_TIME: 2019-09-18 16:46:34<br \/>UPDATE_TIME: 2019-09-18 16:46:34<br \/>CHECK_TIME: NULL<br \/>TABLE_COLLATION: latin1_swedish_ci<br \/>CHECKSUM: NULL<br \/>CREATE_OPTIONS: ENCRYPTION=\"Y\"<br \/>TABLE_COMMENT:\u00a0<br \/>1 row in set (0.02 sec)<br \/><br \/>ERROR:\u00a0<br \/>No query specified<\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<p>2. Encrypt Tables in a Database\u00a0<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre class=\"wp-block-preformatted\"><span style=\"color:var(--color-text);\">mysql&gt; ALTER TABLE db.t1 ENCRYPTION='Y';<\/span><\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<p>3. Disable encryption for an InnoDB table<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<pre>mysql&gt; ALTER TABLE t1 ENCRYPTION='N';<\/pre>\r\n<p>\n\n\n\n<\/p>\r\n<h3>Conclusion :\u00a0<\/h3>\r\n<p>You can encrypt data at rest by using keyring plugin and we can control and manage it by master key rotation. Creating an encrypted Mysql data file setup is as simple as firing a few simple commands. Using an encrypted system is also transparent to services, applications, and users with minimal impact of system resources. Further with Encryption of data at rest, we may also implement encryption in transit.\u00a0<\/p>\r\n<p>\n\n\n\n<\/p>\r\n<p>I hope you found this article informative and interesting. I\u2019d really appreciate any and all feedback.<\/p>\r\n<p>\n\n\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>Word \u201cdata\u201d is very crucial since early 2000 and within a span of these 2 decades is it becoming more crucial. According to Forbes Google believe that in future every organisation will lead to becoming a data company. Well, when it comes to data, security is one of the major concerns that we have to &hellip; <a href=\"https:\/\/opstree.com\/blog\/2019\/09\/24\/mysql-data-at-rest-encryption\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;The Concept Of Data At Rest Encryption In MySql&#8221;<\/span><\/a><\/p>\n","protected":false},"author":172308123,"featured_media":1510,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[28070474,610,4419],"tags":[54146075,1523131,768739289,676319245],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2019\/09\/data_at_rest_encryption.png","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pfDBOm-mX","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/1423"}],"collection":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/users\/172308123"}],"replies":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/comments?post=1423"}],"version-history":[{"count":23,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/1423\/revisions"}],"predecessor-version":[{"id":1518,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/1423\/revisions\/1518"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media\/1510"}],"wp:attachment":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media?parent=1423"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/categories?post=1423"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/tags?post=1423"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}