AWS Lambda 返回权限被拒绝尝试从 S3 存储桶获取对象

Posted

技术标签:

【中文标题】AWS Lambda 返回权限被拒绝尝试从 S3 存储桶获取对象【英文标题】:AWS Lambda returns permission denied trying to GetObject from S3 bucket 【发布时间】:2019-07-08 11:22:54 【问题描述】:

我确实创建了一个 lambda 函数,该函数应该在将文件上传到 S3 存储桶中时将数据上传到 DynamoDB。但是,当文件上传到存储桶中时,我在 CloudWatch 中收到“GetObject 操作:权限被拒绝”。 lambda 函数附加了一个 IAM 角色,以及这些策略:AmazonlambdaFullAccess、AmazonS3FullAccess、AmazonCloudWatchLogsFullAccess、AmazonDynamoDBFullAccess。它有 lambda.amazonaws.com 作为受信任的实体。 该存储桶没有附加任何策略。

 import boto3
 import json
 import urllib

 dynamodb = boto3.resource('dynamodb')
 table = dynamodb.Table('wireshark')
 s3 = boto3.client('s3')
 tests3 = boto3.resource(u's3')

 def lambda_handler(event, context):

     source_bucket = event['Records'][0]['s3']['bucket']['name']
     key = urllib.parse.quote_plus(event['Records'][0]['s3']['object']['key'])
    copy_source = 'Bucket':source_bucket , 'Key':key
    print(event)
    print("Log stream name : ", context.log_stream_name)
    print("Log group name : ", context.log_group_name)
    print("Request Id:", context.aws_request_id)
    print("Mem. limit(MB): ", context.memory_limit_in_mb)

    #just print function
    print("Log stream name : ", context.log_stream_name)
    print("Log group name : ", context.log_group_name)
    print("Request Id:", context.aws_request_id)
    print("Mem. limit(MB): ", context.memory_limit_in_mb)

    try:
        print("Using waiter to waiting for object to persist thru s3 service")
        waiter = s3.get_waiter('object_exists')
        waiter.wait(Bucket=source_bucket, Key=key)
        print("Accessing the receied file and reading the same")
        bucket = tests3.Bucket(u'awslambdas3test2')
        obj = bucket.Object(key=key)
        response = obj.get()
        print("response from file object")
        print(response)

在 Cloudwatch 中:调用 GetObject 操作时发生错误 (AccessDenied):访问被拒绝。 我已经通过 aws 的“策略模拟器”。此 IAM 角色应该能够从任何 S3 存储桶获取对象。 感谢您的帮助。

代码大多来自GitHub。

【问题讨论】:

哪一行产生了错误?您可能需要删除 try 才能找到答案。 bucket = tests3.Bucket(u'awslambdas3test2') 行是对存储桶名称的硬编码。它应该真正使用source_bucket。假设这不是问题,您可以尝试在 Lambda 控制台中测试该函数,方法是使用带有实际存储桶和密钥的 Amazon S3 Put 测试事件。此外,应该不需要使用服务员,因为调用函数时对象将可用。 产生错误的行是 response=obj.get。问题是,文件名不是问题,因为我确实打印了变量“key”,它打印了我要访问的文件的名称。我进行了 Amazon S3 Put 测试,但被拒绝了权限。如上所述,lambda 函数具有对 S3 的完全访问权限,并且存储桶没有任何策略,所以我不明白为什么拒绝权限。 存储桶所有者可能无法访问放置在 Amazon S3 存储桶中的对象,特别是如果该对象是从另一个账户复制并保留相同权限的情况下。您可以使用 AWS CLI 通过aws s3 cp 访问该文件吗? 是的,我已经能够使用 AWS CLI 将文件从存储桶复制到本地存储。我尝试使用另一个 IAM 角色创建另一个 lambda,但仍然无法正常工作。 【参考方案1】:

这是一个将打印文件内容的 AWS Lambda 函数:

import boto3
import os

def lambda_handler(event, context):

    s3_client = boto3.client('s3')

    # For each record

    for record in event['Records']:

        # Get Bucket and Key
        bucket = record['s3']['bucket']['name']
        key    = record['s3']['object']['key']

        # Print the bucket & key to the logs
        print(bucket, key)

        # Download object
        local_filename = '/tmp/' + key
        s3_client.download_file(bucket, key, local_filename)

        # Print contents to log (just to demonstrate concept)
        for line in open(local_filename):
            print(line)

        # Delete file when done, to clear space for future execution
        os.remove(local_filename)

在存储桶上创建一个 Amazon S3 事件以触发此 Lambda 函数,它将文件名和文件内容打印到 CloudWatch Logs。这应该是一个很好的测试,可以确定程序是使用您的代码还是使用权限。

【讨论】:

您提供的 lambda 函数可以读取该文件。看起来问题确实来自函数,但我无法弄清楚问题是什么。 你确定不是bucket = tests3.Bucket(u'awslambdas3test2')中硬编码的桶名吗? 我以为我改变了它,但显然没有,所以它现在有点工作。 “print(response)”行返回“expected str, bytes or os.PathLike object, not dict”。我尝试使用 CSV 文件进行测试,它成功了,但我不明白为什么 python 文件会出现问题。 Object.get() 返回结果字典,包括LastModifiedVersionid 之类的内容。如果您想要对象的内容,请使用Object.get()['Body']。请参阅文档:Object.get()

以上是关于AWS Lambda 返回权限被拒绝尝试从 S3 存储桶获取对象的主要内容,如果未能解决你的问题,请参考以下文章

在不同账户的 Lambda 中从 AWS Athena 查询 S3 文件时访问被拒绝

AWS Lambda S3 访问被拒绝

为啥我的 lambda 函数在尝试访问 S3 存储桶时会被拒绝访问?

当从 s3 获取对象时,aws lambda 函数被拒绝访问

AWS Glue 无法从爬虫创建数据库:权限被拒绝

terraform/aws lambda 函数访问在 s3 上被拒绝