mirror of
https://github.com/containrrr/watchtower.git
synced 2025-12-14 14:10:12 +01:00
Registry authentication was failing silently when pulling images.
Load authentication credentials for available credential stores in order of preference: 1. Environment variables REPO_USER, REPO_PASS 2. Docker config files Request image pull with authentication header. Wait until pull request is complete before exiting function.
This commit is contained in:
parent
ef430b791a
commit
1c59200565
4 changed files with 128 additions and 20 deletions
|
|
@ -3,11 +3,11 @@ package container
|
|||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"io/ioutil"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
dockerclient "github.com/docker/docker/client"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/cli/command"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
@ -146,22 +146,28 @@ func (client dockerClient) IsContainerStale(c Container) (bool, error) {
|
|||
if client.pullImages {
|
||||
log.Debugf("Pulling %s for %s", imageName, c.Name())
|
||||
|
||||
auth := types.AuthConfig {
|
||||
Username: "testuser",
|
||||
Password: "testpassword",
|
||||
}
|
||||
encodedAuth, err := command.EncodeAuthToBase64(auth)
|
||||
var opts types.ImagePullOptions // ImagePullOptions can take a RegistryAuth arg to authenticate against a private registry
|
||||
auth, err := EncodedEnvAuth(imageName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
// credentials environment vars not set, trying Docker config instead
|
||||
auth, err = EncodedConfigAuth(imageName)
|
||||
}
|
||||
if err != nil {
|
||||
log.Debug("No authentication credentials found")
|
||||
opts = types.ImagePullOptions{}
|
||||
} else {
|
||||
opts = types.ImagePullOptions{RegistryAuth: auth, PrivilegeFunc: DefaultAuthHandler}
|
||||
}
|
||||
|
||||
// Note: ImagePullOptions below can take a RegistryAuth arg if 401 on private registry
|
||||
closer, err := client.api.ImagePull(bg, imageName, types.ImagePullOptions{RegistryAuth: encodedAuth})
|
||||
response, err := client.api.ImagePull(bg, imageName, opts)
|
||||
if err != nil {
|
||||
log.Debugf("Error pulling image %s, %s", imageName, err)
|
||||
return false, err
|
||||
}
|
||||
defer closer.Close()
|
||||
defer response.Close()
|
||||
|
||||
// the pull request will be aborted prematurely unless the response is read
|
||||
_, err = ioutil.ReadAll(response)
|
||||
}
|
||||
|
||||
newImageInfo, _, err := client.api.ImageInspectWithRaw(bg, imageName)
|
||||
|
|
@ -174,7 +180,6 @@ func (client dockerClient) IsContainerStale(c Container) (bool, error) {
|
|||
return true, nil
|
||||
} else {
|
||||
log.Debugf("No new images found for %s", c.Name())
|
||||
log.Debugf("Old image ID %s is the same as New Image ID %s", oldImageInfo.ID, newImageInfo.ID)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
93
container/trust.go
Normal file
93
container/trust.go
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
"fmt"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/reference"
|
||||
"github.com/docker/docker/cli/command"
|
||||
"github.com/docker/docker/cliconfig/configfile"
|
||||
"github.com/docker/docker/cliconfig/credentials"
|
||||
)
|
||||
|
||||
|
||||
/*
|
||||
* Return an encoded auth config for the given registry
|
||||
* hardcoded for a test environment
|
||||
*/
|
||||
func EncodedTestAuth(ref string) (string, error) {
|
||||
auth := types.AuthConfig {
|
||||
Username: "testuser",
|
||||
Password: "testpassword",
|
||||
}
|
||||
return EncodeAuth(auth)
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an encoded auth config for the given registry
|
||||
* loaded from environment variables
|
||||
*/
|
||||
func EncodedEnvAuth(ref string) (string, error) {
|
||||
username := os.Getenv("REPO_USER")
|
||||
password := os.Getenv("REPO_PASS")
|
||||
if username != "" && password != "" {
|
||||
auth := types.AuthConfig {
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
log.Debugf("Loaded auth credentials %s from environment for %s", auth, ref)
|
||||
return EncodeAuth(auth)
|
||||
} else {
|
||||
return "", errors.New("Registry auth environment variables (REPO_USER, REPO_PASS) not set")
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an encoded auth config for the given registry
|
||||
* loaded from the docker config
|
||||
*/
|
||||
func EncodedConfigAuth(ref string) (string, error) {
|
||||
server, err := ParseServerAddress(ref)
|
||||
configFile := command.LoadDefaultConfigFile(log.StandardLogger().Out)
|
||||
credStore := CredentialsStore(*configFile)
|
||||
auth, err := credStore.Get(server)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
log.Debugf("Loaded auth credentials %s from Docker config for reference %s", auth, ref)
|
||||
return EncodeAuth(auth)
|
||||
}
|
||||
|
||||
func ParseServerAddress(ref string) (string, error) {
|
||||
repository, _, err := reference.Parse(ref)
|
||||
if err != nil {
|
||||
return ref, err
|
||||
}
|
||||
parts := strings.Split(repository, "/")
|
||||
return parts[0], nil
|
||||
|
||||
}
|
||||
|
||||
// CredentialsStore returns a new credentials store based
|
||||
// on the settings provided in the configuration file.
|
||||
func CredentialsStore(configFile configfile.ConfigFile) credentials.Store {
|
||||
if configFile.CredentialsStore != "" {
|
||||
return credentials.NewNativeStore(&configFile)
|
||||
}
|
||||
return credentials.NewFileStore(&configFile)
|
||||
}
|
||||
|
||||
/*
|
||||
* Base64 encode an AuthConfig struct for transmission over HTTP
|
||||
*/
|
||||
func EncodeAuth(auth types.AuthConfig) (string, error) {
|
||||
return command.EncodeAuthToBase64(auth)
|
||||
}
|
||||
|
||||
func DefaultAuthHandler() (string, error) {
|
||||
log.Error("Authentication requested")
|
||||
return "", fmt.Errorf("Error requesting privilege")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue