阿里云密钥管理服务KMS(Key Management Service)新增了专属KMS产品形态,可以为您提供租户侧独享存储和密钥运算的密钥管理服务,提高使用安全性。本文介绍如何将KMS密钥迁移到专属KMS。

迁移的内容

重要 如果不做迁移,您可以继续使用阿里云KMS,但您将无法提高密钥配额和QPS。
迁移内容说明
密钥您只需要迁移用户主密钥CMK,不需要迁移服务托管的密钥。阿里云会继续支持用户通过免费的方式使用服务托管的密钥,用于云产品的默认加密能力。
说明acs/云产品为别名的都是服务托管的密钥。
业务应用如果您的密钥只在阿里云云产品做加密使用,无需进行业务应用的迁移。如果密钥在您自己管理的业务应用中被使用,您需要将网关从KMS网关切换到专属KMS私有网关。
  • KMS网关:业务通过互联网域名、VPC域名访问KMS,访问时使用AK身份凭证,基于RAM实现对密钥的权限管控。
  • 专属KMS私有网关:通过专属KMS私网域名访问专属KMS,访问时使用Client Key作为身份凭证,基于应用接入点实现对密钥的权限管控。
重要 阿里云将在您所有密钥迁移到专属KMS的1个月后关闭KMS网关入口,您将只能通过专属KMS私有网关调用,请务必在密钥迁移后的1个月内完成业务应用的迁移。

迁移流程

KMS到专属KMS迁移流程

步骤一:判断密钥和业务应用是否可以迁移

如果密钥或者业务应用经判断不支持迁移,您无需关注本文档剩余内容,可以继续使用阿里云KMS。

说明 如果您的密钥只在云产品中做加密使用,只需要判断密钥是否迁移,不需要判断业务应用是否需要迁移。如果您的密钥在业务应用中使用,则需要判断密钥和业务应用是否都可以迁移。

判断密钥是否可以迁移

  • 方式一:通过用户主密钥迁移判断工具进行判断(推荐)
    1. 登录密钥管理服务控制台
    2. 单击用户主密钥,在用户主密钥页面的上方单击主密钥迁移判断工具
    3. 仔细阅读提示信息后单击确定,工具会给出判断结果详情
  • 方式二:根据如下信息自行判断
    如下类型的用户主密钥,暂不支持迁移专属KMS。
    不支持迁移的密钥说明
    多版本密钥目前仅支持迁移有且仅有一个版本的密钥,对于存在多个版本的密钥暂不支持迁移。
    开启轮转的密钥对于开启了自动轮转但目前仅有一个版本的密钥,在关闭密钥轮转后仍可以迁移。
    BYOK密钥BYOK密钥暂不支持迁移,您可以自行将密钥材料导入到专属KMS构建相同的密钥。

判断业务应用是否可以迁移

如果密钥在您自己管理的业务应用中被使用,请根据业务实际情况从以下三方面判断业务应用是否可以迁移。同时满足条件时,业务应用才支持迁移。

条件说明
根据密码运算API判断是否支持迁移如果您的业务应用使用了ReEncrypt(转加密)、ExportDataKey(数据密钥导出)、GenerateAndExportDataKey(生成数据密钥)密钥运算API,暂时无法迁移到专属KMS。
根据应用网络位置判断是否支持迁移
专属KMS部署在您的私有VPC内,其中基础版实例部署在启动时您指定的VPC,标准版实例与HSM集群部署在同一个VPC。当应用和专属KMS实例的网络位置属于如下情况之一时支持迁移。
  • 应用与专属KMS实例在同一VPC内。
  • 应用和专属KMS实例分布在不同VPC(应用和专属KMS实例可以属于同一个阿里云账号下,也可以属于不同阿里云账号)。
  • 应用在非阿里云环境。
    说明 应用在非阿里云环境时,您需要确保已经执行如下操作。
    • 保证网络的联通性,确保业务机器与专属KMS所在的网络已经打通。
    • 保证域名解析正常。
      1. 放行100.100.2.136、100.100.2.138这两段路由,确保在本地IDC上100.100.2.136、100.100.2.138可以ping通。
      2. 在本地IDC配置DNS转发,将kms.aliyuncs.com转发到100.100.2.136、100.100.2.138。
根据应用开发语言判断是否支持迁移目前提供Java、Go、Python三种语言类型的迁移SDK,以支持您将业务应用以较少的代码改动完成从KMS迁移至专属KMS。如果您的业务应用使用其他语言开发,暂不支持迁移至专属KMS,您可以通过智能在线联系技术支持人员反馈需求。

步骤二:选择专属KMS版本

