In your docker-compose file, defining a secret's source and target let you easily rotate your secrets without changing any application code.
The first step I recommend is coming up with standard naming conventions across all your secrets that you and your team can agree on.
An example of a naming convention that we use on my team looks something like this:
# Convention service/stack/website.subject.title.attribute.version # Useage anthonymineocom.azure.sql.host.v1
Regardless of what convention you come up with, be sure to end it in a version. This is the part that makes the rotation easy and trackable. More on this in a bit.
Setting up your docker-compose.yml
Instead of running something like
docker service update --secret..., In your
docker-compose.yml specify the
target for your secrets in the corresponding services.
This is especially important because if you plan for it, the code in your application and how you reference secrets do not need to change. And that's a good thing! Only your
docker-compose.yml file needs to be updated, and of course, you still need to create the secret in Swarm.
Here's a real example of how your docker-compose could look:
version: "3.4" services: # CFML Engine cfml: image: ortussolutions/commandbox:lucee5-2.3.0 environment: DSN_HOST: <<SECRET:company.azure.sql.host>> DSN_DB: <<SECRET:website.dsn.db>> DSN_USERNAME: <<SECRET:website.dsn.username>> DSN_PASSWORD: <<SECRET:website.dsn.password>> secrets: - source: company.azure.sql.host.v1 target: company.azure.sql.host - source: website.dsn.db.v1 target: website.dsn.db - source: website.dsn.username.v1 target: website.dsn.username - source: website.dsn.password.v1 target: website.dsn.password secrets: company.azure.sql.host.v1: external: true website.dsn.db.v1: external: true website.dsn.username.v1: external: true website.dsn.password.v1: external: true
target are listed in an expanded format.
Source is the versioned secret that resides in Docker Swarm. Usually created with
docker secret create.
Target is just a reference or pointer to the actual secret used in your application. The target should not be versioned. If you do, then you will need to update the references in your application.
Think of it as if
target was the alias of
source, which is the actual secret that lives in Docker Swarm.
Rotating your secrets
In our scenario we're going to update our
v1 already exists, we're just going to increment to
First, add the new secret to Docker Swarm.
echo "120minuteIPAALLDAY" | docker secret create website.dsn.password.v2 -
Now, in our
docker-compose.yml we only need to update 2 spots. Our main secrets dictionary, and the secrets dictionary for the service.
version: "3.4" services: # CFML Engine cfml: ... secrets: ... - source: website.dsn.password.v2 target: website.dsn.password secrets: ... website.dsn.password.v2: external: true
And finally... re-deploy the stack with the updated secret.
docker stack deploy -c docker-compose.yml yourstack.
Swarm will then go through the motions of updating the services who's secrets have changed.
Hope this helps! Hit me up on Twitter: @Mineo27 if you have any issues/questions.