You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Node.js中解密AWS RDS Aurora活动流数据?

问题

已启用AWS RDS Aurora MySQL集群活动流,通过Kinesis发布活动数据,采用客户管理的KMS密钥加密。在Node.js运行时的Lambda函数中接收记录,每条记录包含经加密并base64编码的databaseActivityEvents和dataKey字段。

根据AWS文档,解密databaseActivityEvents需四步:

  1. 使用启动活动流时指定的KMS密钥解密dataKey字段,得到明文数据加密密钥;
  2. 对databaseActivityEvents字段进行base64解码,获取二进制格式的审计负载密文;
  3. 用第一步得到的数据加密密钥解密该二进制密文;
  4. 解压解密后的负载。

目前已完成第一步和第二步,但第三步始终无法完成。由于数据格式遵循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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 07:52:28