托管数据密钥

更新时间:
复制 MD 格式

当需要在本地离线加解密数据,且希望密钥由 KMS 集中托管和保护时,可以使用托管数据密钥功能。托管数据密钥持久存储于 KMS,可随时通过控制台或 API 获取密钥明文,完成本地数据加解密操作。

工作原理

托管数据密钥基于 KMS 凭据管家实现,将数据密钥存储至 KMS 凭据中,后续使用时直接从凭据中获取。使用流程如下:

  1. 创建数据密钥时,KMS 会使用配置的加密主密钥对数据密钥进行加密,生成数据密钥密文。

    说明

    导入数据密钥时,需要手动对数据密钥材料进行加密,以生成数据密钥密文。

  2. 生成数据密钥密文后,系统会自动创建一个凭据(数据密钥凭据),将数据密钥密文存储至该凭据中。

  3. 使用 SDK 调用 GetManagedDataKey 接口时,KMS 会从数据密钥凭据中取出数据密钥密文,使用加密主密钥解密后返回数据密钥明文。

  4. 在本地使用获取到的数据密钥明文进行加解密操作。

重要
  • 与 GenerateDataKey 接口产生的一次性数据密钥不同,托管数据密钥可反复获取明文,适用于需要持久化密钥的离线加解密场景。

  • 创建或导入的数据密钥,生成的数据密钥凭据,仅消耗数据密钥的额度,不消耗凭据的额度。

托管数据密钥与信封加密的区别

托管数据密钥和使用 KMS 密钥进行信封加密都是用 KMS 保护数据密钥、在本地用数据密钥明文加解密数据。两者的核心区别只有两点:

  • 数据密钥密文由谁保管:托管数据密钥的密文由 KMS 托管在数据密钥凭据中,应用无需自行保存;信封加密的密文由应用自行保存(通常与数据一起存储),一旦丢失将无法解密数据。

  • 明文能否反复获取:托管数据密钥可随时通过 GetManagedDataKey 接口或控制台反复获取明文,密钥持久化并支持自动轮转;信封加密的明文一次性使用,解密时需调用 Decrypt 接口重新获取明文。

image

对比项

托管数据密钥

KMS 信封加密

数据密钥生命周期

持久化存储于 KMS 凭据中,可反复获取明文。

一次性生成,明文仅在内存中使用,加密完成后需及时销毁。

核心 API

GetManagedDataKey(获取已托管的数据密钥明文)

GenerateDataKey(生成新数据密钥)、Decrypt(解密数据密钥密文)

密钥来源

KMS 自动生成或用户导入自有密钥材料。

KMS 调用时实时生成。

自动轮转

创建方式支持自动轮转并保留多个版本,导入方式不支持。

不涉及轮转,每次加密可使用独立的新数据密钥。

典型场景

需要在本地离线加解密,且希望密钥由 KMS 集中托管保护、需持久化密钥的场景。

加密大量数据(如全磁盘数据)、多文件分别加密、不希望数据上传到 KMS 的场景。

实例要求

仅预付费 KMS 实例支持,按量付费实例及跨地域同步实例(副本实例)不支持。

软件密钥管理实例和硬件密钥管理实例均支持。

额度消耗

占用数据密钥额度

不占用数据密钥额度。

适用范围

使用托管数据密钥功能前,确认满足以下条件:

  • KMS 实例类型:仅预付费实例支持。

    说明

    按量付费实例以及跨地域同步实例(副本实例)均不支持。

  • 实例状态:KMS 实例已连接且未过期。

  • 配额限制:实例的数据密钥数量未达到上限。如已达上限,需先购买数据密钥配额。

  • 网关限制:目前仅支持通过共享网关调用。

创建或导入数据密钥

KMS 提供两种方式获取托管数据密钥:

方式

密钥材料来源

是否支持自动轮转

适用场景

创建

KMS 自动生成

支持

无自有密钥材料,需要 KMS 全托管并支持定期轮转。

导入

用户自行提供

不支持

已有密钥材料,需要自主控制密钥来源。

创建托管数据密钥

