Back to Scaling Containers guides

A Comprehensive Guide to Docker Secrets

Ayooluwa Isaiah
Updated on February 24, 2025

In modern containerized applications, managing sensitive information like passwords, API keys, and SSL certificates poses significant security challenges.

Hard-coding these credentials or using environment variables can expose them to unauthorized access and create security vulnerabilities.

Docker Secrets provides a robust solution by offering encrypted storage and secure distribution of sensitive data to only the containers that need them.

This comprehensive guide will walk you through everything you need to know about implementing and managing Docker Secrets effectively.

Let's get started!

Understanding Docker Secrets

Docker Secrets is a built-in secrets management system that operates at the Docker Swarm level. A secret can be any piece of sensitive data, such as:

  • Database passwords
  • API keys
  • SSH private keys
  • TLS certificates
  • Other confidential configuration data

When you create a secret in Docker, the system encrypts it both at rest and during transit. The encrypted secret is stored in the Swarm's Raft database, which serves as the source of truth for your cluster's desired state. The beauty of this system lies in its granular access control since only containers explicitly granted permission can access the decrypted value of a secret.

The storage and access mechanisms of secrets follow specific patterns based on the container's operating system. In Linux containers, secrets are mounted at /run/secrets/<secret_name>, while Windows containers store them at C:\ProgramData\Docker\secrets. These default locations can be customized during service deployment to match your application's requirements.

The security model of Docker Secrets extends beyond just encryption. Access to secrets is strictly controlled at the node level within your Swarm. Only Swarm managers and nodes running tasks for services that have been explicitly granted access can interact with encrypted secrets.

Docker Secrets implements intelligent memory management to further enhance security. When a container terminates, the system automatically removes any secrets it had access to from both the container's in-memory filesystem and the node's memory.

The system also includes robust handling of network disruptions. If a node loses its connection to the Swarm while running a task that uses secrets, the task retains access to its existing secrets, ensuring application continuity. However, the node won't receive any updates to those secrets until it reestablishes its connection to the Swarm.

Prerequisites

Docker Secrets requires a specific environment setup to function properly. The primary requirement is Docker running in Swarm mode, which provides the orchestration layer necessary for secrets management.

To initialize Docker Swarm, you first need to designate a manager node. This is done using the following command:

 
docker swarm init --advertise-addr <manager_server_ip>
Output
Swarm initialized: current node (9r83zto8qpqiazt6slxfkjypq) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token <token> <manager_server_ip>:<port>


To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

This command transforms your Docker installation into a Swarm manager node and outputs a token that other nodes can use to join the swarm. When adding worker nodes, you'll use the join token provided:

 
docker swarm join --token <token> <manager_server_ip>:<port>
Output
This node joined a swarm as a worker.

Creating and managing Docker secrets

Docker provides several methods for creating secrets, each suited to different use cases. Let's explore these methods in detail:

  • Creating a secret from standard input:
 
echo "mySecurePassword123" | docker secret create db_password -
Output
i2dolb184uoh0kkleerasua9u

You'll see the ID of the secret you just created which may later be used to reference the secret in other Docker commands.

  • Creating a secret from a file:
 
docker secret create ssl_certificate ./path/to/cert.pem

When you create a secret, Docker immediately encrypts it and stores it in the Swarm's distributed database. The original file or input is not retained in unencrypted form.

To manage existing secrets, Docker provides several commands. To view all secrets in the swarm, execute:

 
docker secret ls
 
ID                          NAME          DRIVER    CREATED         UPDATED
i2dolb184uoh0kkleerasua9u   db_password             7 minutes ago   7 minutes ago

To inspect a specific secret's metadata, use:

 
docker secret inspect db_password
Output
[
    {
        "ID": "i2dolb184uoh0kkleerasua9u",
        "Version": {
            "Index": 1455
        },
        "CreatedAt": "2025-02-24T11:47:27.685233322Z",
        "UpdatedAt": "2025-02-24T11:47:27.685233322Z",
        "Spec": {
            "Name": "db_password",
            "Labels": {}
        }
    }
]

