- 1. Storing The .env File.
- 2. Updating a secret config.
- 3. Versioning.
- Securing an .env file?
- Advantages of using an
- Problems With Centralized Config Servers.
- Bonus For Linux Enjoyers.
We all know that first impressions are essential. The same goes for the first sentence of an article. In fact, it might be even more critical for an article because the first sentence is what will determine whether or not someone keeps reading.
But, in the case of this article, stating that working with large-scale systems would make you eligible enough to write about the topic is quite funny. This sentence has a psychological effect that makes readers feel like they are stupid and doomed, assuming they are all working on "Hello World" kind of projects.
Needless to say, as a reader, you may start to wonder: "What in the world does he mean when he said he has worked on large-scale systems?" I mean, literally, everyone is doing that nowadays. I don't think it can be used as a unique selling point or anything; nearly everyone has experience working with large-scale enterprise systems.
Even the most junior engineer has likely worked on a system that processes millions of requests/records daily. So what makes working on large-scale systems so unique? What makes you think your experience is worth anything special? You need to show that you have something unique to offer; otherwise, it's just another redundant sentence in your article. But anyway, let's move on.
Let's start by criticizing each point that looks like a problem with
.env files when in reality, they are not problems at all but rather misconceptions.
This section started by:
The problem is well... It's a file.
Well, I don't know about you and which OS you are currently using, but everything in Linux is literally a file. This includes devices, processes, sockets, files, pipes, etc. However, the critical question is: what's wrong with it?
If you think it is not a good idea to make everything in Linux a file, including env vars, then you have to invite Linus for a debate and discuss the drawbacks of this approach. Provide your solution instead.
Additionally, containers are based on Linux cgroups, namespaces, and other components, which means that they are also built around the concept of everything being a file. This makes Linux a very powerful os for running containers, as everything can be easily managed and controlled via files.
Moreover, everything in k8s is also a file, a YAML file. This concept makes k8s extraordinarily flexible and customizable. You can literally configure anything you want, and there are very few restrictions.
As the author is now working at Google, he has the chance to discuss with the brains behind k8s, argue with them about the drawbacks of files, and share his insights with us. We would love to hear his thoughts on this matter!
Besides, the question is: Who is committing an
.env file to public repos? Literally, no one with at least two brain cells is willing to commit an env file, as far as I know. Some developers on github, me included, commits only templates of this file to help other understand the env vars used in a particular project. There is a
.gitignore file in case you want to ignore that file from being committed; that's the basics, and everyone should be aware of that.
Even if you don't like to include a
.gitignore file for each new repo, you can add a new entry in a global
~/.gitignore file, so you don't have to worry about including that file each time when creating a new repo.
Now, you may wonder: well, how to share the
.env file with other developers? And the answer goes like this: If you're collaborating with other people on a project, it's essential to keep your
.env file private so that only invited collaborators can see it(e.g., create a private repo for the
I have never had access to updating a database password throughout my years working at companies. This is because there is always someone responsible for managing databases. Having access to update passwords would be a huge responsibility and could potentially lead to security breaches.
So, having someone responsible ensures that passwords are kept up to date and secure. It also means that if there is ever a problem with a password, there is only one person who needs to be contacted to fix it. This system may not be perfect, but it is the best way to protect company data.
All I can get are env names and use them within the app. That's it; Nothing else. This is why having a designated person is so important. Not only does it make life easier for employees, but it also helps keep everyone on the same page, safe, and secure.
Environment variables are not parts of the app code, so there is no need to version them. I have never used an app that keeps track of password history changes, and I see no reason why this would be necessary. They are just static values and don't change often.
But in any case, if you want to apply versioning to an
.env file stored in a private repo, you can release a new version for each value change.
Then the author proceeds to provide a solution to a problem that doesn't exist. What's even funnier is that the solution leads to potential security risks. So basically, let someone else do it for you if you don't want to manage your secrets, not to mention that the party you share with is a centralized place. If it gets compromised, everyone's secrets in the whole damn world will get exposed.
So, everyone would instead have control over their secrets and not depend on third parties, especially in case of sensitive information.
We, as developers, use
.env files to store environment variables. These files are not meant for use in production and should be removed/ignored from the codebase before deploying it to production. If you have ever worked with containerized apps, you would know that.
The idea of having an
.env file in a repo is to have an example or template of the required env vars as a form of documentation that tells which variables are needed for this project. They could have default values, but as we all know, they should never contain plain text credentials. It is like telling other developers that X, Y, and Z are used in this app as env vars. Having an
.env template file in a repo sets expectations for other developers and maintains best practices. This would help new developers clone the repo and work with it without any hassle.
The application should then load this template
.env and look for other places to override these default values depending on the current environment. This could be a
.env.local file on the system, already set system environment variables, or variables from config storage. If you ever used Jenkins or built a DevOps pipeline, you probably encountered that.
We get it; it is not a good idea to use
.env files in production because they can contain sensitive information like database passwords, API keys, and other credentials that should not be accessible to others.
However, one thing you can do though is to take additional precautions to keep your
.env file or env vars secure and safe.
.env file is not secure if it's being used for production purposes. Anyone with access to the machine can view and modify it without permission.
However, you can set permissions for this file. I don't know about you, but you can use the following command to secure your env file:
chmod 0400 .env
Doing so, the
.env file can only be read by the owner and no one else. You can use this command in a docker file if you need to copy it into the docker image. But, usually, it is not encouraged to do so. In the case of docker, secrets can be used, which are discussed later in the following sections.
If you have ever worked with laravel, the chances of using the
.env file in production are high. And that is ok as long as you keep it secure. The following is a typical security practice used by Laravel developers:
#Disable index view options -Indexes #hide a Specific File <Files .env> order allow, deny Deny from all </Files>
In docker, you can import env variables with docker-compose using the following command:
docker-compose --env-file .env
Or you can specify the env file within the YAML file:
version: "3.8" services: frontend: image: awesome/webapp env_file: - .env # path to your .env file
If you want to pass secrets, then you can define a secrets section within the
version: "3.8" services: frontend: image: awesome/webapp secrets: - server-certificate secrets: server-certificate: file: ./server.cert
If you are building a docker image, you can create an env file to store secrets and mount the file to the container.
Now you can load the
.env file and give it an id called
my_secret. We can use this key in the next step to access the
.env file. Then modify your Dockerfile so that it mounts the secrets.
FROM python:3.9-slim-buster COPY build-script.sh . RUN --mount=type=secret,id=my_secret . ./build-script.sh
# build-script.sh: cat /run/secrets/my_secret
Now, you can build and inject the
.env file into the container:
export DOCKER_BUILDKIT=1 docker build --progress=plain -t "my_app" --secret id=my_secret,src=.env . --no-cache
Note that these env vars are not logged into the history, so running the following command won't reveal the secrets:
docker history my_app --no-trunc | grep PYPI_PASS
For more info about secrets in docker, you can refer to this piece of docs.
apiVersion: v1 kind: Pod metadata: name: dapi-test-pod spec: containers: - name: test-container image: registry.k8s.io/busybox command: [ "/bin/sh", "-c", "env" ] env: # Define the environment variable - name: SPECIAL_LEVEL_KEY valueFrom: configMapKeyRef: # The ConfigMap containing the value you want to assign to SPECIAL_LEVEL_KEY name: special-config # Specify the key associated with the value key: special.how restartPolicy: Never
Moreover, for security reasons, I have noticed that PyPi has implemented a feature to allow authentication with their servers through using api tokens without the need for passwords anymore. So, now you can store encrypted PyPi credentials within env vars.
If you ever built a pipeline with Azure DevOps, you probably wanted to copy the
.env file into the docker image using Copy files task:
steps: - task: DownloadSecureFile@1 displayName: 'Download secure file' inputs: secureFile: .env - task: CopyFiles@2 displayName: 'Copy Files to: $(System.DefaultWorkingDirectory)' inputs: SourceFolder: '$(Agent.TempDirectory)' Contents: .env TargetFolder: '$(System.DefaultWorkingDirectory)'
If you are using Jenkins, you can inject env variables using plugins like envinject
So, as you can see, it depends on the type of applications you are dealing with to follow the best practices to securely use an
There are so many advantages to using
.env files or environment variables, such as:
Ease of management: Having worked on so many backend projects, I find
.envfiles easy to manage because they are self-explanatory and don't require additional documentation.
.envfiles simplify the task of managing different backends because it allows you to configure all the necessary settings for each backend in one place.
Debugging and testing: It becomes easier because developers can modify a specific environment for each application.
.envfiles templates like
.env.examplecan be added to git repositories, so other developers on the team know what environment variables were used for that project.
Several potential problems can occur when using a centralized config server for an application. If the server goes offline, the app will not be able to start. If the server updates and renames an environment variable that the app is not expecting, the app may crash on the next restart. Finally, if the app is hosted offline, it will not be able to start without an internet connection to load the env vars from outside.
At the end of the day,
.env files and environment variables work fine and are simple enough for development purposes, as long as you know how to use these files. However, it is totally up to you to choose the best approach that aligns with your personal preferences, what works best for your particular application or system.
On Linux, if you want to print out a specific environment variable, like
LOGNAME, of the current process, then run the following command:
strings /proc/$$/environ | grep LOGNAME
And last but not least, remember that everything in Linux is just a file including the command that you have just executed:
Note: This article is not meant to insult anyone by any means; I just wanted to share it with everyone to clarify the situation with
.env and give some tips on how to use them.
Have a lovely weekend, folks.