AWS RDS数据库活动事件经Kinesis Data Stream传输至Lambda后的解密失败问题求助
问题概述
我正尝试解密从AWS RDS流到Kinesis再到Lambda函数的databaseActivityEvents数据,但无论怎么调整代码,解密操作始终返回InvalidCiphertextException: null错误,实在找不到问题所在,希望能得到大家的帮助。
背景与已完成操作
我已经完成了以下资源的配置,且整体数据流是通的:
- 创建了新的Aurora数据库集群
- 在KMS中创建了采用
SYMMETRIC_DEFAULT类型的客户托管密钥 - 使用上述KMS密钥创建了Kinesis数据流,并将其关联到Aurora集群,用于接收数据库活动事件
- 创建了Lambda函数,由Kinesis数据流触发,目前能正常收到包含数据库事件(多为心跳)的JSON格式
event数据
当前现象与代码尝试
1. 收到的Kinesis事件示例(脱敏处理后)
{ "Records": [ { "kinesis": { "kinesisSchemaVersion": "1.0", "partitionKey": "05841e02-874c-4628-b79e-1dcd5d73b256", "sequenceNumber": "49639037278219440985425171458121310232781924676881350674", "data": "eyJ0eXBlIjogIkRhdGFiYXNlQWN0aXZpdHlNb25pdG9yaW5nUmVjb3JkcyIsInZlcnNpb24iOiAiMS4yIiwiZGF0YWJhc2VBY3Rpdml0eUV2ZW50cyI6ICJBWUFEZUNiRTkzekFoU1ZXL2dBblRCSUdEeUFBWHdBQkFCVmhkM010WTNKNWNIUnZMWEIxWW14cFl5MXJaWGtBUkVGeVZta3lWMmxNT1ZSMVJtNXVlVlpMZURsb2MxWllMMWQyYjBwSFdWcDZjVEJOTjBSV1ptUnlRemNyV0dGTE5VWk5ia2wwYjNsT1dUQTRXbTUwTVhaUVFUMDlBQUVBQWtKREFCdEVZWFJoUzJWNUFBQUFnQUFBQUF6MHpuWU9FemV5VGczSWlkZ0FNUHlJTnVRbWJuQmpnMkRZNWt0TEx2WGM0cG5jejlqUkFTcTdZNldDVUxURHpnWkFRYnA2M0hlcmNYL1h1SzdZQkFJQUFBQUFEQUFFQUFBQUFBQUFBQUFBQUFBQUFBQkxubCsxWjZpaWVNTG1Pa21TSS80SC8vLy8vd0FBQUFFQUFBQUFBQUFBQUFBQUFBRUFBQUg2Qkx1czJ3ZEZxelk0cmpENWdaVDQwL21GNEQxbGxabTR3MkJxR2RMN3AwcVg3OXc0TStnVmNLU0FTNWRWb0N5OHFBVlpYRmx3YytKcVZjeWZ4bTdYOHhGL092Q1J5eE5sV2V5NGlKMjlpTU9JTlRLTWRreU84TWlsTm9NOHlmVk9Pb3FudkpBZ0U1Y1VUZjRyVm84WmRpdjBmQ0Q4NWdjUDZUMERRNTlycVNWQmYzQTdtbitHaUZ2LzQ0U1RzbGNwOERzKzFoS3BtYWx0YkxLTnkzN2dEd01IY2ZmbElkeE02S3Y5c1grMUNDdUthdVZ4R3VuM0t1T2MyQnFIQ0lnVGp0enhMMmR6OVpMLytpd1RaZk01cDZCaGlpTDZ0eExTbzBVRSt0NVNZa1pjZ2JRNThlSWozdktlenBnR0FYVXlSTkJDbzdXVkxObVpWQWRnQjJmdUdyaTIzL0phN3dOOEdQcnQ0bEpUdEVTdmJITGE5cUQ4em9JY0krVFcrS1pnMFl0MzVpWjZkaVNOcUdUQUVJcmkxdzVCSjFHaldoNnVHdHl0UGJteElPRkxOUHpLTXE2N2R0dXlLNlVTOFoxRXVzQ3dRQWpqQWVhQ0Nid2J1NDFkblRHMU1KYUI0R1I2Z3RGTDBURjMwdnpBMm1JVmwvZWVDRWdXOHEyQUJqNWV5VXB1UUNlRjRjUjNWUHR2REJnL2VyVjVyeFdVTUxCRGdFZTBkTlpBYWhjVkIzYStyLzBZUmhMVGZCZmoxcHQzcDg2L2JzTlg4a1VqRlBmY1ZLc3B0S2g3Z0twV3ZHZVZpNkxJUGpST1hjNjQ4cW5KYUh1UnV0L3lIY3lqN0VVN1IzdXNweTlhZzlLL1JlcHZXeTlxdGIyUmNLWk1HQjg3Q205eUJtZktyeEVKY25rbWpMTjJORjJ0QUdjd1pRSXhBS1VVbTJFeUExNUNPMzdTYTJpcHA2d3Nvc2xQcVNhRUZlMENRL3VjcnVaeUdIa3Y0c1VxWTRUdXhWa1puN0pUVEFJd1h6YmdYdE1YRldhMnh4U3ZBajhVUDFjVVBRZ2JUeWVTVzNCL244akNadXgwUnY0SWVrT0Y3V2htWnlzSjBISXkiLCJrZXkiIDogIkFRSURBSGhxV0dDdm45b2NQMVJ1a3pFS0xQald6T1ZMNkFzeTRSMllTbkZQNDdTT3l3RzNGMXd2VGhTUDJtTHk5RTBOS1VFcEFBQUFmakI4QmdrcWhraUc5dzBCQndhZ2J6QnRBZ0VBTUdnR0NTcUdTSWIzRFFFSEFUQWVCZ2xnaGtnQlpRTUVBUzR3RVFRTTJ6SWlEdUI5MWVpOUl6ekNBZ0VRZ0R1VDh5REhDWjB3THFjVjVQa25rYy9DZ0lvSmg5U1hxclBkeHBRRHhoMmYxVnJXeGRIdktsNDR0Zjg5QkJpMzlNWXVib1hJRDlzQTRGMkdWZz09In0=", "approximateArrivalTimestamp": 1679260829.009 }, "eventSource": "aws:kinesis", "eventVersion": "1.0", "eventID": "shardId-000000000001:49639037278219440985425171458121310232781924676881350674", "eventName": "aws:kinesis:record", "invokeIdentityArn": "arn:aws:iam::767437170311:role/lambda-admin", "awsRegion": "us-east-1", "eventSourceARN": "arn:aws:kinesis:us-east-1:767437170311:stream/aws-rds-das-cluster-6KXUII5RDIBDAE6U7EQLZST2YI" } ] }
2. 解码Kinesis数据的代码
我先对Kinesis的data字段进行Base64解码并解析为JSON:
const raw = Buffer.from(record.kinesis.data, 'base64').toString('ascii') const json = JSON.parse(raw)
解码后的JSON结构如下:
{ type: 'DatabaseActivityMonitoringRecords', version: '1.2', databaseActivityEvents: 'AYADeCbE93zAhSVW/gAnTBIGDyAAXwABABVhd3MtY3J5cHRvLXB1YmxpYy1rZXkAREFyVmkyV2lMOVR1Rm5ueVZLeDloc1ZYL1d2b0pHWVp6cTBNN0RWZmRyQzcrWGFLNUZNbkl0b3lOWTA4Wm50MXZQQT09AAEAAkJDABtEYXRhS2V5AAAAgAAAAAz0znYOEzeyTg3IidgAMPyINuQmbnBjg2DY5ktLLvXc4pncz9jRASq7Y6WCULTDzgZAQbp63HercX/XuK7YBAIAAAAADAAEAAAAAAAAAAAAAAAAAABLnl+1Z6iieMLmOkmSI/4H/////wAAAAEAAAAAAAAAAAAAAAEAAAH6BLus2wdFqzY4rjD5gZT40/mF4D1llZm4w2BqGdL7p0qX79w4M+gVcKSAS5dVoCy8qAVZXFlwc+JqVcyfxm7X8xF/OvCRyxNlWey4iJ29iMOINTKMdkyO8MilNoM8yfVOOoqnvJAgE5cUTf4rVo8Zdiv0fCD85gcP6T0DQ59rqSVBf3A7mn+GiFv/44STslcp8Ds+1hKpmaltbLKNy37gDwMHcfflIdxM6Kv9sX+1CCuKauVxGun3KuOc2BqHCIgTjtzxL2dz9ZL/+iwTZfM5p6BhiiL6txLSo0UE+t5SYkZcgbQ58eIj3vKezpgGAXUyRNBCo7WVLNmZVAdgB2fuGri23/Ja7wN8GPrt4lJTtESvbHLa9qD8zoIcI+TW+KZg0Yt35iZ6diSNqGTAEIri1w5BJ1GjWh6uGtytPbmxIOFLNPzKMq67dtuyK6US8Z1EusCwQAjjAeaCCbwbu41dnTG1MJaB4GR6gtFL0TF30vzA2mIVl/eeCEgW8q2ABj5eyUpuQCeF4cR3VPtvDBg/erV5rxWUMLBDgEe0dNZAahcVB3a+r/0YRhLTfBfj1pt3p86/bsNX8kUjFPfcVKsptKh7gKpWvGeVi6LIPjROXc648qnJaHuRut/yHcyj7EU7R3uspy9ag9K/RepvWy9qtb2RcKZMGB87Cm9yBmfKrxEJcnkmjLN2NF2tAGcwZQIxAKUUm2EyA15CO37Sa2ipp6wsoslPqSaEFe0CQ/ucruZyGHkv4sUqY4TuxVkZn7JTTAIwXzbgXtMXFWa2xxSvAj8UP1cUPQgbTyeSW3B/n8jCZux0Rv4IekOF7WhmZysJ0HIy', key: 'AQIDAHhqWGCvn9ocP1RukzEKLPjWzOVL6Asy4R2YSnFP47SOywG3F1wvThSP2mLy9E0NKUEpAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM2zIiDuB91ei9IzzCAgEQgDuT8yDHCZ0wLqcV5Pknkc/CgIoJh9SXqrPdxpQDxh2f1VrWxdHvKl44tf89BBi39MYuboXID9sA4F2GVg==' }
3. 解密尝试的代码(报错)
我尝试用以下代码解密databaseActivityEvents字段,但始终抛出InvalidCiphertextException:
const databaseActivityEvents = Buffer.from(json.databaseActivityEvents, 'base64') const params = { KeyId: "c4d1dc19-ce04-4568-9863-d80ec0ff4c58", CiphertextBlob: databaseActivityEvents, EncryptionContext: { "aws:rds:dbc-id": "cluster-DFGNFSATIUGUYQA5DDCCJWTXCQ" } } const results = await kms.decrypt(params).promise() console.log(results.Plaintext.toString('ascii'))
我试过包含或不包含EncryptionContext参数,结果都一样。
4. 正常运行的加密解密测试代码
为了验证KMS密钥和Lambda权限没问题,我写了一段测试代码,能正常完成加密和解密:
// 加密测试 let params = { KeyId: "c4d1dc19-ce04-4568-9863-d80ec0ff4c58", Plaintext: 'Test Ecrypt Me', EncryptionContext: { "Test": "EncryptionContext123" } } let results = await kms.encrypt(params).promise() console.log(results.CiphertextBlob) // 解密测试 params = { KeyId: "c4d1dc19-ce04-4568-9863-d80ec0ff4c58", CiphertextBlob: results.CiphertextBlob, EncryptionContext: { "Test": "EncryptionContext123" } } results = await kms.decrypt(params).promise() console.log(results.Plaintext.toString('ascii'))
这段代码能正常输出加密后的Buffer和明文Test Ecrypt Me,说明KMS密钥本身和Lambda的KMS权限是正常的。
我的困惑
- 我不知道Kinesis在传输数据时是否设置了EncryptionContext,也不清楚该如何查看它的具体值
- 已经排查了密钥权限和基本的编码处理,还是找不到解密失败的原因
求助问题
请问我该如何正确解密databaseActivityEvents字段,以获取RDS实例的更新记录?
可能的解决方案
根据你的情况,我整理了几个可能的排查方向和解决方法:
确认EncryptionContext的正确值
RDS在加密数据库活动流时,使用的EncryptionContext固定键为aws:rds:dbc-id,但值应该是数据库集群的资源ID,而不是你当前使用的集群名称。你可以通过以下方式获取:- AWS控制台:进入RDS集群详情页,查看“配置”标签下的“资源ID”
- AWS CLI:执行
aws rds describe-db-clusters --db-cluster-identifier <你的集群名称>,查看返回结果中的DbClusterResourceId字段
把这个资源ID替换到EncryptionContext的值中再尝试解密。
移除解密参数中的KeyId
解码后的JSON中的key字段是RDS用来加密数据的数据密钥(Data Key),KMS会自动通过这个数据密钥关联到对应的主密钥,所以解密时不需要手动指定KeyId参数,只需要传入CiphertextBlob和正确的EncryptionContext即可。检查KMS密钥的密钥策略
确保你的Lambda角色的ARN被添加到KMS密钥的密钥策略中,拥有kms:Decrypt权限。你可以在KMS控制台的密钥详情页“密钥策略”标签中查看和修改。确认数据处理没有额外编码错误
你当前对databaseActivityEvents的Base64解码是正确的,但可以再确认一下转换后的Buffer是否和原始密文一致,避免在解码过程

