Skip to content

Commit 424ced3

Browse files
Allow elastic agent in containers to use basic auth to get service token (#29651) (#29713)
* Allow elastic agent in containers to use basic auth to get service token Allow the agent to use basic auth defined by env vars to retrieve a service token from Elasticsearch and inject it into the config used for the agent and fleet. * Fix linter * Use Kibana API for all requests. Change from using the ES api to gather the token to the Kibana API. (cherry picked from commit 31c0099) Co-authored-by: Michel Laterman <[email protected]>
1 parent e92cb7d commit 424ced3

File tree

3 files changed

+63
-4
lines changed

3 files changed

+63
-4
lines changed

x-pack/elastic-agent/CHANGELOG.next.asciidoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@
9292
- Snapshot artifact lookup will use agent.download proxy settings. {issue}27903[27903] {pull}27904[27904]
9393
- Fix lazy acker to only add new actions to the batch. {pull}27981[27981]
9494
- Allow HTTP metrics to run in bootstrap mode. Add ability to adjust timeouts for Fleet Server. {pull}28260[28260]
95+
- Fix agent configuration overwritten by default fleet config. {pull}29297[29297]
96+
- Allow agent containers to use basic auth to create a service token. {pull}29651[29651]
9597

9698
==== New features
9799

x-pack/elastic-agent/pkg/agent/cmd/container.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ The following actions are possible and grouped based on the actions.
109109
110110
KIBANA_FLEET_SETUP - set to 1 enables the setup of Fleet in Kibana by Elastic Agent. This was previously FLEET_SETUP.
111111
KIBANA_FLEET_HOST - Kibana host accessible from fleet-server. [$KIBANA_HOST]
112+
KIBANA_FLEET_USERNAME - kibana username to service token [$KIBANA_USERNAME]
113+
KIBANA_FLEET_PASSWORD - kibana password to service token [$KIBANA_PASSWORD]
112114
KIBANA_FLEET_CA - path to certificate authority to use with communicate with Kibana [$KIBANA_CA]
113115
KIBANA_REQUEST_RETRY_SLEEP - specifies sleep duration taken when agent performs a request to kibana [default 1s]
114116
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
117119
be used when the same credentials will be used across all the possible actions above.
118120
119121
ELASTICSEARCH_HOST - elasticsearch host [http://elasticsearch:9200]
122+
ELASTICSEARCH_USERNAME - elasticsearch username [elastic]
123+
ELASTICSEARCH_PASSWORD - elasticsearch password [changeme]
120124
ELASTICSEARCH_CA - path to certificate authority to use with communicate with elasticsearch
121125
KIBANA_HOST - kibana host [http://kibana:5601]
126+
KIBANA_FLEET_USERNAME - kibana username to enable Fleet [$ELASTICSEARCH_USERNAME]
127+
KIBANA_FLEET_PASSWORD - kibana password to enable Fleet [$ELASTICSEARCH_PASSWORD]
122128
KIBANA_CA - path to certificate authority to use with communicate with Kibana [$ELASTICSEARCH_CA]
123129
124130
@@ -193,6 +199,11 @@ func containerCmd(streams *cli.IOStreams, cmd *cobra.Command) error {
193199
}
194200
}
195201

202+
err = ensureServiceToken(streams, &cfg)
203+
if err != nil {
204+
return err
205+
}
206+
196207
// start apm-server legacy process when in cloud mode
197208
var wg sync.WaitGroup
198209
var apmProc *process.Info
@@ -268,6 +279,7 @@ func runContainerCmd(streams *cli.IOStreams, cmd *cobra.Command, cfg setupConfig
268279
if err != nil {
269280
return err
270281
}
282+
271283
logInfo(streams, "Performing setup of Fleet in Kibana\n")
272284
err = kibanaSetup(cfg, client, streams)
273285
if err != nil {
@@ -318,6 +330,48 @@ func runContainerCmd(streams *cli.IOStreams, cmd *cobra.Command, cfg setupConfig
318330
return run(streams, logToStderr)
319331
}
320332

333+
// TokenResp is used to decode a response for generating a service token
334+
type TokenResp struct {
335+
Name string `json:"name"`
336+
Value string `json:"value"`
337+
}
338+
339+
// ensureServiceToken will ensure that the cfg specified has the service_token attributes filled.
340+
//
341+
// If no token is specified it will use the elasticsearch username/password to request a new token from Kibana
342+
func ensureServiceToken(streams *cli.IOStreams, cfg *setupConfig) error {
343+
// There's already a service token
344+
if cfg.Kibana.Fleet.ServiceToken != "" || cfg.FleetServer.Elasticsearch.ServiceToken != "" {
345+
return nil
346+
}
347+
if cfg.Kibana.Fleet.Username == "" || cfg.Kibana.Fleet.Password == "" {
348+
return fmt.Errorf("username/password must be provided to retrieve service token")
349+
}
350+
351+
logInfo(streams, "Requesting service_token from Kibana.")
352+
client, err := kibanaClient(cfg.Kibana, cfg.Kibana.Headers)
353+
if err != nil {
354+
return err
355+
}
356+
357+
code, r, err := client.Connection.Request("POST", "/api/fleet/service-tokens", nil, nil, nil)
358+
if err != nil {
359+
return fmt.Errorf("request to get security token from Kibana failed: %w", err)
360+
}
361+
if code >= 400 {
362+
return fmt.Errorf("request to get security token from Kibana failed with status %d, body: %s", code, string(r))
363+
}
364+
t := TokenResp{}
365+
err = json.Unmarshal(r, &t)
366+
if err != nil {
367+
return fmt.Errorf("unable to decode response: %w", err)
368+
}
369+
logInfo(streams, "Created service_token named:", t.Name)
370+
cfg.Kibana.Fleet.ServiceToken = t.Value
371+
cfg.FleetServer.Elasticsearch.ServiceToken = t.Value
372+
return nil
373+
}
374+
321375
func buildEnrollArgs(cfg setupConfig, token string, policyID string) ([]string, error) {
322376
args := []string{
323377
"enroll", "-f",
@@ -472,6 +526,8 @@ func kibanaClient(cfg kibanaConfig, headers map[string]string) (*kibana.Client,
472526

473527
return kibana.NewClientWithConfigDefault(&kibana.ClientConfig{
474528
Host: cfg.Fleet.Host,
529+
Username: cfg.Fleet.Username,
530+
Password: cfg.Fleet.Password,
475531
ServiceToken: cfg.Fleet.ServiceToken,
476532
IgnoreVersion: true,
477533
Transport: transport,

x-pack/elastic-agent/pkg/agent/cmd/setup_config.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ type kibanaFleetConfig struct {
5858
CA string `config:"ca"`
5959
Host string `config:"host"`
6060
Setup bool `config:"setup"`
61+
Username string `config:"username"`
62+
Password string `config:"password"`
6163
ServiceToken string `config:"service_token"`
6264
}
6365

@@ -104,11 +106,10 @@ func defaultAccessConfig() (setupConfig, error) {
104106
},
105107
Kibana: kibanaConfig{
106108
Fleet: kibanaFleetConfig{
107-
// Remove FLEET_SETUP in 8.x
108-
// The FLEET_SETUP environment variable boolean is a fallback to the old name. The name was updated to
109-
// reflect that its setting up Fleet in Kibana versus setting up Fleet Server.
110-
Setup: envBool("KIBANA_FLEET_SETUP", "FLEET_SETUP"),
109+
Setup: envBool("KIBANA_FLEET_SETUP"),
111110
Host: envWithDefault("http://kibana:5601", "KIBANA_FLEET_HOST", "KIBANA_HOST"),
111+
Username: envWithDefault("elastic", "KIBANA_FLEET_USERNAME", "ELASTICSEARCH_USERNAME"),
112+
Password: envWithDefault("changeme", "KIBANA_FLEET_PASSWORD", "ELASTICSEARCH_PASSWORD"),
112113
ServiceToken: envWithDefault("", "KIBANA_FLEET_SERVICE_TOKEN", "FLEET_SERVER_SERVICE_TOKEN"),
113114
CA: envWithDefault("", "KIBANA_FLEET_CA", "KIBANA_CA", "ELASTICSEARCH_CA"),
114115
},

0 commit comments

Comments
 (0)