func enroll()

in internal/pkg/agent/cmd/enroll.go [366:583]


func enroll(streams *cli.IOStreams, cmd *cobra.Command) error {
	err := validateEnrollFlags(cmd)
	if err != nil {
		return err
	}

	fromInstall, _ := cmd.Flags().GetBool(fromInstallArg)

	hasRoot, err := utils.HasRoot()
	if err != nil {
		return fmt.Errorf("checking if running with root/Administrator privileges: %w", err)
	}
	if hasRoot && !fromInstall {
		binPath, err := os.Executable()
		if err != nil {
			return fmt.Errorf("error while getting executable path: %w", err)
		}
		isOwner, err := isOwnerExec(binPath)
		if err != nil {
			return fmt.Errorf("ran into an error while figuring out if user is allowed to execute the enroll command: %w", err)
		}
		if !isOwner {
			return UserOwnerMismatchError
		}
	}

	pathConfigFile := paths.ConfigFile()
	rawConfig, err := config.LoadFile(pathConfigFile)
	if err != nil {
		return errors.New(err,
			fmt.Sprintf("could not read configuration file %s", pathConfigFile),
			errors.TypeFilesystem,
			errors.M(errors.MetaKeyPath, pathConfigFile))
	}

	cfg, err := configuration.NewFromConfig(rawConfig)
	if err != nil {
		return errors.New(err,
			fmt.Sprintf("could not parse configuration file %s", pathConfigFile),
			errors.TypeFilesystem,
			errors.M(errors.MetaKeyPath, pathConfigFile))
	}

	staging, _ := cmd.Flags().GetString("staging")
	if staging != "" {
		if len(staging) < 8 {
			return errors.New(fmt.Errorf("invalid staging build hash; must be at least 8 characters"), "Error")
		}
	}

	force, _ := cmd.Flags().GetBool("force")
	if fromInstall {
		force = true
	}

	// prompt only when it is not forced and is already enrolled
	if !force && (cfg.Fleet != nil && cfg.Fleet.Enabled) {
		confirm, err := cli.Confirm("This will replace your current settings. Do you want to continue?", true)
		if err != nil {
			return errors.New(err, "problem reading prompt response")
		}
		if !confirm {
			fmt.Fprintln(streams.Out, "Enrollment was cancelled by the user")
			return nil
		}
	}

	// enroll is invoked either manually or from install with redirected IO
	// no need to log to file
	cfg.Settings.LoggingConfig.ToFiles = false
	cfg.Settings.LoggingConfig.ToStderr = true

	logger, err := logger.NewFromConfig("", cfg.Settings.LoggingConfig, cfg.Settings.EventLoggingConfig, false)
	if err != nil {
		return err
	}

	insecure, _ := cmd.Flags().GetBool("insecure")
	url, _ := cmd.Flags().GetString("url")
	enrollmentToken, _ := cmd.Flags().GetString("enrollment-token")
	id, _ := cmd.Flags().GetString("id")
	replaceToken, _ := cmd.Flags().GetString("replace-token")
	fServer, _ := cmd.Flags().GetString("fleet-server-es")
	fElasticSearchCA, _ := cmd.Flags().GetString("fleet-server-es-ca")
	fElasticSearchCASHA256, _ := cmd.Flags().GetString("fleet-server-es-ca-trusted-fingerprint")
	fElasticSearchInsecure, _ := cmd.Flags().GetBool("fleet-server-es-insecure")
	fElasticSearchClientCert, _ := cmd.Flags().GetString("fleet-server-es-cert")
	fElasticSearchClientCertKey, _ := cmd.Flags().GetString("fleet-server-es-cert-key")
	fHeaders, _ := cmd.Flags().GetStringSlice("header")
	fServiceToken, _ := cmd.Flags().GetString("fleet-server-service-token")
	fServiceTokenPath, _ := cmd.Flags().GetString("fleet-server-service-token-path")
	fPolicy, _ := cmd.Flags().GetString("fleet-server-policy")
	fHost, _ := cmd.Flags().GetString("fleet-server-host")
	fPort, _ := cmd.Flags().GetUint16("fleet-server-port")
	fInternalPort, _ := cmd.Flags().GetUint16("fleet-server-internal-port")
	fCert, _ := cmd.Flags().GetString("fleet-server-cert")
	fCertKey, _ := cmd.Flags().GetString("fleet-server-cert-key")
	fPassphrase, _ := cmd.Flags().GetString("fleet-server-cert-key-passphrase")
	fClientAuth, _ := cmd.Flags().GetString("fleet-server-client-auth")
	fInsecure, _ := cmd.Flags().GetBool("fleet-server-insecure-http")
	proxyURL, _ := cmd.Flags().GetString("proxy-url")
	proxyDisabled, _ := cmd.Flags().GetBool("proxy-disabled")
	proxyHeaders, _ := cmd.Flags().GetStringSlice("proxy-header")
	delayEnroll, _ := cmd.Flags().GetBool("delay-enroll")
	daemonTimeout, _ := cmd.Flags().GetDuration("daemon-timeout")
	enrollTimeout, _ := cmd.Flags().GetDuration("enroll-timeout")
	fTimeout, _ := cmd.Flags().GetDuration("fleet-server-timeout")
	skipDaemonReload, _ := cmd.Flags().GetBool("skip-daemon-reload")
	tags, _ := cmd.Flags().GetStringSlice("tag")

	caStr, _ := cmd.Flags().GetString("certificate-authorities")
	CAs := cli.StringToSlice(caStr)
	caSHA256str, _ := cmd.Flags().GetString("ca-sha256")
	caSHA256 := cli.StringToSlice(caSHA256str)
	cert, _ := cmd.Flags().GetString("elastic-agent-cert")
	key, _ := cmd.Flags().GetString("elastic-agent-cert-key")
	keyPassphrase, _ := cmd.Flags().GetString("elastic-agent-cert-key-passphrase")

	ctx := handleSignal(context.Background())

	if enrollTimeout > 0 {
		eCtx, cancel := context.WithTimeout(ctx, enrollTimeout)
		defer cancel()
		ctx = eCtx
	}

	// On MacOS Ventura and above, fixing the permissions on enrollment during installation fails with the error:
	//  Error: failed to fix permissions: chown /Library/Elastic/Agent/data/elastic-agent-c13f91/elastic-agent.app: operation not permitted
	// This is because we are fixing permissions twice, once during installation and again during the enrollment step.
	// When we are enrolling as part of installation on MacOS, skip the second attempt to fix permissions.
	var fixPermissions *utils.FileOwner
	if fromInstall {
		perms, err := getFileOwnerFromCmd(cmd)
		if err != nil {
			// no context is added because the error is clear and user facing
			return err
		}
		fixPermissions = &perms
	}
	if runtime.GOOS == "darwin" {
		fixPermissions = nil
	}

	options := enrollCmdOption{
		EnrollAPIKey:         enrollmentToken,
		ID:                   id,
		ReplaceToken:         replaceToken,
		URL:                  url,
		CAs:                  CAs,
		CASha256:             caSHA256,
		Certificate:          cert,
		Key:                  key,
		KeyPassphrasePath:    keyPassphrase,
		Insecure:             insecure,
		UserProvidedMetadata: make(map[string]interface{}),
		Staging:              staging,
		FixPermissions:       fixPermissions,
		ProxyURL:             proxyURL,
		ProxyDisabled:        proxyDisabled,
		ProxyHeaders:         mapFromEnvList(proxyHeaders),
		DelayEnroll:          delayEnroll,
		DaemonTimeout:        daemonTimeout,
		SkipDaemonRestart:    skipDaemonReload,
		Tags:                 tags,
		FleetServer: enrollCmdFleetServerOption{
			ConnStr:               fServer,
			ElasticsearchCA:       fElasticSearchCA,
			ElasticsearchCASHA256: fElasticSearchCASHA256,
			ElasticsearchInsecure: fElasticSearchInsecure,
			ElasticsearchCert:     fElasticSearchClientCert,
			ElasticsearchCertKey:  fElasticSearchClientCertKey,
			ServiceToken:          fServiceToken,
			ServiceTokenPath:      fServiceTokenPath,
			PolicyID:              fPolicy,
			Host:                  fHost,
			Port:                  fPort,
			Cert:                  fCert,
			CertKey:               fCertKey,
			CertKeyPassphrasePath: fPassphrase,
			ClientAuth:            fClientAuth,
			Insecure:              fInsecure,
			SpawnAgent:            !fromInstall,
			Headers:               mapFromEnvList(fHeaders),
			Timeout:               fTimeout,
			InternalPort:          fInternalPort,
		},
	}

	var storeOpts []storage.ReplaceOnSuccessStoreOptionFunc
	var encryptOpts []storage.EncryptedOptionFunc
	if fixPermissions != nil {
		storeOpts = append(storeOpts, storage.ReplaceOnSuccessStoreWithOwnership(*fixPermissions))
		encryptOpts = append(encryptOpts, storage.EncryptedStoreWithOwnership(*fixPermissions))
	}
	encStore, err := storage.NewEncryptedDiskStore(ctx, paths.AgentConfigFile(), encryptOpts...)
	if err != nil {
		return fmt.Errorf("failed to create encrypted disk store: %w", err)
	}
	store := storage.NewReplaceOnSuccessStore(
		pathConfigFile,
		application.DefaultAgentFleetConfig,
		encStore,
		storeOpts...,
	)

	c, err := newEnrollCmd(
		logger,
		&options,
		pathConfigFile,
		store,
		nil,
	)
	if err != nil {
		return err
	}

	return c.Execute(ctx, streams)
}