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

[Unprivileged] Adjust integration tests to use unprivileged by default #3931

Merged
merged 60 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
53f7ca0
Work on ability to move the control socket.
blakerouse Nov 30, 2023
786b716
Adjust/add tests for unpriveleged.
blakerouse Nov 30, 2023
955e70b
More adjustments.
blakerouse Nov 30, 2023
63dc22c
Adjustments for tests.
blakerouse Dec 1, 2023
0028680
More adjusments for control socket path.
blakerouse Dec 13, 2023
4fb0ddc
Fix symlink oldpath.
blakerouse Dec 13, 2023
3e67fa6
Merge branch 'main' into control-socket-adjust
blakerouse Dec 13, 2023
e3bc626
Add changelog.
blakerouse Dec 13, 2023
f5ea666
Fix trim prefix.
blakerouse Dec 14, 2023
1fe8a3d
Add more logging.
blakerouse Dec 14, 2023
23e89d5
More path adjustments.
blakerouse Dec 14, 2023
40e622c
Inverse symlink create.
blakerouse Dec 14, 2023
797a55b
Fix issue with creating control socket symlink.
blakerouse Dec 14, 2023
91f8036
Merge branch 'main' into control-socket-adjust
blakerouse Dec 14, 2023
561e233
Merge branch 'main' into control-socket-adjust
blakerouse Dec 18, 2023
2140a3d
Fix installtion market issue on Windows.
blakerouse Dec 18, 2023
f87979f
Windows fixes.
blakerouse Dec 18, 2023
a4968ea
Cleanup comment.
blakerouse Dec 18, 2023
f485b54
More fixes.
blakerouse Dec 19, 2023
486e2aa
Merge branch 'main' into control-socket-adjust
blakerouse Dec 19, 2023
9f5033d
Only create the symlink when running as installed.
blakerouse Dec 19, 2023
0514802
Merge branch 'control-socket-adjust' into non-root-more-testing
blakerouse Dec 19, 2023
0b75d0f
Refactor unprivileged in tests to make it the default.
blakerouse Dec 19, 2023
813352a
Only linux.
blakerouse Dec 19, 2023
5ab29d5
Fix test.
blakerouse Dec 19, 2023
05a9618
Merge branch 'main' into control-socket-adjust
blakerouse Jan 3, 2024
b0fcf27
Merge branch 'main' into control-socket-adjust
blakerouse Jan 4, 2024
9da1b5c
Log control socket address for Windows.
blakerouse Jan 4, 2024
dff60d5
Use uniform log line.
blakerouse Jan 4, 2024
37fa7dd
Ensure that installed marker is installed before enrollment.
blakerouse Jan 5, 2024
4a7dec1
Add missing import on Windows.
blakerouse Jan 5, 2024
d5d010b
Fix lint.
blakerouse Jan 5, 2024
e533246
Update commit message.
blakerouse Jan 5, 2024
28a70db
Merge remote-tracking branch 'upstream/main' into control-socket-adjust
blakerouse Jan 5, 2024
97973f9
More adjustments from code review.
blakerouse Jan 5, 2024
35cb5ab
Use/support npipe:/// prefix.
blakerouse Jan 5, 2024
0a09af4
Merge branch 'control-socket-adjust' into non-root-more-testing
blakerouse Jan 5, 2024
2776ea7
Fix dial npipe transform.
blakerouse Jan 5, 2024
2ae1518
Merge branch 'control-socket-adjust' into non-root-more-testing
blakerouse Jan 5, 2024
71d32e5
Merge branch 'main' into non-root-more-testing
blakerouse Jan 5, 2024
382ed5c
More adjustments for testing.
blakerouse Jan 8, 2024
38f3369
More adjustments.
blakerouse Jan 8, 2024
85d746f
Fix IsUnprivileged.
blakerouse Jan 8, 2024
a0bd570
Fix imports.
blakerouse Jan 8, 2024
e4e6a6d
Fix cross platform issues.
blakerouse Jan 9, 2024
06169a1
Merge branch 'main' into non-root-more-testing
blakerouse Jan 9, 2024
5b35352
Merge branch 'main' into non-root-more-testing
blakerouse Jan 16, 2024
0762562
Fix basePath for install.
blakerouse Jan 17, 2024
1018fe3
Move to readable path when running in unprivileged mode.
blakerouse Jan 18, 2024
312131f
Merge branch 'main' into non-root-more-testing
blakerouse Jan 18, 2024
a5f6f64
Merge branch 'main' into non-root-more-testing
blakerouse Jan 19, 2024
7532ca2
Merge branch 'main' into non-root-more-testing
blakerouse Jan 21, 2024
7ad35e7
gosimple
blakerouse Jan 21, 2024
6c06dbc
Fix version constant.
blakerouse Jan 22, 2024
69dff17
Merge branch 'main' into non-root-more-testing
blakerouse Jan 22, 2024
6c98838
Set correct file permissions.
blakerouse Jan 22, 2024
8f9eee8
Merge branch 'main' into non-root-more-testing
blakerouse Jan 22, 2024
7a22a51
Update fleet tests.
blakerouse Jan 23, 2024
bac456f
Merge branch 'main' into non-root-more-testing
blakerouse Jan 23, 2024
13b4355
Merge branch 'main' into non-root-more-testing
blakerouse Jan 23, 2024
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: 1 addition & 1 deletion pkg/component/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ func TestToComponents(t *testing.T) {
OutputType: "elasticsearch",
ID: "endpoint-default",
InputSpec: &InputRuntimeSpec{},
Err: NewErrInputRuntimeCheckFail("No support for RHEL7 on arm64"),
Err: NewErrInputRuntimeCheckFail("Elastic Defend doesn't support RHEL7 on arm64"),
Units: []Unit{
{
ID: "endpoint-default",
Expand Down
46 changes: 37 additions & 9 deletions pkg/testing/fixture_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,25 @@ type InstallOpts struct {
Insecure bool // --insecure
NonInteractive bool // --non-interactive
ProxyURL string // --proxy-url
Unprivileged bool // --unprivileged
DelayEnroll bool // --delay-enroll

// Unprivileged by default installs the Elastic Agent as `--unprivileged` unless
// the platform being tested doesn't currently support it, or it's explicitly set
// to false.
Unprivileged *bool // --unprivileged

EnrollOpts
}

func (i InstallOpts) toCmdArgs() []string {
func (i InstallOpts) IsUnprivileged(operatingSystem string) bool {
if i.Unprivileged == nil {
// not explicitly set, default to true on Linux only (until other platforms support it)
return operatingSystem == "linux"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading:

installOpts := atesting.InstallOpts{
		NonInteractive: true,
		Force:          true,
		Unprivileged:   atesting.NewBool(false),
	}

Should we just invert the name so we don't have to use a pointer type here? I'd rather use Privileged: true as the exception and have it not exactly match the argument name then have to deal with using NewBool.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the InstallOpts will conditional change IsUnprivileged depending on the operating system that is being tested, the code needs it to be a tristate boolean.

  • Unset
  • True
  • False

In the case that it was never set it will we set to true on Linux and false on Windows (for now). If specifically set then that value is used instead. If we didn't use a tristate then the default of false versus setting false explicitly would be unknown so on Linux it would always be changed to true even on a test where false should be forced. Even if we flip this logic by renaming the variable Privileged it results in the same issue.

I also really prefer it to match the command line arguments, all other fields match, don't think we should deviant now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I don't feel that strongly about it and there's a technical reason for it to be like this. I'd be in favour of removing it if it turns out we don't need it once all the platforms support unprivileged.

}
return *i.Unprivileged
}

func (i InstallOpts) toCmdArgs(operatingSystem string) ([]string, error) {
var args []string
if i.BasePath != "" {
args = append(args, "--base-path", i.BasePath)
Expand All @@ -80,16 +92,26 @@ func (i InstallOpts) toCmdArgs() []string {
if i.ProxyURL != "" {
args = append(args, "--proxy-url="+i.ProxyURL)
}
if i.Unprivileged {
args = append(args, "--unprivileged")
}
if i.DelayEnroll {
args = append(args, "--delay-enroll")
}

unprivileged := i.IsUnprivileged(operatingSystem)
if unprivileged {
if operatingSystem != "linux" {
return nil, fmt.Errorf("--unprivileged cannot be set to true unless testing is being done on Linux")
}
args = append(args, "--unprivileged")
}

args = append(args, i.EnrollOpts.toCmdArgs()...)

return args
return args, nil
}

// NewBool returns a boolean pointer.
func NewBool(value bool) *bool {
return &value
}

// Install installs the prepared Elastic Agent binary and registers a t.Cleanup
Expand All @@ -102,9 +124,15 @@ func (i InstallOpts) toCmdArgs() []string {
func (f *Fixture) Install(ctx context.Context, installOpts *InstallOpts, opts ...process.CmdOption) ([]byte, error) {
f.t.Logf("[test %s] Inside fixture install function", f.t.Name())
installArgs := []string{"install"}
if installOpts != nil {
installArgs = append(installArgs, installOpts.toCmdArgs()...)
if installOpts == nil {
// default options when not provided
installOpts = &InstallOpts{}
}
installOptsArgs, err := installOpts.toCmdArgs(f.operatingSystem)
if err != nil {
return nil, err
}
installArgs = append(installArgs, installOptsArgs...)
out, err := f.Exec(ctx, installArgs, opts...)
if err != nil {
return out, fmt.Errorf("error running agent install command: %w", err)
Expand All @@ -125,7 +153,7 @@ func (f *Fixture) Install(ctx context.Context, installOpts *InstallOpts, opts ..
// Windows uses a fixed named pipe, that is always the same.
// It is the same even running in unprivileged mode.
socketPath = paths.WindowsControlSocketInstalledPath
} else if installOpts.Unprivileged {
} else if installOpts.IsUnprivileged(f.operatingSystem) {
// Unprivileged versions move the socket to inside the installed directory
// of the Elastic Agent.
socketPath = paths.ControlSocketFromPath(runtime.GOOS, f.workDir)
Expand Down
9 changes: 0 additions & 9 deletions pkg/testing/tools/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,3 @@ func InstallAgentForPolicy(ctx context.Context, t *testing.T,

return nil
}

// InstallStandaloneAgent force install the Elastic Agent through agentFixture.
func InstallStandaloneAgent(ctx context.Context, agentFixture *atesting.Fixture) ([]byte, error) {
installOpts := atesting.InstallOpts{
NonInteractive: true,
Force: true,
}
return agentFixture.Install(ctx, &installOpts)
}
8 changes: 5 additions & 3 deletions specs/endpoint-security.spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ inputs:
runtime:
preventions:
- condition: ${runtime.arch} == 'arm64' and ${runtime.family} == 'redhat' and ${runtime.major} == '7'
message: "No support for RHEL7 on arm64"
message: "Elastic Defend doesn't support RHEL7 on arm64"
- condition: ${user.root} == false
message: "Elastic Agent must be running as root"
message: "Elastic Defend requires Elastic Agent be running as root"
- condition: ${install.in_default} == false
message: "Elastic Defend requires Elastic Agent be installed at the default installation path"
service: &service
Expand Down Expand Up @@ -56,6 +56,8 @@ inputs:
proxied_actions: *proxied_actions
runtime:
preventions:
- condition: ${user.root} == false
message: "Elastic Defend requires Elastic Agent be running as root"
- condition: ${install.in_default} == false
message: "Elastic Defend requires Elastic Agent be installed at the default installation path"
service:
Expand All @@ -72,7 +74,7 @@ inputs:
runtime:
preventions:
- condition: ${user.root} == false
message: "Elastic Agent must be running as Administrator or SYSTEM"
message: "Elastic Defend requires Elastic Agent be running as Administrator or SYSTEM"
- condition: ${install.in_default} == false
message: "Elastic Defend requires Elastic Agent be installed at the default installation path"
service:
Expand Down
85 changes: 85 additions & 0 deletions testing/integration/endpoint_security_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"text/template"
Expand Down Expand Up @@ -184,6 +185,7 @@ func testInstallAndCLIUninstallWithEndpointSecurity(t *testing.T, info *define.I
installOpts := atesting.InstallOpts{
NonInteractive: true,
Force: true,
Unprivileged: atesting.NewBool(false),
}

policy, err := tools.InstallAgentWithPolicy(ctx, t,
Expand Down Expand Up @@ -242,6 +244,7 @@ func testInstallAndUnenrollWithEndpointSecurity(t *testing.T, info *define.Info,
installOpts := atesting.InstallOpts{
NonInteractive: true,
Force: true,
Unprivileged: atesting.NewBool(false),
}

ctx, cn := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute))
Expand Down Expand Up @@ -354,6 +357,7 @@ func testInstallWithEndpointSecurityAndRemoveEndpointIntegration(t *testing.T, i
installOpts := atesting.InstallOpts{
NonInteractive: true,
Force: true,
Unprivileged: atesting.NewBool(false),
}

ctx, cn := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute))
Expand Down Expand Up @@ -521,6 +525,7 @@ func TestEndpointSecurityNonDefaultBasePath(t *testing.T) {
installOpts := atesting.InstallOpts{
NonInteractive: true,
Force: true,
Unprivileged: atesting.NewBool(false),
BasePath: filepath.Join(paths.DefaultBasePath, "not_default"),
}
policyResp, err := tools.InstallAgentWithPolicy(ctx, t, installOpts, fixture, info.KibanaClient, createPolicyReq)
Expand Down Expand Up @@ -561,6 +566,86 @@ func TestEndpointSecurityNonDefaultBasePath(t *testing.T) {
}, 2*time.Minute, 10*time.Second, "Agent never became DEGRADED with default install message")
}

// Tests that install of Elastic Defend fails if Agent is installed unprivileged.
func TestEndpointSecurityUnprivileged(t *testing.T) {
info := define.Require(t, define.Requirements{
Group: Fleet,
Stack: &define.Stack{},
Local: false, // requires Agent installation
Sudo: true, // requires Agent installation

// Only supports Linux at the moment.
OS: []define.OS{
{
Type: define.Linux,
},
},
})

ctx, cn := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute))
defer cn()

// Get path to agent executable.
fixture, err := define.NewFixture(t, define.Version())
require.NoError(t, err)

t.Log("Enrolling the agent in Fleet")
policyUUID := uuid.New().String()
createPolicyReq := kibana.AgentPolicy{
Name: "test-policy-" + policyUUID,
Namespace: "default",
Description: "Test policy " + policyUUID,
MonitoringEnabled: []kibana.MonitoringEnabledOption{
kibana.MonitoringEnabledLogs,
kibana.MonitoringEnabledMetrics,
},
}
installOpts := atesting.InstallOpts{
NonInteractive: true,
Force: true,
Unprivileged: atesting.NewBool(true), // ensure always unprivileged
}
policyResp, err := tools.InstallAgentWithPolicy(ctx, t, installOpts, fixture, info.KibanaClient, createPolicyReq)
require.NoErrorf(t, err, "Policy Response was: %v", policyResp)

t.Log("Installing Elastic Defend")
pkgPolicyResp, err := installElasticDefendPackage(t, info, policyResp.ID)
require.NoErrorf(t, err, "Policy Response was: %v", pkgPolicyResp)

ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute))
defer cancel()

c := fixture.Client()

errMsg := "Elastic Defend requires Elastic Agent be running as root"
if runtime.GOOS == define.Windows {
errMsg = "Elastic Defend requires Elastic Agent be running as Administrator or SYSTEM"
}
require.Eventually(t, func() bool {
err := c.Connect(ctx)
if err != nil {
t.Logf("connecting client to agent: %v", err)
return false
}
defer c.Disconnect()
state, err := c.State(ctx)
if err != nil {
t.Logf("error getting the agent state: %v", err)
return false
}
t.Logf("agent state: %+v", state)
if state.State != cproto.State_DEGRADED {
return false
}
for _, c := range state.Components {
if strings.Contains(c.Message, errMsg) {
return true
}
}
return false
}, 2*time.Minute, 10*time.Second, "Agent never became DEGRADED with root/Administrator install message")
}

func agentAndEndpointAreHealthy(t *testing.T, ctx context.Context, agentClient client.Client) bool {
t.Helper()

Expand Down
7 changes: 7 additions & 0 deletions testing/integration/groups_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,16 @@ const (
// Fleet group of tests. Used for testing Elastic Agent with Fleet.
Fleet = "fleet"

// FleetPrivileged group of tests. Used for testing Elastic Agent with Fleet installed privileged.
FleetPrivileged = "fleet-privileged"

// FleetAirgapped group of tests. Used for testing Elastic Agent with Fleet and airgapped.
FleetAirgapped = "fleet-airgapped"

// FleetAirgappedPrivileged group of tests. Used for testing Elastic Agent with Fleet installed
// privileged and airgapped.
FleetAirgappedPrivileged = "fleet-airgapped-privileged"

// FQDN group of tests. Used for testing Elastic Agent with FQDN enabled.
FQDN = "fqdn"

Expand Down
Loading
Loading