- Leverage BuildKit for docker build secrets to avoid leaking sensitive data in image layers.
- Avoid plain environment variables; prefer file-based secret mounts.
- Always scan Docker images for exposed secrets to mitigate supply chain risks.
- Read on for actionable best practices and implementation examples.
Secrets management in Docker is a critical security concern for any business. When using Docker containers, it is essential to keep sensitive data such as passwords, API keys, and other credentials secure.
This blog post will discuss some best practices for managing secrets in Docker, including how to store them securely and minimize their exposure. We will explore multiple solutions: using Docker Secrets with Docker Swarm, Docker Compose, or Mozilla SOPS. Feel free to choose what’s more appropriate to your use case. But most importantly is to remember to never hard-code your Docker secrets in plaintext in your Dockerfile!

Following these guidelines ensures that your organization's sensitive information remains safe even when running containerized services.
4 Ways to Store & Manage Secrets in Docker
Using Docker Secrets & Docker Swarm
Docker Secrets and Docker Swarm are two official and complimentary tools allowing to securely manage secrets when running containerized services.
Docker Secrets provides a secure mechanism for storing and retrieving secrets from the system without exposing them in plaintext. It enables users to keep their credentials safe by encrypting the data with a unique key before passing it to the system.
Docker Swarm is a powerful tool for managing clusters of nodes for distributed applications. It provides an effective means of deploying containerized applications at scale. With this tool, you can easily manage multiple nodes within a cluster and automatically distribute workloads among them. This helps ensure that your application has enough resources available at all times, even during peak usage periods or unexpected traffic spikes.
Together, these two tools provide an effective way to ensure that your organization's sensitive information remains safe despite ever-evolving security needs.
Let’s see how create and manage an example secret.
Creating a Secret
To create a secret, we need to first initialize Docker Swarm. You can do so using the following command:
docker swarm initOnce the service is initialized, we can use the docker secret create command to create the secret:
ssh-keygen -t rsa -b 4096 -N "" -f mykey
docker secret create my_key mykey
rm mykeyIn these commands, we first create an SSH key using the ssh-keygen command and write it to mykey. Then, we use the docker secret command to generate the secret. Ensure that you delete the mykey file to avoid any security risks.
You can use the following command to confirm that the secret is created successfully:
docker secret lsWe can now use this secret in our Docker containers. One way is to pass this secret with –secret flag when creating a service.
docker service create --name mongodb --secret my_mongodb_secret redis:latestWe can also pass this secret to docker-compose.yml file. Let’s take a look at an example file:
version: '3.7'
services:
myapp:
image: mydummyapp:latest
secrets:
- my_secret_key
secrets:
my_secret_key:
external: true
In the example compose file, the secrets section defines a secret named my_secret_key (discussed earlier). The myapp service definition specifies that it requires my_secret_key, and Docker will automatically mount it as a file at /run/secrets/my_secret_key in the container.
Using Docker Compose
Docker Compose is a powerful tool for defining and running multi-container applications with Docker. A stack is defined by a docker-compose file allowing you to define and configure the services that make up your application, including their environment variables, networks, ports, and volumes. With Docker Compose, it is easy to set up an application in a single configuration file and deploy it quickly and consistently across multiple environments.
Docker Compose provides an effective solution for managing secrets for organizations handling sensitive data such as passwords or API keys. You can read your secrets from an external file (like a TXT file). But be careful not to commit this file with your code!
version: '3.7'
services:
myapp:
image: myapp:latest
secrets:
- my_secret
secrets:
my_secret:
file: ./my_secret.txtUsing a Sidecar Container
A typical strategy for maintaining and storing secrets in a Docker environment is to use sidecar containers. Secrets can be sent to the main application container via the sidecar container, which can also operate a secrets manager or another secure service.
Let’s understand this using a Hashicorp Vault sidecar for a MongoDB container:
- First, create a Docker Compose (docker-compose.yml) file with two services:
mongoandsecrets. - In the
secretsservice, use an image containing your chosen secret management tool, such as a vault. - Mount a volume from the secrets container to the
mongocontainer so themongocontainer can access the secrets stored in the secrets container. - In the
mongoservice, use environment variables to set the credentials for the MongoDB database, and reference the secrets stored in the mounted volume.
Here is the example compose file:
version: '3.7'
services:
mongo:
image: mongo
volumes:
- secrets:/run/secrets
environment:
MONGO_INITDB_ROOT_USERNAME_FILE: /run/secrets/mongo-root-username
MONGO_INITDB_ROOT_PASSWORD_FILE: /run/secrets/mongo-root-password
secrets:
image: vault
volumes:
- secrets:/secrets
command: ["vault", "server", "-dev", "-dev-root-token-id=myroot"]
ports:
- "8200:8200"
volumes:
secrets:Using Mozilla SOPS
Finally, your Docker host could decrypt a secret locally and pass that value to a Docker container as a temporary environment variable. One such tool for this is Mozilla SOPS. This tutorial assumes that SOPS is already installed on the Docker host. If you need an introduction to SOPS, read a primer here.
The command below shows the decrypted contents of an encrypted file, secret.enc.json. This file is safe to store on disk because it has been encrypted. SOPS can decrypt it because it has access to the encryption key.
$ sops decrypt secret.enc.json
{
"PASSWORD_1: "SuperSecretPassword",
"PASSWORD_2": "AnotherSecretPassword"
} The exec-env feature of SOPS allows us to extract key-value pairs from an encrypted file that is structured as YAML or JSON, and pass these as environment variables to a child process. The following command shows an example of launching a Docker container from the command line in this way.
sops exec-env secret.enc.json 'docker run --rm -it -e PASSWORD_1=$PASSWORD_1 bash -c "echo $PASSWORD_1"'Of course, we could use this alongside Docker Compose, similar to previous examples. Here is an example Compose file, docker-compose.yml:
services:
env_printer:
image: alpine
command: [ "sh", "-c", "echo The secret is: $PASSWORD_1" ]
environment:
- PASSWORD_1To pass environment variables to Docker Compose, but not other processes, run the following command:
# decrypt our file with exec-env and run docker compose which can use these temporary env vars.
sops exec-env secret.enc.json 'docker compose up'Importantly, this environment variable is available only to the process that runs Docker Compose, and not within the shell in which the sops command was run.
Docker Build Secrets: Securing Credentials During Image Creation
One critical gap in Docker secrets management involves handling sensitive data during the image build process. Unlike runtime secrets managed by Docker Swarm or Compose, docker build secrets require special consideration to prevent credentials from being permanently embedded in image layers.
Docker's BuildKit provides a secure --secret mount option that allows build processes to access sensitive data without storing it in the final image. This approach is essential when your build process needs to authenticate with private repositories, download dependencies, or access configuration files containing credentials.
# syntax=docker/dockerfile:1FROM alpineRUN --mount=type=secret,id=api_key \ API_KEY=$(cat /run/secrets/api_key) && \ curl -H "Authorization: Bearer $API_KEY" https://api.example.com/dataTo use this feature, build your image with:
echo "your-secret-key" | docker build --secret id=api_key,src=- .This method ensures that secrets are only available during the build step and are never committed to image layers, preventing accidental exposure when images are shared or stored in registries. Always combine this with multi-stage builds to further isolate build-time dependencies from your final runtime image.
Docker Secrets Without Swarm: Alternative Approaches for Standalone Containers
While Docker's native secrets management requires Swarm mode, many developers need docker secrets without swarm for standalone container deployments. Several practical alternatives exist for single-node environments or development scenarios where Swarm's complexity isn't justified.
External secret management tools like HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault can provide enterprise-grade secret handling for standalone containers. These solutions offer centralized secret storage, rotation capabilities, and fine-grained access controls that surpass basic environment variable approaches.
For simpler scenarios, init containers can fetch secrets from external sources before the main application starts:
version: '3.8'services: secret-fetcher: image: vault:latest command: | sh -c "vault kv get -field=password secret/myapp > /shared/password" volumes: - shared-secrets:/shared myapp: image: myapp:latest depends_on: - secret-fetcher volumes: - shared-secrets:/run/secretsAnother approach involves using encrypted files with tools like age or GPG, where containers decrypt secrets at startup using keys provided through secure channels. This method provides better security than plain environment variables while maintaining simplicity for development environments.
Managing Docker Secret Environment Variables: Best Practices and Security Considerations
The relationship between docker secret environment variables and secure secret management requires careful consideration. While environment variables offer convenience, they present significant security risks when handling sensitive data in containerized environments.
Environment variables are visible in process lists, container inspection commands, and can be accidentally logged or exposed through debugging tools. For truly sensitive data like API keys, database passwords, or certificates, file-based secret mounting provides superior security isolation.
However, when environment variables are necessary, implement these security measures:
# Use secret files to populate environment variablesdocker run -d \ --env-file <(sops -d secrets.env) \ --tmpfs /tmp:noexec,nosuid,size=100m \ myapp:latestFor Docker Compose, leverage external secret files with proper file permissions:
services: webapp: image: webapp:latest environment: - DB_PASSWORD_FILE=/run/secrets/db_password secrets: - db_passwordsecrets: db_password: file: ./secrets/db_password.txtThis approach allows applications to read secrets from files while maintaining the flexibility of environment-based configuration. Always ensure secret files have restrictive permissions (600 or 400) and are excluded from version control through comprehensive .gitignore rules.
Scan for secrets in your Docker images
Hard coding secrets in Docker is a significant security risk, making them vulnerable to attackers. We have seen different best practices to avoid hard-coding secrets in plaintext in your Docker images, but security doesn't stop there.
You should also scan your images for secrets.
All Dockerfiles start with a FROM directive that defines the base image. It's important to understand that when you use a base image, especially from a public registry like Docker Hub, you are pulling external code that may contain hardcoded secrets. More information is exposed than visible in your single Dockerfile. Indeed, it's possible to retrieve a plaintext secret hard-coded in a previous layer starting from your image.
In fact, many public Docker images are concerned: in 2021, we estimated that 7% of the Docker Hub images contained at least one secret.

