预签名的POST URL在本地工作,但不在Lambda中工作

时间:2019-06-17 21:31:15

标签: amazon-web-services amazon-s3 aws-lambda boto3 boto

我有一些Python,可以请求一个预签名的POST URL将一个对象上传到S3存储桶中。它可以在具有Admin权限的IAM用户下在本地运行它,并且我可以使用Postman和cURL将内容上传到存储桶。但是,当尝试在Lambda中运行相同的代码时,它会显示“您提供的AWS Access Key ID在我们的记录中不存在。”

唯一的区别是Lambda函数在没有管理员权限的情况下运行(但确实具有允许其在存储桶上运行任何S3操作的策略),并且正在使用其他(较旧)的Boto3版本。

这是我要使用的代码:https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html#generating-a-presigned-url-to-upload-a-file

我尝试使用从Lambda函数返回的详细信息,与使用本地返回的详细信息完全相同,但是Lambda详细信息不起作用。

6 个答案:

答案 0 :(得分:1)

我遇到了同样的问题,这让我发疯了。在本地一切顺利,一旦部署到 lambda 中,我使用 create_presigned_post 或 create_presigned_url 得到 403。

事实证明 lambda 使用的角色与我的本地 aws 用户所拥有的角色不同。 (在我的例子中,lambda 角色是使用 AWS SAM 自动创建的)在授予 lambda 角色 S3 权限后,错误得到解决。

答案 1 :(得分:0)

好问题。您没有描述如何获取Lambda函数的凭据。您的代码,具体是这样:

s3_client = boto3.client('s3')

期望使用〜/ .aws / credentials文件查找默认凭据。您不会(也不应该)在Lambda执行环境中拥有该文件,但是您可能会在本地环境中拥有该文件。我怀疑您根本没有获得Lambda函数的凭据。

在Lambda中有两个选项可用于获取凭据。

  1. 不使用凭据,但对提供访问所需S3的Lambda函数使用IAM角色。这是最佳做法。如果执行此操作,则不需要凭据。这是最佳做法。
  2. 将凭据设置为lambda函数的环境变量。您可以直接定义AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY,然后上面的代码应将其选中并使用。

答案 2 :(得分:0)

这是100%可行的AWS Lambda解决方案

  1. 附加政策 AmazonS3FullAccess
  2. 使用分段/表单数据上传
  3. 配置S3 CORS
  4. 使用下一个python代码

    import uuid
    import boto3
    
    def lambda_handler(event, context):
    
    s3 = boto3.client('s3')
    
    upload_key = 'myfile.pdf'
    download_key = 'myfile.pdf'
    
    bucket = 'mys3storage'
    
    # Generate the presigned URL for download
    presigned_download_url = s3.generate_presigned_url(
        ClientMethod='get_object',
        Params={
            'Bucket': bucket,
            'Key': download_key,
            'Expires': 3600
        }
    )
    
    # Generate the presigned URL for upload
    presigned_upload_url = s3.generate_presigned_url(
        ClientMethod='put_object',
        Params={
            'Bucket': bucket,
            'Key': upload_key,
            'ContentType': 'application/pdf',
            'Expires': 3600
        }
    )
    
    # return the result
    return {
        "upload_url": presigned_upload_url
        "download_url": download_url
    }
    

答案 3 :(得分:0)

当您使用角色时,需要发布x-amz-security-token

答案 4 :(得分:0)

您可以尝试下面的代码来生成对象的预签名URL

import json
import boto3
from botocore.exceptions import ClientError

s3 = boto3.client('s3')
bucket = 'test1'
download_key = 'path/to/Object.txt'

def lambda_handler(event, context):
    try:
        response = s3.generate_presigned_url('get_object',Params={'Bucket': bucket,'Key': download_key},ExpiresIn=3600)
    except ClientError as e:
        logging.error(e)
        return None
    url = response
    print(url)
    return{
        'url' : url
    }

答案 5 :(得分:0)

Official python tutorial for this 没有在使用 lambda 函数时提及 x-amz-security-token ,但是在将文件上传到 S3 时需要将其作为表单值包含在内。所以总结一下,在使用 lambda 时,请确保附加到函数的角色具有 s3 访问权限,并且额外的表单字段存在 x-amz-security-token 值。

    <form action="URL HERE" method="post" enctype="multipart/form-data">
      <input type="hidden" name="key" value="KEY HERE" />
      <input type="hidden" name="AWSAccessKeyId" value="ACCESS KEY HERE" />

 <!-- ADD THIS ONE -->
  <input type="hidden" name="x-amz-security-token" value="SECURITY TOKEN HERE" />
 <!-- ADD THIS ONE -->
  
    <input type="hidden" name="policy" value="POLICY HERE" />
      <input type="hidden" name="signature" value="SIGNATURE HERE" />
    File:
      <input type="file"   name="file" /> <br />
      <input type="submit" name="submit" value="Upload to Amazon S3" />
    </form>
相关问题