403 запрещенная ошибка в запросе головы REST API S3


Я пытаюсь сделать запрос объекта HEAD к API REST S3, но я продолжаю получать ошибку 403 Forbidden, хотя у меня есть настройка политики с необходимыми разрешениями на S3. Тело ответа пустое, поэтому я не думаю, что это проблема подписи. Я попробовал несколько изменений в политике, но ничего не помогает. Я могу ставить объекты и удалять объекты нормально, просто голова не работает.

Вот моя политика ведра:

{
"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 += "nn#{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

Сгенерированная строка для подписи выглядит следующим образом:

HEADnnn1418590715n/video-thumbnails/1234.jpg"

Решение:

Похоже, в какой-то момент при разработке файла PUT part я на самом деле сломал GET и HEAD. Я передавал пустую строку в качестве тела запроса, вместо того, чтобы передавать ничего, делая MIME-тип необходимым для подписи и нарушая его, потому что я был нет тип MIME. Я просто удалил пустое тело запроса, и оно сработало идеально. Спасибо Майклу за то, что он указал мне неправильное направление(я потратил столько времени на изменение политики ведра).

2 3

2 ответа:

Это все еще может быть ваша подпись, и я подозреваю, что это так, по следующим причинам:

Ваше замечание о том, что тело сообщения-это хорошее наблюдение; однако оно не означает того, что вы заключили, что оно означает.

Отсутствие тела ответа не дает вам никакой информации о природе ошибки, в данном случае, потому что веб-сервер не должен возвращать тело вместе с ответом HEAD, независимо от того, что:

Метод HEAD является идентично GET за исключением того, что сервер MUST NOT возвращает тело сообщения в ответе

- http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html (RFC-2616)

Проверяя это на своей стороне, я подтвердил, что ответ S3 на неподписанный запрос HEAD и на неправильно подписанный запрос HEAD ничем не отличается: он всегда HTTP/1.1 403 Forbidden без тела сообщения.

Обратите также внимание, что подписанный URL для GET недопустим для HEAD, и наоборот наоборот.

Как в S3 Signature Version 2, так и в S3 Signature Version 4, "строка для подписи" включает "http-глагол", который будет GET или HEAD, что означает, что подпись, которая действительна для GET, не будет действительна для HEAD, и наоборот... метод запроса должен быть известен во время подписания, потому что это элемент, который используется в процессе подписания.

Разрешение s3:GetObject является единственным документированным разрешением, необходимым для использования HEAD, который, по-видимому, устраняет разрешения как проблему, если GET работает, что указывает на подпись как потенциальную проблему.

Подтвердил, что голова presigned-URL-адрес будет получать 403-запрещено. Если задать пользовательские заголовки, например content-type объекта. Ответ 403 не будет содержать пользовательского заголовка и все равно получит application/xml.