A short story: I installed a development server on Heroku that is running in production mode.
I am not very familiar to the paypal-sdk-rest gem that is installed in this app (actually I'm new to RoR).
Reading the documentation here https://github.com/paypal/PayPal-Ruby-SDK I found out that there is a config yml file (config/paypal.yml) with the client_id and the client_secret for both Sandbox and Live for development and production environments. And a reference it to in config/initializers/paypal.rb.
When I'm working on localhost I can create payments on Sandbox and when I'm on my AWS server I can create payments on Live. But on Heroku I need it to create payments on Sandbox and not on Live. So I commented the reference to paypal.yml in paypal.rb and stated this in paypal.rb:
#this was added
PayPal::SDK.configure({
:mode => "sandbox",
:client_id => "my-sandbox-id",
:client_secret => "my-sandbox-secret"
})
Before sending files to Heroku I'm testing on localhost and I was expecting to see the sandbox payment page since it was working before removing the configuration file. I'm getting this message error instead:
{"name"=>"BUSINESS_VALIDATION_ERROR",
"details"=>[{"field"=>"validation_error", "issue"=>"Incorrect Template
Id."}], "message"=>"Validation Error.",
"information_link"=>"https://developer.paypal.com/webapps/developer/docs/api/#BUSINESS_VALIDATION_ERROR",
"debug_id"=>"some id here"}
Additional information: before removing the configuration file I was just copying the development info to production. I was testing on Heroku and getting the same error.
Any ideas folks?
I would add the keys via an environment variable. That way each environment will reference the correct key and you don't have to check them into source control. https://github.com/laserlemon/figaro is a good gem if you want to go that route. Alternatively you can set up your config/paypal.yml file to reference the different environments. That would look more like:
development:
:mode: "sandbox"
:client_id: "my-sandbox-id"
production:
:mode: "not-sandbox-er-whatever"
:client_id: "my-not-sandbox-id"
Related
I have a Rails 6 application. In my credentials file, I have both development and production API keys. I want to be able to hide the production API keys since some developers don't need access to the credentials.
In previous versions of Rails, I could grab an environment variable using <%= ENV["MY_VAR"] %> and place that in the secrets.yml file. However, Rails credentials doesn't support executing Ruby in the yml file which makes sense because it's encrypted but this now puts limitations on the ability to prevent other developers from accessing production API keys. Is there anyway around this without hardcoding ENV["MY_VAR"] throughout the Rails app? Here is ultimately what I want to accomplish within my credentials file.
development:
aws: 11111111
production:
aws: <%= ENV["AWS_SECRET"] %>
You can generate credential file per environment
rails credentials:edit --environment development
rails credentials:edit --environment production
This will create the credentials file
config/credentials/development.yml.enc and config/credentials/production.yml.enc, and
encryption keys config/credentials/development.key, config/credentials/production.key
So you can share development key with other developers without need to share production.key
Checkout this commit for more details: https://github.com/rails/rails/pull/33521
So I have New Relic set up on my Rails app, which I run both locally for development and which I deploy to Heroku.
However, the New Relic dashboard shows data from my local setup and not from Heroku. I know because the data I can see corresponds to what's happening on the local environment, and on the new relic dashboard the listed servers includes the hostname of my local machine.
How do I make sure New Relic monitors the heroku environment instead?
New Relic is setup in my app this way:
'newrelic_rpm" gem is included in the Gemfile
config/newrelic.yml exist and has been downloaded from the New Relic setup page
The license key in config/newrelic.yml is the one generated on the New Relic setup page
The heroku environment variables NEW_RELIC_APP_NAME and NEW_RELIC_LICENSE_KEY. The first one is the same name as the Heroku app. The second one contains the same key as the config/newrelic.yml file.
The heroku newrelic:stark addon is added to the heroku app
As per comments, check to make sure you config/newrelic.yml file is monitoring a production application.
Set all newrelic keys only on heroku, not on local app. You only need a reference to: NEW_RELIC_LICENSE_KEY in all places. That constant should have nothing to read locally, and only read the heroku configs in production.
Replace any local license keys with license_key: '<%= ENV["NEW_RELIC_LICENSE_KEY"] %>' and turn development monitor_mode to false and production monitor_mode to true.
All: read comments above for further details if this is unclear.
I am using the figaro gem and have created an application.yml file with all of my variables as per the documentation. This application.yml file is located in a shared folder (I'm using capistrano) and is symlinked to config/application.yml within the current live app directory, however I can only access the variables in the rails console and not the app. My credentials are listed as follows (real details omitted):
Note: I have tried removing the "" speech marks and also prefixing this list with production: with each line having 2 spaces, not tabbed, and it doesn't solve anything. The permissions on the file are exactly the same, 777, as the databse.yml file which was implemented in the same way.
application.yml
FFMPEG_LOCATION: "/path/to/ffmpeg"
EMAIL_USERNAME: "me#gmail.com"
EMAIL_PASSWORD: "password"
S3_BUCKET: "my_bucket"
AWS_SECRET_KEY_ID: "my_secret_key"
AWS_ACCESS_KEY_ID: "my_access_key"
I can access these variables in the production console =>
Loading production environment (Rails 3.2.14)
irb(main):001:0> ENV["S3_BUCKET"]
=> "my-s3-bucket-name"
However they don't return anything in the app itself. I set my linux box up following Ryan's excellent Pro railscast episode http://railscasts.com/episodes/335-deploying-to-a-vps
How can I get these variables accessible in the app itself?
If anyone needs more code just shout.
EDIT
I removed the figaro gem implemented the yaml config shown in the following railscasts tutorial: http://railscasts.com/episodes/85-yaml-configuration-revised. I think this is effectively what the figaro gem was doing however instead of using ENV variables, the tutorial uses CONFIG[:variables] which seem to work great.
Per Comment:
Nginx runs as its own user, so the environment variables need to live in it's space. As a user when you log in and run console, you're accessing a different set of environment variables than the nginx user accesses.
You can do this if you choose by adding them to the nginx config in the main context. But it's probably easier to go with straight yaml and add your secret tokens to your yaml file.
There are lots of secrets that apps have that need to be secured in production when running in public cloud and PaaS environments. Common one is database.yml entries for mysql user and password, but there can be others. Your Google App secret, facebook app secret,... the list goes on. There are no clear way of securing these essentially configuration parameters. You DO NOT want to put these in a file as there is no guarantee who will have access to it.
In Heroku you can specify things via environment variables. In Cloudbees (a Java PaaS) you can specify these as Java System properties. Both Heroku and Cloudbees have a commandline utility for uploading this configuration parameters but there is no support for making this work both in development and production easily.
Question is how do you configure your parameters so that you can develop easily in development but not have the production secret be available in development
Ideally there would be a gem that will work in ruby and jruby environment and PaaS that will allow me to specify me secrets in a YML file that has development settings in development but actual production secrets pulled in from ENV or java.lang.System.getProperty.
##
# file: config/secure_config.yml
development:
db:
user_id: 'dev_mysql_user'
password: 'my_dev_pwd'
google:
app_id: 'xxxxx' # this is the secret for the dev app so it can be visible
app_secret: 'xxxxx'
# ...
production:
db:
user_id: <%= get_secure_config %>
password: <%= get_secure_config %>
google:
app_id: <%= get_secure_config %>
app_secret: <%= get_secure_config %>
Where the get_secure_config helper gets the value from ENV or java.lang.System.getProperty in case of Ruby or jRuby. The finally you can use them in your app as needed. For example in database.yml or in the devise code to authenticate using google.
# config/database.yml
# ...
production:
adapter: mysql2
username: <%= SecureConfig.db.user_id %>
password: <%= SecureConfig.db.password %>
And then for extra coolness the gem should also give me an executable that allows me to push the config to my PaaS
~/work/myproject> bundle exec secure_config -push_to_heroku
or
~/work/myproject> bundle exec secure_config -push_to_cloudbees
Check out Figaro. It's almost exactly what you're after.
You place your sensitive data in a git-ignored YAML file, which are then made available to the app in ENV. It also provides a rake task for configuring your Heroku instance with the variables.
As Daniel Wright suggested above Figaro is great! It does every thing I need for ruby on rails. I needed the same support on JRuby on rails and properties via JVM system properties for Cloudbees PaaS service as well. I have forked Figaro and made these extensions and sent a pull request to laserlemon/Figaro. In the mean time you can pull it using git directive in your gem file.
gem 'figaro', '0.4.2', :git => "git://github.com/RedMicaInc/figaro.git"
Main differences are documented below
How does it work?
It works really well.
There are a few similar solutions out there, and a lot of homegrown attempts. Most namespace your configuration under a Config (or similar) namespace. That's fine, but there's already a place to describe the application environment… ENV!
ENV is a collection of simple string key/value pairs and it works just great for application configuration.
These configuration parameters are also then made available as properties of FigaroSettings object. So if you had a property called MY_PROP you can use it in your code or configuration files using FigaroSettings.my_prop or FigaroSettings.MY_PROP
For JRUBY based applications properties stored in JVM system properties are also available in a similar manner. For instance if you had a property called MY_JAVA_PROP it is accessible as FigaroSettings.MY_JAVA_PROP. Java properties are case sensitive.
As an added bonus, this is exactly how apps on Heroku or Cloudbees are configured. So if you configure your Rails app using ENV, you're already set to deploy to Heroku. For Cloudbees you can use ENV or JVM properties similarly using FigaroSettings.<property>
How does it work with Cloudbees?
Cloudbees provides application configuration in a similar manner.
Typically, to configure your application parameters accessible via JVM system properties, you would do the following from the command line using the cloudbees sdk:
cloudbees config:set -a <my_app> PUSHER_APP_ID=8926
cloudbees config:set -a <my_app> PUSHER_KEY=0463644d89a340ff1132
cloudbees config:set -a <my_app> PUSHER_SECRET=0eadfd9847769f94367b
But Figaro provides a rake task to do just that! Just run:
rake figaro:cloudbees
Optionally, you can pass in the name of the Cloudbees app:
rake figaro:cloudbees[my-awesome-app]
If you just want to see the commands used you can run rake figaro:heroku_test
I'm creating an app that allows users to use their own domain. What method do I use in my Rails app to automatically register their chosen domain with Heroku? I'll also need to deregister it if they change it.
I have contacted Heroku for the same thing, and they just pointed me at their api, and said it is fine to use it that way.
I'm afraid there isn't. Our API is "documented" only by the code of the client.
You may find our google group helpful for getting advice from community members as well: http://groups.google.com/group/heroku/
Oren
Here's the simple how-to:
require 'heroku'
heroku = Heroku::Client.new('heroku_username', 'heroku_password')
heroku.add_domain('heroku_app_name', 'example.com')
heroku.remove_domain('heroku_app_name','example.com')
See the api for more.
Of course I'd recommend against putting a plaintext password into your code. A nice thing you can do is use the heroku environment variables to get your passwords out of the code.
heroku = Heroku::Client.new(ENV['HEROKU_USER'], ENV['HEROKU_PASSWORD'])
and then you can set the environment variables on your app with
$> heroku config:add HEROKU_USER='heroku_username'
$> heroku config:add HEROKU_PASSWORD='heroku_password'
from the command line.
The heroku gem has now been deprecated. You should use the heroku.rb gem instead. The commands have changed slightly, but it's essentially the same.
require 'heroku-api'
heroku = Heroku::API.new(:api_key => API_KEY) # use API Key
heroku = Heroku::API.new(:username => USERNAME, :password => PASSWORD) # use username and password
heroku = Heroku::API.new(:headers => {'User-Agent' => 'custom'}) # use custom header
heroku.delete_domain('app', 'example.com') # remove the 'example.com' domain from the 'app' app
heroku.get_domains('app') # list configured domains for the 'app' app
heroku.post_domain('app', 'example.com') # add 'example.com' domain to the 'app' app
The way you usually add domains in Heroku is using the Heroku API through the Heroku gem.
There's a command called heroku domains:add you can invoke
$ heroku domains:add example.com
As I said before, the client calls the Heroku API. You can extract the Heroku Domain API information from the library and create a custom script that calls the Heroku API to add and remove a domain from your app.
Here's the client source code.
Note. Because you are "reverse engineering" and API which appears to be not documented, you should ask Heroku permission to do that, just to be sure you are not creating something against their TOS.
The gem is from heroku and is the recommended approach. I just contacted Heroku with the same question and this was there response:
You need to tell Heroku about the domain and where to route it as well. The CNAME tells DNS how to get the request to Heroku. Now you must tell Heroku which app to send it to. You do this by adding the domain to your app. In your case you would need to run "heroku domains:add my.domain.com" to your app. You can also do this programmatically from inside your application over our API. See the Heroku gem (http://github.com/heroku/heroku) for an example of how to connect and use the API.