Skip to main content

Docker Secrets

No one doubts that the microservices architecture has proven itself efficient. However, implementing security, especially in an immutable infrastructure context, has been quite a challenge.

With questions ranging from how to separate passwords from the template in an image to how to change a service access password without interrupting it, workarounds abound. But as there's always room for improvement, in version 1.13 our dear friends at Docker launched what was called Docker Secrets.

Docker Secrets is Docker's solution for working with all the secrets aspects in a multi-node and multi-container environment. In other words, a "swarm mode" cluster. A secret can contain anything, but must have a maximum size of 500 KB. For now this beauty is not available outside the Docker Swarm context -- in fact, it's not clear if it will ever be different. For now we are encouraged to use a service to deploy individual containers.

14.1. The docker secret command​

The "docker secret" command comes with some subcommands. They are:

docker secret --help

Usage: docker secret COMMAND

Manage Docker secrets

Options:
--help Print usage

Commands:
create Create a secret from a file or STDIN as content
inspect Display detailed information on one or more secrets
ls List secrets
rm Remove one or more secrets

Run 'docker secret COMMAND --help' for more information on a command.
  • create -- Creates a secret from the content of a file or STDIN.

  • inspect -- Shows detailed information about one or more secrets.

  • ls -- Lists existing secrets.

  • rm -- Removes one or more secrets.

Create

As mentioned, "create" accepts content from both STDIN...

root@linuxtips:~# echo 'my secret' | docker secret create my_secret -
jxr0pilzhtqsiqi1f1fjmmg4t

root@linuxtips:~#

...and from a file:

root@linuxtips:~# docker secret create my_secret my_secret.txt
ci7mse43i5ak378sg3qc4xt04

root@linuxtips:~#

Inspect

Don't worry, "inspect" doesn't show the content of your secret! :P

Instead, it shows a series of information about the secret, including its creation and modification (although there's actually no way to modify a secret; once created, it cannot be updated via CLI, but there's already an endpoint in the Docker Swarm API for updating secrets -- "/secrets/id//update", let's wait and see!)

root@linuxtips:~# docker secret inspect my_secret
[
{
"ID": "ci7mse43i5ak378sg3qc4xt04",
"Version": {
"Index": 808
},
"CreatedAt": "2017-07-02T17:17:18.143116694Z",
"UpdatedAt": "2017-07-02T17:17:18.143116694Z",
"Spec": {
"Name": "my_secret",
"Labels": {}
}
}
]

root@linuxtips:~#

The "inspect" command accepts more than one secret at a time and will show the results in the same sequence.

ls && rm

These are used respectively to list your secrets and remove them.

root@linuxtips:~# docker secret ls
ID NAME CREATED UPDATED
ci7mse43i5ak378sg3qc4xt04 my_secret About a minute ago About a minute ago

root@linuxtips:~#
root@linuxtips:~# docker secret rm my_secret
my_secret

root@linuxtips:~#

14.2. Okay, but how do I use this?​

Secrets are consumed by services, as we mentioned, and this happens through explicit association, using the "--secret" flag when creating a service. Let's look at an example.

First let's create a secret with the database password for our fake application.

root@linuxtips:~# echo 'database_password' | docker secret create db_pass -
kxzgmhlu3ytv64hbqzg30nc8u

root@linuxtips:~#

Now, let's associate it with our app by creating a service.

root@linuxtips:~# docker service create --name app --detach=false --secret db_pass my_app:1.0
npfmry3vcol61cmcql3jiljk2
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Waiting 1 seconds to verify that tasks are stable...

root@linuxtips:~# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
npfmry3vcol6 app replicated 1/1 my_app:1.0

root@linuxtips:~# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
65d1533f5b50 my_app:1.0 "/bin/sh -c ./scri..." 40 seconds ago Up 39 seconds app.1.molbmj0649c7xkzfermkuwrx2

root@linuxtips:~#

It's also possible to grant access to keys for already created services, through the "--secret-add" flag of the "docker service update" command, as well as revoke them, using the "--secret-rm" flag in the same command. See the topic "Updating a service's secret".

14.3. Accessing the secret​

With the service created, the secret will be available to all containers of that service and will be in files within the "/run/secrets" directory, mounted in tmpfs. If your secret is called "db_pass", as in the example, its content will be in "/run/secrets/db_pass".

It's possible to include some parameters when adding a secret to a service, such as the target, which changes the file name at the destination and even security items like uid, gid, and mode:

docker service create --detach=false --name app --secret source=db_pass,target=password,uid=2000,gid=3000,mode=0400 my_app:1.0

Inside the container it would look like this:

root@4dd6b9cbff1a:/app# ls -lhart /run/secrets/
total 12K
-r-------- 1 2000 3000 15 Jul 2 17:44 password
drwxr-xr-x 7 root root 4.0K Jul 2 17:44 ..
drwxr-xr-x 2 root root 4.0K Jul 2 17:44 .

root@4dd6b9cbff1a:/app#

And then your application just needs to read the file contents.

root@8b16b5335334:/app# python
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> secret = open('/run/secrets/password').read()
>>>
>>> print "my secret is: %s" % (secret)
my secret is: new_password
>>>

14.4. Updating a service's secret​

Secrets were designed to be immutable, meaning that if you want to change a service's secret, you'll need to create another secret. The secret swap is quite easy. For example, to swap the secret "db_pass" from the previous example, we would need to do the following:

Create a new secret:

root@linuxtips:~# echo 'new_password' | docker secret create db_pass_1 -
221uzilbsl1ybna7g7014hoqr

root@linuxtips:~#

Add the secret to the previously created app:

root@linuxtips:~# docker service update --secret-rm db_pass --detach=false --secret-add source=db_pass_1,target=password app
app
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Waiting 1 seconds to verify that tasks are stable...

root@linuxtips:~#

After the update, just remove the old secret:

root@linuxtips:~# docker secret rm db_pass
db_pass

root@linuxtips:~#