您可以通过查看专属KMS基础版和标准版之间的差异,根据业务需要选择合适的专属KMS版本。具体信息,请参见专属KMS基础版和标准版的差异

步骤三:迁移密钥

请通过智能在线联系技术支持人员将密钥迁移到专属KMS。同时提供如下信息:需要迁移的密钥、迁移时间窗口(建议在业务低峰期进行迁移)、迁移目标专属KMS实例。
说明 阿里云会在时间窗口内完成密钥迁移。密钥迁移完成后,您可以登录密钥管理服务控制台,在专属KMS页面单击目标实例操作列的管理,查看已完成迁移的密钥。

步骤四:迁移业务应用

如果您的密钥只在云产品中做加密使用,不需要执行本步骤。如果您的密钥在业务应用中使用,您需要在密钥迁移完成后的1个月内完成业务应用的迁移。

  1. 为实例创建应用接入点,并保存Client Key、CA证书。具体操作,请参见基础版快速入门标准版快速入门
  2. 对应用进行改造升级,将网关从KMS切换到专属KMS。
    • 改造示例(JAVA)

      导入Maven依赖

         <!-- add dkms sdk dependency -->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>alibabacloud-dkms-gcs-sdk</artifactId>
            <version>x.x.x</version>
          </dependency>
      
        <dependency>
            <groupId>com.aliyun.kms</groupId>
            <artifactId>kms-transfer-client</artifactId>
            <version>x.x.x</version>
        </dependency>

      代码改造

      改造前业务代码示例:
      import com.aliyuncs.DefaultAcsClient;
      import com.aliyuncs.IAcsClient;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.exceptions.ServerException;
      import com.aliyuncs.profile.DefaultProfile;
      import com.google.gson.Gson;
      import java.util.*;
      import com.aliyuncs.kms.model.v20160120.*;
      
      public class Encrypt {
      
          public static void main(String[] args) {
              DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "<your-access-key-id>", "<your-access-key-secret>");
              IAcsClient client = new DefaultAcsClient(profile);
              // 设置 request 参数
              EncryptRequest request = new EncryptRequest();
              request.setProtocol(ProtocolType.HTTPS);
              request.setAcceptFormat(FormatType.JSON);
              request.setMethod(MethodType.POST);
              request.setKeyId(<keyId>);
              request.setPlaintext(plainText);
      
              try {
                  EncryptResponse response = client.getAcsResponse(request);
                  System.out.println(new Gson().toJson(response));
              } catch (ServerException e) {
                  e.printStackTrace();
              } catch (ClientException e) {
                  System.out.println("ErrCode:" + e.getErrCode());
                  System.out.println("ErrMsg:" + e.getErrMsg());
                  System.out.println("RequestId:" + e.getRequestId());
              }
      
          }
      }
      改造后业务代码示例:
      import com.aliyun.kms.KmsTransferAcsClient;
      import com.aliyun.dkms.gcs.openapi.models.Config;
      import com.aliyuncs.IAcsClient;
      import com.aliyuncs.exceptions.ClientException;
      import com.aliyuncs.exceptions.ServerException;
      import com.aliyuncs.profile.DefaultProfile;
      import com.google.gson.Gson;
      import java.util.*;
      import com.aliyuncs.kms.model.v20160120.*;
      
      public class Encrypt {
      
          public static void main(String[] args) {
              DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "<your-access-key-id>", "<your-access-key-secret>");
      
              Config config = new Config();
             //连接协议,固定为HTTPS。
              config.setProtocol("https");
             //专属KMS实例Client Key。
              config.setClientKeyFile("<your-client-key-file>");
              //专属KMS实例Client Key解密口令。
              config.setPassword("<your client key password>");
             //Endpoint,专属KMS实例服务地址去掉https://。
              config.setEndpoint("<service_id>.cryptoservice.kms.aliyuncs.com");
              IAcsClient client = new KmsTransferAcsClient(profile, config);
              // 设置 request 参数
              EncryptRequest request = new EncryptRequest();
              request.setProtocol(ProtocolType.HTTPS);
              request.setAcceptFormat(FormatType.JSON);
              request.setMethod(MethodType.POST);
              request.setKeyId(<keyId>);
              request.setPlaintext(plainText);
      
              try {
                  EncryptResponse response = client.getAcsResponse(request);
                  System.out.println(new Gson().toJson(response));
              } catch (ServerException e) {
                  e.printStackTrace();
              } catch (ClientException e) {
                  System.out.println("ErrCode:" + e.getErrCode());
                  System.out.println("ErrMsg:" + e.getErrMsg());
                  System.out.println("RequestId:" + e.getRequestId());
              }
      
          }
      }
    • 改造示例(Python)

      安装增加依赖包

      代码改造

      改造前业务代码示例:

      from aliyunsdkcore.auth.credentials import AccessKeyCredential
      from aliyunsdkcore.client import AcsClient
      from aliyunsdkkms.request.v20160120.EncryptRequest import EncryptRequest
      
      
      def encrypt():
          credentials = AccessKeyCredential('<your-access-key-id>', '<your-access-key-secret>')
      
          client = AcsClient(region_id="<your-region-id>", credential=credentials)
      
          request = EncryptRequest()
          request.set_accept_format('json')
          request.set_KeyId("<your-key-id>")
          request.set_Plaintext("<your-plaintext>")
      
          response = client.do_action_with_exception(request)
          print(str(response, encoding='utf-8'))
      
      
      encrypt()

      改造后业务代码示例:

      from alibabacloud_dkms_transfer.kms_transfer_acs_client import KmsTransferAcsClient
      from aliyunsdkcore.auth.credentials import AccessKeyCredential
      from aliyunsdkkms.request.v20160120.EncryptRequest import EncryptRequest
      from openapi.models import Config
      
      
      def encrypt():
          config = Config()
          config.protocol = "https"
          config.client_key_file = "<your-client-key-file-path>"
          config.password = "<your-password>"
          config.endpoint = "<your-endpoint>"
      
          credentials = AccessKeyCredential('<your-access-key-id>', '<your-access-key-secret>')
      
          client = KmsTransferAcsClient(config=config, credential=credentials, verify='<your-ca-certificate-file-path>')
      
          request = EncryptRequest()
          request.set_KeyId("<your-key-id>")
          request.set_Plaintext("<your-plaintext>")
      
          response = client.do_action_with_exception(request)
          print(str(response, encoding='utf-8'))
      
      
      encrypt()
    • 改造示例(Go)

      使用如下方式之一安装依赖包:

      • 使用go mod管理您的依赖:
        require (
            github.com/aliyun/alibabacloud-dkms-transfer-go-sdk vX.X.X
            github.com/aliyun/alibabacloud-dkms-gcs-go-sdk vX.X.X
            github.com/alibabacloud-go/tea vX.X.X
        )
      • 通过go get命令获取远程代码包:
        $ go get -u github.com/aliyun/alibabacloud-dkms-transfer-go-sdk
        $ go get -u github.com/aliyun/alibabacloud-dkms-gcs-go-sdk
        $ go get -u github.com/alibabacloud-go/tea
        说明 SDK的最新版本,请参见alibabacloud-dkms-gcs-go-sdkalibabacloud-dkms-transfer-go-sdk

      代码改造

      改造前业务代码示例:
      import (
          "fmt"
          "github.com/aliyun/alibaba-cloud-sdk-go/services/kms"
      )
      
      func main() {
          client, err := kms.NewClientWithAccessKey("<your-region-id>", "<your-access-key-id>", "<your-access-key-secret>")
          if err != nil {
              panic(err)
          }
      
          request := kms.CreateEncryptRequest()
          request.Scheme = "https"
          request.KeyId = "<your cmk id>"
          request.Plaintext = "<your plaintext>"
      
          response, err := client.Encrypt(request)
          if err != nil {
              panic(err)
          }
      
          fmt.Println(response)
      }
      改造后业务代码示例:
      import (
          "fmt"
          "github.com/alibabacloud-go/tea/tea"
          "github.com/aliyun/alibaba-cloud-sdk-go/services/kms"
          dedicatedkmsopenapi "github.com/aliyun/alibabacloud-dkms-gcs-go-sdk/openapi"
          "github.com/aliyun/alibabacloud-dkms-transfer-go-sdk/sdk"
      )
      
      func main() {
          config := &dedicatedkmsopenapi.Config{
              Protocol:      tea.String("https"),
              ClientKeyFile: tea.String("<your-client-key-file>"),
              Password:      tea.String("<your-client-key-password>"),
              Endpoint:      tea.String("<your-dkms-instance-service-endpoint>"),
          }
      
          client, err := sdk.NewClientWithAccessKey("<your-region-id>", "<your-access-key-id>", "<your-access-key-secret>", config)
          if err != nil {
              panic(err)
          }
      
          request := kms.CreateEncryptRequest()
          request.KeyId = "<your cmk id>"
          request.Plaintext = "<your plaintext>"
      
          response, err := client.Encrypt(request)
          if err != nil {
              panic(err)
          }
      
          fmt.Println(response)
      }