在机密计算场景中,机密计算应用所运行的数据通常通过寄存器加密和内存加密技术进行保护,但程序代码及其处理的数据通常直接存储于云盘中。在此类机密计算环境下,您可能希望在机密实例内部实施数据加密(如LUKS或BitLocker),以确保数据在流出机密计算实例的安全边界之前,进行不受云服务提供商控制的数据加密,并自主管理云盘的加密密钥。本文介绍如何在机密计算实例内实现加密云盘(下文称机密云盘),为您提供更高等级的安全能力。
如您希望在非机密计算实例上加密云盘,建议您使用阿里云块存储提供的加密云盘能力。
加密概述
加密原理
机密云盘基于Linux平台的LUKS2技术实现,提供块存储级别的数据加密保护能力。在机密实例的云盘基础上建立加密云盘需要进行初始化和打开两个流程:
初始化流程:首先确定需要初始化的块设备,通常是实例中云盘的某个分区对应的块设备(如/dev/nvme1n1p1),在本文的上下文中我们称之为卷(Volume)。使用Cryptpilot工具对选定的卷进行初始化,并在后续的流程中使用该卷存储机密数据。
初始化流程会抹去块设备上的原有数据,请谨慎处理,以免操作失误。
打开流程:使用Cryptpilot工具打开已初始化的卷,将会在实例中建立一个新的虚拟块设备。在该块设备上写入的数据将在加密后以密文的形式存储在底层的ECS云盘上,而在该虚拟块设备上进行数据读取时,也将自动对底层ECS云盘上的数据解密。加密和解密的流程发生在Linux内核中,可以有效防止明文泄露到实例外部。
加密算法
机密云盘的加密过程采用KEK(Key Encryption Key,密钥加密密钥)和Master Key(设备唯一密钥)的双层密钥设计。
在初始化流程中会借助安全随机数算法生成Master Key,该密钥直接用于数据加密,采用行业标准的256 Bit AES加密算法。此外,您可以提供一个密码短语(Passphrase)作为凭据。初始化流程会在该凭据的基础上通过密钥派生算法产生KEK,并使用KEK对Master Key进行加密。
在打开卷时,基于您提供的凭据生成KEK,然后使用KEK解密得到Master Key,从而实现对机密数据的解密。此外,通过实例自身的AES硬件加密能力对加解密过程进行加速,可以降低加密带来的性能开销。
凭据存储
机密云盘支持多种凭据存储方式,建议您提前配置卷打开流程所需的凭据信息,避免在实例启动时手动输入凭据。
一次性凭据(One Time Password,OTP):一种特殊的凭据存储方式,如果配置该类型的凭据,在打开卷时会自动生成一个安全的临时凭据对卷进行初始化,并完成卷的打开,您无需单独进行卷的初始化流程。
每次重新打开卷时都将生成不同的凭据,因此适用于临时数据盘或者交换分区(swap)场景,您不应在这种类型的卷上存储需要在实例关机后仍然能持久化的机密数据。
密钥管理服务(Key Management Service,KMS):将凭据存储在阿里云KMS的凭据存储服务中,并在ECS实例中配置KMS的访问信息。当打开卷时,ECS实例会自动访问阿里云KMS以获取凭据用于卷的加解密。这种方式适合需要持久化的机密数据存储。
完整性支持
除了防止机密数据遭受未授权访问和泄露外,在某些场景(例如大语言模型权重存储和训练数据集的存储)中,还需防止攻击者对机密数据进行篡改。机密云盘支持通过AEAD加密模式提供数据的完整性支持。
注意事项
使用流程
步骤一:准备环境
创建机密计算实例。
远程连接机密计算实例。
具体操作,请参见使用Workbench工具以SSH协议登录Linux实例。
安装Cryptpilot。
sudo yum install -y cryptpilot
查看Cryptpilot版本。
cryptpilot --version
步骤二:创建并挂载云盘
加密云盘是会抹去块设备上的原有数据,建议您创建新的数据盘进行操作。
初始化数据盘时,请仅创建分区及文件系统,不挂载文件系统,文件系统需要加密后再挂载。
查看挂载的云盘及分区信息。
lsblk
显示结果如下,表示当前ECS实例挂载了两块云盘:
/dev/nvme0n1
:原有的系统盘。/dev/nvme1n1
:新增的数据盘,其中有2个新的空白分区(/dev/nvme1n1p1
和/dev/nvme1n1p2
)。
步骤三:创建带有ext4文件系统的卷
临时卷在卷被关闭后,卷中的机密数据将丢失,适用于临时数据盘或者交换分区(swap)场景。
持久化卷可以确保卷被关闭后,机密数据依旧存在,适用于需要持久化的机密数据存储场景。
创建并配置
/etc/cryptpilot/volumes/data0.toml
文件。配置文件采用TOML配置语言格式,文件名可以是任意以
.toml
结尾的文本文件,不强制与卷名称相同。以下配置文件中的配置信息,请根据实际情况修改。
sudo bash -c 'cat > /etc/cryptpilot/volumes/data0.toml << EOF # 卷配置 dev = "/dev/nvme1n1p1" # 指定要使用的块设备,即云盘的空白分区,本示例中/dev/nvme1n1p1使用了数据盘的第一个分区。 volume = "data0" # 指定卷的名称,本示例命名为data0。 auto_open = false # true表示系统启动时会自动打开该卷;false表示需要手动打开卷。 makefs = "ext4" # 指定要创建的文件系统类型,本示例为ext4。 integrity = true # true表示启用数据完整性支持;false表示关闭数据完整性支持。 # 凭据配置 [encrypt.otp] # 指定凭据存储类型,这里选择一次性凭据(OTP)类型。 EOF'
查看卷状态。
sudo cryptpilot show
可以看到
data0
卷的配置信息:Initialized列:显示该卷不需要初始化,因为它的存储类型是OTP(一次性凭据)。
Opened列:显示该卷并未打开。
打开卷并查看卷状态。
打开卷。
sudo cryptpilot open data0
查看卷状态。
sudo cryptpilot show
回显如下所示,表示卷已打开(Opened:True)。
检查卷对应的虚拟设备。
sudo file -Ls /dev/mapper/data0
卷在被打开后,将建立一个虚拟块设备,其路径为:
/dev/mapper/<卷的名称>
。
挂载文件系统并查看挂载结果。
将
data0
卷挂载到/mnt/data0
路径上。sudo mkdir -p /mnt/data0 sudo mount -t ext4 /dev/mapper/data0 /mnt/data0
查看挂载结果。
mount | grep data0 ls -la /mnt/data0/
回显结果如下所示,表示卷被成功挂载,且里面是一个空的ext4文件系统。
关闭卷。
本示例中使用的是一次性凭据(OTP)模型,卷被关闭后,其中存储的机密数据将完全丢失。
关闭卷之前请停止读写该卷的业务进程,并取消卷上的文件系统挂载,确保该卷没有被占用。
取消挂载。
sudo umount /mnt/data0
关闭卷。
sudo cryptpilot close data0
查看卷状态。
cryptpilot show
回显如下,表示该卷已被关闭。
在安全的环境中,随机生成用于加密卷的凭据,并以Base64格式编码。
sudo yum install -y coreutils head -c 256 /dev/urandom | base64 -w 0
保存生成的凭据,用于后续创建通用凭据。
创建阿里云KMS实例,并创建一个通用凭据。
机密云盘对所创建KMS实例的密钥管理类型没有限制,您可以按照安全需求按需选择。本文示例选择软件密钥管理类型的KMS实例。
该KMS实例须与ECS实例在同一专有网络(VPC)中。
凭据名称:根据实例填写,本示例为
confidential_cloud_disk_passphrase
。设置凭据值:选择纯文本,输入上一步生成的Base64编码后的凭据。
加密主密钥:选择上一步创建的软件密钥。
请确保已经获得以下内容:
应用身份凭证内容(ClientKeyContent):文件名默认为clientKey_****.json。
凭证口令(ClientKeyPassword):文件名默认为clientKey_****_Password.txt。
KMS实例CA证书:文件名默认为PrivateKmsCA_kst-******.pem。
创建并配置
/etc/cryptpilot/volumes/data1.toml
文件。创建
/etc/cryptpilot/volumes/data1.toml
文件。配置文件。
配置文件采用TOML配置语言格式,文件名可以是任意以
.toml
结尾的文本文件,不强制与卷名称相同。以下配置文件中的配置信息,请根据实际情况修改。
# 卷配置 dev = "/dev/nvme1n1p2" # 指定要使用的块设备,即云盘的空白分区,本示例中/dev/nvme1n1p2使用了数据盘的第一个分区。 volume = "data1" # 指定卷的名称,本示例命名为data1。 auto_open = false # true表示系统启动时会自动打开该卷;false表示需要手动打开卷。 makefs = "ext4" # 指定要创建的文件系统类型,本示例为ext4。 integrity = true # true表示启用数据完整性支持;false表示关闭数据完整性支持。 # 凭据配置 [encrypt.kms] # 指定凭据存储类型,这里选择密钥管理服务(KMS)类型。 secret_name = "confidential_cloud_disk_passphrase" # KMS实例中存储的凭据的名称,即之前示例中的confidential_cloud_disk_passphrase。 # 应用身份凭证内容文件(clientKey_****.json文件)中的内容 client_key = ''' { "KeyId": "KAAP.b183152a-c3bf-43ae-9399-a101607b****", "PrivateKeyData": "MIIJ0wIBAzCCCZ8GCSqGSIb3DQE****" } ''' client_key_password = "258372e962f5204ce648bc66243f****" # 凭证口令文件(clientKey_****_Password.txt文件)中的内容 kms_instance_id = "kst-bjj67d004a85ykq80****" # KMS实例ID # KMS实例CA证书文件(PrivateKmsCA_kst-******.pem文件)中的内容 kms_cert_pem = """ -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIJALTKwWAjvbMiMA0GCSqGSIb3DQEBCwUAMH**** -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3zCCAsegAwIBAgIJAO8qnQyTy8/kMA0GCSqGSIb3DQEBCwUAMH**** -----END CERTIFICATE----- """
查看卷状态。
sudo cryptpilot show
可以看到
data0
卷的配置信息:Initialized列:显示该卷尚未初始化。
Opened列:显示该卷并未打开。
初始化卷并查看卷状态。
初始化卷。
sudo cryptpilot init data1
查看卷状态。
sudo cryptpilot show
回显如下所示,表示卷已初始化(Initialized:True)。
打开卷并查看卷状态。
打开卷。
sudo cryptpilot open data1
查看卷状态。
sudo cryptpilot show
回显如下所示,表示卷已打开(Opened:True)。
检查卷对应的虚拟设备。
sudo file -Ls /dev/mapper/data1
卷在被打开后,将建立一个虚拟块设备,其路径为:
/dev/mapper/<卷的名称>
。
挂载文件系统并写入数据。
将
data1
卷挂载到/mnt/data1
路径上,并创建一个文件/mnt/data1/data.txt
,代表机密数据。sudo mkdir -p /mnt/data1 sudo mount -t ext4 /dev/mapper/data1 /mnt/data1 echo "secret data" | sudo tee /mnt/data1/data.txt > /dev/null
关闭卷,并再次打开卷,检查上次写入的数据。
本示例中使用的是一次性凭据(OTP)模型,卷被关闭后,其中存储的机密数据将完全丢失。
关闭卷之前请停止读写该卷的业务进程,并取消卷上的文件系统挂载,确保该卷没有被占用。
取消挂载并关闭卷。
sudo umount /mnt/data1 sudo cryptpilot close data1
再次打开卷,挂载文件系统并访问卷中的文件。
sudo cryptpilot open data1 sudo mount -t ext4 /dev/mapper/data1 /mnt/data1 cat /mnt/data1/data.txt
可以发现前面写入的数据依然存在,验证了持久化存储能力。
步骤四:配置实例启动时自动打开卷
修改配置文件。
对于需要自动打开的卷,修改其配置文件中的
auto_open
字段的值为true
。(条件可选)对于持久化的卷,需要先手动运行
sudo cryptpilot init <卷名称>
初始化后,才能在实例启动时自动打开卷。重新生成initrd。
每次修改cryptpilot配置后,都需要重新生成initrd,才能确保自动打开卷功能生效。
sudo dracut -v -f
查看卷状态。
sudo cryptpilot show
回显如下所示,表示卷被自动打开。
Cryptpilot配置说明
Cryptpilot默认配置文件目录为/etc/cryptpilot/
,该目录下主要包含以下配置文件:
全局配置:默认路径为
/etc/cryptpilot/global.toml
# Configuration related to cryptpilot boot service. [boot] # Enable this option if you want to see more log when running cryptpilot boot service in initrd stage and in system stage. verbose = false
卷配置:默认路径为
/etc/cryptpilot/volumes/
,每个卷对应一个配置文件凭据存储类型:OTP
# The name of resulting volume with decrypted data, which will be set up below `/dev/mapper/`. volume = "data0" # The path to the underlying encrypted device. dev = "/dev/nvme1n1p1" # Whether or not to open the LUKS2 device and set up mapping during booting. The default value is false. auto_open = true # The file system to initialize on the volume. Allowed values are ["swap", "ext4", "xfs", "vfat"]. If is not specified, or the device is not "empty", i.e. it contains any signature, the operation will be skipped. makefs = "ext4" # Whether or not to enable support for data integrity. The default value is false. Note that integrity cannot prevent a replay (rollback) attack. integrity = true # One Time Password (Temporary volume) [encrypt.otp]
凭据存储类型:KMS
# The name of resulting volume with decrypted data, which will be set up below `/dev/mapper/`. volume = "data0" # The path to the underlying encrypted device. dev = "/dev/nvme1n1p1" # Whether or not to open the LUKS2 device and set up mapping during booting. The default value is false. auto_open = true # The file system to initialize on the volume. Allowed values are ["swap", "ext4", "xfs", "vfat"]. If is not specified, or the device is not "empty", i.e. it contains any signature, the operation will be skipped. makefs = "ext4" # Whether or not to enable support for data integrity. The default value is false. Note that integrity cannot prevent a replay (rollback) attack. integrity = true # Aliyun KMS [encrypt.kms] # The id of KMS instance kms_instance_id = "kst-XXXXXXXXX" # The name of the secret store in the KMS instance. secret_name = "XXXXXXXXX" # Content of the clientKey_****.json file. client_key = ''' { "KeyId": "KAAP.XXXXXXXXX", "PrivateKeyData": "XXXXXXXXX" }''' # Content of the clientKey_****_Password.txt file. client_key_password = "XXXXXXXXX" # The CA cert of the KMS (the content of PrivateKmsCA_kst-******.pem file). kms_cert_pem = """ -----BEGIN CERTIFICATE----- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -----END CERTIFICATE----- """
- 本页导读 (1)
- 加密概述
- 加密原理
- 加密算法
- 凭据存储
- 完整性支持
- 注意事项
- 使用流程
- 步骤一:准备环境
- 步骤二:创建并挂载云盘
- 步骤三:创建带有ext4文件系统的卷
- 步骤四:配置实例启动时自动打开卷
- Cryptpilot配置说明