-
Notifications
You must be signed in to change notification settings - Fork 21.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add credentials using a generic EncryptedConfiguration class #30067
Conversation
railties/lib/rails/application.rb
Outdated
@@ -400,6 +401,13 @@ def secrets | |||
end | |||
end | |||
|
|||
def credentials | |||
@credentials ||= ActiveSupport::EncryptedConfiguration.new \ | |||
config_path: Rails.root.join("config/credentials.yml.enc"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dhh This is great that ActiveSupport::EncryptedConfiguration
takes this file path as an argument.
Do you think we can expand it a little and make it configurable so one can easily work with few encrypted files, ie for "production (and derivative environments, like exposed betas)"?
And have some nice tooling like:
bin/rails credentials:edit config/credentials-with-my-custom-name.yml.enc
that supports out of the box finding key with relative name?
I tried to bring it to secrets in #29909 but I can work on it here if you like the idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see bin/rails encrypted:edit FILE
, which will use the new config/master.key
as its key, and which we can make accessible through something like Rails.application.encrypted.config(path)[:key]
. Let's do that as a separate PR.
Keen to come out with something generic that can be used to deal with many,
separate encrypted files. But less keen to complicate the credentials
feature itself with this. I see credentials as one specific use case for
EncryptedConfiguration, but that there could be many other such uses. So
let's see if we can't come up with some reusable primitives that people can
use to build their own credentials-like feature without burdening the
feature itself.
…On Fri, Aug 4, 2017 at 1:38 AM, Wojciech Wnętrzak ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In railties/lib/rails/application.rb
<#30067 (comment)>:
> @@ -400,6 +401,13 @@ def secrets
end
end
+ def credentials
+ @credentials ||= ActiveSupport::EncryptedConfiguration.new \
+ config_path: Rails.root.join("config/credentials.yml.enc"),
@dhh <https://github.com/dhh> This is great that ActiveSupport::
EncryptedConfiguration takes this file path as an argument.
Do you think we can expand it a little and make it configurable so one can
easily work with few encrypted files, ie for "production (and derivative
environments, like exposed betas)"?
And have some nice tooling like:
bin/rails credentials:edit config/credentials-with-my-custom-name.yml.enc
that supports out of the box finding key with relative name?
I tried to bring it to secrets in #29909
<#29909> but I can work on it here if
you like the idea
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#30067 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAAKtYvIueyQHZZ-XriqpLI7jmwL3Sabks5sUrxWgaJpZM4OtGcA>
.
|
Thinking about this further, I wonder if there's even greater room for simplification. Maybe we can combine the secret_key_base with the RAILS_MASTER_KEY and then simply rely on a single master key that can live in that ENV or in config/master.key. Then we wouldn't have a separate secret_key_base, and all apps would be required to have either RAILS_MASTER_KEY env or config/master.key set. We could further more easily allow other encrypted configurations to piggy back off that env/file key, kinda like we do with the message_verifier generator. Are there any security issues with using the RAILS_MASTER_KEY as the secret_key_base as well? |
…er envs And document the usage.
Still need to make it happen, tho.
Usually we say we change defaults, not "spec" out a release. Can't use backticks in our sdoc generated documentation either.
@config ||= deserialize(read).deep_symbolize_keys | ||
end | ||
|
||
# Saves the current configuration to file, but won't persist any comments that where there already! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"but won't persist any comments there already!" are you mentioning the updated_contents != contents
line to only write contents if they're changed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I mean that #save just serializes the in-memory config hash. It doesn't involve a text editor. Maybe we should drop that entirely.
end | ||
|
||
def config | ||
@config ||= deserialize(read).deep_symbolize_keys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use ActiveSupport::InheritedOptions
here on top of this? It would allow things like Rails.credentials.aws_access_key
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
end | ||
|
||
|
||
attr_reader :content_path, :key_path, :env_key |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do we gain by exposing these readers?
test "change content by key file" do | ||
@encrypted_file.write(@content) | ||
@encrypted_file.change do |file| | ||
file.write(file.read + " and went by the lake") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really dig the flow that Pathnames and the change
method bring! 👏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pathnames are mint!
@@ -404,6 +404,32 @@ def secrets=(secrets) #:nodoc: | |||
@secrets = secrets | |||
end | |||
|
|||
# The secret_key_base is used as the input secret to the application's key generator, which in turn |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had this lined up to deprecate secrets
but looks like it's a bit more involved than that. Let's defer the deprecation to after this is merged.
ActiveSupport::Deprecation.warn(<<-end_of_message.strip_heredoc)
`Rails.application.secrets` has been deprecated in favor of `Rails.application.credentials`
and will be removed in Rails 6.0.
See `bin/rails credentials --help` for more.
end_of_message
(Most trouble is just that our test suite relies on secrets
, so will be seeing some deprecation warnings.)
config.read_encrypted_secrets = true | ||
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] | ||
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files). | ||
# config.require_master_key = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrong production.rb, now I get why I couldn't find it 😅
Today, I faced "the problem", env based encryption, when I trying to integrate Algolia. I think for now, the best practice is using secure_credentials gem. Is there any best practice? |
I'd like to make some things clear: Credentials is a conceptual rethink from Secrets and Encrypted Secrets. It charters a new path and thus solves fewer use cases than the old way did. The Core team is not in anyway opposed to supporting multiple environment credentials as long as it doesn't complicate the existing use case as @dhh made clear #30067 (comment). However, the suggestions we've seen for multi environment credentials so far haven't been up to par. For instance, the
Do volunteer some PRs yourselves! I'm pretty confident to say that multi env credentials are a lot closer than you'd think. The biggest hurdle that I see is people continuing to conceptualize and compare with the secrets way. That's the hard way. 😄 @BerkhanBerkdemir my suggestion is here #30067 (comment). True multi env credentials could perhaps smooth this over. Thanks for all the feedback and ideas! Those who feel the burn know best how to put out the fire, so let's level Rails up together ❤️ |
Thanks for the rallying cry @kaspth What do you think of initializing a key and credentials file for each environment within config/environments? e.g:
Then:
This adds to the config directory a bit but still allows for atomic deploys of environment variables. My hesitation with this is that my setup would require "staging" credentials, which intuitively would require a fourth "staging" environment. CLI could be built so generating this is easy, e.g: It's worth noting, though, Heroku explicitly pushes me away from this approach:
That raises two options:
|
I would give it its own folder such as |
As is normally the case after clicking send, I find myself leaning toward the second option, since the entirety of my fourth "staging" environment would be copy of production, except for credentials. So to round things out:
Would this work? |
Seems to be over complicated, instead it''s easier to use plain old ENV variables. |
hey all - please take a look at #33521 if it would be enough for your usecases |
I didn't find the old system confusing but this new system is very confusing and it confused everyone in our office. The devs are now passing the master key around through Slack. |
There is no After trying many different ways of managing credentials, I've came to not checking |
I had to implement a CI/CD environment for a rails 4.2 app on google cloud. The server image needed to have all the source including secrets but in encrypted .env files. The encrypted files would then be decrypted when instance was created using kms. Now this required different files for our stage/prod envs i.e .env.stage.enc and .env.prod.env. Google project would hold metadata related to cipher file name which are available to instances. systemd task would then decrypt them as .env. So i think we need to have 2 env variables one for master key and another for cipher file. |
Thanks for the further feedback everyone! @morgoth even submitted a PR for us to hammer things out on! I've submitted my thoughts about a potential file structure here: #33521 (comment) @christophermlne can you elaborate on what you and your team found confusing about this setup? Why wasn't it confusing with the old secrets.yml + secrets.yml.enc? @printercu sorry I wasn't clear enough. It's not the files being present, it's having two similarly named files and only one being the encrypted one. I'm less in favor of the ENV variables suggestions to do lookup. Credentials is an attempt to cut down on the number of ENV variables an app should manage. Though we could expose |
Multiple environment credentials have just landed thanks to @morgoth! Feel free to throw as many GitHub reactions on his PR as you want 😄 I'd just like to say thanks to everyone who chimed in here with all their suggestions. It resulted in us ultimately moving forward and making Rails better. We couldn't have asked for a better outcome ❤️ |
Update the project from Rails 5 to Rails 6. This update introduces two major changes to the app: Rails credentials, and the Webpacker gem. Rails credentials ----------------- Rails 5.2 introduced a replacement for Secrets: [Credentials]. Credentials provides a method for saving environment variables in an encrypted format that is safe to keep in the repository. This feature depends on a master key, which must be shared out-of-band. Webpacker --------- The [Webpacker gem] allows for easy integration of [webpack] into Rails apps. This gem is designed to work with the asset pipeline, so existing JavaScript and SASS should continue to work. [Credentials]: rails/rails#30067 [Webpacker gem]: https://github.com/rails/webpacker [webpack]: https://webpack.js.org/
Update the project from Rails 5 to Rails 6. This update introduces two major changes to the app: Rails credentials, and the Webpacker gem. Rails credentials ----------------- Rails 5.2 introduced a replacement for Secrets: [Credentials]. Credentials provides a method for saving environment variables in an encrypted format that is safe to keep in the repository. This feature depends on a master key, which must be shared out-of-band. Webpacker --------- The [Webpacker gem] allows for easy integration of [webpack] into Rails apps. This gem is designed to work with the asset pipeline, so existing JavaScript and SASS should continue to work. [Credentials]: rails/rails#30067 [Webpacker gem]: https://github.com/rails/webpacker [webpack]: https://webpack.js.org/
Update the project from Rails 5 to Rails 6. This update introduces two major changes to the app: Rails credentials, and the Webpacker gem. Rails credentials ----------------- Rails 5.2 introduced a replacement for Secrets: [Credentials]. Credentials provides a method for saving environment variables in an encrypted format that is safe to keep in the repository. This feature depends on a master key, which must be shared out-of-band. Webpacker --------- The [Webpacker gem] allows for easy integration of [webpack] into Rails apps. This gem is designed to work with the asset pipeline, so existing JavaScript and SASS should continue to work. [Credentials]: rails/rails#30067 [Webpacker gem]: https://github.com/rails/webpacker [webpack]: https://webpack.js.org/
Update the project from Rails 5 to Rails 6. This update introduces two major changes to the app: Rails credentials, and the Webpacker gem. Rails credentials ----------------- Rails 5.2 introduced a replacement for Secrets: [Credentials]. Credentials provides a method for saving environment variables in an encrypted format that is safe to keep in the repository. This feature depends on a master key, which must be shared out-of-band. Webpacker --------- The [Webpacker gem] allows for easy integration of [webpack] into Rails apps. This gem is designed to work with the asset pipeline, so existing JavaScript and SASS should continue to work. [Credentials]: rails/rails#30067 [Webpacker gem]: https://github.com/rails/webpacker [webpack]: https://webpack.js.org/
Update the project from Rails 5 to Rails 6. This update introduces two major changes to the app: Rails credentials, and the Webpacker gem. Rails credentials ----------------- Rails 5.2 introduced a replacement for Secrets: [Credentials]. Credentials provides a method for saving environment variables in an encrypted format that is safe to keep in the repository. This feature depends on a master key, which must be shared out-of-band. Webpacker --------- The [Webpacker gem] allows for easy integration of [webpack] into Rails apps. This gem is designed to work with the asset pipeline, so existing JavaScript and SASS should continue to work. [Credentials]: rails/rails#30067 [Webpacker gem]: https://github.com/rails/webpacker [webpack]: https://webpack.js.org/
This file is deprecated and, for this particular app, doesn't contain any real secret. See rails/rails#30067
The combination of config/secrets.yml, config/secrets.yml.enc, and SECRET_BASE_KEY is confusing. It's not clear what you should be putting in these secrets and whether the SECRET_BASE_KEY is related to the setup in general.
This PR will deprecate secrets.yml* and instead adopt config/credentials.yml.enc to signify what these secrets are specifically for: Keeping API keys, database passwords, and any other integration credentials in one place.
This new file is a flat format, not divided by environments, like secrets.yml has been. Most of the time, these credentials are only relevant in production, and if someone does need to have some keys duplicated for different environments, it can be done by hand.
This leaves us with what to do with SECRET_BASE_KEY. For test and development, we'll instead simply derive values for both based off a known constant. These secrets are not supposed to withstand any sort of attack in test or development.
It's only in production (and derivative environments, like exposed betas) where the secret actually needs to be secret. So we will birth the new credentials.yml.enc file with secret_key_base set instead on new apps.
This change will setup the encrypted credentials along with the new application skeleton, because even if you make a mistake and forget your key, it's only production that's impacted. So it won't slow down anyone just getting started with development or test.
Finally, this would leave us with a single RAILS_MASTER_KEY for services like Heroku to set. Once this has become the standard, they could even ask for this key when it's missing on the rails buildkit deploy, such that the setup is all smooth.
Note: We will just keep Rails.secrets and friends around. The Rails.application.credentials setup will be a new, concurrent approach. All new apps would use it, but we wouldn't need to screw existing apps.
Work left:
config.require_master_key
instead ofconfig.read_encrypted_secrets
.