diff --git a/x-pack/plugins/fleet/common/services/index.ts b/x-pack/plugins/fleet/common/services/index.ts index 663cd27deab73..badaff8cb29d3 100644 --- a/x-pack/plugins/fleet/common/services/index.ts +++ b/x-pack/plugins/fleet/common/services/index.ts @@ -7,6 +7,7 @@ export * from './routes'; export * as AgentStatusKueryHelper from './agent_status'; +export * from './package_helpers'; export { packageToPackagePolicyInputs, packageToPackagePolicy, diff --git a/x-pack/plugins/fleet/common/services/package_helpers.test.ts b/x-pack/plugins/fleet/common/services/package_helpers.test.ts new file mode 100644 index 0000000000000..71d3a9018ed5e --- /dev/null +++ b/x-pack/plugins/fleet/common/services/package_helpers.test.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isRootPrivilegesRequired } from './package_helpers'; + +describe('isRootPrivilegesRequired', () => { + it('should return true if root privileges is required at root level', () => { + const res = isRootPrivilegesRequired({ + agent: { + privileges: { + root: true, + }, + }, + } as any); + expect(res).toBe(true); + }); + it('should return true if root privileges is required at datastreams', () => { + const res = isRootPrivilegesRequired({ + data_streams: [ + { + agent: { + privileges: { root: true }, + }, + }, + ], + } as any); + expect(res).toBe(true); + }); + + it('should return false if root privileges is not required', () => { + const res = isRootPrivilegesRequired({ + data_streams: [], + } as any); + expect(res).toBe(false); + }); +}); diff --git a/x-pack/plugins/fleet/common/services/package_helpers.ts b/x-pack/plugins/fleet/common/services/package_helpers.ts new file mode 100644 index 0000000000000..0282d218cec39 --- /dev/null +++ b/x-pack/plugins/fleet/common/services/package_helpers.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { PackageInfo } from '../types'; + +/** + * Return true if a package need Elastic Agent to be run as root/administrator + */ +export function isRootPrivilegesRequired(packageInfo: PackageInfo) { + return ( + packageInfo.agent?.privileges?.root || + packageInfo.data_streams?.some((d) => d.agent?.privileges?.root) + ); +} diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index d8400a8a61b9b..c4d4e9c763766 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -337,6 +337,7 @@ export enum RegistryDataStreamKeys { dataset_is_prefix = 'dataset_is_prefix', routing_rules = 'routing_rules', lifecycle = 'lifecycle', + agent = 'agent', } export interface RegistryDataStream { @@ -355,6 +356,12 @@ export interface RegistryDataStream { [RegistryDataStreamKeys.dataset_is_prefix]?: boolean; [RegistryDataStreamKeys.routing_rules]?: RegistryDataStreamRoutingRules[]; [RegistryDataStreamKeys.lifecycle]?: RegistryDataStreamLifecycle; + [RegistryDataStreamKeys.lifecycle]?: RegistryDataStreamLifecycle; + [RegistryDataStreamKeys.agent]?: RegistryAgent; +} + +export interface RegistryAgent { + privileges?: { root?: boolean }; } export interface RegistryElasticsearch { diff --git a/x-pack/plugins/fleet/common/types/models/package_spec.ts b/x-pack/plugins/fleet/common/types/models/package_spec.ts index d372defd72c0e..60bc051af04fc 100644 --- a/x-pack/plugins/fleet/common/types/models/package_spec.ts +++ b/x-pack/plugins/fleet/common/types/models/package_spec.ts @@ -31,6 +31,9 @@ export interface PackageSpecManifest { RegistryElasticsearch, 'index_template.settings' | 'index_template.mappings' | 'index_template.data_stream' >; + agent?: { + privileges?: { root?: boolean }; + }; asset_tags?: PackageSpecTags[]; } export interface PackageSpecTags { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx index f4e46650f2049..d0b82cf66e641 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx @@ -19,6 +19,7 @@ import { EuiFlexItem, EuiSpacer, EuiErrorBoundary, + EuiCallOut, } from '@elastic/eui'; import type { EuiStepProps } from '@elastic/eui/src/components/steps/step'; @@ -29,7 +30,7 @@ import { import { useCancelAddPackagePolicy } from '../hooks'; -import { splitPkgKey } from '../../../../../../../common/services'; +import { isRootPrivilegesRequired, splitPkgKey } from '../../../../../../../common/services'; import type { NewAgentPolicy } from '../../../../types'; import { useConfig, sendGetAgentStatus, useGetPackageInfoByKeyQuery } from '../../../../hooks'; import { @@ -447,6 +448,26 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ integration={integrationInfo?.name} /> )} + {packageInfo && isRootPrivilegesRequired(packageInfo) ? ( + <> + + } + > + + + + + ) : null} {numTransformAssets > 0 ? ( <> diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx index cd8fbebe7f2a3..517c0552f925b 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/overview/overview.tsx @@ -23,6 +23,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { isIntegrationPolicyTemplate, isPackagePrerelease, + isRootPrivilegesRequired, } from '../../../../../../../../common/services'; import { @@ -37,6 +38,7 @@ import type { PackageInfo, RegistryPolicyTemplate } from '../../../../../types'; import { Screenshots } from './screenshots'; import { Readme } from './readme'; import { Details } from './details'; +import { Requirements } from './requirements'; interface Props { packageInfo: PackageInfo; @@ -277,6 +279,8 @@ export const OverviewPage: React.FC = memo( ]; }, [h1, navItems]); + const requireAgentRootPrivileges = isRootPrivilegesRequired(packageInfo); + return ( @@ -309,6 +313,11 @@ export const OverviewPage: React.FC = memo( + {requireAgentRootPrivileges ? ( + + + + ) : null} {screenshots.length ? ( { + return ( + + + + + +

+ +

+
+
+
+
+ + + + + + + + ), + }, + ]} + /> + +
+ ); +});