托管数据密钥

更新时间:
复制 MD 格式

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

工作原理

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

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

    说明

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

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

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

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

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

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

适用范围

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

  • 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 实例后,单击目标数据密钥的名称,进入详情页。

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

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