仅用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桶。
具体解决步骤
创建真实的AWS S3桶
- S3桶名全局唯一,不能使用
MyS3Bucket这类通用名称,改成唯一名称(比如my-sam-local-demo-bucket-xxxxxx,替换成自己的唯一标识)。 - 可以通过AWS CLI创建:
aws s3 mb s3://你的唯一桶名
- S3桶名全局唯一,不能使用
修改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!' }更新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确保本地AWS凭证拥有桶操作权限
- 检查本地
~/.aws/credentials中的账号是否有权限对该桶执行PutObject和GetObject操作。 - 可以给该账号附加自定义IAM策略(测试场景也可临时用
AmazonS3FullAccess):{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:PutObject", "s3:GetObject"], "Resource": "arn:aws:s3:::你的真实桶名/*" } ] }
- 检查本地
重新测试本地调用
先验证本地凭证能访问桶:aws s3 ls s3://你的真实桶名然后重启SAM本地服务并调用Lambda:
sam local start-lambda # 新开终端执行 sam local invoke LambdaFunction
内容的提问来源于stack exchange,提问作者Hansamal
相关产品推荐
相关产品推荐

