Skip to content

Commit ae0d5ad

Browse files
authored
[Fleet] Avoid enabling agentless inputs by default in default deployment mode (elastic#269428)
The simplified policy API enables all inputs that are enabled by default. This simplifies configuration following the defaults included by package developers. This change slightly changes this behavior to disable agentless-only inputs when agentless is not enabled. With previous implementation the request would have returned a 400 error, with current implementation the agentless-only inputs are silently disabled. There is no way to enable agentless-only inputs in a non-agentless policy.
1 parent eee8feb commit ae0d5ad

2 files changed

Lines changed: 252 additions & 0 deletions

File tree

x-pack/platform/plugins/shared/fleet/common/services/simplified_package_policy_helper.test.ts

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,130 @@ import {
1515
generateInputId,
1616
} from './simplified_package_policy_helper';
1717

18+
/**
19+
* Minimal multi-template package fixture covering both shapes of the
20+
* deployment-mode annotation that drove https://github.com/elastic/kibana/issues/268930:
21+
*
22+
* - `otel`: a normal template with no `deployment_modes` annotation. Implicitly
23+
* allowed in both default and agentless modes.
24+
* - `apache-agentless`: a template marked agentless-only at the template level
25+
* (`deployment_modes.default.enabled = false`). Its `aws/s3` input is also
26+
* annotated `deployment_modes: ['agentless']` for good measure.
27+
* - `mixed`: a template with no template-level annotation but a per-input
28+
* annotation: `httpjson` is unannotated (allowed everywhere), `cel` is
29+
* annotated `deployment_modes: ['agentless']`.
30+
*/
31+
const multiTemplatePkgInfo = {
32+
name: 'good_v3',
33+
title: 'Good v3',
34+
version: '1.0.0',
35+
description: 'Test package with multiple policy templates',
36+
type: 'integration',
37+
format_version: '3.0.0',
38+
owner: { github: 'elastic/fleet' },
39+
policy_templates: [
40+
{
41+
name: 'otel',
42+
title: 'OTel template',
43+
description: 'Default-allowed template',
44+
inputs: [{ type: 'otelcol', title: 'OTel collector', description: '' }],
45+
multiple: true,
46+
},
47+
{
48+
name: 'apache-agentless',
49+
title: 'Apache agentless template',
50+
description: 'Agentless-only template',
51+
deployment_modes: {
52+
agentless: { enabled: true },
53+
default: { enabled: false },
54+
},
55+
inputs: [
56+
{
57+
type: 'aws/s3',
58+
title: 'AWS S3',
59+
description: '',
60+
deployment_modes: ['agentless'],
61+
},
62+
],
63+
multiple: false,
64+
},
65+
{
66+
name: 'mixed',
67+
title: 'Mixed template',
68+
description: 'Template with default-allowed and agentless-only inputs',
69+
inputs: [
70+
{ type: 'httpjson', title: 'HTTP JSON', description: '' },
71+
{
72+
type: 'cel',
73+
title: 'CEL',
74+
description: '',
75+
deployment_modes: ['agentless'],
76+
},
77+
],
78+
multiple: true,
79+
},
80+
],
81+
data_streams: [
82+
{
83+
type: 'logs',
84+
dataset: 'good_v3.otel_logs',
85+
title: 'OTel logs',
86+
release: 'ga',
87+
package: 'good_v3',
88+
ingest_pipeline: 'default',
89+
path: 'otel_logs',
90+
streams: [
91+
{
92+
input: 'otelcol',
93+
title: 'OTel logs stream',
94+
description: '',
95+
vars: [],
96+
template_path: '',
97+
},
98+
],
99+
},
100+
{
101+
type: 'logs',
102+
dataset: 'good_v3.s3_logs',
103+
title: 'S3 logs',
104+
release: 'ga',
105+
package: 'good_v3',
106+
ingest_pipeline: 'default',
107+
path: 's3_logs',
108+
streams: [
109+
{
110+
input: 'aws/s3',
111+
title: 'S3 logs stream',
112+
description: '',
113+
vars: [],
114+
template_path: '',
115+
},
116+
],
117+
},
118+
{
119+
type: 'logs',
120+
dataset: 'good_v3.cel_logs',
121+
title: 'CEL logs',
122+
release: 'ga',
123+
package: 'good_v3',
124+
ingest_pipeline: 'default',
125+
path: 'cel_logs',
126+
streams: [
127+
{
128+
input: 'cel',
129+
title: 'CEL logs stream',
130+
description: '',
131+
vars: [],
132+
template_path: '',
133+
},
134+
],
135+
},
136+
],
137+
latestVersion: '1.0.0',
138+
keepPoliciesUpToDate: false,
139+
status: 'not_installed',
140+
} as unknown as PackageInfo;
141+
18142
function getEnabledInputsAndStreams(newPackagePolicy: NewPackagePolicy) {
19143
return newPackagePolicy.inputs
20144
.filter((input) => input.enabled)
@@ -250,4 +374,120 @@ describe('toPackagePolicy', () => {
250374
expect((simplified as any).var_group_selections).toEqual(varGroupSelections);
251375
});
252376
});
377+
378+
/**
379+
* Regression tests for https://github.com/elastic/kibana/issues/268930.
380+
*
381+
* When a multi-policy-template package is used with the simplified API and
382+
* the resulting policy targets the default deployment mode, inputs that the
383+
* package spec marks as not allowed in default mode (either via a
384+
* template-level `deployment_modes.default.enabled = false` flag or a
385+
* per-input `deployment_modes: ['agentless']` annotation) must come out as
386+
* `enabled: false` so that `validateDeploymentModesForInputs` does not
387+
* reject the policy with a 400.
388+
*
389+
* Agentless mode is intentionally not subject to this filtering: that flow
390+
* already routes through an explicit `policy_template` and would not benefit.
391+
*/
392+
describe('default-mode filtering for multi-template packages', () => {
393+
it('disables inputs from agentless-only templates when no inputs are listed', () => {
394+
const res = simplifiedPackagePolicytoNewPackagePolicy(
395+
{
396+
name: 'good-v3-defaults',
397+
namespace: 'default',
398+
policy_ids: ['policy123'],
399+
},
400+
multiTemplatePkgInfo
401+
);
402+
403+
const apacheInput = res.inputs.find((input) => input.policy_template === 'apache-agentless');
404+
expect(apacheInput).toBeDefined();
405+
expect(apacheInput?.enabled).toBe(false);
406+
});
407+
408+
it('disables agentless-only inputs inside otherwise default-allowed templates', () => {
409+
const res = simplifiedPackagePolicytoNewPackagePolicy(
410+
{
411+
name: 'good-v3-defaults',
412+
namespace: 'default',
413+
policy_ids: ['policy123'],
414+
},
415+
multiTemplatePkgInfo
416+
);
417+
418+
const celInput = res.inputs.find(
419+
(input) => input.policy_template === 'mixed' && input.type === 'cel'
420+
);
421+
const httpjsonInput = res.inputs.find(
422+
(input) => input.policy_template === 'mixed' && input.type === 'httpjson'
423+
);
424+
425+
expect(celInput?.enabled).toBe(false);
426+
expect(httpjsonInput?.enabled).toBe(true);
427+
});
428+
429+
it('keeps inputs without deployment_modes annotations enabled in default mode', () => {
430+
const res = simplifiedPackagePolicytoNewPackagePolicy(
431+
{
432+
name: 'good-v3-defaults',
433+
namespace: 'default',
434+
policy_ids: ['policy123'],
435+
},
436+
multiTemplatePkgInfo
437+
);
438+
439+
const otelInput = res.inputs.find((input) => input.policy_template === 'otel');
440+
expect(otelInput?.enabled).toBe(true);
441+
});
442+
443+
it('disables streams of inputs filtered out by default-mode policy', () => {
444+
const res = simplifiedPackagePolicytoNewPackagePolicy(
445+
{
446+
name: 'good-v3-defaults',
447+
namespace: 'default',
448+
policy_ids: ['policy123'],
449+
},
450+
multiTemplatePkgInfo
451+
);
452+
453+
const apacheInput = res.inputs.find((input) => input.policy_template === 'apache-agentless');
454+
expect(apacheInput?.streams.length).toBeGreaterThan(0);
455+
expect(apacheInput?.streams.every((stream) => stream.enabled === false)).toBe(true);
456+
});
457+
458+
it('does not affect agentless policies (symmetric behavior intentionally omitted)', () => {
459+
const res = simplifiedPackagePolicytoNewPackagePolicy(
460+
{
461+
name: 'good-v3-agentless',
462+
namespace: 'default',
463+
policy_ids: ['policy123'],
464+
supports_agentless: true,
465+
},
466+
multiTemplatePkgInfo
467+
);
468+
469+
const apacheInput = res.inputs.find((input) => input.policy_template === 'apache-agentless');
470+
const celInput = res.inputs.find(
471+
(input) => input.policy_template === 'mixed' && input.type === 'cel'
472+
);
473+
expect(apacheInput?.enabled).toBe(true);
474+
expect(celInput?.enabled).toBe(true);
475+
});
476+
477+
it('is a no-op for packages without deployment_modes annotations', () => {
478+
const res = simplifiedPackagePolicytoNewPackagePolicy(
479+
{
480+
name: 'nginx-1',
481+
namespace: 'default',
482+
policy_ids: ['policy123'],
483+
},
484+
nginxPackageInfo as unknown as PackageInfo
485+
);
486+
487+
expect(getEnabledInputsAndStreams(res)).toEqual({
488+
'nginx-logfile': ['nginx.access', 'nginx.error'],
489+
'nginx-nginx/metrics': ['nginx.stubstatus'],
490+
});
491+
});
492+
});
253493
});

x-pack/platform/plugins/shared/fleet/common/services/simplified_package_policy_helper.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,18 @@ export function simplifiedPackagePolicytoNewPackagePolicy(
237237
options.experimental_data_stream_features;
238238
}
239239

240+
// Disable agentless-only inputs for non-agentless policies; the reverse is unnecessary as the agentless API always passes an explicit policy_template.
241+
if (!supportsAgentless) {
242+
packagePolicy.inputs.forEach((input) => {
243+
if (!isInputAllowedForDeploymentMode(input, 'default', packageInfo)) {
244+
input.enabled = false;
245+
input.streams.forEach((stream) => {
246+
stream.enabled = false;
247+
});
248+
}
249+
});
250+
}
251+
240252
// Build a input and streams Map to easily find package policy stream
241253
const inputMap: InputMap = new Map();
242254
packagePolicy.inputs.forEach((input) => {

0 commit comments

Comments
 (0)