Skip to content

Commit

Permalink
[Fleet] Fix add Fleet server scenarios with subfeatures enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
nchaulet committed Apr 29, 2024
1 parent 70fb22d commit 105ac55
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 21 deletions.
16 changes: 8 additions & 8 deletions x-pack/plugins/fleet/common/authz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ export const calculateAuthz = ({
? !!(fleet.agents?.all && fleet.agentPolicies?.all && fleet.settings?.all)
: fleet.all;

const writeIntegrationPolicies = subfeatureEnabled
? (fleet.agentPolicies?.all && integrations.all) ?? false
: ((fleet.all || fleet.agentPolicies?.all) ?? false) && integrations.all;
const readIntegrationPolicies = subfeatureEnabled
? (fleet.agentPolicies?.read && (integrations.all || integrations.read)) ?? false
: ((fleet.all || fleet.read || fleet.agentPolicies?.read) ?? false) &&
(integrations.all || integrations.read);

// TODO remove fallback when the feature flag is removed
const fleetAuthz: FleetAuthz['fleet'] = subfeatureEnabled
? {
Expand Down Expand Up @@ -140,14 +148,6 @@ export const calculateAuthz = ({
(fleet.all || fleet.read || fleet.setup || fleet.agentPolicies?.read) ?? false,
};

const writeIntegrationPolicies = subfeatureEnabled
? (fleet.agentPolicies?.all && integrations.all) ?? false
: ((fleet.all || fleet.agentPolicies?.all) ?? false) && integrations.all;
const readIntegrationPolicies = subfeatureEnabled
? (fleet.agentPolicies?.read && (integrations.all || integrations.read)) ?? false
: ((fleet.all || fleet.read || fleet.agentPolicies?.read) ?? false) &&
(integrations.all || integrations.read);

return {
fleet: fleetAuthz,
integrations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ import {
EuiButton,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';

import styled from 'styled-components';

import { useStartServices, useFlyoutContext } from '../../hooks';
import { useStartServices, useFlyoutContext, useCheckPermissions } from '../../hooks';
import { FleetServerMissingESPrivileges } from '../../sections/agents/components';

import { QuickStartTab } from './quick_start_tab';
import { AdvancedTab } from './advanced_tab';
Expand Down Expand Up @@ -121,6 +121,17 @@ const Header: React.FunctionComponent<{
export const FleetServerFlyout: React.FunctionComponent<Props> = ({ onClose }) => {
const { tabs, currentTab, setCurrentTab, currentTabContent } = useFleetServerTabs(onClose);

const { permissionsError, isPermissionsLoading } = useCheckPermissions();

let errorContent: React.ReactNode | undefined;
if (permissionsError === 'MISSING_FLEET_SERVER_SETUP_PRIVILEGES') {
errorContent = (
<ContentWrapper gutterSize="none" justifyContent="center" direction="column">
<FleetServerMissingESPrivileges />
</ContentWrapper>
);
}

return (
<EuiFlyout data-test-subj="fleetServerFlyout" onClose={onClose} size="m">
<EuiFlyoutHeader hasBorder aria-labelledby="FleetAddFleetServerFlyoutTitle">
Expand All @@ -132,7 +143,9 @@ export const FleetServerFlyout: React.FunctionComponent<Props> = ({ onClose }) =
/>
</EuiFlyoutHeader>

<EuiFlyoutBody>{currentTabContent}</EuiFlyoutBody>
<EuiFlyoutBody>
{isPermissionsLoading ? null : errorContent ? errorContent : currentTabContent}
</EuiFlyoutBody>
</EuiFlyout>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { FormattedMessage } from '@kbn/i18n-react';

import { MultiRowInput } from '../../../sections/settings/components/multi_row_input';

import { useLink } from '../../../hooks';
import { useAuthz, useLink } from '../../../hooks';

import type { QuickStartCreateForm } from '../hooks';
import { FleetServerHostSelect } from '../components';
Expand All @@ -53,6 +53,10 @@ const GettingStartedStepContent: React.FunctionComponent<QuickStartCreateForm> =
onClose,
}) => {
const { getHref } = useLink();
const authz = useAuthz();
const canWritePolicies =
authz.fleet.allAgentPolicies && authz.integrations.writeIntegrationPolicies;
const isDisabled = fleetServerHosts.length === 0 && !canWritePolicies;

if (status === 'success') {
return (
Expand Down Expand Up @@ -143,6 +147,7 @@ const GettingStartedStepContent: React.FunctionComponent<QuickStartCreateForm> =
defaultMessage: 'Specify name',
})}
{...inputs.nameInput.props}
disabled={isDisabled}
/>
</EuiFormRow>
<EuiFormRow
Expand All @@ -158,6 +163,7 @@ const GettingStartedStepContent: React.FunctionComponent<QuickStartCreateForm> =
<MultiRowInput
data-test-subj="fleetServerSetup.multiRowInput"
{...inputs.hostUrlsInput.props}
disabled={isDisabled}
placeholder={i18n.translate(
'xpack.fleet.fleetServerSetup.fleetServerHostsInputPlaceholder',
{
Expand Down Expand Up @@ -192,6 +198,7 @@ const GettingStartedStepContent: React.FunctionComponent<QuickStartCreateForm> =
isLoading={status === 'loading'}
onClick={submit}
data-test-subj="generateFleetServerPolicyButton"
disabled={isDisabled}
>
{fleetServerHosts.length > 0 ? (
<FormattedMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ async function checkPermissions() {
}

export const useCheckPermissions = () => {
const { data: permissionsError, status } = useQuery(
const { data: permissionsError, isInitialLoading } = useQuery(
['fetch-check-permissions'],
checkPermissions
);
return { isPermissionsLoading: status === 'loading', permissionsError };
return { isPermissionsLoading: isInitialLoading, permissionsError };
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {
import { i18n } from '@kbn/i18n';
import { FormattedRelative, FormattedMessage } from '@kbn/i18n-react';

import { policyHasFleetServer } from '../../../../../../../../common/services';

import { InstallStatus } from '../../../../../types';
import type { GetAgentPoliciesResponseItem, InMemoryPackagePolicy } from '../../../../../types';
import {
Expand Down Expand Up @@ -113,6 +115,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps

const canWriteIntegrationPolicies = useAuthz().integrations.writeIntegrationPolicies;
const canAddAgents = useAuthz().fleet.addAgents;
const canAddFleetServers = useAuthz().fleet.addFleetServers;

const packageAndAgentPolicies = useMemo((): Array<{
agentPolicy?: GetAgentPoliciesResponseItem;
Expand Down Expand Up @@ -264,12 +267,15 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
if (!agentPolicy) {
return null;
}
const canAddAgentsForPolicy = policyHasFleetServer(agentPolicy)
? canAddFleetServers
: canAddAgents;
return (
<PackagePolicyAgentsCell
agentPolicy={agentPolicy}
agentCount={agentPolicy.agents}
onAddAgent={() => setFlyoutOpenForPolicyId(agentPolicy.id)}
canAddAgents={canAddAgents}
canAddAgents={canAddAgentsForPolicy}
hasHelpPopover={showAddAgentHelpForPackagePolicyId === packagePolicy.id}
/>
);
Expand Down Expand Up @@ -301,7 +307,13 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps
},
},
],
[getHref, canWriteIntegrationPolicies, canAddAgents, showAddAgentHelpForPackagePolicyId]
[
getHref,
canWriteIntegrationPolicies,
canAddAgents,
canAddFleetServers,
showAddAgentHelpForPackagePolicyId,
]
);

const noItemsMessage = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { EuiContextMenuItem, EuiPortal } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';

import type { AgentPolicy, InMemoryPackagePolicy } from '../types';

import { useAgentPolicyRefresh, useAuthz, useLink } from '../hooks';
import { policyHasFleetServer } from '../services';

import { AgentEnrollmentFlyout } from './agent_enrollment_flyout';
import { ContextMenuActions } from './context_menu_actions';
Expand All @@ -35,8 +35,12 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{
}) => {
const [isEnrollmentFlyoutOpen, setIsEnrollmentFlyoutOpen] = useState(false);
const { getHref } = useLink();
const canWriteIntegrationPolicies = useAuthz().integrations.writeIntegrationPolicies;
const canAddAgents = useAuthz().fleet.addAgents;
const authz = useAuthz();

const canWriteIntegrationPolicies = authz.integrations.writeIntegrationPolicies;
const isFleetServerPolicy = agentPolicy && policyHasFleetServer(agentPolicy);

const canAddAgents = isFleetServerPolicy ? authz.fleet.addFleetServers : authz.fleet.addAgents;
const refreshAgentPolicy = useAgentPolicyRefresh();
const [isActionsMenuOpen, setIsActionsMenuOpen] = useState(defaultIsOpen);

Expand Down
18 changes: 16 additions & 2 deletions x-pack/plugins/fleet/server/routes/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ export const getCheckPermissionsHandler: FleetRequestHandler<
error: 'MISSING_PRIVILEGES',
} as CheckPermissionsResponse,
});
} else if (request.query.fleetServerSetup) {
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const { has_all_requested: hasAllPrivileges } = await esClient.security.hasPrivileges({
body: { cluster: ['manage_service_account'] },
});

if (!hasAllPrivileges) {
return response.ok({
body: {
success: false,
error: 'MISSING_FLEET_SERVER_SETUP_PRIVILEGES',
} as CheckPermissionsResponse,
});
}
}

return response.ok({ body: { success: true } as CheckPermissionsResponse });
Expand Down Expand Up @@ -142,7 +156,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => {
.post({
path: APP_API_ROUTES.GENERATE_SERVICE_TOKEN_PATTERN,
fleetAuthz: {
fleet: { all: true },
fleet: { allAgents: true },
},
})
.addVersion(
Expand All @@ -159,7 +173,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => {
.post({
path: APP_API_ROUTES.GENERATE_SERVICE_TOKEN_PATTERN_DEPRECATED,
fleetAuthz: {
fleet: { all: true },
fleet: { allAgents: true },
},
})
.addVersion(
Expand Down

0 comments on commit 105ac55

Please sign in to comment.