我正在尝试对S3 REST API执行HEAD对象请求但我仍然收到403 Forbidden错误,即使我在S3上具有必要权限的策略设置。响应主体是空的,所以我不认为它是一个签名问题。我已尝试对政策进行多项更改,但似乎没有任何改变。我能正常PUT对象和DELETE对象,只是HEAD无法正常工作。
这是我的保管政策:
{
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam:: 999999999999:user/User"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-bucket"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::999999999999:user/User"
},
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:DeleteObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
有什么想法吗?
更新
正如迈克尔指出的那样,我的签名似乎有问题,但我没有看到什么。
def generate_url options={}
options[:action] = options[:action].to_s.upcase
options[:expires] ||= Time.now.to_i + 100
file_path = "/" + @bucket_name + "/" + options[:file_name]
string_to_sign = ""
string_to_sign += options[:action]
string_to_sign += "\n\n#{options[:mime_type]}\n"
string_to_sign += options[:expires].to_s
string_to_sign += "\n"
string_to_sign += file_path
signature = CGI::escape(
Base64.strict_encode64(
OpenSSL::HMAC.digest('sha1', SECRET_KEY, string_to_sign)
)
)
url = "https://s3.amazonaws.com"
url += file_path
url += "?AWSAccessKeyId=#{ACCESS_KEY}"
url += "&Expires=#{options[:expires]}"
url += "&Signature=#{signature}"
url
end
生成的要签名的字符串如下所示:
HEAD\n\n\n1418590715\n/video-thumbnails/1234.jpg"
解决方案:
在开发文件PUT部分的某个时刻,我实际上已经破坏了GET和HEAD。我传递一个空字符串作为请求的主体,而不是传递任何东西,使签名上需要mime类型并打破它,因为我没有提供mime类型。我只是删除了空的请求体,它工作得很好。感谢迈克尔指出我走错了方向(我浪费了很多时间来改变存储桶政策)。
答案 0 :(得分:4)
它仍然可能是你的签名,我怀疑它是,原因如下:
您观察到信息正文是一个很好的观察;但是,它并不代表你所得出的结论意味着什么。
缺少响应主体并没有提供任何有关错误性质的信息,在这种情况下,因为Web服务器不应该返回一个正文以及HEAD
响应,否则重要的是:
HEAD
方法与GET
相同,只是服务器MUST NOT
在响应中返回消息正文- http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html(RFC-2616)
对我进行测试,我确认S3对未签名的HEAD
请求和错误签名的HEAD
请求的回复没有区别:它&#39 ; s始终为HTTP/1.1 403 Forbidden
,没有邮件正文。
另请注意,GET
的签名网址对HEAD
无效,反之亦然。
在S3 Signature Version 2和S3 Signature Version 4中,"要签名的字符串"包括" HTTP动词,"这将是GET
或HEAD
,这意味着对GET
有效的签名对HEAD
无效,反之亦然......签名时必须知道方法,因为它是签名过程中使用的元素。
s3:GetObject
权限是使用HEAD
所需的唯一documented权限,如果GET
正在运行,这似乎会消除权限问题,这表明签名是潜在的问题。
答案 1 :(得分:2)
确认HEAD预先签名的URL将获得403 Forbidden。 如果设置自定义标头,例如对象的内容类型。 403响应将不包含自定义标头,仍然可以获得application / xml。
答案 2 :(得分:0)
对@ Michael-sqlbot上面的答案的其他评论...
我面临相同的症状,但根本原因却不同。
如果您尝试对不存在的文件进行HEAD处理,那么这还将返回403禁止的错误, UNLESS 您具有s3:ListBucket权限。
就我而言,我拥有s3.GetObject,s3.PutObject和s3.HeadBucket权限,但是直到我添加s3.ListBucket才获得正确的404-找不到错误。
此处也对此进行了说明:https://aws.amazon.com/premiumsupport/knowledge-center/s3-rest-api-cloudfront-error-403/
答案 3 :(得分:0)
有相同的问题,但有不同的根本原因-试图创建一个存储桶,而不是获取404,而是得到403。由于S3是全局命名空间,所以其他人创建了存储桶,因此我拥有正确的存储桶权限和帐户设置,我仍然会从HEAD请求中获得403。解决方案是先检查存储桶是否全局存在,如果存在,请尝试使用其他存储桶名称。
答案 4 :(得分:0)
我也收到了这个错误提示;在 pytest
期间使用 freezegun
。我已经冻结了过去的时间,并且收到了 403 错误。所以时钟偏差可能会导致这种情况。
我通过尝试另一个 API 调用发现了这个,我收到了:
E botocore.exceptions.ClientError: An error occurred (RequestTimeTooSkewed) when calling the ListObjects operation: The difference between the request time and the current time is too large.