You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
watchtower/pkg/container/trust.go

108 lines
3.4 KiB
Go

package container
import (
"errors"
"os"
"strings"
"github.com/docker/cli/cli/command"
cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/config/credentials"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
log "github.com/sirupsen/logrus"
)
// EncodedAuth returns 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
}
// EncodedEnvAuth returns 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")
password := os.Getenv("REPO_PASS")
if username != "" && password != "" {
auth := types.AuthConfig{
Username: username,
Password: password,
}
log.Debugf("Loaded auth credentials %s for %s", auth, ref)
return EncodeAuth(auth)
}
return "", errors.New("Registry auth environment variables (REPO_USER, REPO_PASS) not set")
}
// EncodedConfigAuth returns 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)
if err != nil {
log.Errorf("Unable to parse the image ref %s", err)
return "", err
}
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
}
credStore := CredentialsStore(*configFile)
auth, _ := 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)
}
// ParseServerAddress extracts the server part from a container image ref
func ParseServerAddress(ref string) (string, error) {
parsedRef, err := reference.Parse(ref)
if err != nil {
return ref, err
}
parts := strings.Split(parsedRef.String(), "/")
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, configFile.CredentialsStore)
}
return credentials.NewFileStore(&configFile)
}
// EncodeAuth Base64 encode an AuthConfig struct for transmission over HTTP
func EncodeAuth(auth types.AuthConfig) (string, error) {
return command.EncodeAuthToBase64(auth)
}
// DefaultAuthHandler will be invoked if an AuthConfig is rejected
// It could be used to return a new value for the "X-Registry-Auth" authentication header,
// but there's no point trying again with the same value as used in AuthConfig
func DefaultAuthHandler() (string, error) {
log.Debug("Authentication request was rejected. Trying again without authentication")
return "", nil
}