diff --git a/x-pack/elastic-agent/CHANGELOG.next.asciidoc b/x-pack/elastic-agent/CHANGELOG.next.asciidoc index dfbe98ddcab..40cecf51b90 100644 --- a/x-pack/elastic-agent/CHANGELOG.next.asciidoc +++ b/x-pack/elastic-agent/CHANGELOG.next.asciidoc @@ -92,6 +92,8 @@ - Snapshot artifact lookup will use agent.download proxy settings. {issue}27903[27903] {pull}27904[27904] - Fix lazy acker to only add new actions to the batch. {pull}27981[27981] - Allow HTTP metrics to run in bootstrap mode. Add ability to adjust timeouts for Fleet Server. {pull}28260[28260] +- Fix agent configuration overwritten by default fleet config. {pull}29297[29297] +- Allow agent containers to use basic auth to create a service token. {pull}29651[29651] ==== New features diff --git a/x-pack/elastic-agent/pkg/agent/cmd/container.go b/x-pack/elastic-agent/pkg/agent/cmd/container.go index f127d972bf1..33f46728b65 100644 --- a/x-pack/elastic-agent/pkg/agent/cmd/container.go +++ b/x-pack/elastic-agent/pkg/agent/cmd/container.go @@ -109,6 +109,8 @@ The following actions are possible and grouped based on the actions. KIBANA_FLEET_SETUP - set to 1 enables the setup of Fleet in Kibana by Elastic Agent. This was previously FLEET_SETUP. KIBANA_FLEET_HOST - Kibana host accessible from fleet-server. [$KIBANA_HOST] + KIBANA_FLEET_USERNAME - kibana username to service token [$KIBANA_USERNAME] + KIBANA_FLEET_PASSWORD - kibana password to service token [$KIBANA_PASSWORD] KIBANA_FLEET_CA - path to certificate authority to use with communicate with Kibana [$KIBANA_CA] KIBANA_REQUEST_RETRY_SLEEP - specifies sleep duration taken when agent performs a request to kibana [default 1s] KIBANA_REQUEST_RETRY_COUNT - specifies number of retries agent performs when executing a request to kibana [default 30] @@ -117,8 +119,12 @@ The following environment variables are provided as a convenience to prevent a l be used when the same credentials will be used across all the possible actions above. ELASTICSEARCH_HOST - elasticsearch host [http://elasticsearch:9200] + ELASTICSEARCH_USERNAME - elasticsearch username [elastic] + ELASTICSEARCH_PASSWORD - elasticsearch password [changeme] ELASTICSEARCH_CA - path to certificate authority to use with communicate with elasticsearch KIBANA_HOST - kibana host [http://kibana:5601] + KIBANA_FLEET_USERNAME - kibana username to enable Fleet [$ELASTICSEARCH_USERNAME] + KIBANA_FLEET_PASSWORD - kibana password to enable Fleet [$ELASTICSEARCH_PASSWORD] KIBANA_CA - path to certificate authority to use with communicate with Kibana [$ELASTICSEARCH_CA] @@ -193,6 +199,11 @@ func containerCmd(streams *cli.IOStreams, cmd *cobra.Command) error { } } + err = ensureServiceToken(streams, &cfg) + if err != nil { + return err + } + // start apm-server legacy process when in cloud mode var wg sync.WaitGroup var apmProc *process.Info @@ -268,6 +279,7 @@ func runContainerCmd(streams *cli.IOStreams, cmd *cobra.Command, cfg setupConfig if err != nil { return err } + logInfo(streams, "Performing setup of Fleet in Kibana\n") err = kibanaSetup(cfg, client, streams) if err != nil { @@ -318,6 +330,48 @@ func runContainerCmd(streams *cli.IOStreams, cmd *cobra.Command, cfg setupConfig return run(streams, logToStderr) } +// TokenResp is used to decode a response for generating a service token +type TokenResp struct { + Name string `json:"name"` + Value string `json:"value"` +} + +// ensureServiceToken will ensure that the cfg specified has the service_token attributes filled. +// +// If no token is specified it will use the elasticsearch username/password to request a new token from Kibana +func ensureServiceToken(streams *cli.IOStreams, cfg *setupConfig) error { + // There's already a service token + if cfg.Kibana.Fleet.ServiceToken != "" || cfg.FleetServer.Elasticsearch.ServiceToken != "" { + return nil + } + if cfg.Kibana.Fleet.Username == "" || cfg.Kibana.Fleet.Password == "" { + return fmt.Errorf("username/password must be provided to retrieve service token") + } + + logInfo(streams, "Requesting service_token from Kibana.") + client, err := kibanaClient(cfg.Kibana, cfg.Kibana.Headers) + if err != nil { + return err + } + + code, r, err := client.Connection.Request("POST", "/api/fleet/service-tokens", nil, nil, nil) + if err != nil { + return fmt.Errorf("request to get security token from Kibana failed: %w", err) + } + if code >= 400 { + return fmt.Errorf("request to get security token from Kibana failed with status %d, body: %s", code, string(r)) + } + t := TokenResp{} + err = json.Unmarshal(r, &t) + if err != nil { + return fmt.Errorf("unable to decode response: %w", err) + } + logInfo(streams, "Created service_token named:", t.Name) + cfg.Kibana.Fleet.ServiceToken = t.Value + cfg.FleetServer.Elasticsearch.ServiceToken = t.Value + return nil +} + func buildEnrollArgs(cfg setupConfig, token string, policyID string) ([]string, error) { args := []string{ "enroll", "-f", @@ -472,6 +526,8 @@ func kibanaClient(cfg kibanaConfig, headers map[string]string) (*kibana.Client, return kibana.NewClientWithConfigDefault(&kibana.ClientConfig{ Host: cfg.Fleet.Host, + Username: cfg.Fleet.Username, + Password: cfg.Fleet.Password, ServiceToken: cfg.Fleet.ServiceToken, IgnoreVersion: true, Transport: transport, diff --git a/x-pack/elastic-agent/pkg/agent/cmd/setup_config.go b/x-pack/elastic-agent/pkg/agent/cmd/setup_config.go index 39cf43de28c..ab163f4b5e7 100644 --- a/x-pack/elastic-agent/pkg/agent/cmd/setup_config.go +++ b/x-pack/elastic-agent/pkg/agent/cmd/setup_config.go @@ -58,6 +58,8 @@ type kibanaFleetConfig struct { CA string `config:"ca"` Host string `config:"host"` Setup bool `config:"setup"` + Username string `config:"username"` + Password string `config:"password"` ServiceToken string `config:"service_token"` } @@ -104,11 +106,10 @@ func defaultAccessConfig() (setupConfig, error) { }, Kibana: kibanaConfig{ Fleet: kibanaFleetConfig{ - // Remove FLEET_SETUP in 8.x - // The FLEET_SETUP environment variable boolean is a fallback to the old name. The name was updated to - // reflect that its setting up Fleet in Kibana versus setting up Fleet Server. - Setup: envBool("KIBANA_FLEET_SETUP", "FLEET_SETUP"), + Setup: envBool("KIBANA_FLEET_SETUP"), Host: envWithDefault("http://kibana:5601", "KIBANA_FLEET_HOST", "KIBANA_HOST"), + Username: envWithDefault("elastic", "KIBANA_FLEET_USERNAME", "ELASTICSEARCH_USERNAME"), + Password: envWithDefault("changeme", "KIBANA_FLEET_PASSWORD", "ELASTICSEARCH_PASSWORD"), ServiceToken: envWithDefault("", "KIBANA_FLEET_SERVICE_TOKEN", "FLEET_SERVER_SERVICE_TOKEN"), CA: envWithDefault("", "KIBANA_FLEET_CA", "KIBANA_CA", "ELASTICSEARCH_CA"), },