From d6198718ba1916bd8260fa02041c1844dd8bacc7 Mon Sep 17 00:00:00 2001 From: igorguz Date: Tue, 2 Nov 2021 11:38:00 -0700 Subject: [PATCH 01/13] Change the Scenarios description --- e2e/_suites/fleet/fleet.go | 13 ++++-- internal/kibana/agents.go | 10 ++++- internal/kibana/api.go | 73 +++++++++++++++++++++++++++++++++ internal/kibana/url_prefixes.go | 3 ++ 4 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 internal/kibana/api.go diff --git a/e2e/_suites/fleet/fleet.go b/e2e/_suites/fleet/fleet.go index ccde9fcfce..2ca431982e 100644 --- a/e2e/_suites/fleet/fleet.go +++ b/e2e/_suites/fleet/fleet.go @@ -104,7 +104,7 @@ func (fts *FleetTestSuite) afterScenario() { _ = fts.deployer.Logs(fts.currentContext, agentService) } - err := fts.unenrollHostname() + err := fts.unenrollHostname(true) if err != nil { manifest, _ := fts.deployer.Inspect(fts.currentContext, agentService) log.WithFields(log.Fields{ @@ -167,6 +167,7 @@ func (fts *FleetTestSuite) contributeSteps(s *godog.ScenarioContext) { s.Step(`^the host is restarted$`, fts.theHostIsRestarted) s.Step(`^system package dashboards are listed in Fleet$`, fts.systemPackageDashboardsAreListedInFleet) s.Step(`^the agent is un-enrolled$`, fts.theAgentIsUnenrolled) + s.Step(`^the agent is un-enrolled without revoke$`, fts.theAgentIsUnenrolledWithoutRevoke) s.Step(`^the agent is re-enrolled on the host$`, fts.theAgentIsReenrolledOnTheHost) s.Step(`^the enrollment token is revoked$`, fts.theEnrollmentTokenIsRevoked) s.Step(`^an attempt to enroll a new agent fails$`, fts.anAttemptToEnrollANewAgentFails) @@ -873,7 +874,11 @@ func (fts *FleetTestSuite) systemPackageDashboardsAreListedInFleet() error { } func (fts *FleetTestSuite) theAgentIsUnenrolled() error { - return fts.unenrollHostname() + return fts.unenrollHostname(true) +} + +func (fts *FleetTestSuite) theAgentIsUnenrolledWithoutRevoke() error { + return fts.unenrollHostname(false) } func (fts *FleetTestSuite) theAgentIsReenrolledOnTheHost() error { @@ -1253,7 +1258,7 @@ func (fts *FleetTestSuite) anAttemptToEnrollANewAgentFails() error { } // unenrollHostname deletes the statuses for an existing agent, filtering by hostname -func (fts *FleetTestSuite) unenrollHostname() error { +func (fts *FleetTestSuite) unenrollHostname(revoke bool) error { span, _ := apm.StartSpanOptions(fts.currentContext, "Unenrolling hostname", "elastic-agent.hostname.unenroll", apm.SpanOptions{ Parent: apm.SpanFromContext(fts.currentContext).TraceContext(), }) @@ -1274,7 +1279,7 @@ func (fts *FleetTestSuite) unenrollHostname() error { "hostname": manifest.Hostname, }).Debug("Un-enrolling agent in Fleet") - err := fts.kibanaClient.UnEnrollAgent(fts.currentContext, agent.LocalMetadata.Host.HostName) + err := fts.kibanaClient.UnEnrollAgent(fts.currentContext, agent.LocalMetadata.Host.HostName, revoke) if err != nil { return err } diff --git a/internal/kibana/agents.go b/internal/kibana/agents.go index b1994aba1e..b007b60445 100644 --- a/internal/kibana/agents.go +++ b/internal/kibana/agents.go @@ -245,7 +245,8 @@ func (c *Client) ListAgents(ctx context.Context) ([]Agent, error) { } // UnEnrollAgent unenrolls agent from fleet -func (c *Client) UnEnrollAgent(ctx context.Context, hostname string) error { +func (c *Client) UnEnrollAgent(ctx context.Context, hostname string, revoke bool) error { + var reqBody = `{}` span, _ := apm.StartSpanOptions(ctx, "UnEnrolling Elastic Agent by hostname", "fleet.agent.un-enroll", apm.SpanOptions{ Parent: apm.SpanFromContext(ctx).TraceContext(), }) @@ -256,7 +257,12 @@ func (c *Client) UnEnrollAgent(ctx context.Context, hostname string) error { return err } - reqBody := `{"revoke": true}` + if revoke == true { + reqBody = `{"revoke": true}` + } + log.WithFields(log.Fields{ + "body": reqBody, + }).Info("This is the body") statusCode, respBody, _ := c.post(ctx, fmt.Sprintf("%s/agents/%s/unenroll", FleetAPI, agentID), []byte(reqBody)) if statusCode != 200 { return fmt.Errorf("could not unenroll agent; API status code = %d, response body = %s", statusCode, respBody) diff --git a/internal/kibana/api.go b/internal/kibana/api.go new file mode 100644 index 0000000000..81df2626a1 --- /dev/null +++ b/internal/kibana/api.go @@ -0,0 +1,73 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package kibana + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" + "go.elastic.co/apm" +) + +type ApiKey struct { + APIKeys []APIKeys `json:"api_keys"` +} +type Metadata struct { + PolicyID string `json:"policy_id,omitempty"` + AgentID string `json:"agent_id,omitempty"` + ManagedBy string `json:"managed_by"` + Managed bool `json:"managed"` + Type string `json:"type"` +} +type APIKeys struct { + ID string `json:"id"` + Name string `json:"name"` + Creation int64 `json:"creation"` + Invalidated bool `json:"invalidated"` + Username string `json:"username"` + Realm string `json:"realm"` + Metadata Metadata `json:"metadata,omitempty"` +} + +// Get _security/api_key +func (c *Client) ListApiKeys(ctx context.Context) ([]ApiKey, error) { + span, _ := apm.StartSpanOptions(ctx, "Listing Api Keys", "fleet.agents.list", apm.SpanOptions{ + Parent: apm.SpanFromContext(ctx).TraceContext(), + }) + defer span.End() + + reqBody := `{}` + statusCode, respBody, err := c.post(ctx, fmt.Sprintf("%s/_security/api_key?realm_name=_service_account&method=GET", ConsoleAPI), []byte(reqBody)) + + if err != nil { + log.WithFields(log.Fields{ + "body": respBody, + "error": err, + }).Error("Could not get Api Keys") + return nil, err + } + + if statusCode != 200 { + log.WithFields(log.Fields{ + "body": respBody, + "error": err, + "statusCode": statusCode, + }).Error("Could not get Api Keys") + + return nil, err + } + var resp struct { + List []ApiKey `json:"list"` + } + + if err := json.Unmarshal(respBody, &resp); err != nil { + return nil, errors.Wrap(err, "could not convert list Api Keys (response) to JSON") + } + + return resp.List, nil +} diff --git a/internal/kibana/url_prefixes.go b/internal/kibana/url_prefixes.go index c73e490984..545d4404be 100644 --- a/internal/kibana/url_prefixes.go +++ b/internal/kibana/url_prefixes.go @@ -22,6 +22,9 @@ const ( // EndpointAPI is the endpoint API EndpointAPI = "/api/endpoint" + + // ConsoleAPI is the console API + ConsoleAPI = "/api/console" ) // getBaseURL will pull in the baseurl or an alternative host based on settings From b85417af07fab5f57d3804793448d316a6c669d1 Mon Sep 17 00:00:00 2001 From: igorguz Date: Wed, 3 Nov 2021 09:14:23 -0700 Subject: [PATCH 02/13] adding to scenario file --- .../fleet/features/fleet_mode_agent.feature | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/e2e/_suites/fleet/features/fleet_mode_agent.feature b/e2e/_suites/fleet/features/fleet_mode_agent.feature index 8c8dd79b4d..b938c6a4a9 100644 --- a/e2e/_suites/fleet/features/fleet_mode_agent.feature +++ b/e2e/_suites/fleet/features/fleet_mode_agent.feature @@ -90,6 +90,23 @@ Examples: Debian | os | | debian | +@un-enroll-without-revoke +@skip:windows +Scenario Outline: Un-enrolling without revoke the deactivates the agent + Given a "" agent is deployed to Fleet with "tar" installer + When the agent is un-enrolled without revoke + Then the agent is listed in Fleet as "inactive" + +@centos +Examples: Centos +| os | +| centos | + +@debian +Examples: Debian + | os | + | debian | + @reenroll @skip:windows Scenario Outline: Re-enrolling the agent activates the agent in Fleet From 1fafae8a6a918394cc412baa9defbfbdcf273f8d Mon Sep 17 00:00:00 2001 From: igorguz Date: Fri, 5 Nov 2021 13:39:09 -0700 Subject: [PATCH 03/13] adding to scenario file --- .../fleet/features/fleet_mode_agent.feature | 4 +- e2e/_suites/fleet/fleet.go | 42 ++++++++++- internal/elasticsearch/client.go | 47 ++++++++++++ internal/kibana/agents.go | 1 + internal/kibana/api.go | 73 ------------------- 5 files changed, 92 insertions(+), 75 deletions(-) delete mode 100644 internal/kibana/api.go diff --git a/e2e/_suites/fleet/features/fleet_mode_agent.feature b/e2e/_suites/fleet/features/fleet_mode_agent.feature index b938c6a4a9..68328dbbec 100644 --- a/e2e/_suites/fleet/features/fleet_mode_agent.feature +++ b/e2e/_suites/fleet/features/fleet_mode_agent.feature @@ -73,12 +73,13 @@ Examples: Debian | os | | debian | -@unenroll +@un-enroll @skip:windows Scenario Outline: Un-enrolling the agent deactivates the agent Given a "" agent is deployed to Fleet with "tar" installer When the agent is un-enrolled Then the agent is listed in Fleet as "inactive" + And the agent Api key invalidated "false" @centos Examples: Centos @@ -96,6 +97,7 @@ Scenario Outline: Un-enrolling without revoke the deactivates the agent Given a "" agent is deployed to Fleet with "tar" installer When the agent is un-enrolled without revoke Then the agent is listed in Fleet as "inactive" + And the agent Api key invalidated "true" @centos Examples: Centos diff --git a/e2e/_suites/fleet/fleet.go b/e2e/_suites/fleet/fleet.go index 2ca431982e..d69c6d13f4 100644 --- a/e2e/_suites/fleet/fleet.go +++ b/e2e/_suites/fleet/fleet.go @@ -11,6 +11,9 @@ import ( "os" "path/filepath" "runtime" + "strconv" + + //"strconv" "strings" "time" @@ -62,6 +65,7 @@ type FleetTestSuite struct { // instrumentation currentContext context.Context DefaultAPIKey string + AgentId string } // afterScenario destroys the state created by a scenario @@ -170,6 +174,7 @@ func (fts *FleetTestSuite) contributeSteps(s *godog.ScenarioContext) { s.Step(`^the agent is un-enrolled without revoke$`, fts.theAgentIsUnenrolledWithoutRevoke) s.Step(`^the agent is re-enrolled on the host$`, fts.theAgentIsReenrolledOnTheHost) s.Step(`^the enrollment token is revoked$`, fts.theEnrollmentTokenIsRevoked) + s.Step(`^the agent Api key invalidated "(([^"]*))"$`, fts.theAgentApiKeyIsInvalidated) s.Step(`^an attempt to enroll a new agent fails$`, fts.anAttemptToEnrollANewAgentFails) s.Step(`^the "([^"]*)" process is "([^"]*)" on the host$`, fts.processStateChangedOnTheHost) s.Step(`^the file system Agent folder is empty$`, fts.theFileSystemAgentFolderIsEmpty) @@ -714,7 +719,6 @@ func theAgentIsListedInFleetWithStatus(ctx context.Context, desiredStatus string retryCount++ return err } - if agentID == "" { // the agent is not listed in Fleet if desiredStatus == "offline" || desiredStatus == "inactive" { @@ -1279,6 +1283,7 @@ func (fts *FleetTestSuite) unenrollHostname(revoke bool) error { "hostname": manifest.Hostname, }).Debug("Un-enrolling agent in Fleet") + fts.AgentId = agent.ID err := fts.kibanaClient.UnEnrollAgent(fts.currentContext, agent.LocalMetadata.Host.HostName, revoke) if err != nil { return err @@ -1605,3 +1610,38 @@ func (fts *FleetTestSuite) theMetricsInTheDataStream(name string, set string) er return nil } + +func (fts *FleetTestSuite) theAgentApiKeyIsInvalidated(invalidated string) error { + invalidatedBool, _ := strconv.ParseBool(invalidated) + body, err := elasticsearch.GetSecurityApiKey() + if err != nil { + log.WithFields(log.Fields{ + "Error": err, + }).Error("Could not return Security Api Keys") + return err + } + if err != nil { + log.WithFields(log.Fields{ + "error": err, + "responseBody": body, + }).Error("Could not parse response into JSON") + return err + } + + for _, item := range body.Children() { + if item.Path("name").Data().(string) == fts.AgentId { + if item.Path("invalidated").Data().(bool) == invalidatedBool { + log.WithFields(log.Fields{ + "agentId": fts.AgentId, + }).Info("The agent Api key invalidated: ", item.Path("invalidated").Data().(bool)) + } else { + log.WithFields(log.Fields{ + "agentId": fts.AgentId, + }).Error("The agent Api key invalidated: ", item.Path("invalidated").Data().(bool)) + return errors.New("The agent Api key invalidated is should be: " + invalidated) + } + } + } + + return nil +} diff --git a/internal/elasticsearch/client.go b/internal/elasticsearch/client.go index 58cdc1de5c..6bf12f9189 100644 --- a/internal/elasticsearch/client.go +++ b/internal/elasticsearch/client.go @@ -9,6 +9,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/Jeffail/gabs/v2" "net" "net/http" "net/url" @@ -369,3 +370,49 @@ func WaitForNumberOfHits(ctx context.Context, indexName string, query map[string err := backoff.Retry(numberOfHits, exp) return result, err } + +// GetSecurityApiKey waits for the elasticsearch SecurityApiKey to return the list of Api Keys. +func GetSecurityApiKey() (*gabs.Container, error) { + //exp := utils.GetExponentialBackOff(60 * time.Second) + + //retryCount := 1 + //body := "" + + //SecurityApiKeys := func() error{ + r := curl.HTTPRequest{ + URL: "http://localhost:9200/_security/api_key?", + BasicAuthPassword: "changeme", + BasicAuthUser: "elastic", + } + + response, err := curl.Get(r) + if err != nil { + log.WithFields(log.Fields{ + "error": err, + "statusEndpoint": r.URL, + }).Warn("The Elasticsearch Cat Indices API is not available yet") + + return nil, err + } + + log.WithFields(log.Fields{ + "statusEndpoint": r.URL, + }).Trace("The Elasticsearch Console SecurityApiKey API is available") + + jsonParsed, err := gabs.ParseJSON([]byte(response)) + if err != nil { + log.WithFields(log.Fields{ + "error": err, + "responseBody": jsonParsed, + }).Error("Could not parse response into JSON") + return jsonParsed, err + } + data := jsonParsed.Path("api_keys") + //body = data + //return nil + //} + + //err := backoff.Retry(SecurityApiKeys, exp) + return data, err + +} diff --git a/internal/kibana/agents.go b/internal/kibana/agents.go index b007b60445..fcc1f861e3 100644 --- a/internal/kibana/agents.go +++ b/internal/kibana/agents.go @@ -78,6 +78,7 @@ func (c *Client) GetAgentIDByHostname(ctx context.Context, hostname string) (str "agentId": agent.ID, "hostname": hostname, }).Trace("Agent Id found") + return agent.ID, nil } diff --git a/internal/kibana/api.go b/internal/kibana/api.go deleted file mode 100644 index 81df2626a1..0000000000 --- a/internal/kibana/api.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -// or more contributor license agreements. Licensed under the Elastic License; -// you may not use this file except in compliance with the Elastic License. - -package kibana - -import ( - "context" - "encoding/json" - "fmt" - - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" - "go.elastic.co/apm" -) - -type ApiKey struct { - APIKeys []APIKeys `json:"api_keys"` -} -type Metadata struct { - PolicyID string `json:"policy_id,omitempty"` - AgentID string `json:"agent_id,omitempty"` - ManagedBy string `json:"managed_by"` - Managed bool `json:"managed"` - Type string `json:"type"` -} -type APIKeys struct { - ID string `json:"id"` - Name string `json:"name"` - Creation int64 `json:"creation"` - Invalidated bool `json:"invalidated"` - Username string `json:"username"` - Realm string `json:"realm"` - Metadata Metadata `json:"metadata,omitempty"` -} - -// Get _security/api_key -func (c *Client) ListApiKeys(ctx context.Context) ([]ApiKey, error) { - span, _ := apm.StartSpanOptions(ctx, "Listing Api Keys", "fleet.agents.list", apm.SpanOptions{ - Parent: apm.SpanFromContext(ctx).TraceContext(), - }) - defer span.End() - - reqBody := `{}` - statusCode, respBody, err := c.post(ctx, fmt.Sprintf("%s/_security/api_key?realm_name=_service_account&method=GET", ConsoleAPI), []byte(reqBody)) - - if err != nil { - log.WithFields(log.Fields{ - "body": respBody, - "error": err, - }).Error("Could not get Api Keys") - return nil, err - } - - if statusCode != 200 { - log.WithFields(log.Fields{ - "body": respBody, - "error": err, - "statusCode": statusCode, - }).Error("Could not get Api Keys") - - return nil, err - } - var resp struct { - List []ApiKey `json:"list"` - } - - if err := json.Unmarshal(respBody, &resp); err != nil { - return nil, errors.Wrap(err, "could not convert list Api Keys (response) to JSON") - } - - return resp.List, nil -} From 48a293e0d978ab1da0bab051deff59841ad411e9 Mon Sep 17 00:00:00 2001 From: igorguz Date: Fri, 5 Nov 2021 13:46:01 -0700 Subject: [PATCH 04/13] Changing Scenario Names and tag --- e2e/_suites/fleet/features/fleet_mode_agent.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e/_suites/fleet/features/fleet_mode_agent.feature b/e2e/_suites/fleet/features/fleet_mode_agent.feature index 68328dbbec..db8387bcc1 100644 --- a/e2e/_suites/fleet/features/fleet_mode_agent.feature +++ b/e2e/_suites/fleet/features/fleet_mode_agent.feature @@ -73,9 +73,9 @@ Examples: Debian | os | | debian | -@un-enroll +@un-enroll-with-revoke @skip:windows -Scenario Outline: Un-enrolling the agent deactivates the agent +Scenario Outline: Un-enrolling with revoke the agent deactivates the agent Given a "" agent is deployed to Fleet with "tar" installer When the agent is un-enrolled Then the agent is listed in Fleet as "inactive" @@ -91,7 +91,7 @@ Examples: Debian | os | | debian | -@un-enroll-without-revoke +@un-enroll @skip:windows Scenario Outline: Un-enrolling without revoke the deactivates the agent Given a "" agent is deployed to Fleet with "tar" installer From 797705cf34edc8b0aa799931a1de3fe87e608f7b Mon Sep 17 00:00:00 2001 From: igorguz Date: Mon, 8 Nov 2021 09:36:42 -0800 Subject: [PATCH 05/13] Changing step description to true --- e2e/_suites/fleet/features/fleet_mode_agent.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/_suites/fleet/features/fleet_mode_agent.feature b/e2e/_suites/fleet/features/fleet_mode_agent.feature index db8387bcc1..85b903ee15 100644 --- a/e2e/_suites/fleet/features/fleet_mode_agent.feature +++ b/e2e/_suites/fleet/features/fleet_mode_agent.feature @@ -79,7 +79,7 @@ Scenario Outline: Un-enrolling with revoke the agent deactivates the agent Given a "" agent is deployed to Fleet with "tar" installer When the agent is un-enrolled Then the agent is listed in Fleet as "inactive" - And the agent Api key invalidated "false" + And the agent Api key invalidated "true" @centos Examples: Centos @@ -91,7 +91,7 @@ Examples: Debian | os | | debian | -@un-enroll +@un-enroll-without-revoke @skip:windows Scenario Outline: Un-enrolling without revoke the deactivates the agent Given a "" agent is deployed to Fleet with "tar" installer From 45e4906acb1d74c59ed18407a50e312886aae698 Mon Sep 17 00:00:00 2001 From: igorguz Date: Tue, 9 Nov 2021 22:40:08 -0800 Subject: [PATCH 06/13] Removing comment out lines --- e2e/_suites/fleet/fleet.go | 1 - internal/elasticsearch/client.go | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/e2e/_suites/fleet/fleet.go b/e2e/_suites/fleet/fleet.go index d69c6d13f4..fdecc77a07 100644 --- a/e2e/_suites/fleet/fleet.go +++ b/e2e/_suites/fleet/fleet.go @@ -13,7 +13,6 @@ import ( "runtime" "strconv" - //"strconv" "strings" "time" diff --git a/internal/elasticsearch/client.go b/internal/elasticsearch/client.go index 6bf12f9189..9e87cc7ddb 100644 --- a/internal/elasticsearch/client.go +++ b/internal/elasticsearch/client.go @@ -373,12 +373,7 @@ func WaitForNumberOfHits(ctx context.Context, indexName string, query map[string // GetSecurityApiKey waits for the elasticsearch SecurityApiKey to return the list of Api Keys. func GetSecurityApiKey() (*gabs.Container, error) { - //exp := utils.GetExponentialBackOff(60 * time.Second) - //retryCount := 1 - //body := "" - - //SecurityApiKeys := func() error{ r := curl.HTTPRequest{ URL: "http://localhost:9200/_security/api_key?", BasicAuthPassword: "changeme", @@ -408,11 +403,6 @@ func GetSecurityApiKey() (*gabs.Container, error) { return jsonParsed, err } data := jsonParsed.Path("api_keys") - //body = data - //return nil - //} - //err := backoff.Retry(SecurityApiKeys, exp) return data, err - } From 41f0b52b1d1b79e8720225c2b5c4211eb47b34c3 Mon Sep 17 00:00:00 2001 From: igorguz Date: Tue, 16 Nov 2021 10:24:11 -0800 Subject: [PATCH 07/13] Fixed per comments by Adam --- e2e/_suites/fleet/fleet.go | 14 +++++++----- internal/elasticsearch/client.go | 38 ++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/e2e/_suites/fleet/fleet.go b/e2e/_suites/fleet/fleet.go index fdecc77a07..e7b94407a4 100644 --- a/e2e/_suites/fleet/fleet.go +++ b/e2e/_suites/fleet/fleet.go @@ -13,6 +13,8 @@ import ( "runtime" "strconv" + //"strconv" + "strings" "time" @@ -1627,16 +1629,18 @@ func (fts *FleetTestSuite) theAgentApiKeyIsInvalidated(invalidated string) error return err } - for _, item := range body.Children() { - if item.Path("name").Data().(string) == fts.AgentId { - if item.Path("invalidated").Data().(bool) == invalidatedBool { + for _, item := range body.APIKeys { + if item.Metadata.AgentID == fts.AgentId { + if item.Invalidated == invalidatedBool { log.WithFields(log.Fields{ "agentId": fts.AgentId, - }).Info("The agent Api key invalidated: ", item.Path("invalidated").Data().(bool)) + "Type": item.Metadata.Type, + }).Info("The agent Api key invalidated: ", item.Invalidated) } else { log.WithFields(log.Fields{ "agentId": fts.AgentId, - }).Error("The agent Api key invalidated: ", item.Path("invalidated").Data().(bool)) + "Type": item.Metadata.Type, + }).Error("The agent Api key invalidated: ", item.Invalidated) return errors.New("The agent Api key invalidated is should be: " + invalidated) } } diff --git a/internal/elasticsearch/client.go b/internal/elasticsearch/client.go index 9e87cc7ddb..6d3346f6f9 100644 --- a/internal/elasticsearch/client.go +++ b/internal/elasticsearch/client.go @@ -9,7 +9,6 @@ import ( "context" "encoding/json" "fmt" - "github.com/Jeffail/gabs/v2" "net" "net/http" "net/url" @@ -35,6 +34,27 @@ type Query struct { ServiceVersion string } +type APIKey struct { + APIKeys []APIKeys `json:"api_keys"` +} +type Metadata struct { + PolicyID string `json:"policy_id, omitempty"` + AgentID string `json:"agent_id, omitempty"` + ManagedBy string `json:"managed_by"` + Managed bool `json:"managed"` + Type string `json:"type"` +} + +type APIKeys struct { + ID string `json:"id"` + Name string `json:"name"` + Creation int64 `json:"creation"` + Invalidated bool `json:"invalidated"` + Username string `json:"username"` + Realm string `json:"realm"` + Metadata Metadata `json:"metadata,omitempty"` +} + // SearchResult wraps a search result type SearchResult map[string]interface{} @@ -372,7 +392,8 @@ func WaitForNumberOfHits(ctx context.Context, indexName string, query map[string } // GetSecurityApiKey waits for the elasticsearch SecurityApiKey to return the list of Api Keys. -func GetSecurityApiKey() (*gabs.Container, error) { +func GetSecurityApiKey() (APIKey, error) { + data := APIKey{} r := curl.HTTPRequest{ URL: "http://localhost:9200/_security/api_key?", @@ -387,22 +408,15 @@ func GetSecurityApiKey() (*gabs.Container, error) { "statusEndpoint": r.URL, }).Warn("The Elasticsearch Cat Indices API is not available yet") - return nil, err + return APIKey{}, err } log.WithFields(log.Fields{ "statusEndpoint": r.URL, + "Response": response, }).Trace("The Elasticsearch Console SecurityApiKey API is available") - jsonParsed, err := gabs.ParseJSON([]byte(response)) - if err != nil { - log.WithFields(log.Fields{ - "error": err, - "responseBody": jsonParsed, - }).Error("Could not parse response into JSON") - return jsonParsed, err - } - data := jsonParsed.Path("api_keys") + json.Unmarshal([]byte(response), &data) return data, err } From 98da734f75878b7f3a2bac62e7e23c916a43a5b9 Mon Sep 17 00:00:00 2001 From: igorguz Date: Tue, 16 Nov 2021 10:35:28 -0800 Subject: [PATCH 08/13] Remove unused url prefix --- internal/kibana/url_prefixes.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/kibana/url_prefixes.go b/internal/kibana/url_prefixes.go index 545d4404be..c73e490984 100644 --- a/internal/kibana/url_prefixes.go +++ b/internal/kibana/url_prefixes.go @@ -22,9 +22,6 @@ const ( // EndpointAPI is the endpoint API EndpointAPI = "/api/endpoint" - - // ConsoleAPI is the console API - ConsoleAPI = "/api/console" ) // getBaseURL will pull in the baseurl or an alternative host based on settings From 81e3395422852584b4a0f680bc400d3522db3089 Mon Sep 17 00:00:00 2001 From: igorguz Date: Thu, 18 Nov 2021 10:00:51 -0800 Subject: [PATCH 09/13] removed functions using gabs, and converted to struct --- .../fleet/features/fleet_mode_agent.feature | 8 +-- e2e/_suites/fleet/fleet.go | 60 ++++++++++--------- internal/elasticsearch/client.go | 4 +- internal/kibana/agents.go | 2 +- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/e2e/_suites/fleet/features/fleet_mode_agent.feature b/e2e/_suites/fleet/features/fleet_mode_agent.feature index 85b903ee15..71cbe1f65e 100644 --- a/e2e/_suites/fleet/features/fleet_mode_agent.feature +++ b/e2e/_suites/fleet/features/fleet_mode_agent.feature @@ -81,10 +81,10 @@ Scenario Outline: Un-enrolling with revoke the agent deactivates the agent Then the agent is listed in Fleet as "inactive" And the agent Api key invalidated "true" -@centos -Examples: Centos -| os | -| centos | +#@centos This test is failing returns false not true it will worked on later +#Examples: Centos +#| os | +#| centos | @debian Examples: Debian diff --git a/e2e/_suites/fleet/fleet.go b/e2e/_suites/fleet/fleet.go index e7b94407a4..21790c3072 100644 --- a/e2e/_suites/fleet/fleet.go +++ b/e2e/_suites/fleet/fleet.go @@ -1613,38 +1613,44 @@ func (fts *FleetTestSuite) theMetricsInTheDataStream(name string, set string) er } func (fts *FleetTestSuite) theAgentApiKeyIsInvalidated(invalidated string) error { + maxTimeout := time.Duration(utils.TimeoutFactor) * time.Minute + exp := utils.GetExponentialBackOff(maxTimeout) + retryCount := 1 + invalidatedBool, _ := strconv.ParseBool(invalidated) - body, err := elasticsearch.GetSecurityApiKey() - if err != nil { - log.WithFields(log.Fields{ - "Error": err, - }).Error("Could not return Security Api Keys") - return err - } - if err != nil { - log.WithFields(log.Fields{ - "error": err, - "responseBody": body, - }).Error("Could not parse response into JSON") - return err - } + apiKeyInvalidated := func() error { + body, err := elasticsearch.GetSecurityApiKey() + if err != nil { + log.WithFields(log.Fields{ + "Error": err, + }).Error("Could not return Security Api Keys") + return err + } - for _, item := range body.APIKeys { - if item.Metadata.AgentID == fts.AgentId { - if item.Invalidated == invalidatedBool { - log.WithFields(log.Fields{ - "agentId": fts.AgentId, - "Type": item.Metadata.Type, - }).Info("The agent Api key invalidated: ", item.Invalidated) - } else { - log.WithFields(log.Fields{ - "agentId": fts.AgentId, - "Type": item.Metadata.Type, - }).Error("The agent Api key invalidated: ", item.Invalidated) - return errors.New("The agent Api key invalidated is should be: " + invalidated) + for _, item := range body.APIKeys { + if item.Metadata.AgentID == fts.AgentId { + if item.Invalidated == invalidatedBool { + log.WithFields(log.Fields{ + "agentId": fts.AgentId, + "Type": item.Metadata.Type, + }).Info("The agent Api key invalidated: ", item.Invalidated) + } else { + log.WithFields(log.Fields{ + "agentId": fts.AgentId, + "Type": item.Metadata.Type, + }).Error("The agent Api key invalidated: ", item.Invalidated) + return errors.New("The agent Api key invalidated is should be: " + invalidated) + } } } + retryCount++ + + return nil } + err := backoff.Retry(apiKeyInvalidated, exp) + if err != nil { + return err + } return nil } diff --git a/internal/elasticsearch/client.go b/internal/elasticsearch/client.go index 6d3346f6f9..fbc7e62d89 100644 --- a/internal/elasticsearch/client.go +++ b/internal/elasticsearch/client.go @@ -406,7 +406,7 @@ func GetSecurityApiKey() (APIKey, error) { log.WithFields(log.Fields{ "error": err, "statusEndpoint": r.URL, - }).Warn("The Elasticsearch Cat Indices API is not available yet") + }).Warn("The Elasticsearch Console SecurityApiKey API is not available yet") return APIKey{}, err } @@ -414,7 +414,7 @@ func GetSecurityApiKey() (APIKey, error) { log.WithFields(log.Fields{ "statusEndpoint": r.URL, "Response": response, - }).Trace("The Elasticsearch Console SecurityApiKey API is available") + }).Trace("The Elasticsearch API is available") json.Unmarshal([]byte(response), &data) diff --git a/internal/kibana/agents.go b/internal/kibana/agents.go index fcc1f861e3..60397805d1 100644 --- a/internal/kibana/agents.go +++ b/internal/kibana/agents.go @@ -263,7 +263,7 @@ func (c *Client) UnEnrollAgent(ctx context.Context, hostname string, revoke bool } log.WithFields(log.Fields{ "body": reqBody, - }).Info("This is the body") + }).Info("Sending un-enrollment request") statusCode, respBody, _ := c.post(ctx, fmt.Sprintf("%s/agents/%s/unenroll", FleetAPI, agentID), []byte(reqBody)) if statusCode != 200 { return fmt.Errorf("could not unenroll agent; API status code = %d, response body = %s", statusCode, respBody) From fafad6be3871ece40bc105175d90cf32f1447e7d Mon Sep 17 00:00:00 2001 From: igorguz Date: Tue, 30 Nov 2021 14:51:43 -0800 Subject: [PATCH 10/13] commiting changes from master --- .../fleet/features/fleet_mode_agent.feature | 114 ++++-------------- 1 file changed, 24 insertions(+), 90 deletions(-) diff --git a/e2e/_suites/fleet/features/fleet_mode_agent.feature b/e2e/_suites/fleet/features/fleet_mode_agent.feature index 8c8dd79b4d..d82e50e061 100644 --- a/e2e/_suites/fleet/features/fleet_mode_agent.feature +++ b/e2e/_suites/fleet/features/fleet_mode_agent.feature @@ -7,138 +7,72 @@ Background: Setting up kibana instance with the default profile @install @skip:windows -Scenario Outline: Deploying the agent - Given a "" agent is deployed to Fleet with "tar" installer +Scenario: Deploying the agent + Given an agent is deployed to Fleet with "tar" installer When the "elastic-agent" process is in the "started" state on the host Then the agent is listed in Fleet as "online" And system package dashboards are listed in Fleet -@centos -Examples: Centos -| os | -| centos | - -@debian -Examples: Debian -| os | -| debian | - @enroll @skip:windows -Scenario Outline: Deploying the agent with enroll and then run on rpm and deb - Given a "" agent is deployed to Fleet +Scenario: Deploying the agent with enroll and then run on rpm and deb + Given an agent is deployed to Fleet When the "elastic-agent" process is in the "started" state on the host Then the agent is listed in Fleet as "online" And system package dashboards are listed in Fleet -@centos -Examples: Centos -| os | -| centos | - -@debian -Examples: Debian -| os | -| debian | - # @upgrade-agent @nightly @skip:windows Scenario Outline: Upgrading the installed agent - Given a "" agent "stale" is deployed to Fleet with "tar" installer + Given an agent "stale" is deployed to Fleet with "tar" installer And certs are installed And the "elastic-agent" process is "restarted" on the host When agent is upgraded to version "latest" Then agent is in version "latest" -@debian -Examples: Debian -| os | -| debian | - @restart-agent @skip:windows -Scenario Outline: Restarting the installed agent - Given a "" agent is deployed to Fleet with "tar" installer +Scenario: Restarting the installed agent + Given an agent is deployed to Fleet with "tar" installer When the "elastic-agent" process is "restarted" on the host Then the agent is listed in Fleet as "online" -@centos -Examples: Centos -| os | -| centos | - -@debian -Examples: Debian -| os | -| debian | - -@unenroll +@un-enroll-with-revoke @skip:windows -Scenario Outline: Un-enrolling the agent deactivates the agent - Given a "" agent is deployed to Fleet with "tar" installer +Scenario: Un-enrolling with revoke agent deactivates the agent + Given an agent is deployed to Fleet with "tar" installer When the agent is un-enrolled Then the agent is listed in Fleet as "inactive" + And the agent Api key invalidated "true" -@centos -Examples: Centos -| os | -| centos | - -@debian -Examples: Debian -| os | -| debian | +@un-enroll-without-revoke +@skip:windows +Scenario: Un-enrolling without revoke deactivates the agent + Given an agent is deployed to Fleet with "tar" installer + When the agent is un-enrolled without revoke + Then the agent is listed in Fleet as "inactive" + And the agent Api key invalidated "true" @reenroll @skip:windows -Scenario Outline: Re-enrolling the agent activates the agent in Fleet - Given a "" agent is deployed to Fleet with "tar" installer +Scenario: Re-enrolling agent activates the agent in Fleet + Given an agent is deployed to Fleet with "tar" installer And the agent is un-enrolled And the "elastic-agent" process is "stopped" on the host And the agent is re-enrolled on the host When the "elastic-agent" process is "started" on the host Then the agent is listed in Fleet as "online" -@centos -Examples: Centos -| os | -| centos | - -@debian -Examples: Debian -| os | -| debian | - @revoke-token -Scenario Outline: Revoking the enrollment token for the agent - Given a "" agent is deployed to Fleet with "tar" installer +Scenario: Revoking the enrollment token for agent + Given an agent is deployed to Fleet with "tar" installer When the enrollment token is revoked Then an attempt to enroll a new agent fails -@centos -Examples: Centos -| os | -| centos | - -@debian -Examples: Debian -| os | -| debian | - @uninstall-host @skip:windows -Scenario Outline: Un-installing the installed agent - Given a "" agent is deployed to Fleet with "tar" installer +Scenario: Un-installing the installed agent + Given an agent is deployed to Fleet with "tar" installer When the "elastic-agent" process is "uninstalled" on the host Then the file system Agent folder is empty - -@centos -Examples: Centos -| os | -| centos | - -@debian -Examples: Debian -| os | -| debian | From 505a7de9d4c592ad764dd0d41c81a999af6d5fd6 Mon Sep 17 00:00:00 2001 From: igorguz Date: Wed, 1 Dec 2021 08:44:15 -0800 Subject: [PATCH 11/13] commiting changes from master --- e2e/_suites/fleet/features/fleet_mode_agent.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/_suites/fleet/features/fleet_mode_agent.feature b/e2e/_suites/fleet/features/fleet_mode_agent.feature index d82e50e061..7e4c35642e 100644 --- a/e2e/_suites/fleet/features/fleet_mode_agent.feature +++ b/e2e/_suites/fleet/features/fleet_mode_agent.feature @@ -24,7 +24,7 @@ Scenario: Deploying the agent with enroll and then run on rpm and deb # @upgrade-agent @nightly @skip:windows -Scenario Outline: Upgrading the installed agent +Scenario: Upgrading the installed agent Given an agent "stale" is deployed to Fleet with "tar" installer And certs are installed And the "elastic-agent" process is "restarted" on the host From 11d2bca89a54216060eae0052527464dd4d173af Mon Sep 17 00:00:00 2001 From: igorguz Date: Wed, 1 Dec 2021 08:46:05 -0800 Subject: [PATCH 12/13] Removing os from the scenarios --- e2e/_suites/fleet/features/fleet_mode_agent.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/e2e/_suites/fleet/features/fleet_mode_agent.feature b/e2e/_suites/fleet/features/fleet_mode_agent.feature index 7e4c35642e..4ffd8e0d52 100644 --- a/e2e/_suites/fleet/features/fleet_mode_agent.feature +++ b/e2e/_suites/fleet/features/fleet_mode_agent.feature @@ -7,7 +7,7 @@ Background: Setting up kibana instance with the default profile @install @skip:windows -Scenario: Deploying the agent +Scenario: Deploying the agent Given an agent is deployed to Fleet with "tar" installer When the "elastic-agent" process is in the "started" state on the host Then the agent is listed in Fleet as "online" @@ -15,7 +15,7 @@ Scenario: Deploying the agent @enroll @skip:windows -Scenario: Deploying the agent with enroll and then run on rpm and deb +Scenario: Deploying the agent with enroll and then run on rpm and deb Given an agent is deployed to Fleet When the "elastic-agent" process is in the "started" state on the host Then the agent is listed in Fleet as "online" @@ -24,7 +24,7 @@ Scenario: Deploying the agent with enroll and then run on rpm and deb # @upgrade-agent @nightly @skip:windows -Scenario: Upgrading the installed agent +Scenario: Upgrading the installed agent Given an agent "stale" is deployed to Fleet with "tar" installer And certs are installed And the "elastic-agent" process is "restarted" on the host @@ -33,7 +33,7 @@ Scenario: Upgrading the installed agent @restart-agent @skip:windows -Scenario: Restarting the installed agent +Scenario: Restarting the installed agent Given an agent is deployed to Fleet with "tar" installer When the "elastic-agent" process is "restarted" on the host Then the agent is listed in Fleet as "online" From 1593067aea0e3efe08fab03f5d3eceb3778e5c25 Mon Sep 17 00:00:00 2001 From: igorguz Date: Wed, 1 Dec 2021 08:59:14 -0800 Subject: [PATCH 13/13] Changing to support remote provider --- internal/elasticsearch/client.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/elasticsearch/client.go b/internal/elasticsearch/client.go index 319f2f0e82..2a1e315e4c 100644 --- a/internal/elasticsearch/client.go +++ b/internal/elasticsearch/client.go @@ -410,11 +410,12 @@ func WaitForNumberOfHits(ctx context.Context, indexName string, query map[string // GetSecurityApiKey waits for the elasticsearch SecurityApiKey to return the list of Api Keys. func GetSecurityApiKey() (APIKey, error) { + esEndpoint := GetElasticSearchEndpoint() data := APIKey{} r := curl.HTTPRequest{ - URL: "http://localhost:9200/_security/api_key?", - BasicAuthPassword: "changeme", + URL: fmt.Sprintf("%s://%s:%d/_security/api_key?", esEndpoint.Scheme, esEndpoint.Host, esEndpoint.Port), + BasicAuthPassword: shell.GetEnv("ELASTICSEARCH_PASSWORD", "changeme"), BasicAuthUser: "elastic", }