如何在Node.js中解密AWS RDS Aurora活动流数据?
问题
已启用AWS RDS Aurora MySQL集群活动流,通过Kinesis发布活动数据,采用客户管理的KMS密钥加密。在Node.js运行时的Lambda函数中接收记录,每条记录包含经加密并base64编码的databaseActivityEvents和dataKey字段。
根据AWS文档,解密databaseActivityEvents需四步:
- 使用启动活动流时指定的KMS密钥解密
dataKey字段,得到明文数据加密密钥; - 对
databaseActivityEvents字段进行base64解码,获取二进制格式的审计负载密文; - 用第一步得到的数据加密密钥解密该二进制密文;
- 解压解密后的负载。
目前已完成第一步和第二步,但第三步始终无法完成。由于数据格式遵循AWS加密SDK规范,无法直接使用Node.js原生crypto包处理,需借助官方AWS SDK实现。尝试过KmsKeyringNode和RawAesKeyringNode,分别报“Malformed resource.”和“unencryptedDataKey has not been set.”错误,因文档不足无法确定正确用法。
需要解决的问题:如何在Node.js中解密来自活动流的数据?
用户已实现的第一步解密dataKey代码:
import { KMSClient, DecryptCommand } from "@aws-sdk/client-kms" ... const encryptedData = data.databaseActivityEvents const encryptedKey = data.key const inputKms = { CiphertextBlob: new Buffer.from(encryptedKey, 'base64'), EncryptionContext: {'aws:rds:dbc-id': "cluster-[id]"}, } const client = new KMSClient({ region: "us-east-1" }) const kmsCommand = new DecryptCommand(inputKms) const kmsResponse = await client.send(kmsCommand) const decryptedKey = kmsResponse.Plaintext
尝试的KmsKeyringNode代码:
export async function decryptByKmsKeyring(encDataBase64: string, encDataKeyBase64: string) { const { decrypt } = buildClient(CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT) const keyring = new KmsKeyringNode({ generatorKeyId: 'arn:aws:kms:us-east-1:[account_id]:key/[key_id]', keyIds: [encDataKeyBase64] }) const result = await decrypt(keyring, Buffer.from(encDataBase64, 'base64')) console.log("plaintext:", result.plaintext) console.log("messageHeader:", result.messageHeader) return result }
尝试的RawAesKeyringNode代码:
export async function decryptRawAesKeyring(encDataBase64: string, key: Uint8Array) { const { decrypt } = buildClient(CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT) const wrappingSuite = RawAesWrappingSuiteIdentifier.AES256_GCM_IV12_TAG16_NO_PADDING const keyring = new RawAesKeyringNode({ keyName: "BC", keyNamespace: "aws-kms", wrappingSuite, unencryptedMasterKey: key }) const result = await decrypt(keyring, Buffer.from(encDataBase64, 'base64')) console.log("plaintext:", result.plaintext) console.log("messageHeader:", result.messageHeader) return result }
解决方案
问题核心是对AWS加密SDK密钥环的用法理解偏差,正确流程是用RawAesKeyringNode配合解密后的明文数据密钥,同时传递正确的加密上下文。以下是完整实现:
1. 安装依赖
确保已安装所需AWS SDK包:
npm install @aws-sdk/client-kms @aws-crypto/client-node
2. 完整解密代码
import { KMSClient, DecryptCommand } from "@aws-sdk/client-kms"; import { buildClient, CommitmentPolicy, RawAesKeyringNode, RawAesWrappingSuiteIdentifier } from "@aws-crypto/client-node"; import { createInflateRaw } from "zlib"; import { promisify } from "util"; // 把zlib的解压方法转为Promise格式 const inflateRaw = promisify(createInflateRaw); export async function decryptRdsActivityEvent(record) { // 解析Kinesis记录中的加密字段 const { databaseActivityEvents: encryptedDataBase64, key: encryptedDataKeyBase64 } = record; // 步骤1:KMS解密dataKey,得到明文数据加密密钥 const kmsClient = new KMSClient({ region: "us-east-1" }); const decryptKeyCmd = new DecryptCommand({ CiphertextBlob: Buffer.from(encryptedDataKeyBase64, "base64"), EncryptionContext: { "aws:rds:dbc-id": "cluster-[id]" } // 替换为你的集群ID }); const kmsRes = await kmsClient.send(decryptKeyCmd); const plaintextDataKey = kmsRes.Plaintext; // 步骤2:用AWS加密SDK解密数据库活动事件密文 const { decrypt } = buildClient(CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT); // 初始化RawAes密钥环,参数匹配RDS活动流的加密规则 const keyring = new RawAesKeyringNode({ keyName: "rds-activity-stream", // 自定义名称,保持唯一即可 keyNamespace: "aws-rds", // 自定义命名空间,解密时需一致 wrappingSuite: RawAesWrappingSuiteIdentifier.AES256_GCM_IV12_TAG16_NO_PADDING, unencryptedMasterKey: plaintextDataKey // 使用KMS解密后的明文密钥 }); // 解密时必须传入和加密时一致的加密上下文 const decryptResult = await decrypt(keyring, Buffer.from(encryptedDataBase64, "base64"), { encryptionContext: { "aws:rds:dbc-id": "cluster-[id]" } }); // 步骤3:解压解密后的明文数据 const decompressedData = await inflateRaw(decryptResult.plaintext); // 转换为JSON对象返回 return JSON.parse(decompressedData.toString()); }
关键说明
RawAesKeyringNode的keyName和keyNamespace可自定义,只要解密时保持一致即可,无需关联KMS密钥。- 加密上下文必须和启动活动流时的配置完全一致,否则解密会失败。
- RDS活动流的加密明文用原始deflate压缩,需用
zlib的inflateRaw方法解压。
错误原因分析
- 使用
KmsKeyringNode时错误将加密后的dataKey传入keyIds,该参数应为KMS密钥ARN列表,而非加密密钥数据。 - 使用
RawAesKeyringNode时未正确传递加密上下文,或密钥套件参数不匹配RDS的加密规则。
内容的提问来源于stack exchange,提问作者Safa Kadir
相关产品推荐
相关产品推荐