创建数据密钥时,KMS 自动生成密钥材料并用指定的加密主密钥进行保护。创建的数据密钥支持配置自动轮转策略。

  1. 登录密钥管理服务控制台,在顶部菜单栏选择地域后,在左侧导航栏单击资源 > 密钥管理。

  2. 在数据密钥页签,选择目标 KMS 实例后,单击创建数据密钥。

  3. 在创建数据密钥面板,配置以下参数。

    参数

    说明

    数据密钥名称

    数据密钥的唯一标识名称。最大长度 128 字符。

    数据密钥字节数

    数据密钥的长度,取值范围 1~1024 字节,默认值 32。常用长度说明如下:

    • 16 字节:适用于 AES-128、SM4。

    • 24 字节:适用于 AES-192。

    • 32 字节:适用于 AES-256。

    主密钥类型

    选择用于保护数据密钥材料的加密主密钥来源。

    • 选择已有主密钥:从当前实例的对称主密钥列表选择。

    • 创建新的主密钥:系统自动为当前实例创建一个新的对称主密钥。

      说明

      可在密钥管理 > 用户主密钥页签下查看和管理创建的密钥。

    加密主密钥

    当主密钥类型为选择已有主密钥时显示。支持从下拉列表搜索并选择同实例的用户主密钥,也可单击高级查询以表格方式选择。

    重要

    仅支持选择对称密钥。

  4. 单击确定,完成创建。

导入托管数据密钥(不推荐)

如果需要使用自有密钥材料,可以将密钥材料导入 KMS 进行托管,导入的数据密钥不支持自动轮转。

步骤一:处理密钥材料

  1. 对原始密钥材料进行 Base64 编码。

  2. 使用加密主密钥加密编码后的密钥材料:

    1. 在密钥管理 > 用户主密钥页签,确定用于保护数据密钥材料的加密主密钥,并记录其密钥 ID。

    2. 调用 Encrypt 接口,对 Base64 编码结果加密,得到密钥材料密文。具体操作,请参见加密解密示例。

步骤二:配置数据密钥

  1. 登录密钥管理服务控制台,在顶部菜单栏选择地域后,在左侧导航栏单击资源 > 密钥管理。

  2. 在数据密钥页签,选择目标 KMS 实例后,单击导入数据密钥。

  3. 在导入数据密钥面板,配置以下参数。

    参数

    说明

    数据密钥名称

    数据密钥的唯一标识名称。最大长度 128 字符。

    数据密钥字节数

    数据密钥的长度,取值范围 1~1024 字节,默认值 32。常用长度说明如下:

    • 16 字节:适用于 AES-128、SM4。

    • 24 字节:适用于 AES-192。

    • 32 字节:适用于 AES-256。

    加密主密钥

    选择用于保护数据密钥材料的加密主密钥,仅从当前实例的对称主密钥列表选择。需和步骤一中用于加密的用户主密钥保持一致。

    说明

    可在密钥管理 > 用户主密钥页签下查看和管理创建的密钥。

    数据密钥内容

    导入步骤一中获取到的密钥材料密文。

  4. 单击确定,完成导入。

应用接入

应用可以通过 API 获取托管数据密钥的明文,完成本地数据加解密。目前仅支持通过共享网关调用相关 API。

相关 API:

步骤一:配置权限

应用通过 API 操作托管数据密钥时,需要为应用的 RAM 身份配置相应权限。以下是最小权限策略示例。

获取数据密钥明文和查询版本的权限

{
  "Version": "1",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "kms:ListManagedDataKeyVersions",
        "kms:GetSecretValue",
        "kms:GetManagedDataKey"
      ],
      "Resource": [
        "acs:kms:{regionId}:{aliuid}:secret/kms-datakey!{dataKeyName}",
        "acs:kms:{regionId}:{aliuid}:secret/kms-datakeyversion!{dataKeyName}!*"
      ]
    }
  ]
}

解密数据密钥材料的权限

获取数据密钥明文时,KMS 需要使用加密主密钥解密密钥材料,因此应用还需要对应 CMK 的 Decrypt 权限。

