Import your own key material into a customer master key (CMK) to maintain full control over the cryptographic material used for encryption and decryption. This is part of the Bring Your Own Key (BYOK) model supported by Key Management Service (KMS).
How it works
When you create a CMK with Origin set to EXTERNAL, KMS does not generate key material for the CMK. The CMK stays in Pending Import status until you complete the import process, which consists of four steps:
Create an external CMK — set
OrigintoEXTERNALso KMS reserves the CMK without generating key material.Get import parameters — download a wrapping public key and an import token. The public key encrypts your key material in transit; the import token binds the upload to the specific CMK.
Encrypt your key material — use the wrapping public key and a supported wrapping algorithm to encrypt your 256-bit AES key material locally before uploading it.
Import the encrypted key material — upload the encrypted key material and the import token. KMS decrypts the key material inside its secure boundary and activates the CMK.
After import, the CMK status changes from Pending Import to Enabled.
Prerequisites
Before you begin, ensure you have:
A KMS instance (the default instance is sufficient for most use cases)
Permissions to call
CreateKey,GetParametersForImport, andImportKeyMaterialA 256-bit symmetric AES key to use as key material, generated from a trusted source of randomness
OpenSSL installed locally (required for the console workflow)
Usage notes
Key material requirements:
| Property | Requirement |
|---|---|
| Type | 256-bit symmetric AES key |
| Wrapping algorithms | RSAES_PKCS1_V1_5, RSAES_OAEP_SHA_1, RSAES_OAEP_SHA_256 |
Binding and rotation rules:
A CMK is permanently bound to the first piece of key material imported into it. Even after the key material expires or is deleted, you cannot import different key material into the same CMK.
To rotate an external CMK, create a new CMK and import new key material into it.
CMKs are independent: a CMK cannot decrypt data that another CMK encrypted, even if both CMKs use identical key material.
You can import only 256-bit AES symmetric keys as key material.
Key material lifetime:
Delete key material at any time by calling
DeleteKeyMaterial, or set an expiration time to have KMS delete it automatically. Deleting key material does not delete the CMK.If key material expires or is deleted and you have not re-imported it, the CMK becomes unusable and any data encrypted under it becomes inaccessible. If you lose your copy of the key material, that data is unrecoverable. Keep a backup copy of your key material in a secure location and set an expiration alarm with enough lead time to re-import before expiration.
After deletion, you can re-import the same key material to make the CMK available again.
Import token constraints:
Each import token is valid for 24 hours and can be reused within that window.
An import token is bound to a specific public key and a specific CMK. After it expires, request a new token and public key pair.
Import key material in the KMS console
Step 1: Create an external CMK
Log in to the KMS console. In the top navigation bar, select the region where you want to create the CMK.
In the left-side navigation pane, choose Resource > Keys.
Click Create Key and configure the following parameters in the Create Key dialog box:
Parameter Description KMS Instance The KMS instance to use. The default value is Default and cannot be changed. Key Type The CMK type. Set to Aliyun_AES_256. Key Usage Encrypt/Decrypt to encrypt or decrypt data, or Sign/Verify to sign data or verify a digital signature. Key Alias An identifier for the CMK. Can contain letters, digits, underscores (_), hyphens (-), and forward slashes (/). Protection Level Software for software-module protection, or Hsm to manage the CMK in a hardware security module (HSM). Description An optional description of the CMK. Rotation Period The automatic rotation interval. Configurable only when Key Type is Aliyun_AES_256 .NoteThis setting applies only to symmetric keys of type Aliyun_AES_256.
Key Material Source Select External. Select I understand the implications of using the external key materials and click OK.
Step 2: Get import parameters
The import parameters consist of a wrapping public key (to encrypt your key material) and an import token (to authenticate the upload).
On the key list page, click the CMK's key ID to open the key management page. In the Key Material section, click Obtain Parameters for Import.
In the Obtain Parameters to Import Key Material dialog box, set Public Key Type to RSA_2048 and Encryption Algorithm to RSAES_OAEP_SHA_1, then click Next.
For RSA_2048 keys, the supported wrapping algorithms are RSAES_PKCS1_V1_5, RSAES_OAEP_SHA_1, and RSAES_OAEP_SHA_256. The default is RSAES_PKCS1_V1_5.
If you select RSA_2048 as the public key type, you can select RSAES_PKCS1_V1_5 (default), RSAES_OAEP_SHA_1, or RSAES_OAEP_SHA_256 as the encryption algorithm.
Select a Public Key Format:
DER Format — the downloaded file has a
.binextension (for example,publickey_f240b730-7e3e-4bd7-877f-4fe22524****.bin).PEM Format — the downloaded file has a
.pemextension (for example,publickey_f240b730-7e3e-4bd7-877f-4fe22524****.pem).
Download the public key and the import token, then click Close.
Step 3: Encrypt your key material
Use the wrapping public key you downloaded to encrypt your key material locally. The example below uses OpenSSL with the RSAES_OAEP_SHA_1 algorithm — use the same algorithm you selected in Step 2.
Generate 32 bytes of random key material:
openssl rand -out KeyMaterial.bin 32Encrypt the key material with the wrapping public key:
# Replace PublicKey.bin with the filename of the public key you downloaded.
# If you selected PEM Format, replace -keyform DER with -keyform PEM.
openssl rsautl -encrypt -in KeyMaterial.bin -oaep \
-inkey PublicKey.bin -keyform DER -pubin \
-out EncryptedKeyMaterial.binEncode the encrypted key material in Base64:
openssl enc -e -base64 -A \
-in EncryptedKeyMaterial.bin \
-out EncryptedKeyMaterial_base64.txtStep 4: Import the encrypted key material
In the left-side navigation pane, choose Resource > Keys.
Click the CMK's key ID to open the key management page. In the Key Material section, click Import Key Material.
In the Import Wrapped Key Material dialog box, upload the required files:
Wrapped Key Material: the
EncryptedKeyMaterial_base64.txtfile from Step 3.Import Token: the import token file downloaded in Step 2.
Set Key Material Expired On to specify when KMS should automatically delete the key material, then click OK.
After the import completes, the CMK status changes from Pending Import to Enabled.
Import key material using Alibaba Cloud CLI
Step 1: Create an external CMK
aliyun kms CreateKey --Origin EXTERNAL --Description "External key"Step 2: Get import parameters
Replace <key-id> with the key ID returned in Step 1.
aliyun kms GetParametersForImport \
--KeyId <key-id> \
--WrappingAlgorithm RSAES_OAEP_SHA_1 \
--WrappingKeySpec RSA_2048The response includes a Base64-encoded wrapping public key and an import token. Decode the public key from Base64 before using it to encrypt your key material.
The public key is a 2048-bit RSA public key. Use the same encryption algorithm that you specified when you retrieved the import parameters. The API returns the public key in Base64-encoded format. You must decode the public key before you use it. KMS supports RSAES_OAEP_SHA_1, RSAES_OAEP_SHA_256, and RSAES_PKCS1_V1_5.
Step 3: Encrypt and encode your key material
Use the decoded public key to encrypt your 256-bit AES key material with a supported wrapping algorithm (RSAES_OAEP_SHA_1, RSAES_OAEP_SHA_256, or RSAES_PKCS1_V1_5), then encode the encrypted result in Base64. You can use the OpenSSL commands from the console workflow in Step 3 above.
Step 4: Import the encrypted key material
Replace the placeholders with your actual values:
| Placeholder | Description |
|---|---|
<key-id> | The key ID of the external CMK |
<encrypted-key-material> | The Base64-encoded encrypted key material |
<import-token> | The import token from Step 2 |
<expire-unix-timestamp> | Expiration time as a UNIX timestamp (seconds). Set to 0 for no expiration. |
aliyun kms ImportKeyMaterial \
--KeyId <key-id> \
--EncryptedKeyMaterial <encrypted-key-material> \
--ImportToken <import-token> \
--KeyMaterialExpireUnix <expire-unix-timestamp>Import key material using KMS SDK
All SDK examples follow the same sequence: create an external CMK → get import parameters → decode the Base64-encoded public key → encrypt key material locally → encode the encrypted material in Base64 → call ImportKeyMaterial.
Authenticate using environment variables rather than hardcoding credentials in your application code. Set ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET before running the examples.
Your AccessKey pair grants access to all API operations in your account. Use a RAM user with the minimum required permissions instead of the root account's AccessKey pair. For more information, see Manage access credentials and Configure environment variables in Linux, macOS, and Windows.
Java
// KmsClient.java
import com.aliyuncs.kms.model.v20160120.*;
import com.aliyuncs.profile.DefaultProfile;
public class KmsClient {
DefaultAcsClient client;
public KmsClient(String region_id, String ak, String secret) {
DefaultProfile profile = DefaultProfile.getProfile(region_id, ak, secret);
this.client = new DefaultAcsClient(profile);
}
public CreateKeyResponse createKey() throws Exception {
CreateKeyRequest request = new CreateKeyRequest();
request.setOrigin("EXTERNAL"); // Create an external CMK.
return this.client.getAcsResponse(request);
}
// Other operations follow the same pattern.
}
// example.java
import com.aliyuncs.kms.model.v20160120.*;
import KmsClient;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.MGF1ParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource.PSpecified;
import java.security.spec.X509EncodedKeySpec;
import java.util.Random;
import javax.xml.bind.DatatypeConverter;
public class CreateAndImportExample {
public static void main(String[] args) {
String regionId = "cn-hangzhou";
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
KmsClient kmsclient = new KmsClient(regionId, accessKeyId, accessKeySecret);
try {
// Step 1: Create an external CMK.
CreateKeyResponse keyResponse = kmsclient.createKey();
String keyId = keyResponse.KeyMetadata.getKeyId();
// Step 2: Generate 32 bytes of random key material.
byte[] keyMaterial = new byte[32];
new Random().nextBytes(keyMaterial);
// Step 3: Get import parameters.
GetParametersForImportResponse paramResponse =
kmsclient.getParametersForImport(keyId, "RSAES_OAEP_SHA_256");
String importToken = paramResponse.getImportToken();
String encryptPublicKey = paramResponse.getPublicKey();
// Step 4: Decode the Base64-encoded wrapping public key.
byte[] publicKeyDer = DatatypeConverter.parseBase64Binary(encryptPublicKey);
KeyFactory keyFact = KeyFactory.getInstance("RSA");
X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyDer);
PublicKey publicKey = keyFact.generatePublic(spec);
// Step 5: Encrypt the key material using RSAES_OAEP_SHA_256.
Cipher oaepFromAlgo = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
String hashFunc = "SHA-256";
OAEPParameterSpec oaepParams = new OAEPParameterSpec(
hashFunc, "MGF1", new MGF1ParameterSpec(hashFunc), PSpecified.DEFAULT);
oaepFromAlgo.init(Cipher.ENCRYPT_MODE, publicKey, oaepParams);
byte[] cipherDer = oaepFromAlgo.doFinal(keyMaterial);
// Step 6: Encode the encrypted key material in Base64.
String encryptedKeyMaterial = DatatypeConverter.printBase64Binary(cipherDer);
// Step 7: Import the key material.
// expireTimestamp: UNIX timestamp in seconds. Use 0 for no expiration.
Long expireTimestamp = 1546272000L;
kmsclient.importKeyMaterial(keyId, encryptedKeyMaterial, expireTimestamp);
} catch (Exception e) {
// Handle exceptions.
}
}
}Go
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"fmt"
"log"
"os"
random "math/rand"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/services/kms"
)
// kmsCreateKey creates an external CMK and returns its key ID.
func kmsCreateKey(client *kms.Client) (string, error) {
request := kms.CreateCreateKeyRequest()
request.Scheme = "https"
request.Origin = "EXTERNAL"
response, err := client.CreateKey(request)
if err != nil {
return "", fmt.Errorf("CreateKey error: %v", err)
}
return response.KeyMetadata.KeyId, nil
}
// kmsGetParametersForImport returns the Base64-encoded wrapping public key and import token.
func kmsGetParametersForImport(client *kms.Client, keyId, wrappingKeySpec, wrappingAlgorithm string) (string, string, error) {
request := kms.CreateGetParametersForImportRequest()
request.Scheme = "https"
request.KeyId = keyId
request.WrappingKeySpec = wrappingKeySpec
request.WrappingAlgorithm = wrappingAlgorithm
response, err := client.GetParametersForImport(request)
if err != nil {
return "", "", fmt.Errorf("GetParametersForImport error: %v", err)
}
return response.PublicKey, response.ImportToken, nil
}
// kmsImportKeyMaterial imports Base64-encoded encrypted key material into the specified CMK.
func kmsImportKeyMaterial(client *kms.Client, keyId, importToken, encryptedKeyMaterial string) error {
request := kms.CreateImportKeyMaterialRequest()
request.Scheme = "https"
request.KeyId = keyId
request.ImportToken = importToken
request.EncryptedKeyMaterial = encryptedKeyMaterial
_, err := client.ImportKeyMaterial(request)
if err != nil {
return fmt.Errorf("ImportKeyMaterial error: %v", err)
}
return nil
}
func randBytes(n int) []byte {
r := random.New(random.NewSource(time.Now().UnixNano()))
bytes := make([]byte, n)
for i := range bytes {
bytes[i] = byte(r.Intn(256))
}
return bytes
}
func main() {
accessKeyId := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
accessKeySecret := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
regionId := "cn-hangzhou"
client, err := kms.NewClientWithAccessKey(regionId, accessKeyId, accessKeySecret)
if err != nil {
log.Fatalf("NewClientWithAccessKey error: %+v", err)
}
// Step 1: Create an external CMK.
keyId, err := kmsCreateKey(client)
if err != nil {
log.Fatalf("kmsCreateKey error: %+v", err)
}
// Step 2: Generate 32 bytes of random key material.
// In production, generate key material in your own key management system.
keyMaterial := randBytes(32)
// Step 3: Get import parameters.
encryptPublicKey, importToken, err := kmsGetParametersForImport(
client, keyId, "RSA_2048", "RSAES_OAEP_SHA_256")
if err != nil {
log.Fatalf("kmsGetParametersForImport error: %v", err)
}
// Step 4: Decode the Base64-encoded wrapping public key.
publicKeyDer, err := base64.StdEncoding.DecodeString(encryptPublicKey)
if err != nil {
log.Fatalf("base64 decode error: %v", err)
}
publicKey, err := x509.ParsePKIXPublicKey(publicKeyDer)
if err != nil {
log.Fatalf("x509.ParsePKIXPublicKey error: %v", err)
}
// Step 5: Encrypt the key material.
cipherDer, err := rsa.EncryptOAEP(
sha256.New(), rand.Reader, publicKey.(*rsa.PublicKey), keyMaterial, nil)
if err != nil {
log.Fatalf("rsa.EncryptOAEP error: %v", err)
}
// Step 6: Encode the encrypted key material in Base64.
encryptedKeyMaterial := base64.StdEncoding.EncodeToString(cipherDer)
// Step 7: Import the key material.
if err := kmsImportKeyMaterial(client, keyId, importToken, encryptedKeyMaterial); err != nil {
log.Fatalf("kmsImportKeyMaterial error: %v", err)
}
}What's next
To verify the key material source of an existing CMK, call DescribeKey and check
KeyMetadata.Origin. A value ofAliyun_KMSindicates a regular CMK;EXTERNALindicates an external CMK.To delete key material, call DeleteKeyMaterial.
For CMK alias management, see Overview.
For symmetric CMK types, see Overview.