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

向S3 Bucket发送Curl请求时遭遇访问拒绝的技术咨询

问题描述

我正尝试从EC2实例向S3 Bucket发送Curl请求以获取桶内特定对象:

  • 由于需要搭建由NGINX实现缓存的透明代理,因此无法使用AWS CLI。
  • 该EC2实例(Linux机器)作为代理服务器,通过NGINX向Bucket发送HTTP请求以实现缓存,实例上未配置SSL证书。
  • Bucket内仅存储图片。

我的Curl请求如下:

curl my-bucket.s3.eu-west-1.amazonaws.com/1450/1349/5467_1012.jpg

但我收到了Access Denied错误。

我已为EC2实例角色附加了全读取权限策略,Bucket策略如下:

{
    "Version": "2012-10-17",
    "Id": "MediaStorageBucketPolicy",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::${current_account}:root"
            },
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "${media_storage_bucket_arn}",
                "${media_storage_bucket_arn}/*"
            ]
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::${current_account}:root"
            },
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "${media_storage_bucket_arn}",
                "${media_storage_bucket_arn}/*"
            ]
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::<account number>:role/ssm-ec2-service-role"
                ]
            },
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "${media_storage_bucket_arn}",
                "${media_storage_bucket_arn}/*"
            ]
        }
    ]
}

请问能否在不公开Bucket的前提下实现该需求?


解决方案(无需公开Bucket)

1. 修复Bucket策略的角色ARN格式错误

你的Bucket策略中角色ARN存在格式问题:arn:aws:I am::<account number>:role/ssm-ec2-service-role 里多了空格,正确格式应为 arn:aws:iam::<account number>:role/ssm-ec2-service-role。这个错误会导致策略无法识别目标角色,直接触发权限拒绝。

2. 确认EC2实例绑定正确角色

  • 登录EC2控制台,找到目标实例,查看「安全」标签下的IAM角色是否为ssm-ec2-service-role。
  • 检查该角色的信任策略是否允许EC2服务扮演它,信任策略需包含:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

3. 为Curl请求添加AWS签名

直接用curl发起的普通HTTP请求不会自动携带EC2实例角色的凭证,S3无法识别请求身份,因此会返回拒绝。需生成带签名的请求,以下是几种可行方式:

方式A:用AWS CLI生成带签名的临时URL

虽然无法直接用AWS CLI操作,但可以用它生成带签名的URL供curl或NGINX使用:

aws s3 presign s3://my-bucket/1450/1349/5467_1012.jpg --expires-in 3600

该命令会生成一个有效期1小时的签名URL,直接用curl访问即可。你可以将此逻辑集成到NGINX配置中,比如通过脚本动态生成URL后转发。

方式B:用脚本生成签名请求

如果是Python环境,可使用requests-aws4auth库自动生成带签名的请求,示例代码:

import requests
from requests_aws4auth import AWS4Auth

aws_auth = AWS4Auth('<account number>', 'eu-west-1', 's3')
url = 'http://my-bucket.s3.eu-west-1.amazonaws.com/1450/1349/5467_1012.jpg'
response = requests.get(url, auth=aws_auth)

可将此脚本封装为内部API服务,让NGINX代理到该服务获取签名后的请求结果。

方式C:使用NGINX AWS签名模块

第三方NGINX模块(如ngx_http_aws_sign)可自动为转发到S3的请求添加AWS签名,无需手动处理,直接利用EC2实例角色的凭证完成身份验证。

4. 验证权限有效性

在EC2实例上执行以下命令,确认角色权限是否正常:

aws s3api get-object --bucket my-bucket --key 1450/1349/5467_1012.jpg test.jpg

如果命令成功,说明角色权限没问题,问题出在curl请求未签名;如果失败,需重新检查角色权限和Bucket策略配置。

5. 保持Bucket阻止公共访问设置

确保Bucket的「阻止公共访问」功能处于开启状态,这不会影响IAM角色的访问,同时符合不公开Bucket的要求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 16:15:30