diff options
author | Kasper Timm Hansen <kaspth@gmail.com> | 2017-02-23 18:15:28 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-23 18:15:28 +0100 |
commit | fbee4e3ce37674eb928298490a35d3dfd1921e67 (patch) | |
tree | 53fb0bb589c7351688c711ddc1ecbb10b7415951 /railties/lib/rails/commands | |
parent | 4734d23c74fb4193aafe7cb04256bb745680d97f (diff) | |
download | rails-fbee4e3ce37674eb928298490a35d3dfd1921e67.tar.gz rails-fbee4e3ce37674eb928298490a35d3dfd1921e67.tar.bz2 rails-fbee4e3ce37674eb928298490a35d3dfd1921e67.zip |
Revert "Revert "Add encrypted secrets""
Diffstat (limited to 'railties/lib/rails/commands')
-rw-r--r-- | railties/lib/rails/commands/secrets/USAGE | 52 | ||||
-rw-r--r-- | railties/lib/rails/commands/secrets/secrets_command.rb | 50 |
2 files changed, 102 insertions, 0 deletions
diff --git a/railties/lib/rails/commands/secrets/USAGE b/railties/lib/rails/commands/secrets/USAGE new file mode 100644 index 0000000000..4b7deb4e2a --- /dev/null +++ b/railties/lib/rails/commands/secrets/USAGE @@ -0,0 +1,52 @@ +=== Storing Encrypted Secrets in Source Control + +The Rails `secrets` commands helps encrypting secrets to slim a production +environment's `ENV` hash. It's also useful for atomic deploys: no need to +coordinate key changes to get everything working as the keys are shipped +with the code. + +=== Setup + +Run `bin/rails secrets:setup` to opt in and generate the `config/secrets.yml.key` +and `config/secrets.yml.enc` files. + +The latter contains all the keys to be encrypted while the former holds the +encryption key. + +Don't lose the key! Put it in a password manager your team can access. +Should you lose it no one, including you, will be able to access any encrypted +secrets. +Don't commit the key! Add `config/secrets.yml.key` to your source control's +ignore file. If you use Git, Rails handles this for you. + +Rails also looks for the key in `ENV["RAILS_MASTER_KEY"]` if that's easier to +manage. + +You could prepend that to your server's start command like this: + + RAILS_MASTER_KEY="im-the-master-now-hahaha" server.start + + +The `config/secrets.yml.enc` has much the same format as `config/secrets.yml`: + + production: + secret_key_base: so-secret-very-hidden-wow + payment_processing_gateway_key: much-safe-very-gaedwey-wow + +But that's where the similarities between `secrets.yml` and `secrets.yml.enc` +end, e.g. no keys from `secrets.yml` will be moved to `secrets.yml.enc` and +be encrypted. + +A `shared:` top level key is also supported such that any keys there is merged +into the other environments. + +=== Editing Secrets + +After `bin/rails secrets:setup`, run `bin/rails secrets:edit`. + +That command opens a temporary file in `$EDITOR` with the decrypted contents of +`config/secrets.yml.enc` to edit the encrypted secrets. + +When the temporary file is next saved the contents are encrypted and written to +`config/secrets.yml.enc` while the file itself is destroyed to prevent secrets +from leaking. diff --git a/railties/lib/rails/commands/secrets/secrets_command.rb b/railties/lib/rails/commands/secrets/secrets_command.rb new file mode 100644 index 0000000000..05e0c228e8 --- /dev/null +++ b/railties/lib/rails/commands/secrets/secrets_command.rb @@ -0,0 +1,50 @@ +require "active_support" +require "rails/secrets" + +module Rails + module Command + class SecretsCommand < Rails::Command::Base # :nodoc: + def help + say "Usage:\n #{self.class.banner}" + say "" + say self.class.desc + end + + def setup + require "rails/generators" + require "rails/generators/rails/encrypted_secrets/encrypted_secrets_generator" + + Rails::Generators::EncryptedSecretsGenerator.start + end + + def edit + require_application_and_environment! + + Rails::Secrets.read_for_editing do |tmp_path| + watch tmp_path do + puts "Waiting for secrets file to be saved. Abort with Ctrl-C." + system("\$EDITOR #{tmp_path}") + end + end + + puts "New secrets encrypted and saved." + rescue Interrupt + puts "Aborted changing encrypted secrets: nothing saved." + rescue Rails::Secrets::MissingKeyError => error + say error.message + end + + private + def watch(tmp_path) + mtime, start_time = File.mtime(tmp_path), Time.now + + yield + + editor_exits_after_open = $?.success? && (Time.now - start_time) < 1 + if editor_exits_after_open + sleep 0.250 until File.mtime(tmp_path) != mtime + end + end + end + end +end |