Skip to content

Commit

Permalink
allow for .dockercfg files to reside in non-home directories
Browse files Browse the repository at this point in the history
This change facilitates OpenShift to mount docker config/auth data captured in Secrets in locations typical of such mounts, which are not off of the pod user's home directory.

Signed-off-by: gabemontero <[email protected]>
  • Loading branch information
gabemontero committed Oct 4, 2019
1 parent f06ac5b commit 98c3ba1
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 26 deletions.
41 changes: 26 additions & 15 deletions pkg/docker/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ type dockerConfigFile struct {
CredHelpers map[string]string `json:"credHelpers,omitempty"`
}

type authPath struct {
path string
legacyFormat bool
}

var (
defaultPerUIDPathFormat = filepath.FromSlash("/run/containers/%d/auth.json")
xdgRuntimeDirPath = filepath.FromSlash("containers/auth.json")
Expand Down Expand Up @@ -84,28 +89,28 @@ func GetAuthentication(sys *types.SystemContext, registry string) (string, strin
}
}

dockerLegacyPath := filepath.Join(homedir.Get(), dockerLegacyHomePath)
var paths []string
pathToAuth, err := getPathToAuth(sys)
paths := []authPath{}
pathToAuth, lf, err := getPathToAuth(sys)
if err == nil {
paths = append(paths, pathToAuth)
paths = append(paths, authPath{path: pathToAuth, legacyFormat: lf})
} else {
// Error means that the path set for XDG_RUNTIME_DIR does not exist
// but we don't want to completely fail in the case that the user is pulling a public image
// Logging the error as a warning instead and moving on to pulling the image
logrus.Warnf("%v: Trying to pull image in the event that it is a public image.", err)
}
paths = append(paths, filepath.Join(homedir.Get(), dockerHomePath), dockerLegacyPath)
paths = append(paths,
authPath{path: filepath.Join(homedir.Get(), dockerHomePath), legacyFormat: false},
authPath{path: filepath.Join(homedir.Get(), dockerLegacyHomePath), legacyFormat: true})

