diff --git a/cmd/dockerd/config_unix.go b/cmd/dockerd/config_unix.go index 3064cfe132..2706b5f1ed 100644 --- a/cmd/dockerd/config_unix.go +++ b/cmd/dockerd/config_unix.go @@ -4,13 +4,9 @@ package main import ( "net" - "path/filepath" "github.com/docker/docker/daemon/config" "github.com/docker/docker/opts" - "github.com/docker/docker/pkg/homedir" - "github.com/docker/docker/pkg/rootless" - "github.com/docker/docker/registry" "github.com/spf13/pflag" ) @@ -59,14 +55,3 @@ func installConfigFlags(conf *config.Config, flags *pflag.FlagSet) { flags.BoolVar(&conf.Rootless, "rootless", conf.Rootless, "Enable rootless mode; typically used with RootlessKit") flags.StringVar(&conf.CgroupNamespaceMode, "default-cgroupns-mode", conf.CgroupNamespaceMode, `Default mode for containers cgroup namespace ("host" | "private")`) } - -// configureCertsDir configures registry.CertsDir() depending on if the daemon -// is running in rootless mode or not. -func configureCertsDir() { - if rootless.RunningWithRootlessKit() { - configHome, err := homedir.GetConfigHome() - if err == nil { - registry.SetCertsDir(filepath.Join(configHome, "docker/certs.d")) - } - } -} diff --git a/cmd/dockerd/docker.go b/cmd/dockerd/docker.go index 55642ef32c..e75615cb41 100644 --- a/cmd/dockerd/docker.go +++ b/cmd/dockerd/docker.go @@ -79,7 +79,6 @@ func newDaemonCommand() (*cobra.Command, error) { flags := cmd.Flags() flags.BoolP("version", "v", false, "Print version information and quit") flags.StringVar(&opts.configFile, "config-file", opts.configFile, "Daemon configuration file") - configureCertsDir() opts.installFlags(flags) installConfigFlags(opts.daemonConfig, flags) installServiceFlags(flags) diff --git a/registry/config.go b/registry/config.go index ff06775c4b..433454624a 100644 --- a/registry/config.go +++ b/registry/config.go @@ -4,13 +4,17 @@ import ( "context" "net" "net/url" + "os" + "path/filepath" "strconv" "strings" + "sync" "github.com/containerd/log" "github.com/distribution/reference" "github.com/docker/docker/api/types/registry" "github.com/docker/docker/internal/lazyregexp" + "github.com/docker/docker/pkg/homedir" ) // ServiceOptions holds command line options. @@ -58,23 +62,50 @@ var ( validHostPortRegex = lazyregexp.New(`^` + reference.DomainRegexp.String() + `$`) - // certsDir is used to override defaultCertsDir. - certsDir string + // certsDir is used to override defaultCertsDir when running with rootlessKit. + // + // TODO(thaJeztah): change to a sync.OnceValue once we remove [SetCertsDir] + // TODO(thaJeztah): certsDir should not be a package variable, but stored in our config, and passed when needed. + setCertsDirOnce sync.Once + certsDir string ) +func setCertsDir(dir string) string { + setCertsDirOnce.Do(func() { + if dir != "" { + certsDir = dir + return + } + if os.Getenv("ROOTLESSKIT_STATE_DIR") != "" { + // Configure registry.CertsDir() when running in rootless-mode + // This is the equivalent of [rootless.RunningWithRootlessKit], + // but inlining it to prevent adding that as a dependency + // for docker/cli. + // + // [rootless.RunningWithRootlessKit]: https://github.com/moby/moby/blob/b4bdf12daec84caaf809a639f923f7370d4926ad/pkg/rootless/rootless.go#L5-L8 + if configHome, _ := homedir.GetConfigHome(); configHome != "" { + certsDir = filepath.Join(configHome, "docker/certs.d") + return + } + } + certsDir = defaultCertsDir + }) + return certsDir +} + // SetCertsDir allows the default certs directory to be changed. This function // is used at daemon startup to set the correct location when running in // rootless mode. +// +// Deprecated: the cert-directory is now automatically selected when running with rootlessKit, and should no longer be set manually. func SetCertsDir(path string) { - certsDir = path + setCertsDir(path) } // CertsDir is the directory where certificates are stored. func CertsDir() string { - if certsDir != "" { - return certsDir - } - return defaultCertsDir + // call setCertsDir with an empty path to synchronise with [SetCertsDir] + return setCertsDir("") } // newServiceConfig returns a new instance of ServiceConfig diff --git a/registry/registry.go b/registry/registry.go index 6b079199dd..a26f976cee 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -8,7 +8,6 @@ import ( "net/http" "os" "path/filepath" - "strings" "time" "github.com/containerd/log" @@ -18,7 +17,14 @@ import ( ) // HostCertsDir returns the config directory for a specific host. +// +// Deprecated: this function was only used internally, and will be removed in a future release. func HostCertsDir(hostname string) string { + return hostCertsDir(hostname) +} + +// hostCertsDir returns the config directory for a specific host. +func hostCertsDir(hostname string) string { return filepath.Join(CertsDir(), cleanPath(hostname)) } @@ -26,11 +32,10 @@ func HostCertsDir(hostname string) string { func newTLSConfig(hostname string, isSecure bool) (*tls.Config, error) { // PreferredServerCipherSuites should have no effect tlsConfig := tlsconfig.ServerDefault() - tlsConfig.InsecureSkipVerify = !isSecure - if isSecure && CertsDir() != "" { - hostDir := HostCertsDir(hostname) + if isSecure { + hostDir := hostCertsDir(hostname) log.G(context.TODO()).Debugf("hostDir: %s", hostDir) if err := ReadCertsDirectory(tlsConfig, hostDir); err != nil { return nil, err @@ -59,7 +64,8 @@ func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error { } for _, f := range fs { - if strings.HasSuffix(f.Name(), ".crt") { + switch filepath.Ext(f.Name()) { + case ".crt": if tlsConfig.RootCAs == nil { systemPool, err := tlsconfig.SystemCertPool() if err != nil { @@ -67,17 +73,17 @@ func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error { } tlsConfig.RootCAs = systemPool } - log.G(context.TODO()).Debugf("crt: %s", filepath.Join(directory, f.Name())) - data, err := os.ReadFile(filepath.Join(directory, f.Name())) + fileName := filepath.Join(directory, f.Name()) + log.G(context.TODO()).Debugf("crt: %s", fileName) + data, err := os.ReadFile(fileName) if err != nil { return err } tlsConfig.RootCAs.AppendCertsFromPEM(data) - } - if strings.HasSuffix(f.Name(), ".cert") { + case ".cert": certName := f.Name() keyName := certName[:len(certName)-5] + ".key" - log.G(context.TODO()).Debugf("cert: %s", filepath.Join(directory, f.Name())) + log.G(context.TODO()).Debugf("cert: %s", filepath.Join(directory, certName)) if !hasFile(fs, keyName) { return invalidParamf("missing key %s for client certificate %s. CA certificates must use the extension .crt", keyName, certName) } @@ -86,11 +92,10 @@ func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error { return err } tlsConfig.Certificates = append(tlsConfig.Certificates, cert) - } - if strings.HasSuffix(f.Name(), ".key") { + case ".key": keyName := f.Name() certName := keyName[:len(keyName)-4] + ".cert" - log.G(context.TODO()).Debugf("key: %s", filepath.Join(directory, f.Name())) + log.G(context.TODO()).Debugf("key: %s", filepath.Join(directory, keyName)) if !hasFile(fs, certName) { return invalidParamf("missing client certificate %s for key %s", certName, keyName) }