S3预签名URL返回403错误排查:Bucket与Lambda权限均正常
问题描述
项目架构:Client -> API Gateway -> Lambda -> 预签名URL;用户获取预签名URL后向S3发起请求。已成功生成并返回预签名URL,但通过Postman或fetch调用时始终返回403错误。
客户端上传代码
async function uploadPic() { // 获取输入文件... var fileName = file.name; // uploadEventPhoto从URL获取Cognito idToken并请求预签名URL,Cognito功能正常,已在其他API资源验证 let url = await uploadEventPhoto(idToken) // 尝试过用formData和直接传文件,都不影响403错误 let formData = new FormData() formData.append("file", file) const requestOptions = { method: 'PUT', headers: { 'Content-Type': "multipart/form-data" }, body: formData }; let putURLResponse= await fetch(url, requestOptions) }
Lambda生成预签名URL代码
def lambda_handler(event, context): # 生成随机字符串的函数已省略,功能正常 rand_id = generate_random_string(8) client = boto3.client('s3',aws_access_key_id='REDACTED',aws_secret_access_key='REDACTED') resp = client.generate_presigned_url("put_object", Params={ "Bucket":"REDACTED", "Key":"REDACTED/REDACTED" }, ExpiresIn=300 ) return { 'statusCode': 200, 'headers': { 'Content-Type': 'image/png', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, PUT, GET, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With' }, 'body': json.dumps(resp) }
客户端获取预签名URL函数
async function uploadEventPhoto(idToken) { // 函数名有误,原本是想传数据给Lambda写入S3,现在仅用Cognito认证调用Lambda获取预签名URL const url = 'https://REDACTED.execute-api.us-west-1.amazonaws.com/dev/Photos'; const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${idToken}` }, }; let resp = await fetch(url, requestOptions) let data = await resp.json() return data }
S3 Bucket政策
{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::REDACTED/*" }, { "Sid": "S3PolicyStmt-DO-NOT-MODIFY-1719269888596", "Effect": "Allow", "Principal": { "Service": "logging.s3.amazonaws.com" }, "Action": "s3:PutObject", "Resource": "arn:aws:s3:::REDACTED/*", "Condition": { "StringEquals": { "aws:SourceAccount": "REDACTED" } } }, { "Sid": "Statement1", "Effect": "Allow", "Principal": "*", "Action": [ "s3:PutObjectAcl", "s3:PutObject" ], "Resource": [ "arn:aws:s3:::REDACTED/*", "arn:aws:s3:::REDACTED" ] } ] }
角色/用户配置
- 已确认Lambda角色拥有S3权限,最初仅配置
putObject,现在改为全权限覆盖所有场景 - 尝试创建新角色并配置正确权限,问题依旧
- 创建新用户并赋予S3权限,在客户端使用其访问密钥,期望用户权限传递到URL,无效
- 尝试不在客户端构造器中使用访问密钥,测试传递Lambda权限,两种方式均无效
S3 Bucket配置
- 最初仅配置公共读取权限,现在改为公共读写权限,仍无法解决403错误
- CORS允许所有来源和方法
- 确保角色拥有对
arn:aws:s3:::REDACTED和arn:aws:s3:::REDACTED/*的访问权限 - 尝试为角色赋予KMS权限,参考相关帖子,无效
其他排查步骤
- 尝试使用
presigned_put_url()无效,切换为presigned_url()仍无法解决 - 使用权限模拟器测试用户和角色向S3 Bucket上传的权限,结果显示均正常
- 请求链接包含角色的
AWSAccessKeyID,看似用户权限已传递,但访问顾问显示密钥未被访问 - 已尝试更多无法记起的排查步骤,问题仍未解决
内容的提问来源于stack exchange,提问作者Jacob Schwarzenberger
相关产品推荐
相关产品推荐