{
  "Version": "1",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt"
      ],
      "Resource": [
        "acs:kms:{regionId}:{aliuid}:key/{keyId}"
      ]
    }
  ]
}

参数说明

  • {regionId}:KMS 实例所在地域 ID,例如 cn-hangzhou。

  • {aliuid}:阿里云账号 ID。

  • {dataKeyName}:数据密钥名称。Resource 中第一行为主凭据权限,第二行通过通配符 * 授权所有版本凭据。

  • {keyId}:加密主密钥的 ID。

说明

通过更改 {dataKeyName} 可以为不同应用授权不同的托管数据密钥,实现细粒度的权限隔离。

步骤二:使用 SDK 接入

通过 KMS SDK 调用 GetManagedDataKey 接口获取数据密钥明文,在本地完成数据加解密。以下以 Go SDK 为例,展示如何使用 AES-GCM 算法进行数据加解密。如需手动下载数据密钥明文,请参见本文手动下载数据密钥明文章节。

加密数据

加密时获取最新版本的数据密钥进行加密,并将版本标识附加在密文头部,便于解密时定位密钥版本。

package main

import (
    "crypto/aes"
    "crypto/cipher"
    cryptorand "crypto/rand"
    "encoding/base64"
    "io"
    "os"

    openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
    kmsclient "github.com/alibabacloud-go/kms-20160120/v4/client"
    "github.com/alibabacloud-go/tea/tea"
)

func EncryptWithManagedDataKey(plaintext []byte, dataKeyName string) ([]byte, error) {
    kms, err := kmsclient.NewClient(&openapi.Config{
        AccessKeyId:     tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")),
        AccessKeySecret: tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")),
        Endpoint:        tea.String("kms.cn-hangzhou.aliyuncs.com"),
    })
    if err != nil {
        return nil, err
    }

    // 获取最新版本的托管数据密钥明文,也可手动下载密钥明文
    getResp, err := kms.GetManagedDataKey(&kmsclient.GetManagedDataKeyRequest{
        DataKeyName: tea.String(dataKeyName),
        UseLatest:   tea.Bool(true),
    })
    if err != nil {
        return nil, err
    }
    dataKeyVersionId := tea.StringValue(getResp.Body.DataKeyVersionId)
    b64PlainDataKey := tea.StringValue(getResp.Body.Plaintext)
    //base64转码
    plainDataKey, err := base64.StdEncoding.DecodeString(b64PlainDataKey)
    if err != nil {
        return nil, err
    }

    // 使用 AES-GCM 加密数据
    block, err := aes.NewCipher(plainDataKey)
    if err != nil {
        return nil, err
    }
    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return nil, err
    }
    nonce := make([]byte, gcm.NonceSize())
    _, err = io.ReadFull(cryptorand.Reader, nonce)
    if err != nil {
        return nil, err
    }

    ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
    // 将版本标识(固定 8 字节)和密文拼接,便于解密时定位密钥版本
    output := append([]byte(dataKeyVersionId), ciphertext...)
    return output, nil
}

解密数据

解密时从密文头部解析版本标识,获取对应版本的数据密钥明文进行解密。

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "fmt"
    "os"

    openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
    kmsclient "github.com/alibabacloud-go/kms-20160120/v4/client"
    "github.com/alibabacloud-go/tea/tea"
)

func DecryptWithManagedDataKey(encrypted []byte, dataKeyName string) ([]byte, error) {
    kms, err := kmsclient.NewClient(&openapi.Config{
        AccessKeyId:     tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")),
        AccessKeySecret: tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")),
        Endpoint:        tea.String("kms.cn-hangzhou.aliyuncs.com"),
    })
    if err != nil {
        return nil, err
    }

    // 从密文头部解析版本标识(前 8 字节)
    dataKeyVersionId := string(encrypted[:8])
    ciphertext := encrypted[8:]

    // 获取对应版本的托管数据密钥明文
    getResp, err := kms.GetManagedDataKey(&kmsclient.GetManagedDataKeyRequest{
        DataKeyName:      tea.String(dataKeyName),
        DataKeyVersionId: tea.String(dataKeyVersionId),
    })
    if err != nil {
        return nil, err
    }
    b64PlainDataKey := tea.StringValue(getResp.Body.Plaintext)
    plainDataKey, err := base64.StdEncoding.DecodeString(b64PlainDataKey)
    if err != nil {
        return nil, err
    }

    // 使用 AES-GCM 解密数据
    block, err := aes.NewCipher(plainDataKey)
    if err != nil {
        return nil, err
    }
    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return nil, err
    }
    nonceSize := gcm.NonceSize()
    if len(ciphertext) < nonceSize {
        return nil, fmt.Errorf("ciphertext too short")
    }

    nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
    return gcm.Open(nil, nonce, ciphertext, nil)
}

