diff --git a/pkg/docker/config/config.go b/pkg/docker/config/config.go index e720dc865a..c2a1d049ab 100644 --- a/pkg/docker/config/config.go +++ b/pkg/docker/config/config.go @@ -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") @@ -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 } } @@ -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 } } @@ -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 @@ -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 } @@ -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) diff --git a/pkg/docker/config/config_test.go b/pkg/docker/config/config_test.go index 4491c61b32..d7b7dd919e 100644 --- a/pkg/docker/config/config_test.go +++ b/pkg/docker/config/config_test.go @@ -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) } } } diff --git a/types/types.go b/types/types.go index af11a2b212..edb1cf66df 100644 --- a/types/types.go +++ b/types/types.go @@ -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.