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.
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:
- 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-cryptBefore adding and comitting the file to be encrypted, you can check it will be encrypted with
$ 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.
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:
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