Skip to content

Gitops for Swarm Using Private Registry

We will see how to store the compose files of a Docker Swarm in git, together with encrypted authentication data to retrieve images from private repositories. We will access a private registry hosted by Gitlab. Authentication to the registry is done with a deploy token, which gives you a username and password giving access only to the relevant registry.

Docker authentication

Authentication to a docker registry is done with the command docker login -u $login --password $password (or alternatively with --password-stdin to avoid putting the password on the command line). Authenticating to a registry results in this output:

decrypt_command my_password_file.enc | docker login --username=gitlab+deploy-token-083403 --password-stdin registry.gitlab.com
WARNING! Your password will be stored unencrypted in /etc/docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Of course this is scary, but using a credential helper has the same problem as the config.json: as far as I know you can only store one credentials entry per registry. Using the same credential for all Gitlab registries is problematic and probably impossible (because you will probably have one set of credential per project). The workaround is use multiple config files and pass the flag --config to select which config directory, and hence which credentials, to use:

decrypt_command my_password_file.enc | docker --config ~/$PROJECT_NAME/etc/docker/ login --username=gitlab+deploy-token-083403 --password-stdin registry.gitlab.com

The previous command creates the file ~/$PROJECT_NAME/etc/docker/ with the credentials used to log in.

Securing the docker config

Deciding on how to protect the credentials will depend on your situation. If the credentials are distinct for each developer (the best solution), you can ensure that the generated file `~/private/$PROJECT_NAME/etc/docker/config.json' is on an encrypted partition that you mount when you need it. If the project automates some docker operations relying on the authentication to the registry in scripts, you need to ensure all team member (and probably also your CI) make their own credentials available to the scripts (either because all members store the docker config file at the same location, or by specifying the config path in an environment variable). This brings the best security, but might be tedious and requires discipline.

If you’re in a small team and all developers access the registry with the same credentials, you can store the config file in git with git-crypt. Setting it up is really easy:

  • Install, eg on a Debian based distribution: apt install git-crypt
  • Initialise in your git repo: git-crypt init
  • Export the git-crypt key generated by init: git-crypt export-key ~/private/keyfile
  • Setup in .gitattributes with a line of this shape: etc/docker/config.json filter=git-crypt diff=git-crypt Before adding and comitting the file to be encrypted, you can check it will be encrypted with git-crypt status:
$ git-crypt status
not encrypted: .env
not encrypted: .envrc
not encrypted: .gitattributes
not encrypted: .gitignore
not encrypted: README
    encrypted: etc/docker/config.json

The file is in clear on your disk, but it is transparently encrypted/decrypted when commited/checked out. To see the repo as it will be pushed, you can issue the command git-crypt lock. To unlock it, you need the encryption key you exported earlier: git-crypt unlock ~/private/keyfile.

You still need to protect the encryption key. However the advantage of git-crypt is that you can protect other secrets in your repo. Of course, you should check git-crypt matches your requirements, at least by reading the README. Eg there are security implications if you want to change the encryption key.

Setting DOCKER_HOST

The easiest way to interact with a Docker Swarm is by setting up your key-based ssh authentication and set the DOCKER_HOST variable environment:

export DOCKER_HOST=ssh://mylogin@swarm_host

This lets you control the remote docker swarm as if it was running locally, eg with docker stack ls. If you don’t use it already, checkout direnv so the environment variable is set automatically when you enter your project directory.

Using credentials with Docker Swarm

Once you have your credential file locally, you can transmit it to the swarm with the flag --with-registry-auth. You end up with a command of this shape:

docker --config etc/docker/ stack deploy --with-registry-auth -c stack-apache.yml apache