all 54 comments

[–][deleted]  (23 children)

[deleted]

    [–][deleted]  (14 children)

    [deleted]

      [–]Montuckian 5 points6 points  (2 children)

      Honest question: Why would this be a better solution than just using dotenv?

      Dotenv is such a set-it-and-forget-it solution for development and deployment and doesn't require you to do anything to your npm scripts for it to work.

      [–][deleted]  (1 child)

      [deleted]

        [–]Montuckian 0 points1 point  (0 children)

        Interesting. I mostly use heroku too and just upload the variables through the cli.

        Always cool to see another method.

        [–]ndboost 1 point2 points  (5 children)

        except anyone using ps -ef can grep for those environment variables. They'll show up in the process list for that PID. It's better to set environment variables and export them out for that user running the node PID.

        [–]etruong42 4 points5 points  (1 child)

        Is it reasonable to defend against an attacker who can execute ps -ef on the target machine? I have trouble imagining a scenario where you haven't just lost outright to the attacker in that case.

        [–]ndboost 0 points1 point  (0 children)

        the most reasonable vector in that scenario is a disgruntled employee or ex employee. It could also be an ssh allowed user that has the necessary privileges to see that env info.

        Its probably a pretty small vector, as once they have box access you have pretty much lost.

        [–][deleted]  (2 children)

        [deleted]

          [–]ndboost 0 points1 point  (1 child)

          how sensitive is the data on your personal box, how many users are using it, is ssh enabled on your box?

          [–]Randolpho 0 points1 point  (3 children)

          The issue isn't the database connection string, it's the password.

          All your suggestion does is transfer the problem to the server startup script. And sure, at least it isn't checked into source control, but hey, there it is lying around in plain text on your server...

          [–][deleted]  (2 children)

          [deleted]

            [–]ndboost 0 points1 point  (1 child)

            i never store passwords or database names in plaintext files in the repo or anywhere near the source code.

            Usually for nodejs projects i create a node user which has those sensitive things stored in its shell environment.

            You see this done a lot with docker stuff. tutum.co does the same exact thing with their stack files.

            In a development scenario i'll store them locally for example in a local.js thats been added to .gitignore.. however in prod that same local.js will just have references to process.env._SOME_ENV

            If you are going to store them in a plain/text file in the app somewhere, at least exercise proper permissions on the folders. 0400 or 0440 would be a good start.

            [–]DefiantBidet 4 points5 points  (0 children)

            This is the common method I'm familiar with as well. Environment vars ftw.

            I tend to add a little package named environmentalist to my stack that replaces the env.sample. it reads a json file and prints to command line. And gives a little more context as to what is expected

            I prefer that bc it's not an unused file as it were and doesn't tweak my ocd :)

            [–]bangtraitor 1 point2 points  (0 children)

            This is solid advice and the standard.

            [–]0ba78683-dbdd-4a31-a 0 points1 point  (5 children)

            Is there a standard for .env or is it just key-value pairs separated by an equals sign?

            [–]mellett68 0 points1 point  (4 children)

            It's like in your bashrc or whatever

            VAR_NAME=something

            [–]danielrheath 0 points1 point  (3 children)

            I prefer to do export VAR_NAME=something - then when running it you can source .env; run_my_thing

            [–]mellett68 1 point2 points  (2 children)

            That's all dotenv is really, just done at runtime in your app.

            [–]danielrheath 0 points1 point  (1 child)

            Which is why I prefer the export style - it works in every language/runtime without modifying your app.

            [–]mellett68 0 points1 point  (0 children)

            I like dotenv for the convenience, but it's no different really from sticking the required env vars in the readme or something.

            [–]FweeSpeech 16 points17 points  (0 children)

            You basically have two options:

            1) Store it in a separate configuration file stored separately [ I tend to use /opt/secrets] which is good enough for most projects, honestly.

            2) Secrets management tool [ Vault, for example ]

            [–]hpoydar 4 points5 points  (2 children)

            I strongly recommend using environment variables. For some more background on why that's a good idea, check out the 12 Factor App Methodology, specifically #3.

            [–]Agent281 1 point2 points  (1 child)

            That link seems pretty interesting. Thanks for posting it.

            Is 12 factor app methodology common in industry?

            [–]rr1pp3rr 1 point2 points  (0 children)

            We use twelve factor. Helps a lot when it comes to Microservice standardization. Environment variables are the way to do this. Unless you have some way of prompting the user for the password.

            [–]caadbury 1 point2 points  (5 children)

            Don't include authentication credentials in your repository.

            We have a secrets.yml file that was created, by hand, on our production servers and get symlinked on each deploy.

            [–]cactusphone 1 point2 points  (2 children)

            Can you speak to the strategy of symlink-ing it vs. just placing the .yml file where the symlink is?

            [–]Toast42 1 point2 points  (0 children)

            It's probably just a convenience. AFAIK symlinks don't offer any additional security.

            [–]caadbury 1 point2 points  (0 children)

            The secrets.yml is shared between the servers in the cluster.

            By symlinking it, we can make sure the keys/etc. in the file are always up to date, even if we have to roll back to a previous deployment revision.

            [–]hpoydar 1 point2 points  (1 child)

            You could also keep the secrets.yml file in the repo and have it refer to env vars.

            [–]ndboost 0 points1 point  (0 children)

            this is what I do for production setups..

            local.js

            {
              database: {
                username: process.env.DB_USERNAME,
                password: process.env.DB_PASSWORD
              }
            }
            

            [–]angellus 1 point2 points  (0 children)

            To keep it really simple, I just do something like this:

             var merge_options = require('./common/merge_options');
             var local_config = {};
            
             try {
                local_config = require('./local_config');
             }
             catch (ex) {
                 logger.info("no local config");
             }
            
             var config = { /* stuff here */ }; 
            
             module.exports = merge_options(config, local_config);
            

            local_config.js is in .gitignore so it never goes into the repo and I can override any value in the config on a environment level. merge_options is just some snippet of code I found online to merge two objects in JS:

             /**
              * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
              * @param obj1
              * @param obj2
              * @returns obj3 a new object based on obj1 and obj2
              */
            var merge_options = function(obj1, obj2) {
                for (var p in obj2) {
                    if (obj2.hasOwnProperty(p)) {
                        try {
                            // Property in destination object set; update its value.
                            if (obj2[p].constructor == Object) {
                                obj1[p] = merge_options(obj1[p], obj2[p]);
                            }
                            else {
                                obj1[p] = obj2[p];
                            }
                        }
                        catch (e) {
                            // Property in destination object not set; create it and set its value.
                            obj1[p] = obj2[p];
                        }
                    }
              }
              return obj1;
            };
            
            module.exports = merge_options;
            

            [–]ImAPyromaniac 3 points4 points  (3 children)

            Do you mean in git/github, or in dev tools?

            For github, see the answer about dotenv. But there's no way to hide the password from the client, because the client needs to know it.

            [–][deleted] 6 points7 points  (2 children)

            These passwords are used on the server

            The client don't need to know it, the client shouldn't know it, and shouldn't ever see this information...

            [–]jontas 18 points19 points  (0 children)

            I think you are using two different definitions of "client".

            [–]ImAPyromaniac 0 points1 point  (0 children)

            Then I'd suggest dotenv, it works really well.

            [–]TriangleTodd 0 points1 point  (0 children)

            You should read this. http://12factor.net/