github.com/rawahars/moby@v24.0.4+incompatible/cmd/dockerd/daemon.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"fmt"
     7  	"net"
     8  	"net/http"
     9  	"os"
    10  	"path/filepath"
    11  	"runtime"
    12  	"sort"
    13  	"strings"
    14  	"sync"
    15  	"time"
    16  
    17  	containerddefaults "github.com/containerd/containerd/defaults"
    18  	"github.com/docker/docker/api"
    19  	apiserver "github.com/docker/docker/api/server"
    20  	buildbackend "github.com/docker/docker/api/server/backend/build"
    21  	"github.com/docker/docker/api/server/middleware"
    22  	"github.com/docker/docker/api/server/router"
    23  	"github.com/docker/docker/api/server/router/build"
    24  	checkpointrouter "github.com/docker/docker/api/server/router/checkpoint"
    25  	"github.com/docker/docker/api/server/router/container"
    26  	distributionrouter "github.com/docker/docker/api/server/router/distribution"
    27  	grpcrouter "github.com/docker/docker/api/server/router/grpc"
    28  	"github.com/docker/docker/api/server/router/image"
    29  	"github.com/docker/docker/api/server/router/network"
    30  	pluginrouter "github.com/docker/docker/api/server/router/plugin"
    31  	sessionrouter "github.com/docker/docker/api/server/router/session"
    32  	swarmrouter "github.com/docker/docker/api/server/router/swarm"
    33  	systemrouter "github.com/docker/docker/api/server/router/system"
    34  	"github.com/docker/docker/api/server/router/volume"
    35  	buildkit "github.com/docker/docker/builder/builder-next"
    36  	"github.com/docker/docker/builder/dockerfile"
    37  	"github.com/docker/docker/cli/debug"
    38  	"github.com/docker/docker/cmd/dockerd/trap"
    39  	"github.com/docker/docker/daemon"
    40  	"github.com/docker/docker/daemon/cluster"
    41  	"github.com/docker/docker/daemon/config"
    42  	"github.com/docker/docker/daemon/listeners"
    43  	"github.com/docker/docker/dockerversion"
    44  	"github.com/docker/docker/libcontainerd/supervisor"
    45  	dopts "github.com/docker/docker/opts"
    46  	"github.com/docker/docker/pkg/authorization"
    47  	"github.com/docker/docker/pkg/homedir"
    48  	"github.com/docker/docker/pkg/jsonmessage"
    49  	"github.com/docker/docker/pkg/pidfile"
    50  	"github.com/docker/docker/pkg/plugingetter"
    51  	"github.com/docker/docker/pkg/rootless"
    52  	"github.com/docker/docker/pkg/sysinfo"
    53  	"github.com/docker/docker/pkg/system"
    54  	"github.com/docker/docker/plugin"
    55  	"github.com/docker/docker/runconfig"
    56  	"github.com/docker/go-connections/tlsconfig"
    57  	"github.com/moby/buildkit/session"
    58  	swarmapi "github.com/moby/swarmkit/v2/api"
    59  	"github.com/pkg/errors"
    60  	"github.com/sirupsen/logrus"
    61  	"github.com/spf13/pflag"
    62  )
    63  
    64  // DaemonCli represents the daemon CLI.
    65  type DaemonCli struct {
    66  	*config.Config
    67  	configFile *string
    68  	flags      *pflag.FlagSet
    69  
    70  	d               *daemon.Daemon
    71  	authzMiddleware *authorization.Middleware // authzMiddleware enables to dynamically reload the authorization plugins
    72  
    73  	stopOnce    sync.Once
    74  	apiShutdown chan struct{}
    75  }
    76  
    77  // NewDaemonCli returns a daemon CLI
    78  func NewDaemonCli() *DaemonCli {
    79  	return &DaemonCli{
    80  		apiShutdown: make(chan struct{}),
    81  	}
    82  }
    83  
    84  func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
    85  	if cli.Config, err = loadDaemonCliConfig(opts); err != nil {
    86  		return err
    87  	}
    88  
    89  	tlsConfig, err := newAPIServerTLSConfig(cli.Config)
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	if opts.Validate {
    95  		// If config wasn't OK we wouldn't have made it this far.
    96  		_, _ = fmt.Fprintln(os.Stderr, "configuration OK")
    97  		return nil
    98  	}
    99  
   100  	configureProxyEnv(cli.Config)
   101  	configureDaemonLogs(cli.Config)
   102  
   103  	logrus.Info("Starting up")
   104  
   105  	cli.configFile = &opts.configFile
   106  	cli.flags = opts.flags
   107  
   108  	if cli.Config.Debug {
   109  		debug.Enable()
   110  	}
   111  
   112  	if cli.Config.Experimental {
   113  		logrus.Warn("Running experimental build")
   114  	}
   115  
   116  	if cli.Config.IsRootless() {
   117  		logrus.Warn("Running in rootless mode. This mode has feature limitations.")
   118  	}
   119  	if rootless.RunningWithRootlessKit() {
   120  		logrus.Info("Running with RootlessKit integration")
   121  		if !cli.Config.IsRootless() {
   122  			return fmt.Errorf("rootless mode needs to be enabled for running with RootlessKit")
   123  		}
   124  	}
   125  
   126  	// return human-friendly error before creating files
   127  	if runtime.GOOS == "linux" && os.Geteuid() != 0 {
   128  		return fmt.Errorf("dockerd needs to be started with root privileges. To run dockerd in rootless mode as an unprivileged user, see https://docs.docker.com/go/rootless/")
   129  	}
   130  
   131  	if err := setDefaultUmask(); err != nil {
   132  		return err
   133  	}
   134  
   135  	// Create the daemon root before we create ANY other files (PID, or migrate keys)
   136  	// to ensure the appropriate ACL is set (particularly relevant on Windows)
   137  	if err := daemon.CreateDaemonRoot(cli.Config); err != nil {
   138  		return err
   139  	}
   140  
   141  	if err := system.MkdirAll(cli.Config.ExecRoot, 0700); err != nil {
   142  		return err
   143  	}
   144  
   145  	potentiallyUnderRuntimeDir := []string{cli.Config.ExecRoot}
   146  
   147  	if cli.Pidfile != "" {
   148  		if err = system.MkdirAll(filepath.Dir(cli.Pidfile), 0o755); err != nil {
   149  			return errors.Wrap(err, "failed to create pidfile directory")
   150  		}
   151  		if err = pidfile.Write(cli.Pidfile, os.Getpid()); err != nil {
   152  			return errors.Wrapf(err, "failed to start daemon, ensure docker is not running or delete %s", cli.Pidfile)
   153  		}
   154  		potentiallyUnderRuntimeDir = append(potentiallyUnderRuntimeDir, cli.Pidfile)
   155  		defer func() {
   156  			if err := os.Remove(cli.Pidfile); err != nil {
   157  				logrus.Error(err)
   158  			}
   159  		}()
   160  	}
   161  
   162  	if cli.Config.IsRootless() {
   163  		// Set sticky bit if XDG_RUNTIME_DIR is set && the file is actually under XDG_RUNTIME_DIR
   164  		if _, err := homedir.StickRuntimeDirContents(potentiallyUnderRuntimeDir); err != nil {
   165  			// StickRuntimeDirContents returns nil error if XDG_RUNTIME_DIR is just unset
   166  			logrus.WithError(err).Warn("cannot set sticky bit on files under XDG_RUNTIME_DIR")
   167  		}
   168  	}
   169  
   170  	lss, hosts, err := loadListeners(cli.Config, tlsConfig)
   171  	if err != nil {
   172  		return errors.Wrap(err, "failed to load listeners")
   173  	}
   174  
   175  	ctx, cancel := context.WithCancel(context.Background())
   176  	waitForContainerDShutdown, err := cli.initContainerd(ctx)
   177  	if waitForContainerDShutdown != nil {
   178  		defer waitForContainerDShutdown(10 * time.Second)
   179  	}
   180  	if err != nil {
   181  		cancel()
   182  		return err
   183  	}
   184  	defer cancel()
   185  
   186  	httpServer := &http.Server{
   187  		ReadHeaderTimeout: 5 * time.Minute, // "G112: Potential Slowloris Attack (gosec)"; not a real concern for our use, so setting a long timeout.
   188  	}
   189  	apiShutdownCtx, apiShutdownCancel := context.WithCancel(context.Background())
   190  	apiShutdownDone := make(chan struct{})
   191  	trap.Trap(cli.stop)
   192  	go func() {
   193  		// Block until cli.stop() has been called.
   194  		// It may have already been called, and that's okay.
   195  		// Any httpServer.Serve() calls made after
   196  		// httpServer.Shutdown() will return immediately,
   197  		// which is what we want.
   198  		<-cli.apiShutdown
   199  		err := httpServer.Shutdown(apiShutdownCtx)
   200  		if err != nil {
   201  			logrus.WithError(err).Error("Error shutting down http server")
   202  		}
   203  		close(apiShutdownDone)
   204  	}()
   205  	defer func() {
   206  		select {
   207  		case <-cli.apiShutdown:
   208  			// cli.stop() has been called and the daemon has completed
   209  			// shutting down. Give the HTTP server a little more time to
   210  			// finish handling any outstanding requests if needed.
   211  			tmr := time.AfterFunc(5*time.Second, apiShutdownCancel)
   212  			defer tmr.Stop()
   213  			<-apiShutdownDone
   214  		default:
   215  			// cli.start() has returned without cli.stop() being called,
   216  			// e.g. because the daemon failed to start.
   217  			// Stop the HTTP server with no grace period.
   218  			if closeErr := httpServer.Close(); closeErr != nil {
   219  				logrus.WithError(closeErr).Error("Error closing http server")
   220  			}
   221  		}
   222  	}()
   223  
   224  	// Notify that the API is active, but before daemon is set up.
   225  	preNotifyReady()
   226  
   227  	pluginStore := plugin.NewStore()
   228  
   229  	var apiServer apiserver.Server
   230  	cli.authzMiddleware = initMiddlewares(&apiServer, cli.Config, pluginStore)
   231  
   232  	d, err := daemon.NewDaemon(ctx, cli.Config, pluginStore, cli.authzMiddleware)
   233  	if err != nil {
   234  		return errors.Wrap(err, "failed to start daemon")
   235  	}
   236  
   237  	d.StoreHosts(hosts)
   238  
   239  	// validate after NewDaemon has restored enabled plugins. Don't change order.
   240  	if err := validateAuthzPlugins(cli.Config.AuthorizationPlugins, pluginStore); err != nil {
   241  		return errors.Wrap(err, "failed to validate authorization plugin")
   242  	}
   243  
   244  	cli.d = d
   245  
   246  	if err := startMetricsServer(cli.Config.MetricsAddress); err != nil {
   247  		return errors.Wrap(err, "failed to start metrics server")
   248  	}
   249  
   250  	c, err := createAndStartCluster(cli, d)
   251  	if err != nil {
   252  		logrus.Fatalf("Error starting cluster component: %v", err)
   253  	}
   254  
   255  	// Restart all autostart containers which has a swarm endpoint
   256  	// and is not yet running now that we have successfully
   257  	// initialized the cluster.
   258  	d.RestartSwarmContainers()
   259  
   260  	logrus.Info("Daemon has completed initialization")
   261  
   262  	routerCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   263  	defer cancel()
   264  
   265  	routerOptions, err := newRouterOptions(routerCtx, cli.Config, d)
   266  	if err != nil {
   267  		return err
   268  	}
   269  	routerOptions.cluster = c
   270  
   271  	httpServer.Handler = apiServer.CreateMux(routerOptions.Build()...)
   272  
   273  	go d.ProcessClusterNotifications(ctx, c.GetWatchStream())
   274  
   275  	cli.setupConfigReloadTrap()
   276  
   277  	// after the daemon is done setting up we can notify systemd api
   278  	notifyReady()
   279  
   280  	// Daemon is fully initialized. Start handling API traffic
   281  	// and wait for serve API to complete.
   282  	var (
   283  		apiWG  sync.WaitGroup
   284  		errAPI = make(chan error, 1)
   285  	)
   286  	for _, ls := range lss {
   287  		apiWG.Add(1)
   288  		go func(ls net.Listener) {
   289  			defer apiWG.Done()
   290  			logrus.Infof("API listen on %s", ls.Addr())
   291  			if err := httpServer.Serve(ls); err != http.ErrServerClosed {
   292  				logrus.WithFields(logrus.Fields{
   293  					logrus.ErrorKey: err,
   294  					"listener":      ls.Addr(),
   295  				}).Error("ServeAPI error")
   296  
   297  				select {
   298  				case errAPI <- err:
   299  				default:
   300  				}
   301  			}
   302  		}(ls)
   303  	}
   304  	apiWG.Wait()
   305  	close(errAPI)
   306  
   307  	c.Cleanup()
   308  
   309  	// notify systemd that we're shutting down
   310  	notifyStopping()
   311  	shutdownDaemon(ctx, d)
   312  
   313  	// Stop notification processing and any background processes
   314  	cancel()
   315  
   316  	if err, ok := <-errAPI; ok {
   317  		return errors.Wrap(err, "shutting down due to ServeAPI error")
   318  	}
   319  
   320  	logrus.Info("Daemon shutdown complete")
   321  	return nil
   322  }
   323  
   324  type routerOptions struct {
   325  	sessionManager *session.Manager
   326  	buildBackend   *buildbackend.Backend
   327  	features       *map[string]bool
   328  	buildkit       *buildkit.Builder
   329  	daemon         *daemon.Daemon
   330  	cluster        *cluster.Cluster
   331  }
   332  
   333  func newRouterOptions(ctx context.Context, config *config.Config, d *daemon.Daemon) (routerOptions, error) {
   334  	opts := routerOptions{}
   335  	sm, err := session.NewManager()
   336  	if err != nil {
   337  		return opts, errors.Wrap(err, "failed to create sessionmanager")
   338  	}
   339  
   340  	manager, err := dockerfile.NewBuildManager(d.BuilderBackend(), d.IdentityMapping())
   341  	if err != nil {
   342  		return opts, err
   343  	}
   344  	cgroupParent := newCgroupParent(config)
   345  	ro := routerOptions{
   346  		sessionManager: sm,
   347  		features:       d.Features(),
   348  		daemon:         d,
   349  	}
   350  
   351  	bk, err := buildkit.New(ctx, buildkit.Opt{
   352  		SessionManager:      sm,
   353  		Root:                filepath.Join(config.Root, "buildkit"),
   354  		EngineID:            d.ID(),
   355  		Dist:                d.DistributionServices(),
   356  		ImageTagger:         d.ImageService(),
   357  		NetworkController:   d.NetworkController(),
   358  		DefaultCgroupParent: cgroupParent,
   359  		RegistryHosts:       d.RegistryHosts(),
   360  		BuilderConfig:       config.Builder,
   361  		Rootless:            d.Rootless(),
   362  		IdentityMapping:     d.IdentityMapping(),
   363  		DNSConfig:           config.DNSConfig,
   364  		ApparmorProfile:     daemon.DefaultApparmorProfile(),
   365  		UseSnapshotter:      d.UsesSnapshotter(),
   366  		Snapshotter:         d.ImageService().StorageDriver(),
   367  		ContainerdAddress:   config.ContainerdAddr,
   368  		ContainerdNamespace: config.ContainerdNamespace,
   369  	})
   370  	if err != nil {
   371  		return opts, err
   372  	}
   373  
   374  	bb, err := buildbackend.NewBackend(d.ImageService(), manager, bk, d.EventsService)
   375  	if err != nil {
   376  		return opts, errors.Wrap(err, "failed to create buildmanager")
   377  	}
   378  
   379  	ro.buildBackend = bb
   380  	ro.buildkit = bk
   381  
   382  	return ro, nil
   383  }
   384  
   385  func (cli *DaemonCli) reloadConfig() {
   386  	reload := func(c *config.Config) {
   387  		// Revalidate and reload the authorization plugins
   388  		if err := validateAuthzPlugins(c.AuthorizationPlugins, cli.d.PluginStore); err != nil {
   389  			logrus.Fatalf("Error validating authorization plugin: %v", err)
   390  			return
   391  		}
   392  		cli.authzMiddleware.SetPlugins(c.AuthorizationPlugins)
   393  
   394  		if err := cli.d.Reload(c); err != nil {
   395  			logrus.Errorf("Error reconfiguring the daemon: %v", err)
   396  			return
   397  		}
   398  
   399  		if c.IsValueSet("debug") {
   400  			debugEnabled := debug.IsEnabled()
   401  			switch {
   402  			case debugEnabled && !c.Debug: // disable debug
   403  				debug.Disable()
   404  			case c.Debug && !debugEnabled: // enable debug
   405  				debug.Enable()
   406  			}
   407  		}
   408  	}
   409  
   410  	if err := config.Reload(*cli.configFile, cli.flags, reload); err != nil {
   411  		logrus.Error(err)
   412  	}
   413  }
   414  
   415  func (cli *DaemonCli) stop() {
   416  	// Signal that the API server should shut down as soon as possible.
   417  	// This construct is used rather than directly shutting down the HTTP
   418  	// server to avoid any issues if this method is called before the server
   419  	// has been instantiated in cli.start(). If this method is called first,
   420  	// the HTTP server will be shut down immediately upon instantiation.
   421  	cli.stopOnce.Do(func() {
   422  		close(cli.apiShutdown)
   423  	})
   424  }
   425  
   426  // shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
   427  // d.Shutdown() is waiting too long to kill container or worst it's
   428  // blocked there
   429  func shutdownDaemon(ctx context.Context, d *daemon.Daemon) {
   430  	var cancel context.CancelFunc
   431  	if timeout := d.ShutdownTimeout(); timeout >= 0 {
   432  		ctx, cancel = context.WithTimeout(ctx, time.Duration(timeout)*time.Second)
   433  	} else {
   434  		ctx, cancel = context.WithCancel(ctx)
   435  	}
   436  
   437  	go func() {
   438  		defer cancel()
   439  		d.Shutdown(ctx)
   440  	}()
   441  
   442  	<-ctx.Done()
   443  	if errors.Is(ctx.Err(), context.DeadlineExceeded) {
   444  		logrus.Error("Force shutdown daemon")
   445  	} else {
   446  		logrus.Debug("Clean shutdown succeeded")
   447  	}
   448  }
   449  
   450  func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
   451  	if !opts.flags.Parsed() {
   452  		return nil, errors.New(`cannot load CLI config before flags are parsed`)
   453  	}
   454  	opts.setDefaultOptions()
   455  
   456  	conf := opts.daemonConfig
   457  	flags := opts.flags
   458  	conf.Debug = opts.Debug
   459  	conf.Hosts = opts.Hosts
   460  	conf.LogLevel = opts.LogLevel
   461  
   462  	if flags.Changed(FlagTLS) {
   463  		conf.TLS = &opts.TLS
   464  	}
   465  	if flags.Changed(FlagTLSVerify) {
   466  		conf.TLSVerify = &opts.TLSVerify
   467  		v := true
   468  		conf.TLS = &v
   469  	}
   470  
   471  	if opts.TLSOptions != nil {
   472  		conf.TLSOptions = config.TLSOptions{
   473  			CAFile:   opts.TLSOptions.CAFile,
   474  			CertFile: opts.TLSOptions.CertFile,
   475  			KeyFile:  opts.TLSOptions.KeyFile,
   476  		}
   477  	} else {
   478  		conf.TLSOptions = config.TLSOptions{}
   479  	}
   480  
   481  	if opts.configFile != "" {
   482  		c, err := config.MergeDaemonConfigurations(conf, flags, opts.configFile)
   483  		if err != nil {
   484  			if flags.Changed("config-file") || !os.IsNotExist(err) {
   485  				return nil, errors.Wrapf(err, "unable to configure the Docker daemon with file %s", opts.configFile)
   486  			}
   487  		}
   488  
   489  		// the merged configuration can be nil if the config file didn't exist.
   490  		// leave the current configuration as it is if when that happens.
   491  		if c != nil {
   492  			conf = c
   493  		}
   494  	}
   495  
   496  	if err := normalizeHosts(conf); err != nil {
   497  		return nil, err
   498  	}
   499  
   500  	if err := config.Validate(conf); err != nil {
   501  		return nil, err
   502  	}
   503  
   504  	// Check if duplicate label-keys with different values are found
   505  	newLabels, err := config.GetConflictFreeLabels(conf.Labels)
   506  	if err != nil {
   507  		return nil, err
   508  	}
   509  	conf.Labels = newLabels
   510  
   511  	// Regardless of whether the user sets it to true or false, if they
   512  	// specify TLSVerify at all then we need to turn on TLS
   513  	if conf.IsValueSet(FlagTLSVerify) {
   514  		v := true
   515  		conf.TLS = &v
   516  	}
   517  
   518  	if conf.TLSVerify == nil && conf.TLS != nil {
   519  		conf.TLSVerify = conf.TLS
   520  	}
   521  
   522  	err = validateCPURealtimeOptions(conf)
   523  	if err != nil {
   524  		return nil, err
   525  	}
   526  
   527  	return conf, nil
   528  }
   529  
   530  // normalizeHosts normalizes the configured config.Hosts and remove duplicates.
   531  // It returns an error if it fails to parse a host.
   532  func normalizeHosts(config *config.Config) error {
   533  	if len(config.Hosts) == 0 {
   534  		// if no hosts are configured, create a single entry slice, so that the
   535  		// default is used.
   536  		//
   537  		// TODO(thaJeztah) implement a cleaner way for this; this depends on a
   538  		//                 side-effect of how we parse empty/partial hosts.
   539  		config.Hosts = make([]string, 1)
   540  	}
   541  	hosts := make([]string, 0, len(config.Hosts))
   542  	seen := make(map[string]struct{}, len(config.Hosts))
   543  
   544  	useTLS := DefaultTLSValue
   545  	if config.TLS != nil {
   546  		useTLS = *config.TLS
   547  	}
   548  
   549  	for _, h := range config.Hosts {
   550  		host, err := dopts.ParseHost(useTLS, honorXDG, h)
   551  		if err != nil {
   552  			return err
   553  		}
   554  		if _, ok := seen[host]; ok {
   555  			continue
   556  		}
   557  		seen[host] = struct{}{}
   558  		hosts = append(hosts, host)
   559  	}
   560  	sort.Strings(hosts)
   561  	config.Hosts = hosts
   562  	return nil
   563  }
   564  
   565  func (opts routerOptions) Build() []router.Router {
   566  	decoder := runconfig.ContainerDecoder{
   567  		GetSysInfo: func() *sysinfo.SysInfo {
   568  			return opts.daemon.RawSysInfo()
   569  		},
   570  	}
   571  
   572  	routers := []router.Router{
   573  		// we need to add the checkpoint router before the container router or the DELETE gets masked
   574  		checkpointrouter.NewRouter(opts.daemon, decoder),
   575  		container.NewRouter(opts.daemon, decoder, opts.daemon.RawSysInfo().CgroupUnified),
   576  		image.NewRouter(
   577  			opts.daemon.ImageService(),
   578  			opts.daemon.RegistryService(),
   579  			opts.daemon.ReferenceStore,
   580  			opts.daemon.ImageService().DistributionServices().ImageStore,
   581  			opts.daemon.ImageService().DistributionServices().LayerStore,
   582  		),
   583  		systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildkit, opts.features),
   584  		volume.NewRouter(opts.daemon.VolumesService(), opts.cluster),
   585  		build.NewRouter(opts.buildBackend, opts.daemon, opts.features),
   586  		sessionrouter.NewRouter(opts.sessionManager),
   587  		swarmrouter.NewRouter(opts.cluster),
   588  		pluginrouter.NewRouter(opts.daemon.PluginManager()),
   589  		distributionrouter.NewRouter(opts.daemon.ImageBackend()),
   590  	}
   591  
   592  	if opts.buildBackend != nil {
   593  		routers = append(routers, grpcrouter.NewRouter(opts.buildBackend))
   594  	}
   595  
   596  	if opts.daemon.NetworkControllerEnabled() {
   597  		routers = append(routers, network.NewRouter(opts.daemon, opts.cluster))
   598  	}
   599  
   600  	if opts.daemon.HasExperimental() {
   601  		for _, r := range routers {
   602  			for _, route := range r.Routes() {
   603  				if experimental, ok := route.(router.ExperimentalRoute); ok {
   604  					experimental.Enable()
   605  				}
   606  			}
   607  		}
   608  	}
   609  
   610  	return routers
   611  }
   612  
   613  func initMiddlewares(s *apiserver.Server, cfg *config.Config, pluginStore plugingetter.PluginGetter) *authorization.Middleware {
   614  	v := dockerversion.Version
   615  
   616  	exp := middleware.NewExperimentalMiddleware(cfg.Experimental)
   617  	s.UseMiddleware(exp)
   618  
   619  	vm := middleware.NewVersionMiddleware(v, api.DefaultVersion, api.MinVersion)
   620  	s.UseMiddleware(vm)
   621  
   622  	if cfg.CorsHeaders != "" {
   623  		c := middleware.NewCORSMiddleware(cfg.CorsHeaders)
   624  		s.UseMiddleware(c)
   625  	}
   626  
   627  	authzMiddleware := authorization.NewMiddleware(cfg.AuthorizationPlugins, pluginStore)
   628  	s.UseMiddleware(authzMiddleware)
   629  	return authzMiddleware
   630  }
   631  
   632  func (cli *DaemonCli) getContainerdDaemonOpts() ([]supervisor.DaemonOpt, error) {
   633  	opts, err := cli.getPlatformContainerdDaemonOpts()
   634  	if err != nil {
   635  		return nil, err
   636  	}
   637  
   638  	if cli.Debug {
   639  		opts = append(opts, supervisor.WithLogLevel("debug"))
   640  	} else {
   641  		opts = append(opts, supervisor.WithLogLevel(cli.LogLevel))
   642  	}
   643  
   644  	if !cli.CriContainerd {
   645  		// CRI support in the managed daemon is currently opt-in.
   646  		//
   647  		// It's disabled by default, originally because it was listening on
   648  		// a TCP connection at 0.0.0.0:10010, which was considered a security
   649  		// risk, and could conflict with user's container ports.
   650  		//
   651  		// Current versions of containerd started now listen on localhost on
   652  		// an ephemeral port instead, but could still conflict with container
   653  		// ports, and running kubernetes using the static binaries is not a
   654  		// common scenario, so we (for now) continue disabling it by default.
   655  		//
   656  		// Also see https://github.com/containerd/containerd/issues/2483#issuecomment-407530608
   657  		opts = append(opts, supervisor.WithCRIDisabled())
   658  	}
   659  
   660  	return opts, nil
   661  }
   662  
   663  func newAPIServerTLSConfig(config *config.Config) (*tls.Config, error) {
   664  	var tlsConfig *tls.Config
   665  	if config.TLS != nil && *config.TLS {
   666  		var (
   667  			clientAuth tls.ClientAuthType
   668  			err        error
   669  		)
   670  		if config.TLSVerify == nil || *config.TLSVerify {
   671  			// server requires and verifies client's certificate
   672  			clientAuth = tls.RequireAndVerifyClientCert
   673  		}
   674  		tlsConfig, err = tlsconfig.Server(tlsconfig.Options{
   675  			CAFile:             config.TLSOptions.CAFile,
   676  			CertFile:           config.TLSOptions.CertFile,
   677  			KeyFile:            config.TLSOptions.KeyFile,
   678  			ExclusiveRootPools: true,
   679  			ClientAuth:         clientAuth,
   680  		})
   681  		if err != nil {
   682  			return nil, errors.Wrap(err, "invalid TLS configuration")
   683  		}
   684  	}
   685  
   686  	return tlsConfig, nil
   687  }
   688  
   689  // checkTLSAuthOK checks basically for an explicitly disabled TLS/TLSVerify
   690  // Going forward we do not want to support a scenario where dockerd listens
   691  // on TCP without either TLS client auth (or an explicit opt-in to disable it)
   692  func checkTLSAuthOK(c *config.Config) bool {
   693  	if c.TLS == nil {
   694  		// Either TLS is enabled by default, in which case TLS verification should be enabled by default, or explicitly disabled
   695  		// Or TLS is disabled by default... in any of these cases, we can just take the default value as to how to proceed
   696  		return DefaultTLSValue
   697  	}
   698  
   699  	if !*c.TLS {
   700  		// TLS is explicitly disabled, which is supported
   701  		return true
   702  	}
   703  
   704  	if c.TLSVerify == nil {
   705  		// this actually shouldn't happen since we set TLSVerify on the config object anyway
   706  		// But in case it does get here, be cautious and assume this is not supported.
   707  		return false
   708  	}
   709  
   710  	// Either TLSVerify is explicitly enabled or disabled, both cases are supported
   711  	return true
   712  }
   713  
   714  func loadListeners(cfg *config.Config, tlsConfig *tls.Config) ([]net.Listener, []string, error) {
   715  	if len(cfg.Hosts) == 0 {
   716  		return nil, nil, errors.New("no hosts configured")
   717  	}
   718  	var (
   719  		hosts []string
   720  		lss   []net.Listener
   721  	)
   722  
   723  	for i := 0; i < len(cfg.Hosts); i++ {
   724  		protoAddr := cfg.Hosts[i]
   725  		proto, addr, ok := strings.Cut(protoAddr, "://")
   726  		if !ok {
   727  			return nil, nil, fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
   728  		}
   729  
   730  		// It's a bad idea to bind to TCP without tlsverify.
   731  		authEnabled := tlsConfig != nil && tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert
   732  		if proto == "tcp" && !authEnabled {
   733  			logrus.WithField("host", protoAddr).Warn("Binding to IP address without --tlsverify is insecure and gives root access on this machine to everyone who has access to your network.")
   734  			logrus.WithField("host", protoAddr).Warn("Binding to an IP address, even on localhost, can also give access to scripts run in a browser. Be safe out there!")
   735  			time.Sleep(time.Second)
   736  
   737  			// If TLSVerify is explicitly set to false we'll take that as "Please let me shoot myself in the foot"
   738  			// We do not want to continue to support a default mode where tls verification is disabled, so we do some extra warnings here and eventually remove support
   739  			if !checkTLSAuthOK(cfg) {
   740  				ipAddr, _, err := net.SplitHostPort(addr)
   741  				if err != nil {
   742  					return nil, nil, errors.Wrap(err, "error parsing tcp address")
   743  				}
   744  
   745  				// shortcut all this extra stuff for literal "localhost"
   746  				// -H supports specifying hostnames, since we want to bypass this on loopback interfaces we'll look it up here.
   747  				if ipAddr != "localhost" {
   748  					ip := net.ParseIP(ipAddr)
   749  					if ip == nil {
   750  						ipA, err := net.ResolveIPAddr("ip", ipAddr)
   751  						if err != nil {
   752  							logrus.WithError(err).WithField("host", ipAddr).Error("Error looking up specified host address")
   753  						}
   754  						if ipA != nil {
   755  							ip = ipA.IP
   756  						}
   757  					}
   758  					if ip == nil || !ip.IsLoopback() {
   759  						logrus.WithField("host", protoAddr).Warn("Binding to an IP address without --tlsverify is deprecated. Startup is intentionally being slowed down to show this message")
   760  						logrus.WithField("host", protoAddr).Warn("Please consider generating tls certificates with client validation to prevent exposing unauthenticated root access to your network")
   761  						logrus.WithField("host", protoAddr).Warnf("You can override this by explicitly specifying '--%s=false' or '--%s=false'", FlagTLS, FlagTLSVerify)
   762  						logrus.WithField("host", protoAddr).Warnf("Support for listening on TCP without authentication or explicit intent to run without authentication will be removed in the next release")
   763  
   764  						time.Sleep(15 * time.Second)
   765  					}
   766  				}
   767  			}
   768  		}
   769  		// If we're binding to a TCP port, make sure that a container doesn't try to use it.
   770  		if proto == "tcp" {
   771  			if err := allocateDaemonPort(addr); err != nil {
   772  				return nil, nil, err
   773  			}
   774  		}
   775  		ls, err := listeners.Init(proto, addr, cfg.SocketGroup, tlsConfig)
   776  		if err != nil {
   777  			return nil, nil, err
   778  		}
   779  		logrus.Debugf("Listener created for HTTP on %s (%s)", proto, addr)
   780  		hosts = append(hosts, addr)
   781  		lss = append(lss, ls...)
   782  	}
   783  
   784  	return lss, hosts, nil
   785  }
   786  
   787  func createAndStartCluster(cli *DaemonCli, d *daemon.Daemon) (*cluster.Cluster, error) {
   788  	name, _ := os.Hostname()
   789  
   790  	// Use a buffered channel to pass changes from store watch API to daemon
   791  	// A buffer allows store watch API and daemon processing to not wait for each other
   792  	watchStream := make(chan *swarmapi.WatchMessage, 32)
   793  
   794  	c, err := cluster.New(cluster.Config{
   795  		Root:                   cli.Config.Root,
   796  		Name:                   name,
   797  		Backend:                d,
   798  		VolumeBackend:          d.VolumesService(),
   799  		ImageBackend:           d.ImageBackend(),
   800  		PluginBackend:          d.PluginManager(),
   801  		NetworkSubnetsProvider: d,
   802  		DefaultAdvertiseAddr:   cli.Config.SwarmDefaultAdvertiseAddr,
   803  		RaftHeartbeatTick:      cli.Config.SwarmRaftHeartbeatTick,
   804  		RaftElectionTick:       cli.Config.SwarmRaftElectionTick,
   805  		RuntimeRoot:            cli.getSwarmRunRoot(),
   806  		WatchStream:            watchStream,
   807  	})
   808  	if err != nil {
   809  		return nil, err
   810  	}
   811  	d.SetCluster(c)
   812  	err = c.Start()
   813  
   814  	return c, err
   815  }
   816  
   817  // validates that the plugins requested with the --authorization-plugin flag are valid AuthzDriver
   818  // plugins present on the host and available to the daemon
   819  func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGetter) error {
   820  	for _, reqPlugin := range requestedPlugins {
   821  		if _, err := pg.Get(reqPlugin, authorization.AuthZApiImplements, plugingetter.Lookup); err != nil {
   822  			return err
   823  		}
   824  	}
   825  	return nil
   826  }
   827  
   828  func systemContainerdRunning(honorXDG bool) (string, bool, error) {
   829  	addr := containerddefaults.DefaultAddress
   830  	if honorXDG {
   831  		runtimeDir, err := homedir.GetRuntimeDir()
   832  		if err != nil {
   833  			return "", false, err
   834  		}
   835  		addr = filepath.Join(runtimeDir, "containerd", "containerd.sock")
   836  	}
   837  	_, err := os.Lstat(addr)
   838  	return addr, err == nil, nil
   839  }
   840  
   841  // configureDaemonLogs sets the logrus logging level and formatting. It expects
   842  // the passed configuration to already be validated, and ignores invalid options.
   843  func configureDaemonLogs(conf *config.Config) {
   844  	if conf.LogLevel != "" {
   845  		lvl, err := logrus.ParseLevel(conf.LogLevel)
   846  		if err == nil {
   847  			logrus.SetLevel(lvl)
   848  		}
   849  	} else {
   850  		logrus.SetLevel(logrus.InfoLevel)
   851  	}
   852  	logrus.SetFormatter(&logrus.TextFormatter{
   853  		TimestampFormat: jsonmessage.RFC3339NanoFixed,
   854  		DisableColors:   conf.RawLogs,
   855  		FullTimestamp:   true,
   856  	})
   857  }
   858  
   859  func configureProxyEnv(conf *config.Config) {
   860  	if p := conf.HTTPProxy; p != "" {
   861  		overrideProxyEnv("HTTP_PROXY", p)
   862  		overrideProxyEnv("http_proxy", p)
   863  	}
   864  	if p := conf.HTTPSProxy; p != "" {
   865  		overrideProxyEnv("HTTPS_PROXY", p)
   866  		overrideProxyEnv("https_proxy", p)
   867  	}
   868  	if p := conf.NoProxy; p != "" {
   869  		overrideProxyEnv("NO_PROXY", p)
   870  		overrideProxyEnv("no_proxy", p)
   871  	}
   872  }
   873  
   874  func overrideProxyEnv(name, val string) {
   875  	if oldVal := os.Getenv(name); oldVal != "" && oldVal != val {
   876  		logrus.WithFields(logrus.Fields{
   877  			"name":      name,
   878  			"old-value": config.MaskCredentials(oldVal),
   879  			"new-value": config.MaskCredentials(val),
   880  		}).Warn("overriding existing proxy variable with value from configuration")
   881  	}
   882  	_ = os.Setenv(name, val)
   883  }