Загрузка файлов AWS S3 возвращается 403: Запрещено с камнями Carrierwave / fog в Rails - PullRequest
0 голосов
/ 11 января 2019

Я почесал голову над этим в течение нескольких дней. В настоящее время работаю над главой 13 (пользовательские микросообщения) Rails Tutorial , и хотя мое приложение отлично работает в процессе разработки, я не могу загрузить изображения на AWS S3, работающие в производстве (подробности здесь, в учебник ). Приложение использует ASW S3 корзины для хранения и CarrierWave / Fog gems для загрузки файлов.

Когда я открываю свое производственное приложение heroku, все работает нормально, кроме загрузки изображений. Когда я пытаюсь загрузить изображение на новый микросообщение, я получаю общее выражение «Извините, но что-то пошло не так». ошибка в браузере. Журналы Heroku показывают: ошибка состояния 403 «Запрещено» при попытке добраться до корзины (подробные журналы приведены ниже).

У других, похоже, были похожие проблемы. В большинстве случаев кажется, что решение состоит в том, чтобы установить правильные разрешения пользователя IAM или установить политику сегмента S3 , но я вполне уверен, что они настроены правильно по двум причинам:

  1. Я могу использовать веб-интерфейс этой учетной записи пользователя для загрузки и управления файлами в корзине, поэтому я знаю, что у него есть доступ.
  2. Я установил инструмент командной строки aws, настроил его на тот же ключ доступа пользователя и секретный ключ, которые использовались в моем веб-приложении, и я могу иметь возможность загружать и извлекать информацию из корзины через CLI.

Тем не менее, я попробовал несколько политик и разрешений пользователей, включая разрешение на полный доступ к Amazon S3 (я считаю, что оно является наиболее общим), и несколько более конкретных версий (см. Последнюю версию ниже).

Другие вещи, которые я пробовал, похоже, работают для других:

