From dad5d583399c389e7ee7a3a56cac79945640ff65 Mon Sep 17 00:00:00 2001 From: Ross Cadogan Date: Tue, 8 Nov 2016 11:29:04 +0000 Subject: [PATCH] Support loading authentication credentials from Docker config file --- README.md | 5 +++-- container/client.go | 9 ++++++--- container/trust.go | 33 +++++++++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f9197e8..901ecaf 100644 --- a/README.md +++ b/README.md @@ -39,12 +39,13 @@ docker run -d \ centurylink/watchtower ``` -If pulling images from a private Docker registry, supply any authentication credentials with the environment variables `REPO_USER` and `REPO_PASS`. +If pulling images from private Docker registries, supply registry authentication credentials with the environment variables `REPO_USER` and `REPO_PASS` +or by mounting the host's docker config file into the container (at the root of the container filesystem `/`). ``` docker run -d \ --name watchtower \ - -e REPO_USER="" -e REPO_PASS="" \ + -v /home//.docker/config.json:/config.json \ -v /var/run/docker.sock:/var/run/docker.sock \ drud/watchtower container_to_watch --debug ``` diff --git a/container/client.go b/container/client.go index c02a1d8..cf2e589 100644 --- a/container/client.go +++ b/container/client.go @@ -147,10 +147,13 @@ func (client dockerClient) IsContainerStale(c Container) (bool, error) { log.Debugf("Pulling %s for %s", imageName, c.Name()) var opts types.ImagePullOptions // ImagePullOptions can take a RegistryAuth arg to authenticate against a private registry - auth, err := EncodedEnvAuth(imageName) + auth, err := EncodedAuth(imageName) if err != nil { - log.Debug("No authentication credentials found") - opts = types.ImagePullOptions{} + log.Debugf("Error loading authentication credentials %s", err) + return false, err + } else if auth == "" { + log.Debugf("No authentication credentials found for %s", imageName) + opts = types.ImagePullOptions{} // empty/no auth credentials } else { opts = types.ImagePullOptions{RegistryAuth: auth, PrivilegeFunc: DefaultAuthHandler} } diff --git a/container/trust.go b/container/trust.go index 5a7e55c..6871333 100644 --- a/container/trust.go +++ b/container/trust.go @@ -8,13 +8,28 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/reference" "github.com/docker/docker/cli/command" + "github.com/docker/docker/cliconfig" "github.com/docker/docker/cliconfig/configfile" "github.com/docker/docker/cliconfig/credentials" ) +/** + * Return an encoded auth config for the given registry + * loaded from environment variables or docker config + * as available in that order + */ +func EncodedAuth(ref string) (string, error) { + auth, err := EncodedEnvAuth(ref) + if err != nil { + auth, err = EncodedConfigAuth(ref) + } + return auth, err +} + /* * Return an encoded auth config for the given registry * loaded from environment variables + * Returns an error if authentication environment variables have not been set */ func EncodedEnvAuth(ref string) (string, error) { username := os.Getenv("REPO_USER") @@ -34,17 +49,27 @@ func EncodedEnvAuth(ref string) (string, error) { /* * Return an encoded auth config for the given registry * loaded from the docker config + * Returns an empty string if credentials cannot be found for the referenced server * The docker config must be mounted on the container */ func EncodedConfigAuth(ref string) (string, error) { server, err := ParseServerAddress(ref) - configFile := command.LoadDefaultConfigFile(log.StandardLogger().Out) - credStore := CredentialsStore(*configFile) - auth, err := credStore.Get(server) + configDir := os.Getenv("DOCKER_CONFIG") + if configDir == "" { + configDir = "/" + } + configFile, err := cliconfig.Load(configDir) if err != nil { + log.Errorf("Unable to find default config file %s", err) return "", err } - log.Debugf("Loaded auth credentials %s from Docker config for reference %s", auth, ref) + credStore := CredentialsStore(*configFile) + auth, err := credStore.Get(server) // returns (types.AuthConfig{}) if server not in credStore + if auth == (types.AuthConfig{}) { + log.Debugf("No credentials for %s in %s", server, configFile.Filename) + return "", nil + } + log.Debugf("Loaded auth credentials %s from %s", auth, configFile.Filename) return EncodeAuth(auth) }