The inspect command provides metadata about the secret but never reveals the actual secret content.

Finally, you can remove secrets by passing the secret ID or name to the following command:

 
docker secret rm db_password

Using secrets in Docker Services

When you create a service that needs access to secrets, you specify this requirement in the service configuration. The secrets are then mounted into the container at runtime. Here's a comprehensive example:

 
docker service create \
    --name secure_webapp \
    --secret source=db_password,target=db_password,mode=0400 \
    --secret source=ssl_certificate \
    my_webapp:latest
Output
0pnoym4rb0yyl8jk52uvm5ny8
overall progress: 1 out of 1 tasks
1/1: running   [==================================================>]
verify: Service converged

In this example, we're creating a service named secure_webapp with access to two secrets. The mode parameter specifies the file permissions inside the container. By default, secrets are mounted at /run/secrets/<secret_name>, but you can customize this using the target parameter.

The application can then read the secret value by accessing the mounted file at:

 
cat /run/secrets/db_password

You can see if the secret is mounted on a container using the command below:

 
docker container exec $(docker ps --filter name=<container-name> -q) ls -l /run/secrets
Output
total 4
-r--r--r--    1 root     root            24 Feb 25 12:51 db_password

To prevent a service from having access to the container, use:

 
docker service update --secret-rm db_password <container-name>

Afterward, the /run/secrets directory will no longer exist in the container:

 
docker container exec $(docker ps --filter name=<container-name> -q) ls -l /run/secrets
Output
ls: /run/secrets: No such file or directory

Using secrets in Docker Compose

Docker Compose integration with Secrets provides a declarative way to manage sensitive information in your containerized applications through the secrets top-level key.

Here's an example:

compose.yaml
services:
  web:
    image: nginx:latest
secrets:
- source: site_ssl
target: ssl_cert
mode: 0400
- source: site_key
target: ssl_key
mode: 0400
ports: - "443:443" database: image: postgres:latest
secrets:
- source: db_password
target: postgres_password
mode: 0400
environment: - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password
secrets:
site_ssl:
file: ./certs/site.crt
site_key:
file: ./certs/site.key
db_password:
external: true

In this configuration, secrets can be defined in three ways:

  • File-based secrets, where the content comes from a file on the host system.
  • External secrets, which are pre-existing secrets in the Docker Swarm.
  • Environment-specific secrets, which can be different between development and production.

The mode property defines the file permissions in octal notation, allowing fine-grained access control within the container, while target allows you to customize the name and location of the secret within the container.

Docker Secrets best practices

1. Secret rotation

Regular rotation of secrets minimizes the impact of potential security breaches. You can create a new secret version by running:

 
echo "newPassword123" | docker secret create db_password_v2 -

Then update your services to use new secret:

 
docker service update \
    --secret-rm db_password_v1 \
    --secret-add source=db_password_v2,target=db_password \
    myservice

2. Monitoring secrets usage

While Docker doesn't provide built-in audit logging for secrets, you can implement monitoring at the service level:

 
docker service update --monitor \
    --secret-add source=new_secret,target=secret \
    myservice

3. Access control management

Implement strict access controls by limiting secret access to only essential services. When creating services, explicitly define which secrets each service needs:

 
docker service create \
    --name restricted_service \
    --secret source=required_secret,mode=0400 \
    --no-resolve-image \
    myapp:latest

Integration with third-party tools

While Docker Secrets provides robust native secrets management, many organizations require integration with enterprise-grade external secret management solutions.

These integrations enhance Docker's capabilities with additional features like automated rotation, fine-grained access control, and compliance monitoring. Let's look at a few of the most popular ones below:

HashiCorp vault integration

HashiCorp Vault integration with Docker can be implemented through several approaches. The most common method uses the Vault Agent to retrieve secrets:

