From fbee4e3ce37674eb928298490a35d3dfd1921e67 Mon Sep 17 00:00:00 2001 From: Kasper Timm Hansen Date: Thu, 23 Feb 2017 18:15:28 +0100 Subject: Revert "Revert "Add encrypted secrets"" --- railties/lib/rails/commands/secrets/USAGE | 52 ++++++++++++++++++++++ .../lib/rails/commands/secrets/secrets_command.rb | 50 +++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 railties/lib/rails/commands/secrets/USAGE create mode 100644 railties/lib/rails/commands/secrets/secrets_command.rb (limited to 'railties/lib/rails/commands') 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 -- cgit v1.2.3 From 9fdf326a5f6f7e10594dd6205cfc8e0425fb3e67 Mon Sep 17 00:00:00 2001 From: Kasper Timm Hansen Date: Thu, 23 Feb 2017 18:47:23 +0100 Subject: Yank the intricate immediately-exiting editor recognition. Most editors support a wait flag of some kind which prevents their process from exiting until the file or window is closed. Prefer people to assign that themselves than us mucking around with File mtimes or other such things. Example of an editor config: ``` export EDITOR="atom --wait" ``` --- railties/lib/rails/commands/secrets/secrets_command.rb | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'railties/lib/rails/commands') diff --git a/railties/lib/rails/commands/secrets/secrets_command.rb b/railties/lib/rails/commands/secrets/secrets_command.rb index 05e0c228e8..3ba8c0c85b 100644 --- a/railties/lib/rails/commands/secrets/secrets_command.rb +++ b/railties/lib/rails/commands/secrets/secrets_command.rb @@ -21,10 +21,8 @@ module Rails 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 + puts "Waiting for secrets file to be saved. Abort with Ctrl-C." + system("\$EDITOR #{tmp_path}") end puts "New secrets encrypted and saved." @@ -33,18 +31,6 @@ module Rails 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 -- cgit v1.2.3