Skip to content

Commit c740ced

Browse files
pkoutsovasilismergify[bot]
authored andcommitted
skip: TestUpgradeAgentWithTamperProtectedEndpoint_DEB install same version over the installed agent (#9244)
(cherry picked from commit e9cc69a) # Conflicts: # testing/integration/ess/endpoint_security_test.go
1 parent dabdaa9 commit c740ced

File tree

1 file changed

+370
-0
lines changed

1 file changed

+370
-0
lines changed

testing/integration/ess/endpoint_security_test.go

Lines changed: 370 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,376 @@ var protectionTests = []struct {
5959
},
6060
}
6161

62+
<<<<<<< HEAD
63+
=======
64+
func TestUpgradeAgentWithTamperProtectedEndpoint_DEB(t *testing.T) {
65+
info := define.Require(t, define.Requirements{
66+
Group: integration.Deb,
67+
Stack: &define.Stack{},
68+
Local: false, // requires Agent installation
69+
Sudo: true, // requires Agent installation
70+
OS: []define.OS{
71+
{
72+
Type: define.Linux,
73+
},
74+
},
75+
})
76+
77+
t.Run("Upgrade from older version to newer version", func(t *testing.T) {
78+
upgradeFromVersion, err := upgradetest.PreviousMinor()
79+
require.NoError(t, err)
80+
testTamperProtectedInstallUpgrade(t, info, "deb", upgradeFromVersion.String(), true, false)
81+
})
82+
83+
t.Run("Install same version over the installed agent", func(t *testing.T) {
84+
t.Skip("This constantly fails, so skipping until further investigation is done and a fix is implemented")
85+
testTamperProtectedInstallUpgrade(t, info, "deb", define.Version(), false, false)
86+
})
87+
88+
t.Run("Upgrade with endpoint stopped before upgrade", func(t *testing.T) {
89+
upgradeFromVersion, err := upgradetest.PreviousMinor()
90+
require.NoError(t, err)
91+
testTamperProtectedInstallUpgrade(t, info, "deb", upgradeFromVersion.String(), true, true)
92+
})
93+
94+
t.Run("Make sure unprotected upgrades are not broken", func(t *testing.T) {
95+
testUnprotectedInstallUpgrade(t, info, "deb")
96+
})
97+
}
98+
99+
func TestUpgradeAgentWithTamperProtectedEndpoint_RPM(t *testing.T) {
100+
info := define.Require(t, define.Requirements{
101+
Group: integration.RPM,
102+
Stack: &define.Stack{},
103+
Local: false, // requires Agent installation
104+
Sudo: true, // requires Agent installation
105+
OS: []define.OS{
106+
{
107+
Type: define.Linux,
108+
Distro: "rhel",
109+
},
110+
},
111+
})
112+
113+
t.Run("Upgrade from older version to newer version", func(t *testing.T) {
114+
upgradeFromVersion, err := upgradetest.PreviousMinor()
115+
require.NoError(t, err)
116+
testTamperProtectedInstallUpgrade(t, info, "rpm", upgradeFromVersion.String(), true, false)
117+
})
118+
119+
t.Run("Install same version over the installed agent", func(t *testing.T) {
120+
testTamperProtectedInstallUpgrade(t, info, "rpm", define.Version(), false, false)
121+
})
122+
123+
t.Run("Upgrade with endpoint stopped before upgrade", func(t *testing.T) {
124+
upgradeFromVersion, err := upgradetest.PreviousMinor()
125+
require.NoError(t, err)
126+
testTamperProtectedInstallUpgrade(t, info, "rpm", upgradeFromVersion.String(), true, true)
127+
})
128+
t.Run("Make sure unprotected upgrades are not broken", func(t *testing.T) {
129+
testUnprotectedInstallUpgrade(t, info, "rpm")
130+
})
131+
}
132+
133+
func getEndpointVersion(t *testing.T) string {
134+
cmd := exec.Command("sudo", "/opt/Elastic/Endpoint/elastic-endpoint", "version")
135+
output, err := cmd.CombinedOutput()
136+
require.NoError(t, err)
137+
// version: 8.18.0-SNAPSHOT, compiled: Wed Feb 19 01:00:00 2025, branch: HEAD, commit: c450b50f91507c3166b072df8557f5efd871103a
138+
endpointVersionFragment, _, found := strings.Cut(string(output), ",")
139+
require.True(t, found)
140+
141+
endpointVersion, found := strings.CutPrefix(endpointVersionFragment, "version: ")
142+
require.True(t, found)
143+
144+
return endpointVersion
145+
}
146+
147+
func getInstallCommand(ctx context.Context, packageFormat string, srcPkg string, envVars []string) (*exec.Cmd, error) {
148+
args := []string{}
149+
150+
if len(envVars) != 0 {
151+
args = append(args, envVars...)
152+
}
153+
154+
switch packageFormat {
155+
case "deb":
156+
// since the previous agent is enrolled it means that the /etc/elastic-agent/elastic-agent.yml has changed
157+
// and dpkg will ask if we want to overwrite it. Since this is a non-interactive install we need to
158+
// force to keep the existing config
159+
args = append(args, "dpkg", "--force-confold", "-i")
160+
case "rpm":
161+
args = append(args, "rpm", "-Uvh", "--force")
162+
default:
163+
return nil, fmt.Errorf("unknown package format for install command: %s", packageFormat)
164+
}
165+
args = append(args, srcPkg)
166+
return exec.CommandContext(ctx, "sudo", args...), nil
167+
}
168+
169+
func addEndpointCleanup(t *testing.T, uninstallToken string) {
170+
t.Cleanup(func() {
171+
_, err := os.Stat("/opt/Elastic/Endpoint/elastic-endpoint")
172+
if os.IsNotExist(err) {
173+
t.Log("Endpoint binary does not exist, aborting endpoint cleanup")
174+
return
175+
}
176+
177+
out, err := exec.Command("sudo", "systemctl", "stop", "ElasticEndpoint").CombinedOutput()
178+
if err != nil {
179+
t.Log(string(out))
180+
t.Logf("error while stopping Elastic Endpoint: %s", err.Error())
181+
}
182+
183+
if atesting.KeepInstalledFlag() {
184+
t.Logf("\"Keep installed\" flag is set, won't be removing endpoint. If you want to remove endpoint later on, use the following uninstall token: %s", uninstallToken)
185+
return
186+
}
187+
188+
uninstallContext, uninstallCancel := context.WithTimeout(context.Background(), 5*time.Minute)
189+
defer uninstallCancel()
190+
191+
t.Logf("Uninstalling endpoint with the following uinstall token: %s", uninstallToken)
192+
_, err = exec.CommandContext(uninstallContext, "/opt/Elastic/Endpoint/elastic-endpoint", "uninstall", "--uninstall-token", uninstallToken).CombinedOutput()
193+
if err != nil {
194+
t.Fatalf("error when cleaning up elastic-endpoint: uninstall token %s", uninstallToken)
195+
}
196+
197+
t.Log("Endpoint is successfully uninstalled by the cleanup function")
198+
})
199+
}
200+
201+
func installFirstAgent(ctx context.Context, t *testing.T, info *define.Info, isProtected bool, packageFormat string, upgradeFromVersion string) (*atesting.Fixture, string) {
202+
var fixture *atesting.Fixture
203+
var err error
204+
205+
if upgradeFromVersion == define.Version() {
206+
fixture, err = define.NewFixtureFromLocalBuild(t, define.Version(), atesting.WithPackageFormat(packageFormat))
207+
} else {
208+
fixture, err = atesting.NewFixture(
209+
t,
210+
upgradeFromVersion,
211+
atesting.WithFetcher(atesting.ArtifactFetcher()),
212+
atesting.WithPackageFormat(packageFormat),
213+
)
214+
}
215+
require.NoError(t, err, "failed to create fixture")
216+
err = fixture.Prepare(ctx)
217+
require.NoError(t, err, "failed to prepare fixture")
218+
219+
t.Log("Creating a generic policy and enrollment token")
220+
policy := createBasicPolicy()
221+
policyResp, enrollKeyResp := createPolicyAndEnrollmentToken(ctx, t, info.KibanaClient, policy)
222+
223+
t.Log("Install elastic defend")
224+
pkgPolicyResp, err := installElasticDefendPackage(t, info, policyResp.ID)
225+
require.NoErrorf(t, err, "Policy Response was: %v", pkgPolicyResp)
226+
227+
updateReq := kibana.AgentPolicyUpdateRequest{
228+
Name: policy.Name,
229+
Namespace: policy.Namespace,
230+
IsProtected: &isProtected,
231+
}
232+
233+
t.Log("Updating the policy to set \"is_protected\" to true")
234+
_, err = info.KibanaClient.UpdatePolicy(ctx, policyResp.ID, updateReq)
235+
236+
t.Log("Get the policy uninstall token")
237+
uninstallToken, err := tools.GetUninstallToken(ctx, info.KibanaClient, policyResp.ID)
238+
require.NoError(t, err, "failed to get uninstall token")
239+
240+
opts := atesting.InstallOpts{}
241+
t.Log("Install and enroll the first agent")
242+
_, err = tools.InstallAgentForPolicyWithToken(ctx, t, opts, fixture, info.KibanaClient, enrollKeyResp)
243+
require.NoError(t, err, "failed to install agent for policy with token")
244+
245+
addEndpointCleanup(t, uninstallToken)
246+
247+
agentClient := fixture.Client()
248+
err = agentClient.Connect(ctx)
249+
require.NoError(t, err, "could not connect to the initial agent")
250+
251+
require.Eventually(t,
252+
func() bool { return agentAndEndpointAreHealthy(t, ctx, agentClient) },
253+
endpointHealthPollingTimeout,
254+
time.Second,
255+
"Endpoint component or units are not healthy prior to upgrade.",
256+
)
257+
258+
t.Log("The initial installation of both the agent and endpoint are healthy")
259+
260+
return fixture, uninstallToken
261+
}
262+
263+
func testUnprotectedInstallUpgrade(
264+
t *testing.T,
265+
info *define.Info,
266+
packageFormat string,
267+
) {
268+
ctx := t.Context()
269+
270+
upgradeFromVersion, err := upgradetest.PreviousMinor()
271+
require.NoError(t, err)
272+
273+
installFirstAgent(ctx, t, info, false, packageFormat, upgradeFromVersion.String())
274+
275+
initEndpointVersion := getEndpointVersion(t)
276+
t.Logf("The initial endpoint version is %s", initEndpointVersion)
277+
278+
t.Log("Setup agent fixture with the test build")
279+
fixture, err := define.NewFixtureFromLocalBuild(t, define.Version(), atesting.WithPackageFormat(packageFormat))
280+
require.NoError(t, err)
281+
err = fixture.Prepare(ctx)
282+
require.NoError(t, err, "failed to prepare fixture")
283+
284+
t.Log("Getting source package")
285+
srcPkg, err := fixture.SrcPackage(ctx)
286+
require.NoError(t, err)
287+
288+
t.Log("Installing the second agent, upgrading from the older version")
289+
installCmd, err := getInstallCommand(ctx, fixture.PackageFormat(), srcPkg, nil)
290+
require.NoError(t, err)
291+
292+
out, err := installCmd.CombinedOutput()
293+
t.Log(string(out))
294+
require.NoError(t, err, "agent installation with package manager should not fail")
295+
296+
err = fixture.SetDebRpmClient()
297+
require.NoError(t, err, "could not set DEB/RPM client")
298+
299+
upgradedAgentClient := fixture.Client()
300+
err = upgradedAgentClient.Connect(ctx)
301+
require.NoError(t, err, "could not connect to the upgraded agent")
302+
303+
require.Eventually(t,
304+
func() bool { return agentAndEndpointAreHealthy(t, ctx, upgradedAgentClient) },
305+
endpointHealthPollingTimeout,
306+
time.Second,
307+
"Endpoint component or units are not healthy after the upgrade.",
308+
)
309+
310+
t.Log("Validate that the initial endpoint version is smaller than the upgraded version")
311+
upgradedEndpointVersion := getEndpointVersion(t)
312+
t.Logf("The upgraded endpoint version is %s", upgradedEndpointVersion)
313+
314+
startEndpointVersion, err := version.ParseVersion(initEndpointVersion)
315+
require.NoError(t, err)
316+
317+
parsedUpgradedVersion, err := version.ParseVersion(upgradedEndpointVersion)
318+
require.NoError(t, err)
319+
320+
t.Logf("Comparing start version %s to upgraded version %s", startEndpointVersion.String(), parsedUpgradedVersion.String())
321+
require.True(t, startEndpointVersion.Less(*parsedUpgradedVersion))
322+
323+
t.Log("trying to uinstall without token, not expecting error")
324+
out, err = exec.Command("sudo", "elastic-agent", "uninstall", "-f").CombinedOutput()
325+
t.Log(string(out))
326+
require.NoError(t, err)
327+
328+
_, err = exec.LookPath("elastic-agent")
329+
require.Error(t, err)
330+
331+
t.Log("successfully uninstalled agent and endpoint")
332+
}
333+
334+
func testTamperProtectedInstallUpgrade(
335+
t *testing.T,
336+
info *define.Info,
337+
packageFormat string,
338+
initialVersion string,
339+
checkVersionUpgrade bool,
340+
stopEndpointBeforeUpgrade bool,
341+
) {
342+
ctx := t.Context()
343+
344+
fixture, uninstallToken := installFirstAgent(ctx, t, info, true, packageFormat, initialVersion)
345+
346+
initEndpointVersion := getEndpointVersion(t)
347+
t.Logf("The initial endpoint version is %s", initEndpointVersion)
348+
349+
// Optionally stop the endpoint service before upgrade
350+
if stopEndpointBeforeUpgrade {
351+
t.Log("Stopping endpoint service before upgrade as requested")
352+
out, err := exec.Command("sudo", "systemctl", "stop", "ElasticEndpoint").CombinedOutput()
353+
t.Log(string(out))
354+
require.NoError(t, err, "failed to stop ElasticEndpoint before upgrade")
355+
}
356+
357+
// try to uninstall the agent without a token and assert failure
358+
out, err := exec.Command("sudo", "elastic-agent", "uninstall", "-f").CombinedOutput()
359+
t.Log(string(out))
360+
require.Error(t, err, "uninstalling agent without a token should fail because of tamper protection")
361+
t.Log("Tamper protection for the initial installation of the agent is enabled")
362+
363+
if checkVersionUpgrade {
364+
t.Log("Setup agent fixture with the test build")
365+
fixture, err = define.NewFixtureFromLocalBuild(t, define.Version(), atesting.WithPackageFormat(packageFormat))
366+
require.NoError(t, err, "failed to create agent fixture")
367+
err = fixture.Prepare(ctx)
368+
require.NoError(t, err, "failed to prepare agent fixture")
369+
}
370+
371+
t.Log("Getting source package")
372+
srcPkg, err := fixture.SrcPackage(ctx)
373+
require.NoError(t, err, "failed to get source package")
374+
375+
t.Log("Installing the second agent, upgrading from the older version")
376+
installCmd, err := getInstallCommand(ctx, fixture.PackageFormat(), srcPkg, nil)
377+
require.NoError(t, err, "failed to get install command")
378+
379+
out, err = installCmd.CombinedOutput()
380+
t.Log(string(out))
381+
require.NoError(t, err, "agent installation with package manager should not fail")
382+
383+
err = fixture.SetDebRpmClient()
384+
require.NoError(t, err, "failed to set deb/rpm client")
385+
386+
upgradedAgentClient := fixture.Client()
387+
err = upgradedAgentClient.Connect(ctx)
388+
require.NoError(t, err, "could not connect to the upgraded agent")
389+
390+
require.Eventually(t,
391+
func() bool { return agentAndEndpointAreHealthy(t, ctx, upgradedAgentClient) },
392+
endpointHealthPollingTimeout,
393+
time.Second,
394+
"Endpoint component or units are not healthy after the upgrade.",
395+
)
396+
397+
if checkVersionUpgrade {
398+
t.Log("Validate that the initial endpoint version is smaller than the upgraded version")
399+
upgradedEndpointVersion := getEndpointVersion(t)
400+
t.Logf("The upgraded endpoint version is %s", upgradedEndpointVersion)
401+
402+
startEndpointVersion, err := version.ParseVersion(initEndpointVersion)
403+
require.NoError(t, err, "failed to parse initial endpoint version")
404+
405+
parsedUpgradedVersion, err := version.ParseVersion(upgradedEndpointVersion)
406+
require.NoError(t, err, "failed to parse upgraded endpoint version")
407+
408+
t.Logf("Comparing start version %s to upgraded version %s", startEndpointVersion.String(), parsedUpgradedVersion.String())
409+
require.True(t, startEndpointVersion.Less(*parsedUpgradedVersion))
410+
}
411+
412+
// try to uninstall the agent without token and assert that endpoint is not removed
413+
t.Log("trying to uninstall without token, expecting error")
414+
out, err = exec.Command("sudo", "elastic-agent", "uninstall", "-f").CombinedOutput()
415+
t.Log(string(out))
416+
require.Error(t, err, "uninstalling agent without a token should fail because of tamper protection")
417+
t.Log("tamper protection for the upgraded agent is enabled")
418+
419+
// uninstall with the token and assert that endpoint is indeed removed.
420+
t.Log("trying to uninstall with token, not expecting any error")
421+
out, err = exec.Command("sudo", "elastic-agent", "uninstall", "-f", "--uninstall-token", uninstallToken).CombinedOutput()
422+
t.Log(string(out))
423+
require.NoError(t, err, string(out))
424+
425+
_, err = exec.LookPath("elastic-agent")
426+
require.Error(t, err, "expected elastic-agent binary to not exist in PATH after uninstall")
427+
428+
t.Log("successfully uninstalled endpoint using the uninstall token")
429+
}
430+
431+
>>>>>>> e9cc69aec (skip: TestUpgradeAgentWithTamperProtectedEndpoint_DEB install same version over the installed agent (#9244))
62432
// TestInstallAndCLIUninstallWithEndpointSecurity tests that the agent can
63433
// install and uninstall the endpoint-security service while remaining healthy.
64434
//

0 commit comments

Comments
 (0)