compose.yaml
services:
  vault-agent:
    image: vault:latest
    volumes:
      - ./vault-agent-config.hcl:/etc/vault/vault-agent-config.hcl
      - ./vault-agent-templates:/etc/vault/templates
    environment:
      - VAULT_ADDR=https://vault.example.com
      - VAULT_TOKEN=${VAULT_TOKEN}

  application:
    image: myapp:latest
    depends_on:
      - vault-agent
    volumes:
      - ./secrets:/run/secrets

The Vault Agent configuration file (vault-agent-config.hcl) might look like this:

 
pid_file = "/tmp/vault-agent.pid"

auto_auth {
  method "token" {
    config {
      token = env.VAULT_TOKEN
    }
  }
}

template {
  source      = "/etc/vault/templates/db-creds.tmpl"
  destination = "/run/secrets/db-credentials"
}

AWS secrets manager integration

AWS Secrets Manager integration typically involves using the AWS SDK or CLI within your containerized applications. Here's an implementation pattern:

compose.yaml
services:
  application:
    image: myapp:latest
    environment:
      - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
      - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
      - AWS_REGION=us-west-2
    command: ["./fetch-secrets.sh"]

The fetch-secrets.sh script might contain:

fetch-secrets.sh
#!/bin/bash

# Fetch secret from AWS Secrets Manager
secret=$(aws secretsmanager get-secret-value \
    --secret-id myapp/database/credentials \
    --query SecretString \
    --output text)

# Parse and store the secret
echo $secret | jq -r .password > /run/secrets/db_password

Azure key vault integration

Azure Key Vault integration can be achieved using the Azure SDK or managed identity authentication:

compose.yaml
services:
  application:
    image: myapp:latest
    environment:
      - AZURE_TENANT_ID=${AZURE_TENANT_ID}
      - AZURE_CLIENT_ID=${AZURE_CLIENT_ID}
      - AZURE_CLIENT_SECRET=${AZURE_CLIENT_SECRET}
      - KEY_VAULT_NAME=mycompany-keyvault

Example implementation using Azure SDK in Python:

 
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

credential = DefaultAzureCredential()
vault_url = f"https://{os.environ['KEY_VAULT_NAME']}.vault.azure.net/"
client = SecretClient(vault_url=vault_url, credential=credential)

secret = client.get_secret("database-password")
with open('/run/secrets/db_password', 'w') as f:
    f.write(secret.value)

Kubernetes integration

For Kubernetes environments, the External Secrets Operator provides a unified interface for multiple secret management systems:

 
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: database-credentials
spec:
  refreshInterval: "1h"
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: database-secret
  data:
    - secretKey: password
      remoteRef:
        key: database/credentials
        property: password

Final thoughts

Docker Secrets provides a robust foundation for managing sensitive information in containerized environments. The system's integration with Docker Swarm, combined with its security features and flexible implementation options, makes it a powerful tool for modern application deployment.

Success with Docker Secrets requires understanding not just the technical implementation, but also the security implications and best practices. Regular auditing, proper secret rotation, and careful access control management are essential components of a comprehensive secrets management strategy.

As container orchestration continues to evolve, Docker Secrets remains a crucial component in building secure, scalable applications. Organizations should invest time in properly implementing and maintaining their secrets management infrastructure to ensure the security and reliability of their containerized applications.

Thanks for reading!

Author's avatar
Article by
Ayooluwa Isaiah
Ayo is a technical content manager at Better Stack. His passion is simplifying and communicating complex technical ideas effectively. His work was featured on several esteemed publications including LWN.net, Digital Ocean, and CSS-Tricks. When he's not writing or coding, he loves to travel, bike, and play tennis.
Got an article suggestion? Let us know
Next article
How to Scale Docker Swarm Horizontally in Production
Learn how to horizontally scale in/out an existing Docker Swarm cluster, experiment with scalability constraints, and investigate auto scaling solutions
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Make your mark

Join the writer's program

Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.

Write for us
Writer of the month
Marin Bezhanov
Marin is a software engineer and architect with a broad range of experience working...
Build on top of Better Stack

Write a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email.

community@betterstack.com

or submit a pull request and help us build better products for everyone.

See the full list of amazing projects on github