使用 MariaDB Server 和 Intel® TDX 保护您的数据

2023 年,英特尔推出了 Intel® Trust Domain Extensions (Intel® TDX),这是其最新的机密计算技术,通过证明确保硬件隔离虚拟机在使用中的数据保护,并验证硬件和软件的完整性。
在这篇博客文章中,我们将展示 MariaDB Server 可以正确地在启用了 Intel® TDX 的虚拟机上运行,并且内存中的数据受到保护,即使虚拟机所在的宿主操作系统也无法访问。 通过将英特尔的机密计算技术与 MariaDB Server 内置的静态数据和传输中数据保护相结合,客户可以获得端到端的保护解决方案。
随着云计算服务的日益普及,保护敏感数据的需求不断增加,这一进展至关重要。云提供商现在提供基于 Intel® TDX 的机密计算服务。如需了解更多技术细节,请访问 英特尔网站。
前言
今年,我们在 SUSECON 上与英特尔代表进行了讨论,促成了我们合作测试 MariaDB Server 与 Intel® TDX 的机会。作为此次合作的一部分,我们将发布几篇博客文章,重点介绍 MariaDB Server 和 Intel® TDX 的结合。
这篇特定文章将演示存储在服务器内存中的数据如何受到保护,防止未经授权的访问,即使是利用内核漏洞的攻击者或恶意管理员用户也无法访问。
我们将从两个角度利用 Intel® TDX
- 一名 DBA 在自己的虚拟机上配置 MariaDB 以存储敏感的银行信息.
- 第三方托管服务提供商
现在,让我们保持介绍简短,深入了解技术细节!
宿主配置
我们正在一个配备了 Xeon Scalable 第 5 代 Emerald Rapids 系列 CPU 的系统上安装 Ubuntu 24.04 操作系统。
~/tdx$ cat /etc/os-release
PRETTY_NAME="Ubuntu 24.04 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04 LTS (Noble Numbat)"
~/tdx$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 45 bits physical, 57 bits virtual
Byte Order: Little Endian
CPU(s): 224
On-line CPU(s) list: 0-223
Vendor ID: GenuineIntel
Model name: INTEL(R) XEON(R) PLATINUM 8570
CPU family: 6
Model: 207
Thread(s) per core: 2
Core(s) per socket: 56
Socket(s): 2
Stepping: 2
我们按照 Canonical 的说明设置宿主操作系统和访客操作系统。如果您正在寻找更详细的替代方案,英特尔提供了关于设置 Intel® TDX 的出色 文档。
在宿主端,BIOS 设置已经按照 Canonical 的说明进行了配置。如果您正在设置自己的裸金属实例,请记住在 BIOS 设置中启用 TDX。
我们只需要运行配置脚本。
# Clone the Canonical's Intel® TDX repository
git clone -b noble-24.04 https://github.com/canonical/tdx.git
# Setup Intel® TDX in host OS
cd tdx
sudo ./setup-tdx-host.sh
# Reboot
sudo reboot
# Verify that Intel® TDX is enabled
$ sudo dmesg | grep -i tdx
[ 5.340815] virt/tdx: BIOS enabled: private KeyID range [64, 128)
...
...
[ 21.984224] virt/tdx: module initialized
配置虚拟机
首先,我们需要生成稍后由 QEMU 使用的访客映像。Canonical 提供了一个脚本,用于生成包含 Intel® TDX 工具的访客映像,基础映像是 ubuntu-24.04 云映像,不需要任何内核更改。
# Creating an Intel® TDX qcow2 disk image
cd tdx/guest-tools/image/
sudo ./create-td-image.sh
为了稍后比较 Intel® TDX 提供的虚拟机保护与常规虚拟机的区别,我们还创建了一个常规磁盘映像,只需从映像创建脚本中移除 Intel® TDX 工具即可。
我们最终会在仓库树下得到两个磁盘映像。
:~/tdx/guest-tools/image$ ls -l *qcow*
-rwxrwxrwx 1 root root 1903362048 Oct 17 23:30 regular-guest-ubuntu-24.04-generic.qcow2
-rwxrwxrwx 1 root root 4116250624 Oct 17 06:23 tdx-guest-ubuntu-24.04-generic.qcow2
在 Canonical TDX 仓库中,我们还可以找到两个 示例域 XML 文件,用于引导 Intel® TDX 保护的虚拟机(也称为 Trust Domain)和常规虚拟机。我在 XML 文件中添加了 hostfwd=tcp::0-:3306
,让 QEMU 为客户端-服务器连接分配一个随机端口。
引导这两个虚拟机的推荐方法是使用仓库中提供的 libvirt 封装器 tdvirsh
。
./tdvirsh new \
--td-image ./image/regular-guest-ubuntu-24.04-generic.qcow2 \
--xml-template ./regular_vm.xml.template
./tdvirsh new \
--td-image ./image/tdx-guest-ubuntu-24.04-generic.qcow2 \
--xml-template ./trust_domain.xml.template
结果是两个虚拟机都会启动,并且都会在下面的示例中为 SSH 和 MariaDB Server 分配随机端口。
./tdvirsh list
Id Name State
---------------------------------------------------------------------------
27 tdvirsh-trust_domain-ae41a94c-43f3-4bf0-9c30-b66a13ca6b42 running (ssh:38231 45017, cid:3)
30 tdvirsh-regular_vm-00c643ab-205d-41b5-873d-a60800b284f3 running (ssh:45545 38053, cid:4)
使用 SSH 连接到 Intel® TDX 保护的虚拟机,我们可以轻松验证此虚拟机内部是否已启用 Intel® TDX。
root@tdx-guest:~# sudo dmesg | grep -i tdx
[ 0.000000] tdx: Guest detected
[ 0.000000] DMI: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 2024.02-3+tdx1.0 07/03/2024
[ 0.278473] process: using TDX aware idle routine
[ 0.330149] Memory Encryption Features active: Intel TDX
[ 6.454503] systemd[1]: Detected confidential virtualization tdx.
[ 6.470694] systemd[1]: Hostname set to <tdx-guest>.
配置 MariaDB Server
我们将在两个虚拟机上配置 MariaDB Server 11.4.3。自 11.4.1 起,客户端与服务器之间的连接默认启用 SSL,这自动为我们带来了传输中数据保护。服务器将在内存中生成证书并使用它们。有关进一步阅读,我们发表过 关于它的博客文章。
请注意,Intel® TDX 本身不保护写入磁盘的数据,即静态数据。有两种选项可以保护这种状态下的数据:(1)应用程序级文件加密和(2)访客操作系统级文件加密。我们选择第一个选项,因为 MariaDB Server 已经提供了此功能。
更详细地说,我们将使用 file-key-management 插件 为 InnoDB 存储引擎设置 静态数据保护。
总的来说,我们执行以下步骤
- 安装服务器。您可以从下载页面下载最新的 MariaDB Server 11.4。
- 为静态数据保护生成密钥文件
- 在服务器配置文件中启用静态数据保护
- 绑定到公共接口以允许远程连接
- 重启服务器以应用更改
在安装 MariaDB Server 后,在两个虚拟机内部执行的步骤
# Keyfile generation
root@tdx-guest:~# mkdir /etc/mysql/encryption
root@tdx-guest:~# (echo -n "1;" ; openssl rand -hex 32 ) | sudo tee -a /etc/mysql/encryption/keyfile
1;56f9e484de0016b19c4de543430e729367838033db1d3ea724dc9624f1f3ae4b
# Server configuration
root@tdx-guest:~# cat <<EOL >> /etc/mysql/my.cnf
[mariadb]
plugin_load_add = file_key_management
loose_file_key_management_filename = /etc/mysql/encryption/keyfile
innodb_encrypt_log = ON
innodb_encrypt_temporary_tables = ON
innodb_encryption_threads = 4
bind-address = 0.0.0.0
EOL
root@tdx-guest:~# systemctl restart mariadb
最后一步是为远程连接创建一个用户。
CREATE USER 'user12'@'%' IDENTIFIED BY 'password123';
GRANT ALL PRIVILEGES ON *.* TO 'user12'@'%' WITH GRANT OPTION;
数据集准备。
对于我们的部署,我们将使用安装在宿主操作系统中的 mariadb 命令行客户端与数据库服务器交互。在实际的生产环境中,客户端将安装在另一台机器上。
以下步骤将针对两个虚拟机重复执行。首先,让我们验证 MariaDB Server 是否已配置为保护传输中的数据和静态数据。
# Connect to the server
mariadb -uuser12 -ppassword123 -h localhost -P #FW_PORT#
# Verify that the connection is secured (data-in-transit protection)
MariaDB [(none)]> SHOW STATUS LIKE 'Ssl_cipher';
+---------------+------------------------+
| Variable_name | Value |
+---------------+------------------------+
| Ssl_cipher | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+
# Check that the encryption plugin is ON (data-at-rest protection)
MariaDB [(none)]> SHOW VARIABLES LIKE '%encryption%';
+------------------------------------------+---------+
| Variable_name | Value |
+------------------------------------------+---------+
| file_key_management_encryption_algorithm | aes_cbc |
| innodb_default_encryption_key_id | 1 |
| innodb_encryption_rotate_key_age | 1 |
| innodb_encryption_rotation_iops | 100 |
| innodb_encryption_threads | 4 |
+------------------------------------------+---------+
MariaDB [(none)]> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE "%key%";
+---------------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+---------------------+---------------+
| file_key_management | ACTIVE |
+---------------------+---------------+
在设置数据库时,我们创建加密表以确保静态数据保护,并向表中添加一些虚拟数据。我们从客户端执行以下操作
# Prepare dataset
CREATE DATABASE Customers;
USE Customers;
CREATE TABLE Individuals (
ID INT AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(100) NOT NULL,
Email VARCHAR(100),
PhoneNumber VARCHAR(15) NOT NULL,
Address VARCHAR(255)
) ENGINE=InnoDB, ENCRYPTED='YES';
INSERT INTO Individuals (Name, Email, PhoneNumber, Address)
VALUES ('Razvan Varzaru', 'razvan@provider.com', '+40700060000', '456 Real Rd, Bucharest, Romania');
INSERT INTO Individuals (Name, Email, PhoneNumber, Address)
VALUES ('John Doe', 'john.doe@provider.com', '+40700060001', '123 Fake St, Springfield, USA');
CREATE TABLE Accounts (
AccountID INT AUTO_INCREMENT PRIMARY KEY,
CustomerID INT,
AccountNumber VARCHAR(50) NOT NULL,
Currency VARCHAR(3) NOT NULL,
Balance DECIMAL(15, 2) NOT NULL,
FOREIGN KEY (CustomerID) REFERENCES Individuals(ID)
) ENGINE=InnoDB, ENCRYPTED='YES';
INSERT INTO Accounts (CustomerID, AccountNumber, Currency, Balance)
VALUES (1, 'ACC123456789', 'EUR', 1000.00);
INSERT INTO Accounts (CustomerID, AccountNumber, Currency, Balance)
VALUES (2, 'ACC444555666', 'GBP', 1500.00);
如果我们检查数据,我们会看到敏感的账户信息存在
MariaDB [Customers]> SELECT * FROM Individuals;
+----+----------------+-----------------------+--------------+---------------------------------+
| ID | Name | Email | PhoneNumber | Address |
+----+----------------+-----------------------+--------------+---------------------------------+
| 1 | Razvan Varzaru | razvan@provider.com | +40700060000 | 456 Real Rd, Bucharest, Romania |
| 2 | John Doe | john.doe@provider.com | +40700060001 | 123 Fake St, Springfield, USA |
+----+----------------+-----------------------+--------------+---------------------------------+
MariaDB [Customers]> SELECT * FROM Accounts;
+-----------+------------+---------------+----------+---------+
| AccountID | CustomerID | AccountNumber | Currency | Balance |
+-----------+------------+---------------+----------+---------+
| 1 | 1 | ACC123456789 | EUR | 1000.00 |
| 2 | 2 | ACC444555666 | GBP | 1500.00 |
+-----------+------------+---------------+----------+---------+
内存转储
现在是时候检查这个设置如何保护传输中的数据、静态数据和使用中的数据了。为了展示这一点,我们假设存在一个拥有完整宿主操作系统权限的恶意管理员,并执行一个强力攻击。这样的管理员可以对每个正在运行的虚拟机执行内存转储。
首先,不带 Intel® TDX 保护的常规虚拟机
# Memory dump of the regular domain
:~/memdumps$ virsh dump tdvirsh-regular_vm-00c643ab-205d-41b5-873d-a60800b284f3 ./regular-dom-mem-dump.file --memory-only
# Suppose ACC123 it's just a standard pattern for identifying the bank and the account type.
:~/memdumps$ strings regular-dom-mem-dump.file | grep -aE -B 5 -A 5 'ACC123'
Balance
Razvan Varzaru
razvan@provider.com
+40700060000
456 Real Rd, Bucharest, Romania
ACC123456789
1000.00i
John Doe
john.doe@provider.com
+40700060001
123 Fake St, Springfield, USA
--
AUE1
default-character-set=utf8mb3
default-collation=utf8mb3_general_ci
infimum
supremum
ACC123456789EUR
ACC444555666GBP
I:6769510
E:ID_MM_CANDIDATE=1
G:systemd
Q:systemd
...
...
# and there's more output to it
如果足够耐心并进一步调查结果,我们可以发现 Razvan 的账号是 ACC123456789,余额是 1,000.00 欧元。
正如我们所见,即使有静态数据和传输中数据保护,管理员基本上可以读取所有敏感数据。
现在让我们在受 Intel® TDX 保护的虚拟机上尝试相同的操作。
# Memory dump of the TD
:~/memdumps$ virsh dump tdvirsh-trust_domain-ae41a94c-43f3-4bf0-9c30-b66a13ca6b42 ./tdx-dom-mem-dump.file --memory-only
:~/memdumps$ strings tdx-dom-mem-dump.file | grep -aE -B 5 -A 5 'ACC123'
# Nothing!
:~/memdumps$ strings tdx-dom-mem-dump.file | grep -aE -B 5 -A 5 'Razvan'
:~/memdumps$
# Nothing x2!
确实,它无缝运行。有了 Intel® TDX 和正确配置的 MariaDB Server 安装,数据保护得到了有效保障,无论是静态的、传输中的还是使用中的。这种设置确保了外部任何一方都无法访问或读取存储在受 Intel® TDX 保护的 MariaDB Server 中的敏感信息。
尽管如此,目前的状态仍有一些限制
- 我们通过进行主内存转储来断定数据在使用中受到保护,但如果您在任何外部基础设施提供商处部署相同的工作负载,您通常没有宿主操作系统访问权限,因此无法执行此测试。因此,为了解决这个问题,可以将 MariaDB Server 与证明相结合,以远程验证保护保证。
- 用于静态数据保护的密钥是在 TD 内部创建的。因此,这需要允许登录的虚拟机管理员。此外,此密钥被写入一个不受 Intel® TDX 保护的文件中。
总而言之,通过利用 Intel® TDX 的特性,我们可以完全保护我们的数据免受未经授权的访问,并维护我们的信息资产的完整性。在未来的博客文章中,我们将探讨如何解决上面提到的限制。