Securing and Making Node.js Apps Flexible with Environment Variables
Welcome to Module 2: Node Production Preparation. First of all, how do you secure your app by using environment variables? Environment variables, they're great, great tools that will allow you to prevent accidentally publishing sensitive information, not use GitHub, GitLab, or Gitbucket or any other repository for your code, because they might be hacked and they are hacked periodically. You can check out the links in the footnotes.
Code is less flexible when you actually hardcode some sensitive information or some environment specific information, such as the URL of your database. Because if you are moving your code from environment to environment, that variable needs to change. Let's take a look at this code example. You might have done a similar coding and I did too, especially on the earlier stages when all I have is just one file. Why bother?
Well, obviously, this code is not flexible at all. If I want to move it from my development environment to a QA, such as staging or maybe CI/CD environment where I have a different database, I should have a different database at least, and that code will be very inflexible. I have to modify the value actually in the code because I have my username, "admin", and then I have the password right there in the connection URL. Same thing with API Key and API Secret. It's not flexible at all and then as I've mentioned, the version control systems, they might be hacked or you might accidentally publish it. So it's not a good practice.
The best practice is to use environment variables. For example, MY_ENV_VAR, all capitals with underscore, has the value of "Hello". And then within my Node.js code, I can use process.env.MY_ENV_VAR. Similarly, I can run the command on the next line. In this case, in order for me to save the environment variable, I would need to say "export." This is just a Linux standard command and please notice that there's no spaces. There are no spaces either before or after the equal sign when you define the value for environment variable.
Now, more examples. So going back to that piece of code where we are connected to the database and making our OAuth call, now we can grab them from environment variables, process.env.API_KEY, process.env.API_SECRET, and process.env.DATABASE_URL. This way, it's very easy to transport our code. Our code becomes very flexible and portable. We can just change the environment variable. We don't have to modify the code itself. And by the way, a lot of libraries support NODE_ENV. When you set it to "production," their behavior will change.
For example, Express, one of the most popular Node.js frameworks, has a different level of error messaging and error stack tracing when you use it in production. It has fewer because obviously in production, you don't want to output a lot of that information. It might expose you, make your application more vulnerable to attackers. Some of the ways to populate environment variables or env vars.
First of all, we can populate them in AWS EC2 user data. This is a specific place where we initialize our environment, either our cloud environment or our application environment. So that's a perfect place to set them up. Also we could set env vars in Dockerfile. AWS has a special mechanism for provisioning infrastructure. It's called CloudFormation, and we can set them up right in the CloudFormation blueprint or provide parameters, which when we create a stack from the CloudFormation blueprint, those parameters will be set.
Also, most of the cloud providers, they have some type of a client, a CLI client, Command Line Interface client, and they would allow you to set those environment variables, especially platform as a service, such as Elastic Beanstalk or Heroku. With the command line, you can save any environment variable for that particular app in a cloud, so the value would be saved.