Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to grant permissions to AWS user for Hartl's rails tutorial

I don't know how (or where also) to grant read and write permission to the user from AWS so users can post pictures on sample_app in production enviroment. This is final task in 11th chapter, it isn't covered by tutorial and I can't find solution anywhere.

This is carrier_wave.rb file:

if Rails.env.production?
  CarrierWave.configure do |config|
    config.fog_credentials = {
      # Configuration for Amazon S3
      :provider              => 'AWS',
      :aws_access_key_id     => ENV['lalala'],
      :aws_secret_access_key => ENV['oloalle']
    }
    config.fog_directory     =  ENV['name of bucket']
  end
end

This is procedure from tutorial: 1) create AWS IAM User and record access and secret key - done

2) create S3 bucket - done

3) grant read and write permission to the user created in the previous step - how???

4) I then run this three commands:

$ heroku config:set S3_ACCESS_KEY=lalala
$ heroku config:set S3_SECRET_KEY=oloalle
$ heroku config:set S3_BUCKET=name of bucket

5) push to git and heroku - done

6) heroku pg:reset DATABASE - done

7)heroku run rake db:migrate and here I get this message:

Running `rake db:migrate` attached to terminal... up, run.7906
rake aborted!
ArgumentError: Missing required arguments: aws_access_key_id, aws_secret_access_key
/app/vendor/bundle/ruby/2.0.0/gems/fog-core-1.28.0/lib/fog/core/service.rb:244:in `validate_options'
/app/vendor/bundle/ruby/2.0.0/gems/fog-core-1.28.0/lib/fog/core/service.rb:268:in `handle_settings'
/app/vendor/bundle/ruby/2.0.0/gems/fog-core-1.28.0/lib/fog/core/service.rb:98:in `new'
/app/vendor/bundle/ruby/2.0.0/gems/fog-core-1.28.0/lib/fog/storage.rb:25:in `new'
/app/vendor/bundle/ruby/2.0.0/gems/carrierwave-0.10.0/lib/carrierwave/uploader/configuration.rb:83:in `eager_load_fog'
/app/vendor/bundle/ruby/2.0.0/gems/carrierwave-0.10.0/lib/carrierwave/uploader/configuration.rb:96:in `fog_credentials='
/app/config/initializers/carrier_wave.rb:3:in `block in <top (required)>'
/app/vendor/bundle/ruby/2.0.0/gems/carrierwave-0.10.0/lib/carrierwave/uploader/configuration.rb:118:in `configure'
/app/vendor/bundle/ruby/2.0.0/gems/carrierwave-0.10.0/lib/carrierwave.rb:14:in `configure'
/app/config/initializers/carrier_wave.rb:2:in `<top (required)>'
/app/vendor/bundle/ruby/2.0.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
/app/vendor/bundle/ruby/2.0.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load'
/app/vendor/bundle/ruby/2.0.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:240:in `load_dependency'
/app/vendor/bundle/ruby/2.0.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/engine.rb:652:in `block in load_config_initializer'
/app/vendor/bundle/ruby/2.0.0/gems/activesupport-4.2.0/lib/active_support/notifications.rb:166:in `instrument'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/engine.rb:651:in `load_config_initializer'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/engine.rb:616:in `block (2 levels) in <class:Engine>'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/engine.rb:615:in `each'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/engine.rb:615:in `block in <class:Engine>'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/initializable.rb:30:in `instance_exec'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/initializable.rb:30:in `run'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/initializable.rb:55:in `block in run_initializers'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/initializable.rb:44:in `each'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/initializable.rb:44:in `tsort_each_child'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/initializable.rb:54:in `run_initializers'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/application.rb:352:in `initialize!'
/app/config/environment.rb:5:in `<top (required)>'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/application.rb:328:in `require'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/application.rb:328:in `require_environment!'
/app/vendor/bundle/ruby/2.0.0/gems/railties-4.2.0/lib/rails/application.rb:443:in `block in run_tasks_blocks'
Tasks: TOP => db:migrate => environment
(See full trace by running task with --trace)
like image 994
Alek Avatar asked Feb 11 '15 21:02

Alek


3 Answers

Here is my tutorial that I created to pick up where Michael Hartl left off at the end of Ruby on Rails Tutorial (3rd Ed.) Chapter 11. It should answer your question and more.

Getting the railstutorial.org Sample App to work between Heroku and AWS was a huge pain in the ass. But I did it. If you found this tutorial, that means you're probably encountering an error you can't get past. That's fine. I had a few of them.

2020 Note: It's possible that everything here referencing a Region for S3 is no longer needed, or perhaps was never needed. When I originally got this all to work properly it was after adding the region information. However, S3 Buckets all share a global namespace. So if anybody is still reading this, try it all without the region stuff first, and leave a comment about whether it works or not. Anyway, back to the tutorial...

The first thing you need to do is go back over the code that Hartl provided. Make sure you typed it (or copy/pasted it) in exactly as shown. Out of all the code in this section, there is only one small addition you might need to make. The "region" environment variable. This is needed if you create a bucket that is not in the default US area. More on this later. Here is the code for /config/initializers/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

That line :region => ENV['S3_REGION'] is a problem for a lot of people. More on that later.

You should be using that block of code exactly as shown. Do NOT put your actual keys in there. We'll send them to Heroku separately.

If you had to add that line of code, don't forget to commit it to git and push it to Heroku.

Now let's move on to your AWS account and security.

  1. First of all, create your AWS account. For the most part, it is like signing up for any web site. Make a nice long password and store it someplace secure, like an encrypted password manager. When you make your account, you will be given your first set of AWS keys. You will not be using those in this tutorial, but you might need them at some point in the future so save those somewhere safe as well.
  2. Go to the S3 section and make a bucket. It has to have a unique name, so I usually just put the date on the end and that does it. For example, you might name it "my-sample-app-bucket-20160126". Once you have created your bucket, click on the name, then click on Properties. It's important for you to know what "Region" your bucket is in. Find it, and make a note of it. You'll use it later.
  3. Your main account probably has full permissions to everything, so let's not use that for transmitting random data between two web services. This could cost you a lot of money if it got out. We'll make a limited user instead. Make a new User in the IAM section. I named it "fog", because that's the cloud service software that handles the sending and receiving. When you create it, you will have the option of displaying and/or downoading the keys associated with the new user. It's important you keep this in a safe and secure place. It does NOT go into your code, because that will probably end up in a repository where other people can see it. Also, don't give this new user a password, since it will not be logging into the AWS dashboard.
  4. Make a new Group. I called mine "s3railsbucket". This is where the permissions will be assigned. Add "fog" to this group.
  5. Go to the Policies section. Click "Create Policy" then select "Create Your Own Policy". Give it a name that starts with "Allow" so it will show up near the top of the list of policies. It's a huge list. Here's what I did:

Policy Name: AllowFullAccessToMySampleAppBucket20160126
Description: Allows remote write/delete access to S3 bucket named my-sample-app-bucket-20160126.
Policy Document:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "s3:*",
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::my-sample-app-bucket-20160126",
                "arn:aws:s3:::my-sample-app-bucket-20160126/*"
            ]
        }
    ]
}
  1. Go back to the Group section, select the group you made, then add your new policy to the group.

That's it for AWS configuration. I didn't need to make a policy to allow "fog" to list the contents of the bucket, even though most tutorials I tried said that was necessary. I think it's only necessary when you want a user that can log in through the dashboard.

Now for the Heroku configuration. This stuff gets entered in at your command prompt, just like 'heroku run rake db:migrate' and such. This is where you enter the actual Access Key and Secret Key you got from the "fog" user you created earlier.

$ heroku config:set S3_ACCESS_KEY=THERANDOMKEYYOUGOT  
$ heroku config:set S3_SECRET_KEY=an0tHeRstRing0frAnDomjUnK  
$ heroku config:set S3_REGION=us-west-2  
$ heroku config:set S3_BUCKET=my-sample-app-bucket-20160126

Look again at that last one. Remember when you looked at the Properties of your S3 bucket? This is where you enter the code associated with your region. If your bucket is not in Oregon, you will have to change us-west-2 to your actual region code. This link worked when this tutorial was written:

http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region

If that doesn't work, Google "AWS S3 region codes".

After doing all this and double-checking for mistakes in the code, I got Heroku to work with AWS for storage of pictures!

like image 71
Max Wilder Avatar answered Oct 21 '22 17:10

Max Wilder


In Services -> IAM, click on 1 User(s) underneath IAM Resources. Select your user you want to have the permission. In this user's profile, click onAttach User Policy. Click on Select for Amazon S3 Full Access and finally Apply Policy.

like image 5
Florent Ferry Avatar answered Oct 21 '22 18:10

Florent Ferry


For others in future, this answer helped me a lot.

Go on Heroku, on your application, go to settings, hit Reveal Config Vars.

Click on on Edit on the right side and enter your secrets there:

S3_BUCKET: name of your bucket goes here
S3_ACCESS_KEY: xxxxx
S3_SECRET_KEY: xxxx

On config/initializers/carrierwave.rb or wherever you're entering your secrets should have:

CarrierWave.configure do |config|
  config.root = Rails.root.join('tmp') # adding these...
  config.cache_dir = 'carrierwave' # ...two lines

  config.fog_credentials = {
    :provider               => 'AWS',                        # required
    :s3_access_key_id      => ENV['S3_ACCESS_KEY'],                        # required
    :s3_secret_access_key  => ENV['S3_SECRET_KEY'],                     # required
    :region                 => 'eu-west-1',                  # optional, defaults to 'us-east-1'
    :host                   => 's3.example.com',             # optional, defaults to nil
    :endpoint               => 'https://s3.example.com:8080' # optional, defaults to nil
  }
  config.fog_directory  = ENV['S3_Bucket']                             # required
  config.fog_public     = false                                   # optional, defaults to true
  config.fog_attributes = {'Cache-Control'=>'max-age=315576000'}  # optional, defaults to {}
end
like image 4
Alek Avatar answered Oct 21 '22 18:10

Alek