Fortunately, you can easily detect them with ggshield (GitGuardian CLI). For example:
ggshield secret scan docker ubuntu:22.04
Conclusion
To sum up, managing secrets in Docker is a crucial part of preserving the security of your containerized apps. Docker includes several built-in tools for maintaining secrets, such as Docker Secrets and Docker Compose files.
Additionally, organizations can use third-party solutions like HashiCorp Vault and Mozilla SOPS to manage secrets in Docker. These technologies offer extra capabilities like access control, encryption, and audit logging to strengthen the security of your secret management.
Finally, finding and limiting accidental or unintended exposure of sensitive information is crucial to handling secrets in Docker. Companies are invited to use secret scanning tools such as GitGuardian to scan the Docker images built in their CI/CD pipelines as mitigation to prevent supply-chain attacks.
If you want to know more about Docker security, we also summarized some of the best practices in a cheat sheet.
We hope this blog post has provided you with a better understanding of how to manage secrets in Docker and keep your applications secure.
It is part of a series on secrets management with popular technologies, have a look!



FAQ
What are the most secure methods for managing secrets in Docker environments?
For production-grade security, leverage Docker Secrets with Swarm, external secret managers like HashiCorp Vault, or encrypted file-based solutions such as Mozilla SOPS. These approaches ensure secrets are never stored in plaintext or embedded in images, and provide access control, audit logging, and secret rotation capabilities.
How can I use Docker secrets without enabling Swarm mode?
While native Docker secrets require Swarm, alternatives include using external secret managers (e.g., Vault, AWS Secrets Manager), sidecar or init containers to inject secrets at runtime, or encrypted files decrypted at container startup. These methods provide secure secret delivery for standalone or Compose-based deployments.
How does Docker BuildKit improve secret handling during image builds?
Docker BuildKit introduces the --secret mount, allowing sensitive data to be accessed only during the build phase, without persisting it in image layers. This prevents credentials from being exposed in built images or registries, addressing a critical gap in Docker secrets management at build time.
Are environment variables safe for storing sensitive data in Docker containers?
Environment variables are convenient but not recommended for highly sensitive data, as they can be exposed via process listings, container inspection, or logs. Prefer file-based secret mounting or external secret managers to reduce exposure risk. If environment variables are necessary, restrict permissions and avoid logging sensitive values.
What are best practices for scanning Docker images for hardcoded secrets?
Regularly scan Docker images using automated tools like GitGuardian's ggshield to detect embedded secrets, including those inherited from base images. Integrate secret scanning into CI/CD pipelines and ensure all images, not just source code, are checked for accidental secret exposure to mitigate supply chain risks.
How can I securely inject secrets into Docker Compose services?
Use the secrets key in your Compose file to mount secrets as files inside containers, or leverage external secret managers with sidecar or init containers. Avoid committing secret files to version control and enforce strict file permissions to prevent unauthorized access.
Why is it important to avoid hardcoding secrets in Dockerfiles or images?
Hardcoding secrets in Dockerfiles or images exposes them to anyone with access to the image, including public registries or layered image history. This significantly increases the risk of credential leakage and potential breaches. Always use secure secret injection mechanisms and scan images for accidental exposures.
