Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.0](backport #29651) Allow elastic agent in containers to use basic auth to get service token #29713

Merged
merged 1 commit into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions x-pack/elastic-agent/CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -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

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