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

仅用AWS SAM创建本地S3桶上传文件遇权限错误,求非LocalStack方案

问题:SAM本地调用Lambda上传S3时权限拒绝(不使用LocalStack)

我希望仅通过AWS SAM创建本地S3存储桶,并通过Python脚本上传文件。以下是我的代码:

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: An example SAM template for a Python Lambda function

Resources:
  MyS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: MyS3Bucket
  LambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: lambda_function.lambda_handler
      Runtime: python3.9
      Timeout: 10
      Policies:
        - S3ReadPolicy:
            BucketName: !Ref MyS3Bucket
        - S3WritePolicy:
            BucketName: !Ref MyS3Bucket
      Environment:
        Variables:
          S3_BUCKET: !Ref MyS3Bucket

Outputs:
  LambdaFunctionArn:
    Description: "ARN of the Lambda Function"
    Value: !GetAtt LambdaFunction.Arn

lambda_function.py

import boto3

s3 = boto3.client('s3')

def lambda_handler(event, context):
    # Upload a file to S3 bucket
    file_content = b"Your file content here"
    s3.put_object(Bucket='MyS3Bucket', Key='example.txt', Body=file_content)
    
    return {
        'statusCode': 200,
        'body': 'File uploaded successfully!'
    }

使用sam local start-lambda启动SAM,再用sam local invoke LambdaFunction调用Lambda时,出现权限拒绝错误:

{"errorMessage": "An error occurred (AccessDenied) when calling the PutObject operation: Access Denied", "errorType": "ClientError", "requestId": "ef7b2bfe-688a-4f77-8a0c-867887f9c2ee", "stackTrace": ["  File \"/var/task/lambda_function.py\", line 8, in lambda_handler\n    s3.put_object(Bucket='MyS3Bucket', Key='example.txt', Body=file_content)\n", "  File \"/var/runtime/botocore/client.py\", line 553, in _api_call\n    return self._make_api_call(operation_name, kwargs)\n", "  File \"/var/runtime/botocore/client.py\", line 1009, in _make_api_call\n    raise error_class(parsed_response, operation_name)\n"]}

请问仅用AWS SAM实现该需求的解决办法是什么?(不想使用LocalStack这类第三方工具)


解决方案

核心原因说明

AWS SAM本地模式不会模拟S3服务,所有S3 API调用都会直接发送到真实的AWS S3服务。模板中定义的Policies是部署到AWS云环境时给Lambda角色用的,本地运行Lambda时不生效,本地代码使用的是你机器上~/.aws/credentials文件中的AWS凭证。同时,SAM本地也不会自动帮你创建真实的S3桶。

具体解决步骤

  1. 创建真实的AWS S3桶

    • S3桶名全局唯一,不能使用MyS3Bucket这类通用名称,改成唯一名称(比如my-sam-local-demo-bucket-xxxxxx,替换成自己的唯一标识)。
    • 可以通过AWS CLI创建:
      aws s3 mb s3://你的唯一桶名
      
  2. 修改Lambda代码,使用环境变量而非硬编码桶名
    把硬编码的桶名替换为从环境变量读取,既符合最佳实践,也能和模板配置保持一致:

    import boto3
    import os
    
    s3 = boto3.client('s3')
    # 从环境变量获取桶名
    BUCKET_NAME = os.environ['S3_BUCKET']
    
    def lambda_handler(event, context):
        file_content = b"Your file content here"
        s3.put_object(Bucket=BUCKET_NAME, Key='example.txt', Body=file_content)
        
        return {
            'statusCode': 200,
            'body': 'File uploaded successfully!'
        }
    
  3. 更新template.yaml中的桶名
    将模板里的BucketName替换为你刚创建的真实桶名:

    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Description: An example SAM template for a Python Lambda function
    
    Resources:
      MyS3Bucket:
        Type: AWS::S3::Bucket
        Properties:
          BucketName: my-sam-local-demo-bucket-xxxxxx  # 替换为你的真实桶名
      LambdaFunction:
        Type: AWS::Serverless::Function
        Properties:
          Handler: lambda_function.lambda_handler
          Runtime: python3.9
          Timeout: 10
          Policies:
            - S3ReadPolicy:
                BucketName: !Ref MyS3Bucket
            - S3WritePolicy:
                BucketName: !Ref MyS3Bucket
          Environment:
            Variables:
              S3_BUCKET: !Ref MyS3Bucket
    
    Outputs:
      LambdaFunctionArn:
        Description: "ARN of the Lambda Function"
        Value: !GetAtt LambdaFunction.Arn
    
  4. 确保本地AWS凭证拥有桶操作权限

    • 检查本地~/.aws/credentials中的账号是否有权限对该桶执行PutObject和GetObject操作。
    • 可以给该账号附加自定义IAM策略(测试场景也可临时用AmazonS3FullAccess):
      {
          "Version": "2012-10-17",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": ["s3:PutObject", "s3:GetObject"],
                  "Resource": "arn:aws:s3:::你的真实桶名/*"
              }
          ]
      }
      
  5. 重新测试本地调用
    先验证本地凭证能访问桶:

    aws s3 ls s3://你的真实桶名
    

    然后重启SAM本地服务并调用Lambda:

    sam local start-lambda
    # 新开终端执行
    sam local invoke LambdaFunction
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 13:07:47