Working with Docker, you may have encountered the challenge of setting up and securing environment variables. With Docker becoming an essential tool in many CI/CD pipelines, understanding the management of environment variables is crucial.
Consider environment variables as the adjustable settings on a car. Just as you can adjust the seat, mirrors, and temperature to suit your preferences, you can set environment variables to customize your Docker environment.
This blog post will cover what environment variables are, how to set them up and secure them in Docker, and how to manage them effectively.
TL;DR: What are Docker environment variables?
Docker environment variables are dynamic-named values stored within the Docker container that can be used by running processes. They are crucial for storing configuration parameters needed by your applications, such as database passwords or API keys. Read on for more advanced methods, background, tips, and tricks on managing Docker environment variables.
# Setting an environment variable in Docker
Understanding Environment Variables
Before we delve into the specifics of setting up environment variables with Docker, let’s first understand what environment variables are and their importance.
Environment variables are dynamic-named values that can affect the way running processes will behave on a computer. They are part of the environment in which a process runs.
For instance, a running process can query the value of the
TEMP environment variable to discover a suitable location to store temporary files, or the
USERPROFILE variable to find the directory structure owned by the user running the process.
Environment Variables in Docker
In the context of Docker, environment variables hold a significant role. They store configuration parameters that your applications need to run.
These parameters could range from database passwords, API keys, to even the home directories of your applications. By storing these parameters as environment variables, you can keep your applications flexible and portable.
This flexibility allows the same Docker image to be used across different environments with varying configurations.
Docker Configuration Environment Variables
Docker offers two types of variables that you can use for configuration: ARG and ENV.
The ARG variables are only available during the build of a Docker image (using the
docker build command), not when a container is up and running. On the other hand, ENV variables are available during the build of the Docker image as well as when the Docker container is running.
Let’s illustrate this with an example. Suppose you have a variable that defines the version of your application. You could define this as an ARG variable in your Dockerfile, and then pass the version number during the build process:
RUN echo $version > version.txt
And then build the Docker image with the
docker build --build-arg version=1.0.0 -t my-app .
However, if you need to access this
version variable while the Docker container is running, you would need to use an ENV variable:
CMD echo $version
In this case, the
version variable is available during the build and when the Docker container is running. However, it’s important to note that ARG variables are not available after the image is built, which can lead to them being overwritten if the same ARG is defined in a subsequent build stage.
Hardcoding vs Environment Variables
You might be wondering, why do we need environment variables? Why can’t we just hardcode our configuration parameters directly into our code or Dockerfile? The answer lies in the principles of good software development practices and security.
Firstly, hardcoding secrets such as database passwords or API keys directly into your code is a bad practice. It makes your application less secure as anyone who gains access to your codebase will be able to see these secrets. This is where environment variables come into the picture. By storing these secrets as environment variables, you can keep them separate from your code, making your application more secure.
// Bad practice
const dbPassword = 'mysecretpassword';
// Good practice
const dbPassword = process.env.DB_PASSWORD;
Example of setting environment variables in Docker:
Secondly, environment variables make your code more readable and maintainable. Imagine having to change a hardcoded database password that is used in multiple places in your code. You would have to find each instance and change it manually, which is time-consuming and error-prone. On the other hand, if you were using an environment variable, you would only need to change it in one place.
Updating Configuration Parameters
Last but not least, environment variables make it easy to update configuration parameters. If you want to change the value of a parameter, you can simply update the environment variable, without needing to rebuild your Docker image or redeploy your application. This makes environment variables a flexible and powerful tool in managing your Docker environment.
Comparison of updating configuration parameters with and without environment variables:
|Without Environment Variables||Find each instance in the code and change it manually.|
|With Environment Variables||Change the value in one place.|
Risks and Security
While environment variables provide a lot of flexibility and convenience, they also come with risks if not properly secured.
For instance, if you’re storing sensitive information like database passwords or API keys as environment variables, they could be exposed if your Docker image or container gets compromised.
The first step to addressing this would be to ensure that the system environment variables are as secure as you can make them by ensuring that the file system permissions don’t allow untrusted users to read each other’s files. However, for high security applications, this approach may not be sufficient by itself.
Docker’s Shadowing Feature
Docker provides a feature called ‘shadowing’, which can help mitigate this risk. Shadowing allows you to specify different values for the same environment variable at build time and runtime in the Dockerfile. This means you can use dummy values for your sensitive environment variables during the build process, and then replace them with the real values when the Docker container is running.
Example of securing environment variables in Docker:
And then run the Docker container with the
-e flag to specify the real value:
docker run -e DB_PASSWORD=mysecretpassword my-app
Note that this approach trades one security flaw for another. Entering a password on the command line will make the password show up in the list of running processes, as well as in the linux command history, so is not recommended.
User Prompt For Secrets — Maximum Security
An even better approach for very high security applications is to wrap the process in a bash script that takes the secret as a user input. This is not going to be appropriate for use cases requiring unattended operation, but can be a good option for programs that are started manually.
Here’s a basic example of a bash script that would be used to start a Docker container with a sensitive environment variable taken as user input:
echo "Please enter the DB password: "
read -s DB_PASSWORD
docker run -e DB_PASSWORD=$DB_PASSWORD my-app
In this script:
-s option to
read causes it to silently read the input, so the password won’t be displayed as the user types it.
- We save the password the user enters to the
- Then, we start the Docker container with
-e flag to specify the environment variable.
Remember to add execution permissions to the script file:
chmod +x start_my_app.sh
Then, you can simply run the script:
In this comprehensive guide, we’ve explored the vital role of Docker environment variables. These dynamic-named values are not mere conveniences; they are essential tools for managing configuration parameters for our applications. They enable us to store a wide variety of data, from database passwords to API keys, thereby making our Docker images more flexible and portable. This versatility makes environment variables an indispensable tool in any developer’s arsenal.
However, the power of environment variables comes with a responsibility to secure them properly. If not appropriately managed, environment variables can expose sensitive information, leading to potential security risks. It’s crucial to understand these risks and take steps to mitigate them. Docker’s ‘shadowing’ feature is one such step. It allows you to specify different values for the same environment variable at build time and runtime, thus helping to keep your sensitive data safe, even in a compromised Docker environment.
In conclusion, environment variables form an integral part of Docker. Understanding how to use and secure them is crucial for any developer working with Docker. So, start leveraging environment variables in your Docker projects, and experience the transformative impact they can have on your development process!