I think we have a common opinion in many points, but not in all. I don’t know if this is all off topic, but I like to drive this discussion a little bit further.
First we should clarify some words. This is how I understand the terms. We talked about “behavior”. It is what and how the application does things. “behavior” is defined with your
source code and can be influenced by configuration. “configuration” is every thing resided inside the config folder, environment variables and some times settings your read from other sources like
databases.
I consider now only configuration, which can be placed into an environment variable or config file. I don’t consider settings, which need to be placed within a secondary source.
“configuration” can by devided roughly into sensitive (e.g. passwords) and not sensitive parts (e.g. asset host name).
Both configurations can be devided into parts which are most likly to be changed, likly to be changed and unlikly to be changed.
I assume for my considerations that you have a build and deployment chain in place and every change to the source needs to be run through your
chain.
In this case I would put sensitive configurations always into an environment variable.
For not sensisitve configurations I would put every thing which is most likly to be changed into environment variables,
configurations which are likly to be changed, well it depends, configurations which are unlikly to be changed I put into config files
under the config folder.
Now comes environment files into play. Rails defines the known environments, but staging, integration and so on is also called an environment. When I follow your advice against
seperate environments within Rails then your running environments diverge from your Rails environments and every time you look at your configuration you have to make a mental shift.
If you are at development, look at development.rb, If you are at production look at production.rb, when you are at test look at your test.rb for all other environment look at production.rb.
I like the convention look at the configuration of your current environment in every case. This enables you to use ENV[‘STAGING_DB_URL’] for staging and ENV[‘PRODUCTION_DB_URL’]
within your database.yml with an “staging” section.
I think every body should use the right tool for the job and there should not be a recommendation against different environment rbs,
I think I lost you on my example of running the RAILS_ENV=production code locally & why it was safer without production config info checked in.
In my case I’m using a .env
file and already have all the creds I need for local development i.e. stripe API token and AWS etc. They’re all set for my own personal development account. When I want to profile the behavior of a production app, it is super safe for me to use RAILS_ENV=production
locally and be 100% confident that i’m not going to send out emails or blow away a production memcache because it’s using the exact same configuration as my development environment. When someone has all that info checked in as soon as they use RAILS_ENV=production
then the app is a live loaded gun.
To me it boils down to move sensisitive configurations into environment variables. With this I totally concour. Furthor more I would use different environment variable names for production, development and so on.
As you mentioned this technique doesn’t protect against the case where you ssh into your production box by accident and run a bad command. But neither does relying on someone to remember to run RAILS_ENV=staging
, sure it might catch a slip up or two, but I guarantee if you rely on this, one day someone will forget that preface and tears will be made.
Yes, some day, some one, but it will happen a little tiny bit less often as without it.
It’s also why we should potentially build in safe guards for the really dangerous components, like dropping databases.
It’s the same as with RAILS_ENV=staging. You will need to build in an option to disable this safe guard, simply because
it will be in the way of automation tasks. If you have an option in place like ‘-i’ of rm -rfi /, some people will use it, some will not. If you change the
meaning, that you have to use the switch to disable the safe guard, people will tend to use this switch every time or use an alisias
to disable the safe guard. It’s the same argumentation you use against a RAILS_ENV=staging, I think.
If you always have to remember to do something i.e. you always have to remember to preface every command with RAILS_ENV=staging, then it’s insecure by default. If you’re requiring the user to do the right thing 100% of the time, over the long run you’ll always lose. Almost all major incidents and security breaches have a human component. My desire is to mitigate this as much as possible.
If a user has to press “yes” every time, he will press “yes” also at the wrong time. So in this point your right. But it also is true for your safe guard.
These tickets came all types of customers. They came from some of our largest customers who have been running on the platform longer than I have worked there and new developers on free accounts. Every developer is capable of making a mistake. I’m not trying to pull rank here with my “i’ve been doing this for X long” i’m saying that i’ve seen A LOT of developers and apps make this mistake. This isn’t an idea i’m pulling out of my butt here. At one point this was the largest ticket producer by a fair margin. After I introduced the article and added a warning, they’ve mostly disappeared I’ve heard basically no complaint or pushback of the concept from people who have done this. It’s not so much an “opinion”, that can be “really wrong”, as it is a hypothesis that i’ve tested on hundreds-of-thousands/millions of rails apps and gotten a lot of positive confirmation on.
It depends on which part of your post you reference to. Is the test for Rails.env.staging? a bad practice? Yes, for this setting like you display it in your post it’s true. Within your post you say it “keeping your staging
as close to production
as possible”. This is also true. But is it a bad practice to have a staging.rb, then No.
Tell me what you want to do on Heroku and I can tell you how it’s possible. If you needed to generate files I would hook into the rake assets:precompile
call.
Thanks for this offer, but I don’t use heroku. It was only an example. I use dedicated servers + chef + capistrano.
Great, this is what i’m talking about. Your staging or development server should not be capable of accessing any sensitive 3rd party services tied to production. If you check them into your app, then they’re accessible. You’re doing what i’m advocating here. I don’t care about how you store the information i.e. put it in an env var or some other configuration management toolchain, just whatever you do don’t put all your secrets in your app and check them in to your source control and make them available to all running instances of your app.
Yeah, in this point we concour.