如何用Python匿名访问带区域限制的AWS S3公开存储桶?
问题描述
我有一个AWS S3公开存储桶,桶策略仅允许来自us-west-1和us-west-2区域的访问。想通过boto3/s3fs在Python中匿名访问该桶并列出所有文件,无需凭证登录。
对应的桶策略片段:
{ "Sid": "Statement2", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "s3:GetObject", "s3:GetBucketLocation", "s3:ListBucket", "s3:GetBucketAcl" ], "Resource": [ "arn:aws:s3:::MY-BUCKET", "arn:aws:s3:::MY-BUCKET/*" ], "Condition": { "StringEquals": { "aws:RequestedRegion": [ "us-west-1", "us-west-2" ] } } }
尝试过的代码:
import boto3 from botocore.config import Config import botocore s3_client = boto3.client('s3', region_name='us-west-2', config=Config(signature_version=botocore.UNSIGNED)) s3_client.list_objects(Bucket='MY-BUCKET')
运行后返回访问拒绝错误,但不指定请求区域时代码可以正常工作,需要解决这个配置问题。
解决思路与方案
原因分析
指定region_name时,boto3会直接向该区域的S3端点发送请求,但如果你的桶实际不在us-west-2区域,S3会因为aws:RequestedRegion不匹配桶的真实区域而拒绝请求。不指定区域时,boto3会先请求全局S3端点,自动重定向到桶的实际区域,此时aws:RequestedRegion匹配桶的真实区域,请求得以通过。
方案1:调整桶策略(推荐)
方式A:添加桶实际所在区域到允许列表
如果知道桶的实际区域(比如us-east-1),直接将其加入aws:RequestedRegion的允许列表:
"Condition": { "StringEquals": { "aws:RequestedRegion": [ "us-west-1", "us-west-2", "us-east-1" // 替换为你的桶实际区域 ] } }
方式B:改用客户端来源区域限制
如果要限制的是发起请求的客户端所在区域,将aws:RequestedRegion替换为aws:SourceRegion:
"Condition": { "StringEquals": { "aws:SourceRegion": [ "us-west-1", "us-west-2" ] } }
方案2:修改boto3代码,动态获取桶区域
先匿名获取桶的实际区域,再用该区域创建客户端发起请求:
import boto3 from botocore.config import Config import botocore # 匿名获取桶的实际区域 s3_client_no_region = boto3.client('s3', config=Config(signature_version=botocore.UNSIGNED)) bucket_region = s3_client_no_region.get_bucket_location(Bucket='MY-BUCKET')['LocationConstraint'] # 处理us-east-1的特殊情况(get_bucket_location返回None) if not bucket_region: bucket_region = 'us-east-1' # 使用桶实际区域创建客户端并列出文件 s3_client = boto3.client('s3', region_name=bucket_region, config=Config(signature_version=botocore.UNSIGNED)) response = s3_client.list_objects(Bucket='MY-BUCKET') # 遍历输出文件 for obj in response.get('Contents', []): print(obj['Key'])
方案3:使用s3fs简化实现
s3fs默认会自动处理区域重定向,无需手动指定区域,直接匿名初始化即可:
import s3fs # 匿名创建文件系统实例 fs = s3fs.S3FileSystem(anon=True) # 列出桶内所有文件 files = fs.ls('MY-BUCKET') print(files)
内容的提问来源于stack exchange,提问作者Minh Phan
相关产品推荐
相关产品推荐

