Trending keywords: security, cloud, container,
Docker secrets are sensitive data, values or configurations used by a containerized application or system that should not be visible and available only to those containers that need access to it.
This post provides a comprehensive guide to using Docker secrets, defining them and the types of data that are considered secrets, how to set up secrets using Docker CLI and Docker Compose and security best practices for it.
Definition of sensitive information
Sensitive information is a piece of data that presents a high risk of exposure and financial loss to the organization if an unauthorized party gains access to it. Secrets are considered sensitive information, meaning they are not meant to be shared publicly; instead, they are meant to be hard to access and view in plain form.
You can denote any piece of information as sensitive depending on the context. For example, in the context of Docker containers, application secrets, database credentials, and SSH keys are more sensitive than leaked employee emails. If an attacker can access your systems due to unsafe practices, they can do much more direct damage.
On the other hand, employee emails can be easily inferred or guessed, and they’re not necessarily meant to be hidden. Sure, they can be used for phishing attempts and other social engineering attacks, but their exposure does not create an immediate risk.
So, when using Docker secrets, you first need to categorize the pieces of information that are sensitive according to context. You must also follow best practices for handling them securely. We will describe the different types of secrets that you need to be aware of below.
Types of Docker Secrets
Secrets are credentials used to provide access to privileged accounts, applications, and services. They are essentially the “keys to the kingdom,” and handing them to complete strangers will get you into trouble. Here are some representative examples of secrets:
A password is a single string of text or a token that is known only to you and a third-party provider. Passwords and access tokens are examples of secrets. You wouldn’t want them exposed to unknown parties since they could use them to log into your backend, impersonate your account, and then use this leverage to perform malicious attacks.
An SSH key (and more specifically, the private key part) is considered a secret. The SSH protocol is an access control system, and its primary purpose is to authenticate users and systems. You can use the SSH protocol to log in remotely from one computer to another in a secure manner.
As a public key can be restored from a private key (but not the other way around), exposing a private key means that an attacker can use it to log into your system.
SSL is a communication protocol that establishes secure communication between clients and servers. When you’re visiting a website, for example, it keeps internet connections secure when you’re using login forms or interacting with online banking so that no middleman can see the contents of your account.
SSL(TLS) certificates can also be used for mTLS communication between application services and can prevent various kinds of attacks.
Other Sensitive Data
Other important pieces of sensitive information can include:
- Database credentials: Usernames and database names can be used to connect to databases. If attackers somehow gain access to a password value, they still have to guess the rest of the credentials to gain access.
- Hard-coded credentials: Sometimes an application has a hidden backdoor coded with specific credentials that allow access into the system. Although they’re hard-coded, these credentials still pose a risk if they’re exposed to the public.
Manage Secrets with Docker CLI
Let’s spin up our local Docker daemon and show you how to manage Docker secrets using the CLI.
docker secrets –help command lists the available options we have for managing secrets:
Let’s go through them one by one.
To create a new secret, you’ll use the
create command. You need to provide a file or consume the contents of the secret from the command line:
For technical and security reasons, you cannot create secrets if your
dockerd service is not in swarm mode. If it isn’t, you’ll get a message like this:
docker swarm init will enable swarm mode so that you can create secrets using the CLI:
$ docker info |grep Swarm Swarm: inactive $ docker swarm init Swarm initialized: current node (dfqc8qfvy8992lmmx737d0p4e) is now a manager. $ docker info |grep Swarm Swarm: active $ docker secret create my_credentials secret.json szv7anyechly226td0gmdtvxk
The string you get after running this command is a unique ID field for reference.
Here is an example of the STDIN use case:
$ echo -n "password" | docker secret create a_password -Aixt00c7zvhr1b1n9w673lz22Code language: PHP (php)
docker secret ls
You can inspect the list of secrets using the
docker secret ls command:
$ docker secret ls ID NAME DRIVER CREATED UPDATED aixt00c7zvhr1b1n9w673lz22 a_password 3 minutes ago 3 minutes ago szv7anyechly226td0gmdtvxk my_credentials 5 minutes ago 5 minutes ago
This shows the ID field that we mentioned earlier, the secret’s name, and the time elapsed since it was created and last updated. The DRIVER is the name of the provider used to fetch the secret’s value from an external secret store (which could be Vault, for example).
docker secret inspect
You can inspect a specific secret by using the
docker secret inspect command. You will need to provide either the ID or the name:
Of course, you don’t really get to see the actual values of the secret payload here. You just get to see the metadata.
docker secret rm
Finally, you can delete a secret using the
docker secret rm command passing the ID/name of the secret:
$ docker secret rm a_password a_password
You cannot delete a secret if it is used by a service or container. To see this in practice, you can create the following service, consume the secret, and then try to delete it:
To unmount a secret from a service, you can use the
docker service update command with the
You can add the secret back after you’ve created another one using the
docker service update command with the
$ docker service update --secret-add my_credentials memcached
Note that the actual contents of the secret are not encrypted, but they’re passed (as when you create a secret):
Manage Secrets with Docker Compose
You can also specify secrets using Docker compose. When you define the
docker-compose.yml file, you need to add specific fields that will be used to create and mount the secrets in the container services. For example, take a look at the following Redis service:
version: "3.9" services: redis: image: redis:latest container_name: redis command: [ "bash", "-c", ' docker-entrypoint.sh --requirepass "$(cat $REDIS_PASS_FILE)" ' ] volumes: - .:/var/lib/redis/data - ./redis.conf:/usr/local/etc/redis/redis.conf environment: REDIS_PASS_FILE: /run/secrets/redis_password secrets: - redis_password ports: - "6379" secrets: redis_password: file: redis_password.txtCode language: PHP (php)
There is a global
secrets field that specifies the source of the secrets. In this case, the secret is located in the local file called
redis_password.txt. It uses the name
redis_password as the secret name in the Redis service definition.
The last part is actually to make sure that the Redis server reads that value from
/run/secrets/redis_password. Because the current image does not allow reading that from a file, we need to use an
env variable and the
cat command to pipe it into the
Some images allow us to read the password without having to use a custom command. For example, the official
mysql image as well as the
MYSQL_PASSWORD_FILE env variables can be used to point to the mounted secrets files.
Note that you don’t have to use
docker secret create beforehand, as docker-compose will manage that for you.
How Does Docker Store Secrets?
To get a bit more technical, the way that Docker handles secrets for containers is as follows:
The Docker CLI interacts with the
dockerd service using HTTP for managing secrets. For example, this code deals with sending a
docker secret create command to the daemon.
dockerd service handles the list of
docker secret commands and interacts with the container backend service.
In the container backend, when a container is created, it avoids storing credentials and secrets within environmental variables; instead, it provides the files
/run/secrets/<secret_name> ( or
C:\ProgramData\Docker\secrets<secret_name> on Windows) under the mount in a
This section of the code is responsible for mounting the secrets in the container. This is called during the createSpec function, which is the base call when creating a container based on an image. Finally, the definitions of secret types are located here.
Docker Security Best Practices
To ensure the security of your Docker containers, you need to follow certain security practices when handling secrets. Follow these Dockerfile security best practices and recommendations for safeguarding the sensitive information stored within these environments:
Avoid Passing Secrets as Environment Variables
Passing secrets via environment (env) variables is convenient, but unsafe. Using the
docker inspect command, anyone with the right access to the node can inspect the values in plain form:
Use a Secrets Management Service
Although Docker mounts secrets in containers in a safe way, the actual storage of the secrets needs to be managed by the IT team. Things like secret rotation, access control, and encryption are delegated to a dedicated secrets service like Vault. This could work as part of an automation script, for example.
A secrets management service will securely store all the secrets that your organization needs to operate. When building containers and services via CI/CD pipelines, the secrets are fetched and passed on as inline variables to the Docker service or docker-compose.
If a secret needs to be rotated, then the workflow will go through all containers and update them with that secret, triggering an application reload. This enables the safe storage and retrieval of secrets in application containers.
Avoid Putting Secrets in Dockerfiles
You should never put secrets in a Dockerfile. For obvious reasons, this includes hard-coding secrets into version control (which is unsafe by default).
This concludes our exploration of Docker secrets. We need secrets to keep code and configurations separate as well as to ensure that application credentials are not exposed to the public.
In this guide, we explained what Docker secrets are and why they are important for security and compliance. We also showed you how to manage secrets using Docker CLI and Docker Compose. Finally, we described several Docker security best practices for managing secrets.
When it comes to Docker secrets, detecting threats and suspicious behavior in a scalable way requires a more sophisticated tool.
With Falco, you can create a “Runtime Security” layer that will actively detect and prevent secrets from escaping encrypted status, either by monitoring env variables or certain system calls or by committing them to version control.