Skip to content

Commit

Permalink
[Fleet] Display package root requirements (#170478)
Browse files Browse the repository at this point in the history
  • Loading branch information
nchaulet authored Nov 7, 2023
1 parent 9b8f0fa commit 34bdce9
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 1 deletion.
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/common/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

export * from './routes';
export * as AgentStatusKueryHelper from './agent_status';
export * from './package_helpers';
export {
packageToPackagePolicyInputs,
packageToPackagePolicy,
Expand Down
40 changes: 40 additions & 0 deletions x-pack/plugins/fleet/common/services/package_helpers.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
18 changes: 18 additions & 0 deletions x-pack/plugins/fleet/common/services/package_helpers.ts
Original file line number Diff line number Diff line change
@@ -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)
);
}
7 changes: 7 additions & 0 deletions x-pack/plugins/fleet/common/types/models/epm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ export enum RegistryDataStreamKeys {
dataset_is_prefix = 'dataset_is_prefix',
routing_rules = 'routing_rules',
lifecycle = 'lifecycle',
agent = 'agent',
}

export interface RegistryDataStream {
Expand All @@ -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 {
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/fleet/common/types/models/package_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
EuiFlexItem,
EuiSpacer,
EuiErrorBoundary,
EuiCallOut,
} from '@elastic/eui';
import type { EuiStepProps } from '@elastic/eui/src/components/steps/step';

Expand All @@ -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 {
Expand Down Expand Up @@ -447,6 +448,26 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({
integration={integrationInfo?.name}
/>
)}
{packageInfo && isRootPrivilegesRequired(packageInfo) ? (
<>
<EuiCallOut
size="s"
color="warning"
title={
<FormattedMessage
id="xpack.fleet.createPackagePolicy.requireRootCalloutTitle"
defaultMessage="Requires root privileges"
/>
}
>
<FormattedMessage
id="xpack.fleet.createPackagePolicy.requireRootCalloutDescription"
defaultMessage="Elastic Agent needs to be run with root/administrator privileges for this integration."
/>
</EuiCallOut>
<EuiSpacer size="m" />
</>
) : null}
{numTransformAssets > 0 ? (
<>
<TransformInstallWithCurrentUserPermissionCallout count={numTransformAssets} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import {
isIntegrationPolicyTemplate,
isPackagePrerelease,
isRootPrivilegesRequired,
} from '../../../../../../../../common/services';

import {
Expand All @@ -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;
Expand Down Expand Up @@ -277,6 +279,8 @@ export const OverviewPage: React.FC<Props> = memo(
];
}, [h1, navItems]);

const requireAgentRootPrivileges = isRootPrivilegesRequired(packageInfo);

return (
<EuiFlexGroup alignItems="flexStart" data-test-subj="epm.OverviewPage">
<SideBar grow={2}>
Expand Down Expand Up @@ -309,6 +313,11 @@ export const OverviewPage: React.FC<Props> = memo(
</EuiFlexItem>
<EuiFlexItem grow={3}>
<EuiFlexGroup direction="column" gutterSize="l" alignItems="flexStart">
{requireAgentRootPrivileges ? (
<EuiFlexItem>
<Requirements />
</EuiFlexItem>
) : null}
{screenshots.length ? (
<EuiFlexItem>
<Screenshots
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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 React, { memo } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiFlexGroup, EuiFlexItem, EuiText, EuiDescriptionList, EuiToolTip } from '@elastic/eui';

export const Requirements: React.FC = memo(() => {
return (
<EuiFlexGroup direction="column" gutterSize="s">
<EuiFlexItem>
<EuiFlexGroup
direction="row"
alignItems="center"
gutterSize="xs"
justifyContent="spaceBetween"
>
<EuiFlexItem grow={false}>
<EuiText>
<h4>
<FormattedMessage
id="xpack.fleet.epm.requirementsTitle"
defaultMessage="Requirements"
/>
</h4>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>

<EuiFlexItem>
<EuiDescriptionList
type="column"
compressed
listItems={[
{
title: i18n.translate('xpack.fleet.epm.requirements.permissionLabel', {
defaultMessage: 'Permissions',
}),
description: (
<>
<EuiToolTip
content={i18n.translate(
'xpack.fleet.epm.requirements.permissionRequireRootTooltip',
{
defaultMessage:
'Elastic agent needs to be run with root or administor privileges',
}
)}
>
<FormattedMessage
id="xpack.fleet.epm.requirements.permissionRequireRootMessage"
defaultMessage="root privileges"
/>
</EuiToolTip>
</>
),
},
]}
/>
</EuiFlexItem>
</EuiFlexGroup>
);
});

0 comments on commit 34bdce9

Please sign in to comment.