Будучи новым разработчиком, я чувствую, что у меня пока нет технических знаний для диагностики этого, и, честно говоря, это немного обескураживает, поэтому я надеюсь на помощь. Вот некоторые вопросы, которые у меня есть, и возможные направления для изучения, которые я хотел бы изучить подробнее:

  • Вопрос: Если я смогу получить доступ к ведру с помощью aws-cli, я не смогу ли я также использовать героку с несущей / туманом, используя те же учетные данные, или я что-то недопонимаю о том, как герою достает S3 ведро?
  • Возможная проблема: Carrierwave или ImageMagick создают временный файл при загрузке изображения. В некоторых случаях кажется, что это может помешать загрузке. Кто-то дал расплывчатый ответ об этом здесь , но я не понимаю, какие действия могут помочь избавиться от этой проблемы.
  • Возможная проблема: У кого-то, похоже, были проблемы с Rails strong params при этом. Я не мог понять, как отладить это ... Когда я использую byebug, чтобы открыть интерактивную консоль на сервере в месте ошибки (в моем методе micropost_controller #create), сразу после загрузки файла изображение находится в параметрах хэш, но ключ :picture переменной экземпляра @micropost равен nil (в то же время ключ :content не равен nil, он содержит любой текст, который я отправил с изображением, как и должно быть).

Ссылка на остальную часть кода на GitHub , если это поможет.

Извините за скучность. Любое руководство будет с благодарностью.


Ошибка:

2019-01-07T08:11:37.684069+00:00 app[web.1]: F, [2019-01-07T08:11:37.683926 #22] FATAL -- : [363c5115-f872-43b4-857a-10d1d7d11737] Excon::Error::Forbidden (Expected(200) <=> Actual(403 Forbidden)
2019-01-07T08:11:37.684074+00:00 app[web.1]: excon.error.response
2019-01-07T08:11:37.684077+00:00 app[web.1]: :body          => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>***</RequestId><HostId>***=</HostId></Error>"
2019-01-07T08:11:37.684079+00:00 app[web.1]: :cookies       => [
2019-01-07T08:11:37.684081+00:00 app[web.1]: ]
2019-01-07T08:11:37.684082+00:00 app[web.1]: :headers       => {
2019-01-07T08:11:37.684085+00:00 app[web.1]: "Connection"       => "close"
2019-01-07T08:11:37.684086+00:00 app[web.1]: "Content-Type"     => "application/xml"
2019-01-07T08:11:37.684088+00:00 app[web.1]: "Date"             => "Mon, 07 Jan 2019 08:11:36 GMT"
2019-01-07T08:11:37.684090+00:00 app[web.1]: "Server"           => "AmazonS3"
2019-01-07T08:11:37.684092+00:00 app[web.1]: "x-amz-id-2"       => "***"
2019-01-07T08:11:37.684094+00:00 app[web.1]: "x-amz-request-id" => "***"
2019-01-07T08:11:37.684096+00:00 app[web.1]: }
2019-01-07T08:11:37.684098+00:00 app[web.1]: :host          => "bucket-name.s3-us-west-1.amazonaws.com"
2019-01-07T08:11:37.684099+00:00 app[web.1]: :local_address => "*********"
2019-01-07T08:11:37.684101+00:00 app[web.1]: :local_port    => ******
2019-01-07T08:11:37.684103+00:00 app[web.1]: :path          => "/uploads/micropost/picture/306/ocean2.jpeg"
2019-01-07T08:11:37.684104+00:00 app[web.1]: :port          => 443
2019-01-07T08:11:37.684106+00:00 app[web.1]: :reason_phrase => "Forbidden"
2019-01-07T08:11:37.684108+00:00 app[web.1]: :remote_ip     => "*******"
2019-01-07T08:11:37.684110+00:00 app[web.1]: :status        => 403
2019-01-07T08:11:37.684111+00:00 app[web.1]: :status_line   => "HTTP/1.1 403 Forbidden\r\n"
2019-01-07T08:11:37.684113+00:00 app[web.1]: ):
2019-01-07T08:11:37.684217+00:00 app[web.1]: F, [2019-01-07T08:11:37.684147 #22] FATAL -- : [363c5115-f872-43b4-857a-10d1d7d11737]
2019-01-07T08:11:37.684392+00:00 app[web.1]: F, [2019-01-07T08:11:37.684328 #22] FATAL -- : [363c5115-f872-43b4-857a-10d1d7d11737] app/controllers/microposts_controller.rb:7:in `create'

Политика использования ковша:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::***********:user/user-name"
            },
            "Action": [
                "s3:AbortMultipartUpload",
                "s3:ListBucket",
                "s3:GetObject",
                "s3:PutObject",
                "s3:PutObjectAcl",
                "s3:DeleteObject",
                "s3:GetObjectVersion"
            ],
            "Resource": [
                "arn:aws:s3:::bucket-name/*",
                "arn:aws:s3:::bucket-name"
            ]
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::*******:user/user-name"
            },
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation"
            ],
            "Resource": "arn:aws:s3:::bucket-name",
            "Condition": {}
        }
    ]
}

CORS:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

Текущий инициализатор: carrier_wave.rb

if Rails.env.production?
  CarrierWave.configure do |config|
    config.fog_credentials = {
      # Configuration for Amazon S3
      :provider              => 'AWS',
      :aws_access_key_id     => ENV['S3_ACCESS_KEY'],
      :aws_secret_access_key => ENV['S3_SECRET_KEY'],
      :region                => ENV['S3_REGION']
    }
    config.fog_directory     =  ENV['S3_BUCKET']
  end
end

picture_uploader.rb

class PictureUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
  process resize_to_limit: [400, 400]

  if Rails.env.production?
    storage :fog
  else
    storage :file
  end

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # Add a white list of extensions which are allowed to be uploaded.
  def extension_whitelist
    %w(jpg jpeg gif png)
  end
end
...