MySQL 中的加密:Keystore

期待新课程开始招生 “数据库” 我们为您准备了一篇有用文章的翻译。

MySQL 中的加密:Keystore

透明数据加密(TDE)出现在 用于 MySQL 的 Percona 服务器 和 MySQL 已经有一段时间了。 但是您有没有想过它在幕后是如何工作的以及 TDE 会对您的服务器产生什么影响? 在本系列文章中,我们将了解 TDE 的内部工作原理。 让我们从密钥存储开始,因为这是任何加密工作所必需的。 然后我们将仔细研究 Percona Server for MySQL/MySQL 中的加密工作原理以及 Percona Server for MySQL 具有哪些附加功能。

MySQL 密钥环

密钥环是允许服务器查询、创建和删除本地文件 (keyring_file) 或远程服务器(例如 HashiCorp Vault)上的密钥的插件。 密钥始终缓存在本地以加快检索速度。

插件可以分为两类:

  • 本地存储。 例如,本地文件(我们称之为基于文件的密钥环)。
  • 远程存储。 例如,Vault Server(我们称之为基于服务器的密钥环)。

这种分离很重要,因为不同类型的存储的行为略有不同,不仅在存储和检索密钥时,而且在运行它们时也是如此。

使用文件存储时,启动时,存储的全部内容都会加载到缓存中:密钥 ID、密钥用户、密钥类型和密钥本身。

对于服务器端存储(例如 Vault Server),启动时仅加载密钥 ID 和密钥用户,因此获取所有密钥不会减慢启动速度。 密钥是延迟加载的。 也就是说,只有在实际需要时才会从 Vault 加载密钥本身。 下载后,密钥将缓存在内存中,以便将来不需要通过与 Vault 服务器的 TLS 连接来访问它。 接下来,让我们看看密钥存储中存在哪些信息。

关键信息包含以下内容:

  • 密钥 ID — 密钥标识符,例如:
    INNODBKey-764d382a-7324-11e9-ad8f-9cb6d0d5dc99-1
  • 密钥类型 — 基于所使用的加密算法的密钥类型,可能的值:“AES”、“RSA”或“DSA”。
  • 密钥长度 — 密钥长度(以字节为单位),AES:16、24 或 32,RSA 128、256、512 和 DSA 128、256 或 384。
  • 用户 - 钥匙的所有者。 如果密钥是系统密钥,例如主密钥,则此字段为空。 如果使用 keyring_udf 创建密钥,则此字段标识密钥的所有者。
  • 钥匙本身

密钥由 key_id、user 对唯一标识。

存储和删除密钥也存在差异。

文件存储速度更快。 您可能认为密钥存储只是将密钥写入文件一次,但事实并非如此,这里还发生了更多事情。 每当进行文件存储修改时,都会首先创建所有内容的备份副本。 假设该文件名为 my_biggest_secrets,则备份副本将为 my_biggest_secrets.backup。 接下来,更改缓存(添加或删除密钥),如果一切成功,则将缓存重置为文件。 在极少数情况下,例如服务器故障,您可能会看到此备份文件。 下次加载密钥时(通常在服务器重新启动后),备份文件将被删除。

当在服务器存储中保存或删除密钥时,存储必须使用“发送密钥”/“请求删除密钥”命令连接到 MySQL 服务器。

让我们回到服务器启动速度。 除了启动速度受到Vault本身的影响之外,还存在启动时需要从Vault中检索多少密钥的问题。 当然,这对于服务器存储尤其重要。 启动时,服务器检查加密表/表空间需要哪个密钥,并向存储请求密钥。 在具有主密钥加密的“干净”服务器上,必须有一个主密钥,并且必须从存储中检索该主密钥。 然而,例如,当备份服务器从主服务器恢复备份时,可能需要更多数量的密钥。 在这种情况下,应提供主密钥的轮换。 这将在以后的文章中更详细地介绍,尽管在这里我想指出,使用多个主密钥的服务器可能需要更长的时间来启动,特别是在使用服务器端密钥存储时。

现在让我们更多地讨论一下 keyring_file。 当我开发keyring_file时,我还关心如何在服务器运行时检查keyring_file的更改。 在5.7中,检查是根据文件统计信息进行的,这不是一个理想的解决方案,在8.0中它被替换为SHA256校验和。

第一次运行 keyring_file 时,将计算文件统计信息和校验和,服务器会记住这些信息,并且仅在匹配时才应用更改。 当文件更改时,校验和会更新。

我们已经讨论了有关密钥保管库的许多问题。 然而,还有一个经常被遗忘或误解的重要主题:跨服务器共享密钥。

