github.com/rumpl/bof@v23.0.0-rc.2+incompatible/cmd/dockerd/daemon.go (about)

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