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

Lambda生成S3预签名URL时始终返回Access Denied求助排查

问题:Lambda生成S3预签名URL返回Access Denied

问题背景

通过Lambda生成S3预签名URL,访问时始终返回“Access Denied”。Lambda能正常列出桶内对象、上传文件,但生成的预签名URL无法访问,仅当对象设为公开时才能正常打开。

签名代码(Go)

sess, err := session.NewSession(&aws.Config{Region: aws.String("us-east-2")})
if err != nil {
    log.Fatal(err)
}

svc := s3.New(sess)

key := strconv.FormatInt(accountID, 10) + "/"

params := &s3.ListObjectsV2Input{
    Bucket:    aws.String(os.Getenv("S3_USER_BUCKET")),
    Prefix:    aws.String(key + loc[0] + "/"),
    Delimiter: aws.String("/"),
}


resp, err := svc.ListObjectsV2(params)

if err != nil {
    return nil, err
}

if *resp.KeyCount == 0 {
    return nil, nil
}


for _, key := range resp.Contents {
    if *key.Size == 0 {
        continue
    }
    req, _ := svc.GetObjectRequest(&s3.GetObjectInput{
        Bucket: aws.String(os.Getenv("S3_USER_BUCKET")),
        Key:    aws.String(*key.Key),
    })

    urlStr, err := req.Presign(15 * time.Minute)
}

Lambda执行角色权限

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:*",
                "s3-object-lambda:*"
            ],
            "Resource": "*"
        }
    ]
}

Lambda信任策略

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

S3桶策略

{
    "Version": "2012-10-17",
    "Id": "S3BukcetPolicyVPCAccessOnly",
    "Statement": [
        {
            "Sid": "DenyIfNotFromAllowedVPC",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::iscore-users",
                "arn:aws:s3:::iscore-users/*"
            ],
            "Condition": {
                "StringNotEquals": {
                    "aws:SourceVpc": "vpc-{ID HERE}"
                }
            }
        }
    ]
}

测试情况

  • Lambda部署在指定VPC内,能正常列出对象,响应示例:
2023-03-10T18:49:11.275-05:00   Contents: [{
2023-03-10T18:49:11.275-05:00   ETag: "\"TAG\"",
2023-03-10T18:49:11.275-05:00   Key: "KEY",
2023-03-10T18:49:11.275-05:00   LastModified: 2023-03-10 17:23:30 +0000 UTC,
2023-03-10T18:49:11.275-05:00   Size: 3664382,
2023-03-10T18:49:11.275-05:00   StorageClass: "STANDARD"
2023-03-10T18:49:11.275-05:00   }
  • 生成的预签名URL示例(已脱敏):
https://BUCKET_NAME.s3.us-east-2.amazonaws.com/35/Scotland/Inverness/c2b8e69f-b746-4a7c-97ef-1931573c338c?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAQMATP5I3KR3QUD74%2F20230310%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20230310T234911Z&X-Amz-Expires=900&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEMj%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMiJGMEQCIA6BAtAHaqXuqBVug4s%2BAwU5tGPaTbYaRUEAU4Wg8mG2AiBnQwyfLnb4ryPlKX2PLGWEUkHKtQHSaJRy77XaNHelryrxAgiB%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAAaDDAyNTgxMDY5MjY2MiIMq7OanPDNAOiHaVpoKsUCorxYhoNxj1YyF7d4pcnrur1ndrWVDAaZbkF2LWyqExG1%2F57Ocdyc74GuYgd6x%2FLGLNzkXJt6NZryvrK2xy0Zx5Gg0Jxf9mmvaC5MCPrhpkgfA92U%2F1sJ5odFwyzsbK%2F2WzvY6gy1t5hT0zTcVebu%2BZ0vMCS5BqfSQJcTKMNi%2FRqZTpsb8CRjjakkIuj27ZfJirdmzykWYK9N7b4Mgm1LCBsf643V2uUsw1mUzfkzaZeTSLXYcteHN%2FTajHGt82Bh8Vzgq6%2BuAj7Yh0%2BIBJVyqK1sIdT9UgWiQt%2F09th2ep4cwEJ8ApKB0Cbl3YejevZ9QbIBluZJnKbnu%2B26RZ9N4ZvTW0hdHnWHbQJOA%2Fz43btJGLQTvbPJl2P%2BlYbCnyKXA5X6Kh56CeW8y%2FNoGmkTM%2B7GZ%2FsHXfpHUlg6ueM6iQRprMMejzDxg6%2BgBjqfAXjiT1zTkBYbE9ntg5cgZuOmVS%2B66tNTeOXMkAbd%2BU3fSssBFZQgBN0WMwfyCMCUrs7aWw6coRntFofOHdpvwK%2FKSnmydYPbuxcH7FvJH%2FV4pwEFzMfjwgkcQQyEJCAF%2Bt3JX2xEltX5D7NO3jB8hU4yGdo9ZOpfhuWT3AUJMS0LU8hYfMCc%2BhrL%2F%2BrljKJ5NVLQEpj8gX7nJViORpOyUQ%3D%3D&X-Amz-SignedHeaders=host&X-Amz-Signature=19472da6b7b3f77bff201be08b6bf9417222395f82c565d632661f78f5344d60
  • 生成URL后数秒内访问,排除凭证过期问题;对象设为公开可正常访问,说明对象本身无损坏。

问题原因

你的S3桶策略设置了Deny所有非指定VPC来源的GetObject请求,而预签名URL的访问请求来自外部客户端(不在你的VPC内),因此被桶策略直接拒绝。

Lambda能正常操作是因为它部署在指定VPC内,符合桶策略的允许条件;但预签名URL是给外部用户使用的,访问时请求来源不在VPC,触发了Deny规则。

解决方案

方案1:修改桶策略,允许预签名URL的访问

在桶策略中添加一条Allow规则,允许由你的Lambda角色签名的预签名URL请求(S3桶策略中Deny优先级高于Allow,需明确排除预签名的情况)。

修改后的桶策略示例:

{
    "Version": "2012-10-17",
    "Id": "S3BukcetPolicyVPCAccessOnly",
    "Statement": [
        {
            "Sid": "AllowPresignedRequestsFromLambdaRole",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::iscore-users/*",
            "Condition": {
                "StringEquals": {
                    "aws:PrincipalArn": "arn:aws:iam::你的账号ID:role/你的Lambda执行角色名称"
                }
            }
        },
        {
            "Sid": "DenyIfNotFromAllowedVPC",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::iscore-users",
                "arn:aws:s3:::iscore-users/*"
            ],
            "Condition": {
                "StringNotEquals": {
                    "aws:SourceVpc": "vpc-{ID HERE}"
                },
                "StringNotEquals": {
                    "aws:PrincipalArn": "arn:aws:iam::你的账号ID:role/你的Lambda执行角色名称"
                }
            }
        }
    ]
}

方案2:使用VPC端点+CloudFront(适合严格VPC控制场景)

如果必须限制所有访问都来自VPC,可以设置S3 VPC端点,然后通过CloudFront配置Origin Access Control(OAC),让预签名URL的请求通过CloudFront并经过VPC端点访问S3。此方案配置相对复杂。

方案3:移除桶策略中的Deny规则(不推荐,除非无VPC访问限制需求)

如果不需要强制所有S3访问都来自指定VPC,可以删除桶策略中的Deny规则,仅保留Lambda角色的权限即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 21:25:02