Skip to content
This repository has been archived by the owner on Sep 17, 2024. It is now read-only.

Igor api key validation #1783

Open
wants to merge 37 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d619871
Change the Scenarios description
IgorGuz2000 Nov 2, 2021
5619378
Merge remote-tracking branch 'upstream/master' into Igor_API_Key_vali…
IgorGuz2000 Nov 3, 2021
b85417a
adding to scenario file
IgorGuz2000 Nov 3, 2021
1fafae8
adding to scenario file
IgorGuz2000 Nov 5, 2021
48a293e
Changing Scenario Names and tag
IgorGuz2000 Nov 5, 2021
4fcda4e
Merge branch 'master' into Igor_API_Key_validation
IgorGuz2000 Nov 5, 2021
797705c
Changing step description to true
IgorGuz2000 Nov 8, 2021
425a07c
Merge remote-tracking branch 'origin/Igor_API_Key_validation' into Ig…
IgorGuz2000 Nov 8, 2021
45e4906
Removing comment out lines
IgorGuz2000 Nov 10, 2021
314f5c1
Merge branch 'master' into Igor_API_Key_validation
IgorGuz2000 Nov 11, 2021
0408187
Merge remote-tracking branch 'upstream/master' into Igor_API_Key_vali…
IgorGuz2000 Nov 11, 2021
5085a8a
Merge remote-tracking branch 'upstream/master' into Igor_API_Key_vali…
IgorGuz2000 Nov 15, 2021
c4b80e3
Merge branch 'master' into Igor_API_Key_validation
IgorGuz2000 Nov 15, 2021
491337c
Merge remote-tracking branch 'upstream/master' into Igor_API_Key_vali…
IgorGuz2000 Nov 15, 2021
41f0b52
Fixed per comments by Adam
IgorGuz2000 Nov 16, 2021
1a3e166
Merge remote-tracking branch 'origin/Igor_API_Key_validation' into Ig…
IgorGuz2000 Nov 16, 2021
add18ed
Merge remote-tracking branch 'upstream/master' into Igor_API_Key_vali…
IgorGuz2000 Nov 16, 2021
98da734
Remove unused url prefix
IgorGuz2000 Nov 16, 2021
81e3395
removed functions using gabs, and converted to struct
IgorGuz2000 Nov 18, 2021
aee3cc7
Merge branch 'master' into Igor_API_Key_validation
IgorGuz2000 Nov 18, 2021
afeee1b
Merge branch 'master' into Igor_API_Key_validation
IgorGuz2000 Nov 29, 2021
d4b6240
Merge remote-tracking branch 'upstream/master' into Igor_API_Key_vali…
IgorGuz2000 Nov 30, 2021
fb2e52a
Merge remote-tracking branch 'origin/Igor_API_Key_validation' into Ig…
IgorGuz2000 Nov 30, 2021
fafad6b
commiting changes from master
IgorGuz2000 Nov 30, 2021
80ad66e
Merge remote-tracking branch 'upstream/master' into Igor_API_Key_vali…
IgorGuz2000 Dec 1, 2021
505a7de
commiting changes from master
IgorGuz2000 Dec 1, 2021
11d2bca
Removing os from the scenarios
IgorGuz2000 Dec 1, 2021
1593067
Changing to support remote provider
IgorGuz2000 Dec 1, 2021
d15774c
Merge branch 'master' into Igor_API_Key_validation
IgorGuz2000 Dec 6, 2021
bc2b638
Merge branch 'master' into Igor_API_Key_validation
IgorGuz2000 Dec 13, 2021
d53e11d
Merge branch 'master' into Igor_API_Key_validation
IgorGuz2000 Dec 15, 2021
67f90eb
Merge branch 'master' into Igor_API_Key_validation
IgorGuz2000 Dec 17, 2021
45a2735
Merge branch 'master' into Igor_API_Key_validation
IgorGuz2000 Dec 17, 2021
8ab1871
Merge branch 'main' into Igor_API_Key_validation
IgorGuz2000 Jan 4, 2022
3a7a753
Merge branch 'main' into Igor_API_Key_validation
IgorGuz2000 Jan 11, 2022
e15903e
Merge branch 'main' into Igor_API_Key_validation
IgorGuz2000 Jan 19, 2022
b60ad26
Merge branch 'main' into Igor_API_Key_validation
IgorGuz2000 Jan 20, 2022
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
50 changes: 24 additions & 26 deletions e2e/_suites/fleet/features/fleet_mode_agent.feature
Original file line number Diff line number Diff line change
Expand Up @@ -7,58 +7,56 @@ Background: Setting up kibana instance with the default profile