for _, path := range paths {
legacyFormat := path == dockerLegacyPath
username, password, err := findAuthentication(registry, path, legacyFormat)
username, password, err := findAuthentication(registry, path.path, path.legacyFormat)
if err != nil {
logrus.Debugf("Credentials not found")
return "", "", err
}
if username != "" && password != "" {
logrus.Debugf("Returning credentials from %s", path)
logrus.Debugf("Returning credentials from %s", path.path)
return username, password, nil
}
}
Expand Down Expand Up @@ -163,13 +168,16 @@ func RemoveAllAuthentication(sys *types.SystemContext) error {
// The path can be overriden by the user if the overwrite-path flag is set
// If the flag is not set and XDG_RUNTIME_DIR is set, the auth.json file is saved in XDG_RUNTIME_DIR/containers
// Otherwise, the auth.json file is stored in /run/containers/UID
func getPathToAuth(sys *types.SystemContext) (string, error) {
func getPathToAuth(sys *types.SystemContext) (string, bool, error) {
if sys != nil {
if sys.AuthFilePath != "" {
return sys.AuthFilePath, nil
return sys.AuthFilePath, false, nil
}
if sys.LegacyFormatAuthFilePath != "" {
return sys.LegacyFormatAuthFilePath, true, nil
}
if sys.RootForImplicitAbsolutePaths != "" {
return filepath.Join(sys.RootForImplicitAbsolutePaths, fmt.Sprintf(defaultPerUIDPathFormat, os.Getuid())), nil
return filepath.Join(sys.RootForImplicitAbsolutePaths, fmt.Sprintf(defaultPerUIDPathFormat, os.Getuid())), false, nil
}
}

Expand All @@ -182,11 +190,11 @@ func getPathToAuth(sys *types.SystemContext) (string, error) {
// This means the user set the XDG_RUNTIME_DIR variable and either forgot to create the directory
// or made a typo while setting the environment variable,
// so return an error referring to $XDG_RUNTIME_DIR instead of xdgRuntimeDirPath inside.
return "", errors.Wrapf(err, "%q directory set by $XDG_RUNTIME_DIR does not exist. Either create the directory or unset $XDG_RUNTIME_DIR.", runtimeDir)
return "", false, errors.Wrapf(err, "%q directory set by $XDG_RUNTIME_DIR does not exist. Either create the directory or unset $XDG_RUNTIME_DIR.", runtimeDir)
} // else ignore err and let the caller fail accessing xdgRuntimeDirPath.
return filepath.Join(runtimeDir, xdgRuntimeDirPath), nil
return filepath.Join(runtimeDir, xdgRuntimeDirPath), false, nil
}
return fmt.Sprintf(defaultPerUIDPathFormat, os.Getuid()), nil
return fmt.Sprintf(defaultPerUIDPathFormat, os.Getuid()), false, nil
}

// readJSONFile unmarshals the authentications stored in the auth.json file and returns it
Expand Down Expand Up @@ -220,7 +228,7 @@ func readJSONFile(path string, legacyFormat bool) (dockerConfigFile, error) {

// modifyJSON writes to auth.json if the dockerConfigFile has been updated
func modifyJSON(sys *types.SystemContext, editor func(auths *dockerConfigFile) (bool, error)) error {
path, err := getPathToAuth(sys)
path, legacyFormat, err := getPathToAuth(sys)
if err != nil {
return err
}
Expand All @@ -232,6 +240,9 @@ func modifyJSON(sys *types.SystemContext, editor func(auths *dockerConfigFile) (
}
}

if legacyFormat {
return fmt.Errorf("writes to %s using legacy format are not supported", path)
}
auths, err := readJSONFile(path, false)
if err != nil {
return errors.Wrapf(err, "error reading JSON file %q", path)
Expand Down
23 changes: 13 additions & 10 deletions pkg/docker/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,31 +33,34 @@ func TestGetPathToAuth(t *testing.T) {
}()

for _, c := range []struct {
sys *types.SystemContext
xrd string
expected string
sys *types.SystemContext
xrd string
expected string
legacyFormat bool
}{
// Default paths
{&types.SystemContext{}, "", "/run/containers/" + uid + "/auth.json"},
{nil, "", "/run/containers/" + uid + "/auth.json"},
{&types.SystemContext{}, "", "/run/containers/" + uid + "/auth.json", false},
{nil, "", "/run/containers/" + uid + "/auth.json", false},
// SystemContext overrides
{&types.SystemContext{AuthFilePath: "/absolute/path"}, "", "/absolute/path"},
{&types.SystemContext{RootForImplicitAbsolutePaths: "/prefix"}, "", "/prefix/run/containers/" + uid + "/auth.json"},
{&types.SystemContext{AuthFilePath: "/absolute/path"}, "", "/absolute/path", false},
{&types.SystemContext{LegacyFormatAuthFilePath: "/absolute/path"}, "", "/absolute/path", true},
{&types.SystemContext{RootForImplicitAbsolutePaths: "/prefix"}, "", "/prefix/run/containers/" + uid + "/auth.json", false},
// XDG_RUNTIME_DIR defined
{nil, tmpDir, tmpDir + "/containers/auth.json"},
{nil, tmpDir + "/thisdoesnotexist", ""},
{nil, tmpDir, tmpDir + "/containers/auth.json", false},
{nil, tmpDir + "/thisdoesnotexist", "", false},
} {
if c.xrd != "" {
os.Setenv("XDG_RUNTIME_DIR", c.xrd)
} else {
os.Unsetenv("XDG_RUNTIME_DIR")
}
res, err := getPathToAuth(c.sys)
res, lf, err := getPathToAuth(c.sys)
if c.expected == "" {
assert.Error(t, err)
} else {
require.NoError(t, err)
assert.Equal(t, c.expected, res)
assert.Equal(t, c.legacyFormat, lf)
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,15 @@ type SystemContext struct {
RegistriesDirPath string
// Path to the system-wide registries configuration file
SystemRegistriesConfPath string
// If not "", overrides the default path for the authentication file
// If not "", overrides the default path for the authentication file, but only new format files
AuthFilePath string
// if not "", overrides the default path for the authentication file, but with the legacy format;
// the code currently will by default look for legacy format files like .dockercfg in the $HOME dir;
// but in addition to the home dir, openshift may mount .dockercfg files (via secret mount)
// in locations other than the home dir; openshift components should then set this field in those cases;
// this field is ignored if `AuthFilePath` is set (we favor the newer format);
// only reading of this data is supported;
LegacyFormatAuthFilePath string
// If not "", overrides the use of platform.GOARCH when choosing an image or verifying architecture match.
ArchitectureChoice string
// If not "", overrides the use of platform.GOOS when choosing an image or verifying OS match.
Expand Down

0 comments on commit 98c3ba1

Please sign in to comment.