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

使用Python Lambda+KMS加密S3视频文件并转存时遇错求排查

问题排查与修正

1. 直接触发的KeyError原因

你的代码尝试从response['ResponseMetadata']['HTTPHeaders']['x-amz-server-side-encryption-aws-kms-key-id']获取KMS密钥ID,但这个字段仅在原S3对象使用SSE-KMS加密存储时才会存在。如果原对象未加密或使用其他加密方式(如SSE-S3),该字段不存在,直接访问会抛出KeyError。

另外,即使原对象用了SSE-KMS,AWS SDK也提供了更可靠的字段获取密钥ID:response['SSEKMSKeyId'],而非从HTTP响应头提取。

2. 核心逻辑错误

你的需求是将视频转存到另一个S3桶并通过KMS加密,但当前代码逻辑存在问题:

  • 一次性将原S3对象的明文读入内存(若原对象是SSE-KMS加密,S3会自动解密返回明文),视频文件通常较大,易导致Lambda内存溢出
  • 调用KMSencrypt API加密整个文件内容,属于客户端加密,后续读取需手动调用KMSdecrypt API,无法被S3兼容工具直接处理

如果你的真实需求是让目标桶对象通过S3服务端KMS加密存储(即SSE-KMS),无需手动调用KMS加密API,只需在上传时指定加密参数即可,S3会自动完成加密,更高效安全。

3. 修正后的代码(推荐:S3服务端SSE-KMS加密)

采用流式传输避免内存溢出,直接让S3完成服务端加密:

import boto3
from botocore.exceptions import ClientError

def lambda_handler(event, context):
    s3_client = boto3.client('s3')
    
    # 解析S3事件
    s3_event = event['Records'][0]['s3']
    source_bucket = s3_event['bucket']['name']
    object_key = s3_event['object']['key']
    target_bucket = 'decryptedfiles'  # 注:桶名与加密转存的需求不符,建议改为encryptedfiles更合理
    
    try:
        # 获取原对象流式数据
        response = s3_client.get_object(Bucket=source_bucket, Key=object_key)
        
        # 上传到目标桶并指定SSE-KMS加密
        s3_client.put_object(
            Bucket=target_bucket,
            Key=object_key,
            Body=response['Body'],  # 流式传输,避免内存溢出
            ServerSideEncryption='aws:kms',
            # 可指定自定义KMS密钥ARN,不指定则用S3默认KMS密钥
            # SSEKMSKeyId='your-kms-key-arn'
        )
        print(f"对象 {object_key} 已成功加密转存到 {target_bucket}")
    except ClientError as e:
        print(f"操作失败: {e.response['Error']['Message']}")
        raise e

4. 若坚持使用客户端加密(不推荐,仅适合小文件)

解决内存和密钥获取问题的示例代码:

import boto3
from botocore.exceptions import ClientError

def lambda_handler(event, context):
    s3_client = boto3.client('s3')
    kms_client = boto3.client('kms')
    
    s3_event = event['Records'][0]['s3']
    source_bucket = s3_event['bucket']['name']
    object_key = s3_event['object']['key']
    target_bucket = 'decryptedfiles'
    # 建议手动指定KMS密钥ARN,而非依赖原对象密钥
    kms_key_id = 'your-kms-key-arn'

    try:
        # 读取原对象数据(仅适合小文件)
        response = s3_client.get_object(Bucket=source_bucket, Key=object_key)
        plaintext_data = response['Body'].read()
        
        # KMS加密数据
        encrypted_response = kms_client.encrypt(
            Plaintext=plaintext_data,
            KeyId=kms_key_id
        )
        encrypted_data = encrypted_response['CiphertextBlob']
        
        # 上传加密后的数据
        s3_client.put_object(
            Bucket=target_bucket,
            Key=object_key,
            Body=encrypted_data
        )
        print(f"对象 {object_key} 已成功客户端加密并上传")
    except KeyError as e:
        print(f"密钥ID获取失败: {e}")
        raise e
    except ClientError as e:
        print(f"操作失败: {e.response['Error']['Message']}")
        raise e

5. 必要的权限配置

Lambda执行角色需添加以下权限:

  • s3:GetObject(源桶)
  • s3:PutObject(目标桶)
  • 使用SSE-KMS时:kms:GenerateDataKey(对应KMS密钥)
  • 使用客户端加密时:kms:Encrypt(对应KMS密钥)

内容的提问来源于stack exchange,提问作者Aishwarya Joshi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 20:13:11