Table of Contents
Why Secrets and Environment Variables Matter
In almost every real application you will need to provide configuration values that should not be hard coded. Some of these values are harmless, like a time zone or a feature flag. Others are highly sensitive, like database passwords, API keys, and private tokens.
Docker gives you multiple ways to pass such values into containers without baking them directly into images. In this chapter you learn the basic ideas behind using environment variables and secrets with containers, why they matter for security, and what patterns to avoid.
Never store passwords, API keys, or private tokens directly in your source code or Docker images.
Environment Variables in Containers
Environment variables are key value pairs that a process can read from its environment. Many applications already support configuration through variables like $PORT, $DB_HOST, or $NODE_ENV. Docker makes it easy to define these when you start a container.
Conceptually, when you use environment variables with Docker you are doing two things. You are keeping configuration outside of the image so the same image can be reused in multiple environments, and you are reducing the risk of accidentally committing secrets to version control.
In practice, you typically pass environment variables to containers at runtime using Docker commands or configuration files. The image itself stays generic. Only when you run the container do you inject values like connection strings, credentials, and environment specific options.
Treat any environment variable that contains a secret as sensitive data. Do not print it to logs or expose it in debugging output.
Basic Ways to Pass Environment Variables
When you start a container you have several ways to provide environment variables. Each has different trade offs in terms of convenience and risk of leaking secrets.
One common method is to pass variables directly on the command line. While this is simple, it can expose the values through shell history or process listings, depending on the system and tools you use. For regular configuration this can be acceptable. For secrets it is usually better to use a slightly more careful method.
Another option is to use a separate file that contains key value pairs. With this approach you keep configuration in a file that you can protect with file system permissions, and you can avoid typing secrets directly into commands. This also makes it easier to share non sensitive configuration among team members while ignoring sensitive files in version control.
A third pattern is to rely on variables that are already present in the host environment. In this case you set values in your shell or CI system, and then instruct Docker to pass them through. This allows you to centralize secret management at the operating system or pipeline level.
Regardless of the method you choose, you should clearly separate configuration intended for development from configuration intended for production. Use different values for each environment so that even if a development secret is leaked, it cannot be used against production systems.
Security Risks of Environment Variables
Although environment variables are simple and widely supported, they are not a perfect way to manage secrets. You need to be aware of how they can leak and how to reduce that risk.
A main issue is visibility. Many tools can display environment variables for debugging or inspection. If a process crashes and dumps its environment into a log file, any secret values stored there can become visible to people or systems that should not see them. Similarly, some process inspection tools can reveal the environment of running processes, depending on permissions.
Another risk is accidental logging by your own application. It can be convenient to log configuration at startup, but if you print out all variables without filtering, you may send passwords or tokens straight into log storage where they are harder to control or delete.
Finally, environment variables are not encrypted by Docker. They exist in plaintext inside the container. Security relies on controlling who can access the host or the container and how logs and debugging tools are used.
Never log complete environment dumps in production. Always filter or mask any variable that might contain a secret.
Introduction to Docker Secrets
To handle truly sensitive data in a more controlled way, Docker provides the concept of secrets in its orchestration features. While the practical mechanics belong in deployment topics, the security idea is important here.
A Docker secret is designed to hold confidential data such as passwords, certificates, or encryption keys. It is stored and transmitted in a safer way than ordinary environment variables. The secret is only exposed to the containers that explicitly need it, and typically only at runtime in memory or in a restricted file.
This model reduces the risk that secrets end up in places where they are easy to leak. Instead of passing secrets on the command line or embedding them in the image, you treat them as separate objects with explicit access control.
In simple local setups, many beginners still rely on environment variables. As your deployment becomes more serious, it becomes necessary to adopt a secrets mechanism that matches your orchestrator or cloud provider.
Differences Between Secrets and Environment Variables
Environment variables and secrets often look similar from the point of view of your application: both end up as values the code can read. The difference is in how they are delivered, stored, and protected.
Environment variables are part of the process environment. They are easy to use and well supported, but they are also relatively exposed. Any tool that has sufficient permissions to inspect the process can often read them. They also tend to be copied into crash reports, diagnostic dumps, and similar artifacts.
Secrets, on the other hand, are treated as special data that should have a limited lifetime and limited surface area. Depending on the platform, a secret may only appear in a memory backed file system inside the container, may be encrypted at rest by the orchestrator, and may never be written to image layers or standard logs.
From a security perspective, it is often acceptable to keep non sensitive configuration in environment variables, such as feature flags or cache sizes. For values that could cause financial loss or serious data exposure if leaked, a secret mechanism is strongly preferred.
Use environment variables for general configuration. Use secrets mechanisms for passwords, private keys, and tokens that protect real assets.
Handling Secrets in Development vs Production
Managing secrets looks different in development, testing, and production. It is important not to treat all environments the same.
In development, convenience usually matters more. You might run containers on your own machine and use environment variables or simple configuration files to pass known test credentials. The risk is limited, particularly if those credentials do not grant access to any production data or services.
In production, you need stronger guarantees. Secrets should be short lived, rotated regularly, and stored in dedicated systems such as cloud key management services or secret managers. Docker and your orchestrator then pull secrets from these systems and inject them into containers at runtime without exposing them to developers directly.
A common pattern is to give developers fake or low privilege credentials for development, and restrict access to real production secrets to automated systems controlled by operations or security teams.
Never reuse production secrets in development or test environments. Always use separate credentials with limited scope and access.
Avoiding Common Mistakes with Secrets
There are several recurring mistakes beginners make when handling secrets with Docker. Being aware of them helps you avoid introducing vulnerabilities.
One frequent mistake is baking secrets directly into a Dockerfile, for example by using a RUN instruction that contains a password, or by copying a configuration file with credentials into the image. This permanently embeds the secret into that image layer. Even if you later remove the file inside the image, the data remains in the layer history.
Another mistake is committing configuration files with real secrets into version control. Even if you later delete them or overwrite them with placeholder values, the secret still exists in the commit history. Anyone with access to the repository can retrieve it.
A third issue is over sharing. Sometimes, a secret is made available to every container in a system simply because it is easier to manage that way. This means that a compromise of any one service can reveal credentials that were not meant for it. Instead, each service should receive only the secrets it truly needs.
Finally, many teams forget about rotation. If an API key or database password never changes, then any leak has a long lived impact. Regular rotation reduces the window of exposure and forces systems to be ready for credential changes.
Do not store real secrets in Dockerfiles, in image layers, or in version control. Provide them only at runtime and only to the services that need them.
Principles for Safer Secret Management
Even without advanced tools, you can follow some basic principles when working with Docker and secrets.
First, separate configuration from code. Your Docker images should contain application code and generic defaults, but not environment specific or secret values. When you move from development to staging to production, you should be able to keep the image the same and only change the configuration that is provided at runtime.
Second, minimize exposure. Give each container only the secrets it needs, and no more. If a service only needs read access to a database, do not provide it with credentials that grant write access. Limit the number of people and systems that can see or modify production secrets.
Third, consider the full lifecycle. Think about how secrets are created, stored, transmitted, used, logged, backed up, and destroyed. Protect each step. For example, if you back up logs, be sure those logs never contain secrets. If you back up configuration, ensure the backups are encrypted.
Fourth, plan for leaks. Assume that at some point, a secret will be exposed accidentally. Make it easy to rotate secrets quickly. Document where secrets are used so you know which systems to update when a rotation is required.
Design your system so that secrets can be rotated quickly and safely. A secret that cannot be changed is a long term liability.
Summary
Secrets and environment variables are central to secure containerized applications. Environment variables provide an easy way to configure containers without altering images, but they are not suitable for all confidential data. Dedicated secrets mechanisms reduce exposure by controlling how sensitive values are stored and delivered.
By keeping secrets out of images and source control, limiting who can access them, and preparing for rotation, you build a foundation for safer Docker usage that will carry over as you move to more advanced orchestration and deployment setups.