S3跨区重建后CORS预签名POST上传仅支持AWS4-HMAC-SHA256报错咨询
问题背景
我删除了原有S3存储桶,在其他区域完成重建,恢复了原有的公共访问阻止设置(已阻止所有公共访问)。
恢复的存储桶策略
{ "Version": "2012-10-17", "Id": "<hidden>", "Statement": [ { "Sid": "Stmt<hidden>", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<hidden>" }, "Action": [ "s3:ListBucket", "s3:ListBucketVersions", "s3:GetBucketLocation", "s3:Get*", "s3:Put*" ], "Resource": "arn:aws:s3:::<hidden>" } ] }
恢复的CORS策略
[ { "AllowedHeaders": [ "Authorization" ], "AllowedMethods": [ "GET", "POST", "PUT" ], "AllowedOrigins": [ "<hidden>" ], "ExposeHeaders": [], "MaxAgeSeconds": 3000 } ]
所用IAM用户权限配置
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "s3:GetAccessPoint", "s3:PutAccountPublicAccessBlock", "s3:GetAccountPublicAccessBlock", "s3:ListAllMyBuckets", "s3:ListAccessPoints", "s3:ListJobs", "s3:CreateJob" ], "Resource": "*" }, { "Sid": "VisualEditor1", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:ListBucketVersions", "s3:GetBucketLocation", "s3:Get*", "s3:Put*", "s3:DeleteObject" ], "Resource": [ "my nice buckets" ] } ] }
所有配置均未改动,仅将存储桶从us-east-2迁移至us-east-1以适配AWS Elastic Transcoder,此前在原区域正常运行的CORS预签名POST上传功能现在报错。
完整错误信息
<?xml version="1.0" encoding="UTF-8"?> <Error><Code>InvalidArgument</Code><Message>Only AWS4-HMAC-SHA256 is supported</Message><ArgumentName>X-Amz-Algorithm</ArgumentName><ArgumentValue>undefined</ArgumentValue><RequestId></RequestId><HostId></HostId></Error>
生成预签名POST的代码
import boto3 class PrivateGeneratePresignedUrlResource(APIView): def get(self, request, *args, **kwargs): userid = kwargs.get('userid') contentpostid = kwargs.get('contentpostid') contenttype = kwargs.get('contentype') if checkIfUserEmailIsValidated(request.user): if checkIfUserIsContentCreator(request.user): if checkIfUserIsActive(request.user): user = getUserObject(request.user) if user.id == int(userid): contentcreatorobject = user.contentcreatoruserid get_object_or_404(ContentFeedPost, id = int(contentpostid), contentcreator= contentcreatorobject) keytime = datetime.now().strftime('%H%M%S%f') randomkey = random.randrange(10000000000000, 99999999999999) awskey = keytime + str(randomkey) + 'raw' fields = {'acl': 'bucket-owner-full-control', 'x-amz-meta-user': userid, 'x-amz-meta-contentpost': contentpostid, 'x-amz-meta-rawbucketkey': str(awskey), 'content-type': contenttype} conditions = [ {'acl': 'bucket-owner-full-control'}, {'x-amz-meta-user': userid}, {'x-amz-meta-contentpost': contentpostid}, {'x-amz-meta-rawbucketkey': str(awskey)}, {'content-type': contenttype} ] s3 = boto3.client('s3', aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY, region_name=AWS_US_1_REGION) post = s3.generate_presigned_post( Bucket=AWS_S3_SHOFI_KIRKE_UPLOAD_BUCKET_NAME, Key=awskey, Fields=fields, Conditions=conditions ) print('here is the post>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>') print(post) return Response({ 'url': post['url'], 'fields': post['fields'], 'uriroot': AWS_S3_SHOFI_KIRKE_UPLOAD_BUCKET_ROOT_URI }) context = {'param userid is not request user id'} return Response(context, status=HTTP_401_UNAUTHORIZED ) context = {'content creator is not active'} return Response(context, status=HTTP_401_UNAUTHORIZED) context = {'user is not content creator'} return Response(context, status=HTTP_401_UNAUTHORIZED) context = {'user needs to validate email'} return Response(context, status=HTTP_401_UNAUTHORIZED)
解决方案
- 错误核心原因是boto3初始化S3客户端时没有显式指定使用AWS Signature Version 4(即AWS4-HMAC-SHA256),us-east-1区域S3对签名版本的要求和原us-east-2区域存在差异,导致生成的预签名参数中缺少X-Amz-Algorithm字段,前端上传时该字段值为undefined触发报错。
- 首先在代码头部引入botocore的Config类:
from botocore.config import Config
- 修改S3客户端初始化代码,显式指定签名版本为s3v4:
s3 = boto3.client('s3', aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY, region_name=AWS_US_1_REGION, config=Config(signature_version='s3v4') )
- 额外校验点:修改完成后如果仍有报错,检查前端上传逻辑是否完整携带了接口返回的
fields中所有参数,确保X-Amz-Algorithm、X-Amz-Credential、X-Amz-Signature等签名相关字段都被正确加入上传表单,没有遗漏。
内容的提问来源于stack exchange,提问作者Christopher Jakob
相关产品推荐
相关产品推荐

