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