mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
Updates docker pull to pull related attestation manifest and any signatures for that manifest in cosign referrer objects. These objects are transferred with the image when running docker save and docker load and can be used to identify the image in future updates. Push is not updated atm as the currect push semantics in containerd mode do not have correct immutability guaranteed and don't work with image indexes. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
174 lines
4.6 KiB
Go
174 lines
4.6 KiB
Go
package daemon
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/containerd/containerd/v2/core/remotes/docker"
|
|
hostconfig "github.com/containerd/containerd/v2/core/remotes/docker/config"
|
|
cerrdefs "github.com/containerd/errdefs"
|
|
"github.com/moby/moby/v2/daemon/pkg/registry"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const (
|
|
defaultPath = "/v2"
|
|
)
|
|
|
|
// RegistryHosts returns the registry hosts configuration for the host component
|
|
// of a distribution image reference.
|
|
func (daemon *Daemon) RegistryHosts(host string) ([]docker.RegistryHost, error) {
|
|
hosts, err := hostconfig.ConfigureHosts(context.Background(), hostconfig.HostOptions{
|
|
// TODO: Also check containerd path when updating containerd to use multiple host directories
|
|
HostDir: hostconfig.HostDirFromRoot(registry.CertsDir()),
|
|
})(host)
|
|
if err == nil {
|
|
// Merge in legacy configuration if provided
|
|
if cfg := daemon.config().Config; len(cfg.Mirrors) > 0 || len(cfg.InsecureRegistries) > 0 {
|
|
hosts, err = daemon.mergeLegacyConfig(host, hosts)
|
|
}
|
|
}
|
|
|
|
return hosts, err
|
|
}
|
|
|
|
func (daemon *Daemon) mergeLegacyConfig(host string, hosts []docker.RegistryHost) ([]docker.RegistryHost, error) {
|
|
// If no hosts provided, nothing to do.
|
|
// If multiple hosts provided, then a mirror configuration is already provided and
|
|
// should not overwrite with legacy config.
|
|
if len(hosts) == 0 || len(hosts) > 1 {
|
|
return hosts, nil
|
|
}
|
|
sc := daemon.registryService.ServiceConfig()
|
|
if host == "docker.io" && len(sc.Mirrors) > 0 {
|
|
hosts = mirrorsToRegistryHosts(sc.Mirrors, hosts[0])
|
|
}
|
|
hostDir := hostconfig.HostDirFromRoot(registry.CertsDir())
|
|
for i := range hosts {
|
|
t, ok := hosts[i].Client.Transport.(*http.Transport)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if t.TLSClientConfig == nil {
|
|
certsDir, err := hostDir(host)
|
|
if err != nil && !cerrdefs.IsNotFound(err) {
|
|
return nil, err
|
|
} else if err == nil {
|
|
c, err := loadTLSConfig(certsDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t.TLSClientConfig = c
|
|
}
|
|
}
|
|
if daemon.registryService.IsInsecureRegistry(hosts[i].Host) {
|
|
if t.TLSClientConfig == nil {
|
|
t.TLSClientConfig = &tls.Config{} //nolint: gosec // G402: TLS MinVersion too low.
|
|
}
|
|
t.TLSClientConfig.InsecureSkipVerify = true
|
|
|
|
hosts[i].Client.Transport = docker.NewHTTPFallback(hosts[i].Client.Transport)
|
|
}
|
|
}
|
|
return hosts, nil
|
|
}
|
|
|
|
func mirrorsToRegistryHosts(mirrors []string, dHost docker.RegistryHost) []docker.RegistryHost {
|
|
var mirrorHosts []docker.RegistryHost
|
|
for _, mirror := range mirrors {
|
|
h := dHost
|
|
h.Capabilities = docker.HostCapabilityPull | docker.HostCapabilityResolve | docker.HostCapabilityReferrers
|
|
|
|
u, err := url.Parse(mirror)
|
|
if err != nil || u.Host == "" {
|
|
u, err = url.Parse(fmt.Sprintf("dummy://%s", mirror))
|
|
}
|
|
if err == nil && u.Host != "" {
|
|
h.Host = u.Host
|
|
h.Path = strings.TrimSuffix(u.Path, "/")
|
|
|
|
// For compatibility with legacy mirrors, ensure ends with /v2
|
|
// NOTE: Use newer configuration to completely override the path
|
|
if !strings.HasSuffix(h.Path, defaultPath) {
|
|
h.Path = path.Join(h.Path, defaultPath)
|
|
}
|
|
if u.Scheme != "dummy" {
|
|
h.Scheme = u.Scheme
|
|
}
|
|
} else {
|
|
h.Host = mirror
|
|
h.Path = defaultPath
|
|
}
|
|
|
|
mirrorHosts = append(mirrorHosts, h)
|
|
}
|
|
return append(mirrorHosts, dHost)
|
|
}
|
|
|
|
func loadTLSConfig(d string) (*tls.Config, error) {
|
|
fs, err := os.ReadDir(d)
|
|
if err != nil && !errors.Is(err, os.ErrNotExist) && !errors.Is(err, os.ErrPermission) {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
type keyPair struct {
|
|
Certificate string
|
|
Key string
|
|
}
|
|
var (
|
|
rootCAs []string
|
|
keyPairs []keyPair
|
|
)
|
|
for _, f := range fs {
|
|
switch filepath.Ext(f.Name()) {
|
|
case ".crt":
|
|
rootCAs = append(rootCAs, filepath.Join(d, f.Name()))
|
|
case ".cert":
|
|
keyPairs = append(keyPairs, keyPair{
|
|
Certificate: filepath.Join(d, f.Name()),
|
|
Key: filepath.Join(d, strings.TrimSuffix(f.Name(), ".cert")+".key"),
|
|
})
|
|
}
|
|
}
|
|
|
|
tc := &tls.Config{
|
|
MinVersion: tls.VersionTLS12,
|
|
}
|
|
if len(rootCAs) > 0 {
|
|
systemPool, err := x509.SystemCertPool()
|
|
if err != nil {
|
|
if runtime.GOOS == "windows" {
|
|
systemPool = x509.NewCertPool()
|
|
} else {
|
|
return nil, errors.Wrapf(err, "unable to get system cert pool")
|
|
}
|
|
}
|
|
tc.RootCAs = systemPool
|
|
}
|
|
|
|
for _, p := range rootCAs {
|
|
dt, err := os.ReadFile(p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tc.RootCAs.AppendCertsFromPEM(dt)
|
|
}
|
|
|
|
for _, kp := range keyPairs {
|
|
cert, err := tls.LoadX509KeyPair(kp.Certificate, kp.Key)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to load keypair for %s", kp.Certificate)
|
|
}
|
|
tc.Certificates = append(tc.Certificates, cert)
|
|
}
|
|
return tc, nil
|
|
}
|