Skip to content

Commit

Permalink
Allow elastic agent in containers to use basic auth to get service to…
Browse files Browse the repository at this point in the history
…ken (#29651)

* 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.
  • Loading branch information
michel-laterman committed Jan 5, 2022
1 parent b8cfea6 commit 31c0099
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 4 deletions.
1 change: 1 addition & 0 deletions x-pack/elastic-agent/CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
- 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

Expand Down
56 changes: 56 additions & 0 deletions x-pack/elastic-agent/pkg/agent/cmd/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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,
Expand Down
9 changes: 5 additions & 4 deletions x-pack/elastic-agent/pkg/agent/cmd/setup_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}

Expand Down Expand Up @@ -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"),
},
Expand Down

0 comments on commit 31c0099

Please sign in to comment.