@install
@skip:windows
Scenario Outline: 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"
And system package dashboards are listed in Fleet

# @enroll
# @skip:windows
# Scenario Outline: 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 |
@enroll
@skip:windows
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

# @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
When agent is upgraded to version "latest"
Then agent is in version "latest"


@restart-agent
@skip:windows
Scenario Outline: 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"

@unenroll
@un-enroll-with-revoke
@skip:windows
Scenario Outline: Un-enrolling the agent deactivates the agent
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"

@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
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
Expand All @@ -67,14 +65,14 @@ Scenario Outline: Re-enrolling the agent activates the agent in Fleet
Then the agent is listed in Fleet as "online"

@revoke-token
Scenario Outline: Revoking the enrollment token for the agent
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

@uninstall-host
@skip:windows
Scenario Outline: Un-installing the installed agent
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
64 changes: 59 additions & 5 deletions e2e/_suites/fleet/fleet.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (
"os"
"path/filepath"
"runtime"
"strconv"

//"strconv"
IgorGuz2000 marked this conversation as resolved.
Show resolved Hide resolved

"strings"
"time"

Expand Down Expand Up @@ -62,6 +66,7 @@ type FleetTestSuite struct {
// instrumentation
currentContext context.Context
DefaultAPIKey string
AgentId string
}

// afterScenario destroys the state created by a scenario
Expand Down Expand Up @@ -105,7 +110,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{
Expand Down Expand Up @@ -248,8 +253,10 @@ 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(`^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)
Expand Down Expand Up @@ -779,7 +786,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" {
Expand Down Expand Up @@ -939,7 +945,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 {
Expand Down Expand Up @@ -1326,7 +1336,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(),
})
Expand All @@ -1347,7 +1357,8 @@ func (fts *FleetTestSuite) unenrollHostname() error {
"hostname": manifest.Hostname,
}).Debug("Un-enrolling agent in Fleet")

err := fts.kibanaClient.UnEnrollAgent(fts.currentContext, agent.LocalMetadata.Host.HostName)
fts.AgentId = agent.ID
err := fts.kibanaClient.UnEnrollAgent(fts.currentContext, agent.LocalMetadata.Host.HostName, revoke)
if err != nil {
return err
}
Expand Down Expand Up @@ -1684,3 +1695,46 @@ func (fts *FleetTestSuite) theMetricsInTheDataStream(name string, set string) er

return nil
}

func (fts *FleetTestSuite) theAgentApiKeyIsInvalidated(invalidated string) error {
maxTimeout := time.Duration(utils.TimeoutFactor) * time.Minute
exp := utils.GetExponentialBackOff(maxTimeout)
retryCount := 1

invalidatedBool, _ := strconv.ParseBool(invalidated)
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)
}
}
}
retryCount++

return nil
}

err := backoff.Retry(apiKeyInvalidated, exp)
if err != nil {
return err
}
return nil
}
52 changes: 52 additions & 0 deletions internal/elasticsearch/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,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{}

Expand Down Expand Up @@ -386,3 +407,34 @@ 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() (APIKey, error) {
esEndpoint := GetElasticSearchEndpoint()
data := APIKey{}

r := curl.HTTPRequest{
IgorGuz2000 marked this conversation as resolved.
Show resolved Hide resolved
URL: fmt.Sprintf("%s://%s:%d/_security/api_key?", esEndpoint.Scheme, esEndpoint.Host, esEndpoint.Port),
BasicAuthPassword: shell.GetEnv("ELASTICSEARCH_PASSWORD", "changeme"),
BasicAuthUser: "elastic",
}

response, err := curl.Get(r)
if err != nil {
log.WithFields(log.Fields{
"error": err,
"statusEndpoint": r.URL,
}).Warn("The Elasticsearch Console SecurityApiKey API is not available yet")

return APIKey{}, err
}

log.WithFields(log.Fields{
"statusEndpoint": r.URL,
"Response": response,
}).Trace("The Elasticsearch API is available")

json.Unmarshal([]byte(response), &data)

return data, err
}
11 changes: 9 additions & 2 deletions internal/kibana/agents.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -245,7 +246,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(),
})
Expand All @@ -256,7 +258,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("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)
Expand Down