-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
Provide encrypted secrets #25095
Comments
Related with https://github.com/Shopify/ejson |
cc @burke if you have opinions about this. |
Yeah, ejson is good inspiration, but I'd like to retain YAML (it's way more friendly than JSON) and the interface should be integrated with Rails fully. |
🙏 |
Does This way the unencrypted version can hold dev and test secrets — thereby acting as a manifest as well — and keep production secrets to the encrypted version. Although this assumes no dev or test secrets need encryption. Which I can't glean from your description if that's what you mean, @dhh. |
Happy to keep secrets.yml as well. We'll need to anyway for backwards On Sat, May 21, 2016 at 3:56 PM, Kasper Timm Hansen <
|
I think this is a great idea and would keep accidental version control commits from being a security nightmare. If you'd like some help on the implemention I'd be happy to work on this with someone else |
Please do take a stab at it! On Sat, May 21, 2016 at 8:08 PM, Shakycode notifications@github.com wrote:
|
@dhh Awesome, myself and @danielpclark are going to pair on this and see what we come up with. I'm heavy security minded so this would be a fun PR. Thanks for letting us work on this! 👍 |
Updated the original ticket to include the idea of keeping both an encrypted and an unencrypted secrets file at the same time. |
If the rationale behind this is to prevent people from committing secret information to their repository, why not take the opportunity to guide people towards taking full advantage of environment variables—perhaps by incorporating something like dotenv as part of the default build—rather than implementing a potentially awkward workaround? |
@dnch Totally. That is the current guidance, but there's a foggy gray area around "where do these env vars come from?" We can do better. We demonstrate using However! Some sensitive config are better off being versioned along with source code. The big bonuses are atomic deploys, versioned config, and dev/prod parity. Atomic deploys directly from source: A change can be driven by source commits alone without careful coordination in lock step with an external provisioning mechanism (Vault, etcd, NFS-mounted shared config dir, Chef encrypted databags, packaging/slugging). That means a deploy can rolled back without special coordination and separate branches can be deployed to the same provisioned environment but use different secrets without "branching" at the secret-store layer. Dev parity: We can use the same mechanism in development and deployment. From the application's point of view, it just has config available to it. There's nothing else to do. Decrypting config to make it available to the app is a deployment/packaging step. (For more in this vein, check out https://github.com/elasticdog/transcrypt. It uses git clean/smudge filters to transparently encrypt/decrypt files in a git repos.) |
My objective is rather to avoid having to deal with a rash of ENVs! So in many ways the opposite. That's the approach I consider awkward.
|
This is great news. I sincerely ask that when you create the new scheme, please take the time to consider the different ways a developer needs to use and handle the secrets and come up with an awesome experience that's easy and works. I break the experiences for managing secrets into 3 areas:
I thought the
Lastly I know you can't cover all cases but there are a couple of major camps people fall in like Heroku and non-Heroku, or like ENV's and don't like ENV's, etc. If you can cover each major group's use case in managing secrets with a decent scheme, then just think how awesome they would all feel, the man hours saved and mistakes prevented! |
nods Thanks @dhh and @jeremy—I've got a better idea where you're coming from, now. The ability to do atomic deploys purely from source would be a neat win and something I hadn't considered. The potential use / distribution of the production master key across development environments raises a red flag, though. Do you think it would be worthwhile having Rails default to using the unencrypted secrets.yml in test / dev (thus negating the need to provide the master key on server-boot) and only reading the encrypted version in production? To reinforce the desired behaviour, it could be taken one step further by having secrets.yml added to the default Would similar behaviour apply to database.yml? Is it worth incorporating database.yml into secrets.yml? |
Yeah, no. Production secrets floating around dev laptops → 🤐. The unencrypted dev/test vs encrypted prod behavior is what's intended (and proposed). That requires Ideally, we could have separate keys for dev/test and prod/staging, suggesting that we have separate secrets files. Database credentials (but not the rest of the database configuration+settings) would be a good fit. This is pretty susceptible to scope creep, though! Limiting this to a straightforward extension of secrets.yml behavior is just enough to ratchet forward a wee bit. |
Agree. Let's start with the straight extension of secrets. We could think about how database.yml could potentially reference an encrypted secret.
|
This looks like the Ansible Vault feature (http://docs.ansible.com/ansible/playbooks_vault.html), right down to the YAML file. Would it make sense to have this feature work with Ansible Vault secret files? |
Don't think we would want to tie a Rails feature to Ansible, but let's On Thu, May 26, 2016 at 3:20 PM, Jay Godse notifications@github.com wrote:
|
Few thoughts after reading through the thread... Env Vars
Different environments
Heroku and similar
One key fits all?
|
personally, in all my projects i gitignore secrets.yml and database.yml, create secrets.yml.default and database.yml.default with dev and test stuff which are checked in, and bin/setup cp's them to original filename. new dev just has to clone and do bin/setup to get up and running, same for CI servers. doesn't solve atomic deploy situation but might be a safer default if the primary objective is to help people avoid checking production secrets into the repo. if the primary objective is atomic deploys, however, then you'll need to have it in the repo encrypted, i guess. |
we often find ourselves in situations where we have to store environment-dependent config values (e.g. "auto_logout_after_x_seconds") and end up putting them in the secrets.yml even though they are not exactly secrets simply because there doesn't seem to be a better place. ENV variables are one alternative but then again they have their own problems. Could there be something like a more general config.yml? |
FWIW I've been working on a ruby implementation of ejson (rebranded 'ecfg') with support for yaml and toml: https://github.com/shopify/ecfg-ruby. It's pure ruby, but with a dependency on rbnacl-libsodium, which has a native extension. Does this seem like a useful thing to pursue further? |
burke, cool. For this I'm looking to stick with YAML and to have it integrated with our rails command. So don't think it's a direct fit. |
Cool. Note that this iteration does support yaml fwiw. |
the issue I am seeing is sharing the how do we change that master key? a solution I am seeing is to use GPG to encrypt/decrypt. this allow to register individual keys for employees and external services.
|
I am now seeing the same red flag had already been raised and answered. I still would like to play with the idea of using GPG, the list of allowed keys could be maintained via a list of authorized emails, with keys automatically fetched and revoked on save. |
Happy to see a full proposal for that. Want to be sure that we hide the On Mon, Oct 24, 2016 at 3:05 PM, Mathieu Jobin notifications@github.com
|
This is what ecfg does. We can hire it behind the rails command if that is the only concern that you have about it. It does support yaml now. |
Yeah — the pure-ruby yaml parser is a little horrifying but it does exist in this version, along with toml and json: https://github.com/Shopify/ecfg-ruby/tree/master/lib/ecfg/parser |
I have a feeling configuring To help prevent this, we could have a config setting where we do |
@BenMorganIO I don't think it's a good idea to export a global like that on a machine that runs multiple apps. Idea is that you'd start the server with that export, not keep it in .bash_profile. |
Cool that would keep things even simpler 👍 |
Was just talking with @rafaelfranca about this and ejson/ecfg. This turned out longer than I expected, sorry for the wall of text. We can easily enough change There are two primary benefits we get from using ejson/ecfg at Shopify:
Point 2 is addressed because we use public key crypto. Each encrypted file embeds a public key, and the matching private key is retrieved from disk, in a location that is readable by the decryptor but not by the application. This permission isolation is not really feasible for Rails since we can't very well create users, setuid, etc. I think the idea of using an environment variable is probably an okay solution, since we could just remove the variable after decrypting secrets so that the application wouldn't have trivial access to it (it would be up to the deployment to isolate the launcher script or whatever has access to the key from the application). It's important in our use-case to have secrets separated by environment. I think the right precedence to merge things into
Files 2 and 4 would be edited directly, and files 1 and 3 would be edited via (e.g.) WorkflowIf the encrypted file _public_key: "c9aff3dc4fe87be13516ea97634d0f03325b5ac5a1311dc503172e78bc43e955"
s3_access_key_id: "EJ[1:LmOKDfK....<snip>...]"
s3_secret_access_key: "EJ[1:LmOKDfK...<snip>...]" When we run _public_key: "c9aff3dc4fe87be13516ea97634d0f03325b5ac5a1311dc503172e78bc43e955"
s3_access_key_id: "AKIAASDFGHJKLZXCVBNM"
s3_secret_access_key: "pH8iRdXt2eyEyL3s8fPYNAyapH8iRdXt2eyEyL3s8fPYNAya" Any changed values would be replaced and encrypted in the file on disk. If the private key was not available locally, the file opened in _public_key: "c9aff3dc4fe87be13516ea97634d0f03325b5ac5a1311dc503172e78bc43e955"
s3_access_key_id: "<ecfg key not available; replace to update>"
s3_secret_access_key: "<ecfg key not available; replace to update>" When running
Key detectionAs far as key detection goes, when we start supporting multiple files with multiple keypairs, we can't just use I think the best option would be to set
Imagine the first key would be for Another option: Given the keypair:
...we could set: Boot/DecryptionWhen booting Rails in development, the process would be:
|
@burke Thank you for a good writeup. I think that made it clear on the implementation. Are you or @rafaelfranca actually going to implement the patch to Rails, or should I start working on it? I do have some feedback from your suggestions though:
On the other hand, it seems like most projects people will have at least these files:
That could get tedious over time though if you're configuring many environments and having multiple secrets. I think secrets.yml master: &master
_public_key: 52abdb909730f7a40262d5deb42bb1d24c4c1182122d1c76facd3a8105f6a12c
secret_key_base: cc6cef8495...
s3_access_key_id: AKIAASDFGHJKLZXCVBNM
s3_secret_access_key: pH8iRdXt2eyEyL3s8fPYNAyapH8iRdXt2eyEyL3s8fPYNAya
staging:
<<: *master
_public_key: c9aff3dc4fe87be13516ea97634d0f03325b5ac5a1311dc503172e78bc43e955
secret_key_base: "EJ[1:LmOKDfK...<snip>...]"
production:
<<: *master
_public_key: ad80e0e3c9ef5d4315d6f2dd3a2dbf92e96ec50ddaead4ccc37b17a9b36e4d0c
secret_key_base: "EJ[1:4id8Us...<snip>...]"
s3_access_key_id: "EJ[1:Rj4mwis...<snip>...]"
s3_secret_access_key: "EJ[1:K4id93O...<snip>...]" So, I honestly don't know if ecfg would support this specific use case, but I don't think it'd be too hard to implement. What do you think about my suggestion? |
You might take a look at @ahoward's Sekrets Gem as (at least) a proof of concept. Provides the core functionally described above, encrypted YAML files can be loaded by calling Keys are managed it two ways, through the environment as proposed above (SEKRETS_KEY) but also in a file, RAILS_ROOT/.sekrets.key by default. The file is an interesting approach. It simplifies per app keys, especially in development. And Sekrets ships with a Capistrano task that will upload the key file to the new deploy if it exists locally. |
I like the concept of having a file at the root being the key. This would make things pretty straightforward, especially for beginners. Also, I love the recommendation to use |
we've been using the sekrets gem @dojo4 for years with very, very good results. happy to contribute code or lessons learned. i will say that the optional file key is mandatory for newbs with many projects where env settings are the confusinz |
Picking this up again. I like the option of a optional file key in addition to the ENV approach. That's solid. Also liking the simple API from sekrets. Also, I'd like to start with just one secrets.enc.yml file that uses the same env mapping in there. That should be the default. Happy to have an overlay of secrets.production.enc.yml that can happen on top of that, but that shouldn't be part of the default setup. I don't fully understand the need to use public/private key and embedding the public key, compared to just using a single key as with sekrets. Happy to be further educated, but the single key approach strikes me as simpler and good enough. Who's interested in taking this work forward? If this is going to make it into Rails 5.1, we need to have a real PR in place within about a month. |
I don't personally have cycles to spare to drive this through anytime soon, but a couple of comments: Public/private key is useful on larger teams. It can be useful to give everyone access to update secrets but not necessarily retrieve them, so that we don't have to rotate high-value secrets each time a developer leaves the organization. Having separate keys per environment has an additional benefit of making it really difficult for e.g. staging to be misconfigured as production and start sending emails to customers, etc. Shared key is definitely simpler. We (Shopify) wouldn't be able to switch to a solution this simple, but it would be a huge step forward for a lot of users. Merging everything in a single file divided up by environment is sensible, and could even be made to work in the case of key-per-environment by just teaching the tool about public keys or shared key fingerprints or something embedded in subtrees. |
I think single key approach is a good start and a good step up from our current offering. Good enough for V1 MVP, I'd say. I'll take a look at @dhh I still can tackle this if we need it by the end of Jan. |
@sikachu / @dhh - feel free to ping me for any questions/help : ara@dojo4.com - i think it is simple and portable enough to drop in easily tho. the only rails/version dependent code is, i think, the cap recipe but even that might 'just work TM' |
@burke i also consider pub/pri keys and gave up for two reasons: 1) 80/20 rule as you point out 2) branches in git with differently encrypted keys actually solves some of the issues you point out. food for thought. |
last comment: if anyone would like to be a contributor to sekrets repo lemme know... |
Keeping important secrets in config/secrets.yml isn't a good idea, as all these secrets are stored in plaintext when the file is checked into version control. That's a shame. The application should be able to store actual secrets that it need to talk to internal and external services.
We can get there by providing an additional secrets file under config/secrets.yml.enc along with an interface to both edit and read this file.
To edit the file, I'm thinking something like:
To enable servers and services to read this file, we can set a single environment variable, like RAILS_MASTER_KEY.
We should ask for this master key if it's not available when booting the server, if config/secrets.yml.enc is present:
Note that config/secrets.yml.enc is in addition to config/secrets.yml. We can still use the latter for secrets that aren't critical, like dev/test secret_base_key. Then it'll become a user-action to add config/secrets.yml.enc (which should be created on-demand the first time
rails secrets:edit
is called). At the initiation time, the user will be asked to set the master key.The two secrets files should then be merged at runtime, with enc taking priority.
The text was updated successfully, but these errors were encountered: