Marcio Cunha

Docker Secrets: How to Store Passwords and Credentials Without Hardcoding

Learn how to securely manage sensitive credentials and passwords in Docker environments, preventing leaks and ensuring production system integrity.

Marcio Cunha12 min
Also available in:EspañolPortuguês
Summary
  • Storing credentials incorrectly in standard environment variables compromises the security of any cloud infrastructure.
  • Docker Secrets isolates encrypted sensitive data directly in the orchestrator's memory, keeping it out of image build histories.
  • Injecting temporary files via tmpfs ensures passwords and private keys leave no persistent traces on the physical hard drive.
  • Adopting external vault-based architectures complements the Docker ecosystem for complex microservices environments.
  • Strict separation between source code and operational secrets eliminates accidental credential exposure in public repositories.

The Silent Danger of Hardcoded Credentials in Source Code

When developing modern applications, the temptation to place database passwords, API keys, and access tokens directly into source code configuration files is huge. In practice, this means opening your front door and leaving the key in the lock. Code is regularly shared among teams, pushed to remote repositories, and can easily end up exposed due to a simple oversight. Modern software engineering demands that sensitive data, known in technical jargon as 'secrets', remain completely isolated from application logic.

Docker revolutionized how we package and distribute software, but it also facilitated a common mistake: embedding passwords directly inside container images. A Docker image is built in layers, much like an onion. Every command executed during the build process records a permanent layer. If you pass a secret key during this process, it remains permanently recorded in the image history, even if you try to delete it in the next command. Anyone with access to the image can extract this information using basic inspection tools.

Understanding Docker's Native Secrets Mechanism

To solve this security problem without complicating the developer's life, the Docker ecosystem introduced a native feature called Docker Secrets. This is a mechanism available when running Docker in Swarm mode (an integrated tool for managing multiple computers as a single system). In practice, Swarm creates an encrypted vault inside the cluster itself, ensuring passwords travel securely across the network and are delivered only to containers that actually need them.

When a secret is created in Docker, it receives a name and a value. Docker stores this data encrypted at rest in the manager's internal database. When a service starts and requests that specific secret, Docker injects the data directly into the container's memory as a file located in the /run/secrets/ directory. This means the password never passes through traditional environment variables—which are notoriously easy to leak through debugging logs or process monitoring tools.

Implementing Secrets in Practice with Docker Swarm

To see this technology working in practice, we need to initialize Swarm mode on our local environment or production server. The command docker swarm init turns your machine into a single manager. Next, we can create our first secret using the terminal with a simple command that reads the value directly from a secure file or standard input.

echo 'my-super-secret-password-123' | docker secret create db_password -

With the secret created and encrypted by Docker, the next step is associating it with a service. In the Docker Compose configuration file, which we use to declare how our application should run, we indicate which services are allowed to see that secret. Docker handles all the heavy lifting of distribution and access permissions behind the scenes.

version: '3.8'
services:
  web:
    image: my-app:latest
    deploy:
      replicas: 2
    secrets:
      - db_password
secrets:
  db_password:
    external: true

How Data Reaches the Container Securely

One of the biggest questions for those starting with container architectures is knowing exactly where the secret ends up and how the application should read it. In practice, the application doesn't need any complex libraries or external key server connections. It simply needs to open a standard file on the container's virtual disk.

Since the /run/secrets/ directory is mounted on a tmpfs file system—meaning it resides entirely in the machine's volatile RAM and is never written to physical disk—the risk of residual leakage is virtually zero. When the container stops, all secrets instantly disappear from memory without leaving magnetic or electronic traces.

Alternatives for Environments Without Docker Swarm

Although native Docker Secrets is excellent, it requires Swarm mode enabled, which might feel like overkill if you are running just a single simple server with good old traditional Docker Compose. In scenarios where Swarm isn't feasible, the engineering community has adopted alternative strategies to maintain credential security without sacrificing simplicity.

The most common approach is using local environment files (like the famous .env file) combined with strict operating system permission restrictions and mandatory inclusion of these files in the project's .gitignore. Although .env is convenient, it still suffers from the problem of injecting data into environment variables, which can be accidentally exposed by any diagnostic script run inside the container.

Common Pitfalls and Critical Security Mistakes

Even with modern isolation tools, some bad habits persist among novice and experienced developers alike. The most serious mistake is printing or logging the contents of environment variables or secret directories during application startup for debugging purposes. A simple command like console.log(process.env) can send your credentials directly to a third-party logging service.

Another frequent mistake is reusing the same secret across multiple environments (development, staging, and production). If the production key leaks in a poorly configured test environment, the entire main system is compromised. The golden rule of software engineering security is absolute isolation: every environment must have entirely independent and rotatable credentials.

Final Thoughts on Secret Management

Protecting passwords and credentials in Docker-based environments is no longer an operational luxury; it's a basic requirement of digital survival for any modern application. By abandoning the archaic practice of embedding sensitive data into source code or image layers, you significantly elevate the technical maturity of your infrastructure.

The conscious adoption of tools like Docker Secrets, combined with a clear understanding of where data resides in memory, ensures your team can scale systems with peace of mind. After all, true software robustness is measured not just by the features it delivers, but by its ability to keep user data safe against unforeseen threats.