WL#12079: Encrypt binary log caches at rest

Affects: Server-8.0   —   Status: Complete

EXECUTIVE SUMMARY

When encrypting binary log files, MySQL server shall also encrypt temporary files created when binary log caches spill to disk.

USER STORIES

As a MySQL DBA/operator/instance owner, I want to enable binary log encryption so that no data shall be leaked to an operating system user having access to the file system where the MySQL server instance stores content of binary log caches into temporary files.

As a Security Administrator, I want, binary log, relay log and binary log cache temporary file to be encrypted to follow the security compliance requirements.

FUNCTIONAL REQUIREMENTS

F-1: A cipher that supports stream encryption MUST be used to encrypt the content of binary log caches that spill to disk when binlog_encryption is on.

F-2: AES with CTR mode SHOULD be used as the stream encryption algorithm in order to re-use already implemented infra-structure.

F-3: One-tier encryption MUST be used due to the volatility of the temporary files created by binary log cache spills. Such files are deleted upon server stop/crash thus preventing the usage of two-tier encryption.

F-4: The encryption key for the created temporary files SHOULD ONLY be stored in memory, within the server process, since it's use is bound to the server lifetime.

NON-FUNCTIONAL REQUIREMENTS

NF-1: Only the content written to disk shall be encrypted when binlog_encryption is on.

Interface Specification

I-1: No new options

I-2: No new files

I-3: No changes in existing syntax

I-4: No new commands

I-5: No new tools

HIGH LEVEL SPECIFICATION

IO_CACHE is a structure used in binary logging to keep the serialized representation of binary log events of an ongoing transaction, in a stream of bytes. This byte stream is stored in a memory buffer, up to a maximum allowed size - as defined by binlog_cache_size/binlog_stmt_cache_size. When the memory buffer size becomes greater than the maximum allowed size, the exceeding content of the memory buffer is stored into a temporary file. The byte stream is written into the binary log file during the flush stage of the transaction. The memory buffer and temporary file are cleaned and truncated after the transaction is committed.

This worklog will make the binary log cache temporary file storing binary log events of ongoing transaction respect binlog_encryption option.

Single tier encryption

The binlog cache object is tied to the client session (THD) lifetime. The binlog cache object is created when the session is instantiated, and it is destroyed when the session is closed. So binlog cache objects do not need encryption header or a keyring because:

1) Client sessions do not need to survive server restarts;

2) The encrypted temporary file is only accessed by the binlog cache object itself. It is the owner of the file password and initialization vector, and it does not need to share them.

  | Single tier                |
  |----------------------------|

  +---------------+  protects  +-----------+
  | File Password | ---------> | File Data |
  +---------------+            +-----------+

Each binlog cache will have its own randomly generated file password and initialization vector, using the same version of encryption used by binary and relay log files.

File password

Each IO_CACHE file password shall be randomly generated (by using my_rand_buffer) on IO_CACHE initialization. The file password and initialization vector only exists in memory and are never stored on disk.

The file password and initialization vector will be changed to new randomly generated ones every time the binlog cache is reset (every time after a transaction is committed). See explanation below. A client session that executing many transactions will use the same IO_CACHE structure all the time (and, if encrypted, using the same file password and initialization vector if we do not change them per transaction). The content of the IO_CACHE will vary, but the file password and initialization vector being used will be the same. This might be considered an issue from the security point of view. Changing the IO_CACHE encryption file password and initialization vector when resetting it will remove any concern in this respect, and shall not imply in a big performance penalty.

Operations

Client sessions will have their binary log caches unencrypted when binlog_encryption=OFF.

Client sessions will have their binary log caches encrypted when binlog_encryption=ON.

Every time a transaction commits, it requests its binlog cache to be reset (the cache is reset because it will be reused in the next transaction of the same session). On this reset operation, the binlog cache will:

  • Check binlog_encryption value to enable or disable its encryption;

  • When binlog_encryption is enabled, will close the ciphers and open them again using new file password and initialization vector.

UPGRADE/DOWNGRADE and CROSS-VERSION REPLICATION

There is no issue on upgrade/downgrade and cross-version replication.

Three new mysql_file_* wrappers

The worklog shall introduce three wrappers to replace the following functions in IO_CACHE code:

  • mysql_file_seek (replaced by mysql_encryption_file_seek);
  • mysql_file_read (replaced by mysql_encryption_file_read);
  • mysql_file_write (replaced by mysql_encryption_file_write);

The wrappers will take care of initializing the ciphers and calling the functions to encrypt/decrypt data going to/coming from disk.

The wrapper function just calls mysql_file_(...) if binlog_encryption is off, it does encryption/decryption related things around calling the mysql_file_(...) if binlog_encryption is on. For instance,

my_off_t mysql_encryption_file_seek(IO_CACHE *cache, my_off_t pos, int whence, myf flags) { if (cache->m_encryptor) cache->m_encryptor->set_stream_offset(pos); if (cache->m_decryptor) cache->m_decryptor->set_stream_offset(pos); return mysql_file_seek(cache->file, pos, whence, flags); }

Changes in end_io_cache

The end_io_cache function shall take care of deleting the ciphers when necessary.

Changes in IO_CACHE_binlog_cache_storage::open

The IO_CACHE_binlog_cache_storage::open function shall take care of initializing IO_CACHE ciphers when binlog_encryption=ON.

Changes in IO_CACHE_binlog_cache_storage::reset

The IO_CACHE_binlog_cache_storage::reset function shall take care of initializing IO_CACHE ciphers when binlog_encryption=ON when they are not initialized yet or deinitializing IO_CACHE ciphers when binlog_encryption=OFF. It shall also take care of generating new random password for the ciphers.