我的意思是说? 集群中的每台服务器(例如 Percona Server)必须在 Vault Server 上有一个单独的位置,Percona Server 必须在其中存储其密钥。 保存在存储中的每个主密钥在其标识符中都包含 Percona 服务器的 GUID。 它为什么如此重要? 想象一下,您只有一台 Vault 服务器,并且集群中的所有 Percona 服务器都使用该一台 Vault 服务器。 问题似乎很明显。 如果所有 Percona 服务器都使用没有唯一标识符的主密钥,例如 id = 1、id = 2 等,那么集群中的所有服务器将使用相同的主密钥。 GUID提供的是服务器之间的区分。 如果已经存在唯一的 GUID,为什么还要谈论服务器之间共享密钥呢? 还有另一个插件 - keyring_udf。 使用此插件,您的服务器用户可以将他们的密钥存储在 Vault 服务器上。 例如,当用户在 server1 上创建密钥,然后尝试在 server2 上创建具有相同 ID 的密钥时,就会出现问题,例如:

--server1:
select keyring_key_store('ROB_1','AES',"123456789012345");
1
--1 значит успешное завершение
--server2:
select keyring_key_store('ROB_1','AES',"543210987654321");
1

等待。 两台服务器都使用相同的 Vault 服务器,keyring_key_store 函数在 server2 上不应该失败吗? 有趣的是,如果您尝试在一台服务器上执行相同的操作,您将收到错误:

--server1:
select keyring_key_store('ROB_1','AES',"123456789012345");
1
select keyring_key_store('ROB_1','AES',"543210987654321");
0

没错,ROB_1 已经存在。

我们先讨论第二个例子。 正如我们之前所说,keyring_vault 或任何其他密钥环插件都会将所有密钥 ID 缓存在内存中。 因此,创建新密钥后,ROB_1 被添加到 server1 中,并且除了将该密钥发送到 Vault 之外,该密钥也被添加到缓存中。 现在,当我们尝试第二次添加相同的密钥时,keyring_vault 会检查该密钥是否存在于缓存中并抛出错误。

在第一种情况下,情况有所不同。 Server1 和 server2 有单独的缓存。 将 ROB_1 添加到 server1 和 Vault 服务器上的密钥缓存后,server2 上的密钥缓存不同步。 server2 上的缓存中没有 ROB_1 密钥。 因此,ROB_1 密钥被写入 keyring_key_store 和 Vault 服务器,这实际上会覆盖 (!) 之前的值。 现在 Vault 服务器上的 ROB_1 密钥是 543210987654321。有趣的是,Vault 服务器不会阻止此类操作,并且可以轻松覆盖旧值。

现在我们可以明白为什么 Vault 中的服务器分区很重要 - 当您使用 keyring_udf 并希望在 Vault 中存储密钥时。 如何在 Vault 服务器上实现这种分离?

有两种方法可以划分到 Vault 中。 您可以为每个服务器创建不同的安装点,或在同一安装点内使用不同的路径。 最好用例子来说明这一点。 让我们先看看各个挂载点:

--server1:
vault_url = http://127.0.0.1:8200
secret_mount_point = server1_mount
token = (...)
vault_ca = (...)

--server2:
vault_url = http://127.0.0.1:8200
secret_mount_point = sever2_mount
token = (...)
vault_ca = (...)

在这里您可以看到 server1 和 server2 使用不同的安装点。 分割路径时,配置将如下所示:

--server1:
vault_url = http://127.0.0.1:8200
secret_mount_point = mount_point/server1
token = (...)
vault_ca = (...)
--server2:
vault_url = http://127.0.0.1:8200
secret_mount_point = mount_point/sever2
token = (...)
vault_ca = (...)

在这种情况下,两台服务器使用相同的安装点“mount_point”,但路径不同。 当您使用此路径在 server1 上创建第一个机密时,Vault 服务器会自动创建一个“server1”目录。 对于 server2 来说一切都是相似的。 当您删除 mount_point/server1 或 mount_point/server2 中的最后一个机密时,Vault 服务器也会删除这些目录。 如果您使用路径分离,则必须仅创建一个装载点并更改配置文件,以便服务器使用单独的路径。 可以使用 HTTP 请求创建安装点。 使用 CURL 可以这样完成:

curl -L -H "X-Vault-Token: TOKEN" –cacert VAULT_CA
--data '{"type":"generic"}' --request POST VAULT_URL/v1/sys/mounts/SECRET_MOUNT_POINT

所有字段(TOKEN、VAULT_CA、VAULT_URL、SECRET_MOUNT_POINT)对应配置文件的参数。 当然,您可以使用 Vault 实用程序来执行相同的操作。 但自动创建挂载点会更容易。 我希望这些信息对您有用,我们将在本系列的下一篇文章中见到您。

MySQL 中的加密:Keystore

阅读更多:

来源: habr.com

添加评论