如何修复AWS KMS解密时unencryptedDataKey has not been set报错
问题现象
基于AWS官方教程使用AWS KMS服务,通过AWS Management Console中已配置完成的Master Key实现数据加密,加密流程可正常运行,但解密生成的密文时抛出错误:unencryptedDataKey has not been set。
复现代码
密钥环初始化逻辑
const generatorKeyId = 'arn:aws:kms:eu-central-1:51426*****:alias/my-key'; const keyIds = []; const keyring = new KmsKeyringNode({ generatorKeyId, keyIds }); console.log(keyring);
运行后打印的KmsKeyringNode实例内容如下:
KmsKeyringNode { clientProvider: [Function (anonymous)], keyIds: [], generatorKeyId: 'arn:aws:kms:eu-central-1:51426*****:alias/my-key', grantTokens: undefined, isDiscovery: false, discoveryFilter: undefined }
加密逻辑
const context = { stage: 'demo', purpose: 'simple demonstration app', origin: 'eu-central-1', }; /* 待加密明文字符串 */ const cleartext = 'my-cypher-teststring'; const { encrypt, decrypt } = buildClient(CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT); const { result } = await encrypt(keyring, cleartext, { encryptionContext: context }); console.log("RESULT", result)
加密流程运行后控制台输出:
RESULT <Buffer 02 05 78 02 4b 48 c9 96 75 f8 08 5e 33 d0 91 18 67 51
31 4c 7a 9d a9 ac bd df e
解密逻辑
const { plaintext, messageHeader } = await decrypt(keyring, result); console.log("Plaintext", plaintext) console.log("MessageHeader", messageHeader)
执行解密时抛出异常栈如下:
Error AM [ExceptionsHandler] unencryptedDataKey has not been set - { stack: [ 'Error: unencryptedDataKey has not been set\n' + ' at needs (/Users/xxxxx/xxxx/node_modules/@aws-crypto/material-management/src/needs.ts:21:11)\n' + ' at NodeDecryptionMaterial.getUnencryptedDataKey (/Users/xxxx/xxxx/node_modules/@aws-crypto/material-management/src/cryptographic_material.ts:417:10)\n' + ' at NodeDefaultCryptographicMaterialsManager.decryptMaterials (/Users/xxxxxx/yyyyyy/node_modules/@aws-crypto/material-management-node/src/node_cryptographic_materials_manager.ts:109:20)\n' + ' at processTicksAndRejections (node:internal/process/task_queues:96:5)' ] }
根因分析
该错误本质是解密流程中,密钥环没能从KMS服务拿到解密后的明文数据密钥,常见触发原因有三个:
- 初始化
KmsKeyringNode时未显式指定KMS客户端,默认凭证链加载的身份/默认区域配置和密钥所在区域不匹配,或者身份没有对应KMS密钥的解密权限,导致调用KMS解密数据密钥失败。 - 传入解密方法的密文存在截断、损坏:比如直接将二进制Buffer转UTF-8字符串导致二进制数据丢失,或者存储/传输过程中密文被截断,无法解析出加密后的数据密钥字段。
- 加密时配置的
encryptionContext与解密时传入的上下文不匹配,KMS会拒绝解密数据密钥请求,最终拿不到明文数据密钥。
修复方案
按以下步骤逐一排查修复:
- 显式初始化和密钥同区域的KMS客户端,传入密钥环构造函数,避免默认配置匹配错误:
const { KMSClient } = require("@aws-sdk/client-kms"); // 配置和KMS密钥一致的区域 const kmsClient = new KMSClient({ region: "eu-central-1", // 本地调试可临时配置凭证,生产环境请使用云资源绑定的IAM角色,不要硬编码密钥 // credentials: { // accessKeyId: "你的访问密钥ID", // secretAccessKey: "你的访问密钥" // } }); const generatorKeyId = 'arn:aws:kms:eu-central-1:51426*****:alias/my-key'; const keyring = new KmsKeyringNode({ generatorKeyId, keyIds: [], clientProvider: () => kmsClient }); - 校验运行环境绑定的IAM身份权限:无论是本地调试的用户身份,还是云上EC2/Lambda/ECS绑定的IAM角色,都需要具备目标KMS密钥的以下权限,同时KMS密钥自身的资源策略要允许该身份执行对应操作:
kms:Encryptkms:Decryptkms:GenerateDataKey
- 校验密文完整性:如果密文需要存储或跨服务传输,不要直接将Buffer转成UTF-8字符串,要转成Base64编码,解密前再解码回Buffer,避免二进制数据损坏:
// 加密后转Base64存储/传输 const encryptedBase64 = result.toString("base64"); // 解密前先转回原始Buffer const ciphertext = Buffer.from(encryptedBase64, "base64"); const { plaintext } = await decrypt(keyring, ciphertext); - 如果解密时显式传入
encryptionContext参数,必须保证和加密时传入的键值对完全一致,键名、值、大小写都不能有差异。
内容的提问来源于stack exchange,提问作者MrsBookik
相关产品推荐
相关产品推荐

