Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Rails Secrets in Source Code Problem

Rails Secrets in Source Code Problem

The Rails ecosystem has a systemic issue with storing secrets in source code. This violates the principle of least privilege, and undermines a host of protections built into the framework. In essence, it's poor key management, and creates one of the best attack vectors for defeating otherwise-strong cryptography and authentication measures in place.

The issue is widespread:

  • Rails generates config/initializers/secret_token.rb (and does not gitignore it). Therefore, most Rails apps use the same secret token for test mode, development mode and production mode, which anyone who can read the application source code has access to.

  • Additionally, authors of RubyGems do not usually address the issue of proper secret management when giving instructions to their users. Even Stripe provides a bad example in their sample Rails payments app. There's nothing library authors can easily point to and say: Use this, and you'll be doing it right. Thus, this class of vulnerability propagates throughout the ecosystem.

Common Mitigation Strategies

Devops typically use one of three systems to secure secrets intended for the production environment:

  1. Store secrets in config files on production which are symlinked in by Capistrano at deploy time. This is the most common secure approach. 37signals, EY, etc. use this.
  2. ENV vars. Heroku strongly pushes this. It can also be done outside of Heroku using envdir or rbenv-vars. This can be a bit harder to setup outside of Heroku. For example, I use envdir but it's not trivial to have environment changes apply across graceful Unicorn restarts, so I've switched back to stopping the processes entirely and starting them from scratch.
  3. Store encrypted secrets in version control (e.g. app version control or an ops repository), and limit the decryption key to production. Twitter uses this system.

Goals for a Rails-standard Solution

  • Self-documenting. The presence of the config instantly drives awareness.
  • Secure-by-default. We should ship with a secure configuration, requiring explicit developer action to make it insecure.
  • Simple to deploy. Translation: don't require envdir or rbenv-vars.

Other Considerations

  • config/database.yml can contain passwords. In fact, for production environments, it should. How do these relate to any proposed solution?
  • Secrets are by nature environment-specific. How does this relate to existing Rails configuration infrastructure (specifically, config/environments/*.rb)?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.