设置自动轮转策略(可选)

自动轮转会定期生成新版本的密钥材料,旧版本保留可用。

重要

导入的数据密钥不支持轮转。

  1. 登录密钥管理服务控制台,在顶部菜单栏选择地域后,在左侧导航栏单击资源 > 密钥管理。

  2. 在数据密钥页签,选择目标 KMS 实例后,单击目标数据密钥的名称,进入详情页。

  3. 在版本列表区域,单击设置轮转。参考如下说明,完成配置后,单击确定。

    参数

    说明

    自动轮转

    开启或关闭自动轮转。

    轮转周期

    轮转周期,取值范围 7~365 天,默认值 7 天。

    警告

    数据密钥轮转一次,消耗一次数据密钥的额度,请合理规划轮转策略,避免不必要的额度消耗。

其他操作

手动下载数据密钥明文

通过控制台下载数据密钥的明文材料,用于本地离线加解密。启用自动轮转后,数据密钥存在多个版本,从列表下载默认获取最新版本,如需下载历史版本可进入详情页的版本列表操作。

重要

下载的材料为 Base64 编码格式,需要先解码后才能用于加解密操作。

从数据密钥列表下载

  • 下载单个数据密钥明文:

    1. 在数据密钥页签,选择目标 KMS 实例后,单击目标数据密钥的操作列的下载明文。

    2. 浏览器自动下载明文文件,文件名格式为 PlainDataKey_{数据密钥名称}_{版本ID}.txt。

  • 批量下载:

    1. 在数据密钥页签,选择目标 KMS 实例后,勾选多个数据密钥。

    2. 单击列表下方的批量下载明文。

    3. 系统将所有选中密钥的最新版本明文打包为 ZIP 文件下载(文件名格式:dataKeys_{地域ID}_{时间戳}.zip)。

从数据密钥详情页下载

通过数据密钥详情页,可以选择任意版本下载明文材料。

  1. 在数据密钥页签,选择目标 KMS 实例后,单击目标数据密钥的名称,进入详情页。

  2. 在版本列表区域,单击目标版本操作列的下载明文。

    说明

    版本列表中的所有版本数据,均可以使用。

计划删除数据密钥

删除数据密钥为不可逆操作。为防止误删,KMS 采用计划删除机制,在预删除周期内可随时撤销删除。预删除周期结束后,数据密钥将被永久删除。

警告

数据密钥删除后无法恢复,使用该密钥加密的数据将无法解密,请在删除前确认不再需要该密钥。

执行计划删除

  1. 在数据密钥页签,选择目标 KMS 实例后,单击目标数据密钥操作列的计划删除。

  2. 在对话框中,设置预删除周期(7~30 天,默认 30 天)后,单击确定。

撤销计划删除

预删除周期内,可以随时撤销删除操作,恢复数据密钥的正常状态。

  1. 在数据密钥页签,选择目标 KMS 实例后,找到处于计划删除状态的数据密钥。

  2. 单击目标数据密钥操作列的撤销删除。

  3. 在确认对话框中,单击确定。

查看版本和轮转信息

  1. 登录密钥管理服务控制台,在顶部菜单栏选择地域后,在左侧导航栏单击资源 > 密钥管理。

  2. 在数据密钥页签,选择目标 KMS 实例后,单击目标数据密钥的名称,进入详情页。

    • 在版本列表列表区域可查看轮转后的各版本信息。

    • 在基础信息区域可查看上次轮转时间、下次轮转时间、轮转周期等。