华为云DEW/KMS实操:自定义密钥、信封加密到云服务加密与密钥轮换
一、为什么需要单独理解 KMS
很多人第一次接触华为云数据加密服务(DEW,Data Encryption Workshop)时,会把它和云硬盘加密、OBS 服务端加密混在一起。实际上这些服务的加密能力底层都依赖 KMS(Key Management Service,密钥管理服务)托管的密钥。理解 KMS 的密钥层级和“信封加密”,才能在合规要求(等保、数据安全法)下正确选型,也能避免“密钥被禁用后数据读不出来”这类事故。
先厘清三个核心概念:
- CMK(Customer Master Key,客户主密钥):KMS 中托管的根密钥,永远不会以明文形式离开 KMS 硬件安全模块(HSM),用来加密下层的数据密钥,而不是直接加密业务数据。
- DEK(Data Encryption Key,数据密钥):真正用来加密业务数据的密钥。通过 KMS 的 GenerateDataKey 接口生成,会同时返回“明文 DEK”和“被 CMK 加密后的密文 DEK”。
- 信封加密(Envelope Encryption):用 DEK 在本地加密数据,再用 CMK 加密 DEK,最后只持久化密文 DEK 和密文数据。需要解密时先调 KMS 解出明文 DEK,再解数据。这样大量数据的加解密不必每次都走 KMS,既安全又省调用次数。
二、创建自定义 CMK
登录控制台进入“数据加密服务 DEW → 密钥管理服务 KMS → 密钥”,点击“创建密钥”:
- 密钥类型选“对称密钥”(默认 AES-256),别名建议按用途命名,如
cmk-evs-prod、cmk-obs-finance,不要用中文和特殊字符。 - 密钥来源选“KMS”,由云内 HSM 生成;有合规硬件要求可选“专属 HSM”。
- 密钥材料来源默认“KMS 生成密钥材料”。如果企业要自己导入密钥材料,可选择“外部”,后续导入自有材料,这种密钥的生命周期由你掌控,但材料一旦过期/丢失数据将无法恢复。
- 勾选“启用自动轮换”,建议周期设为 365 天。注意轮换的是 KMS 内部用于加密 DEK 的密钥材料,旧材料仍保留,老数据照常可解,无需重新加密存量数据。
系统为每个区域的每个服务预置了“默认主密钥”(如 evs/default、obs/default),开箱即用但不能独立轮换、不能跨账号授权。生产环境建议创建自定义 CMK,便于按业务域隔离权限和审计。
三、用 Python 做一次完整的信封加密
下面用华为云 Python SDK(kms 端点)演示标准信封加密流程。AK/SK 建议通过环境变量或 IAM 元数据注入,不要写死在代码里。
import os
from huaweicloudsdkcore.auth.credentials import BasicCredentials
from huaweicloudsdkkms import KmsClient, GenerateDataKeyRequest, DecryptDataKeyRequest
from huaweicloudsdkkms.kms.model import GenerateDataKeyRequestBody, DecryptDataKeyRequestBody
from cryptography.fernet import Fernet
import base64
cred = BasicCredentials(os.environ["HUAWEI_AK"], os.environ["HUAWEI_SK"])
client = KmsClient.new_builder().with_credentials(cred).with_region("cn-north-4").build()
KEY_ID = "cmk-xxxxxxxx" # 自定义 CMK ID
# 1. 生成数据密钥,同时拿到明文 DEK 和密文 DEK
req = GenerateDataKeyRequest(body=GenerateDataKeyRequestBody(key_id=KEY_ID, datakey_length="64"))
resp = client.generate_data_key(req)
plain_dek = resp.plain_text # base64 明文 DEK,仅内存中使用
cipher_dek = resp.cipher_text # 持久化保存这个
# 2. 用明文 DEK 在本地加密业务数据(Fernet 需要 urlsafe base64 key)
fernet = Fernet(base64.urlsafe_b64encode(base64.b64decode(plain_dek)[:32]))
cipher_data = fernet.encrypt(b"sensitive business payload")
# 3. 落盘:只保存密文 DEK + 密文数据,明文 DEK 用完即弃
with open("sealed.bin", "wb") as f:
f.write(cipher_dek.encode() + b"\n" + cipher_data)
# 4. 解密:先调 KMS 解出明文 DEK
dreq = DecryptDataKeyRequest(body=DecryptDataKeyRequestBody(cipher_text=cipher_dek))
dresp = client.decrypt_data_key(dreq)
fernet2 = Fernet(base64.urlsafe_b64encode(base64.b64decode(dresp.plain_text)[:32]))
print(fernet2.decrypt(cipher_data)) # b'sensitive business payload'
关键点:明文 DEK 绝不能写盘、不能进日志;持久化层只放密文 DEK。这样即使存储盘被拖走,攻击者拿到的也只是无法单独使用的密文 DEK,没有 KMS 调用权限就解不开。
四、云服务侧的一键加密
大部分场景不需要自己写信封加密,云服务在创建资源时直接关联 CMK 即可,服务端自动完成信封加密:
- EVS 云硬盘:创建磁盘时展开“加密”,选择自定义 CMK。加密在宿主机层面进行,对挂载的 ECS 透明,应用无感知。注意加密属性只能在创建时指定,已存在的未加密盘不能直接转加密,需要通过创建加密盘再迁移数据。
- OBS 对象存储:桶配置 → 默认加密,选择 SSE-KMS 并指定 CMK。上传对象默认用该密钥做服务端加密,下载时自动解密。SSE-KMS 相比 SSE-OBS(托管密钥)支持审计和自有密钥轮换。
- RDS / GaussDB:创建实例时开启磁盘加密并选择 CMK,实例的数据文件、自动备份、日志都会加密。
- SFS 弹性文件、DEW 凭据管理、镜像服务 IMS 等同样支持挂载 KMS 密钥。
五、密钥授权与最小权限
KMS 通过 IAM 策略控制“谁能使用这个 CMK”。给业务子账号授权时遵循最小原则:只授予 kms:generate-data-key、kms:decrypt 等必要动作,并在策略 Resource 中限定具体 CMK,而不是 *。跨账号共享密钥时使用 KMS 的“授权(Grant)”能力,可精确到允许的操作并随时撤销。
所有加解密、轮换、授权操作都会在 CTS 云审计服务留下记录,建议结合 CTS 事件订阅,对“计划删除密钥”“禁用密钥”等高风险操作配置告警。
六、常见坑与排查
- 密钥处于“计划删除”等待期导致业务报错:CMK 一旦被计划删除,等待期(默认 7~30 天)内密钥不可用,依赖它的 EVS/RDS/OBS 都会读写失败。发现误删应立即在控制台“取消计划删除”恢复。生产密钥删除前务必确认无资源依赖。
- 开启了加密但 ECS 无法挂载磁盘:检查 ECS 所在委托/子账号是否有该 CMK 的 kms 权限,服务端加密需要调用 KMS 接口,权限不足会挂载失败。
- 自动轮换后担心老数据:KMS 轮换保留全部历史密钥版本,密文 DEK 内部带有版本标识,解密时自动路由到对应版本,无需手动处理。
- 导入外部密钥材料:材料过期或被删除后数据永久不可恢复,务必在本地安全留存材料备份,普通业务优先用 KMS 生成材料。
小结
KMS 的核心价值是“密钥与数据分离、明文密钥不出 HSM”。日常使用记住三条:能用服务端 SSE-KMS 就不自己造轮子;自己做信封加密时明文 DEK 用完即弃、只持久化密文 DEK;生产密钥开启自动轮换并通过 IAM 最小授权 + CTS 审计管住高风险操作。这样既满足合规,又能把密钥相关的运维风险降到最低。
- 点赞
- 收藏
- 关注作者
评论(0)