Skip to content

Commit

Permalink
[Cloud Security][Fleet] Deployment instructions update for CSP Integr…
Browse files Browse the repository at this point in the history
…ations (#155476)

## Summary

This PR is for updating the Deployment instructions when trying to add
agent to CSP integration.
Previously we were using isK8sPackage
[ref](https://github.com/elastic/kibana/blob/main/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/hooks.tsx#L73-L82),
but it seems to be very dedicated for kubernetes integration and this
seems to be causing an issue when showing prompts such as the one listed
on this ticket #151701

This PR created another function that handles this for CSP integration
while not affecting how isK8sPackage affecting other integrations

Moved to different PR for another time:
- Add new prompt message for CSPM under Mac tab option

**Definition of done**

- [x] Undo `kspm` effect on showing the mentioned prompt above
- [x] Show/Select k8s deployment method when `kspm` is part of the agent
policy
- [x] Warn when `cloudbeat` doesn't support/suggest to use specific
deployment (examples: using k8s deployment when running `cspm` or
deploying `cloudbeat` on darwin)

![screen_shot_2023-04-20_at_11 35
18_pm](https://user-images.githubusercontent.com/8703149/233559874-fb38aae9-f0a1-4455-925d-8837b253c794.png)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
animehart and kibanamachine authored May 18, 2023
1 parent fbd5ec0 commit fc5a39a
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 31 deletions.
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/common/constants/epm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const FLEET_KUBERNETES_PACKAGE = 'kubernetes';
export const FLEET_UNIVERSAL_PROFILING_SYMBOLIZER_PACKAGE = 'profiler_symbolizer';
export const FLEET_CLOUD_SECURITY_POSTURE_PACKAGE = 'cloud_security_posture';
export const FLEET_CLOUD_SECURITY_POSTURE_KSPM_POLICY_TEMPLATE = 'kspm';
export const FLEET_CLOUD_SECURITY_POSTURE_CSPM_POLICY_TEMPLATE = 'cspm';
export const FLEET_CLOUD_SECURITY_POSTURE_CNVM_POLICY_TEMPLATE = 'vuln_mgmt';

export const PACKAGE_TEMPLATE_SUFFIX = '@package';
export const USER_SETTINGS_TEMPLATE_SUFFIX = '@custom';
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export {
FLEET_KUBERNETES_PACKAGE,
FLEET_CLOUD_SECURITY_POSTURE_PACKAGE,
FLEET_CLOUD_SECURITY_POSTURE_KSPM_POLICY_TEMPLATE,
FLEET_CLOUD_SECURITY_POSTURE_CSPM_POLICY_TEMPLATE,
FLEET_CLOUD_SECURITY_POSTURE_CNVM_POLICY_TEMPLATE,
FLEET_ENDPOINT_PACKAGE,
// Saved object type
AGENT_POLICY_SAVED_OBJECT_TYPE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,15 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { useState, useEffect } from 'react';
import { useState, useEffect, useMemo } from 'react';
import { i18n } from '@kbn/i18n';

import type { PackagePolicy, AgentPolicy } from '../../types';
import { sendGetOneAgentPolicy, useStartServices } from '../../hooks';
import {
FLEET_KUBERNETES_PACKAGE,
FLEET_CLOUD_SECURITY_POSTURE_PACKAGE,
FLEET_CLOUD_SECURITY_POSTURE_KSPM_POLICY_TEMPLATE,
} from '../../../common';
import { FLEET_KUBERNETES_PACKAGE, FLEET_CLOUD_SECURITY_POSTURE_PACKAGE } from '../../../common';
import { getCloudFormationTemplateUrlFromPackagePolicy } from '../../services';

import type { K8sMode } from './types';
import type { K8sMode, CloudSecurityIntegrationType } from './types';

// Packages that requires custom elastic-agent manifest
const K8S_PACKAGES = new Set([FLEET_KUBERNETES_PACKAGE]);
Expand Down Expand Up @@ -51,6 +48,7 @@ export function useAgentPolicyWithPackagePolicies(policyId?: string) {

export function useIsK8sPolicy(agentPolicy?: AgentPolicy) {
const [isK8s, setIsK8s] = useState<K8sMode>('IS_LOADING');

useEffect(() => {
async function checkifK8s() {
if (!agentPolicy) {
Expand All @@ -64,20 +62,44 @@ export function useIsK8sPolicy(agentPolicy?: AgentPolicy) {
: 'IS_NOT_KUBERNETES'
);
}

checkifK8s();
}, [agentPolicy]);

return { isK8s };
}

export function useCloudSecurityIntegration(agentPolicy?: AgentPolicy) {
const cloudSecurityIntegration = useMemo(() => {
if (!agentPolicy) {
return undefined;
}

const integrationType = getCloudSecurityIntegrationTypeFromPackagePolicy(agentPolicy);
const cloudformationUrl = getCloudFormationTemplateUrlFromPackagePolicy(agentPolicy);

return {
integrationType,
cloudformationUrl,
};
}, [agentPolicy]);

return { cloudSecurityIntegration };
}

const isK8sPackage = (pkg: PackagePolicy) => {
const name = pkg.package?.name as string;
if (name === FLEET_CLOUD_SECURITY_POSTURE_PACKAGE) {
return pkg.inputs.some(
(input) =>
input.enabled && input.policy_template === FLEET_CLOUD_SECURITY_POSTURE_KSPM_POLICY_TEMPLATE
);
}

return K8S_PACKAGES.has(name);
};

const getCloudSecurityIntegrationTypeFromPackagePolicy = (
agentPolicy: AgentPolicy
): CloudSecurityIntegrationType | undefined => {
const packagePolicy = agentPolicy?.package_policies?.find(
(input) => input.package?.name === FLEET_CLOUD_SECURITY_POSTURE_PACKAGE
);
if (!packagePolicy) return undefined;
return packagePolicy?.inputs?.find((input) => input.enabled)
?.policy_template as CloudSecurityIntegrationType;
};
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ import { Instructions } from './instructions';
import { MissingFleetServerHostCallout } from './missing_fleet_server_host_callout';
import type { FlyOutProps, SelectionType, FlyoutMode } from './types';

import { useIsK8sPolicy, useAgentPolicyWithPackagePolicies } from './hooks';
import {
useIsK8sPolicy,
useAgentPolicyWithPackagePolicies,
useCloudSecurityIntegration,
} from './hooks';

export * from './agent_policy_selection';
export * from './agent_policy_select_create';
Expand Down Expand Up @@ -99,7 +103,8 @@ export const AgentEnrollmentFlyout: React.FunctionComponent<FlyOutProps> = ({
}
}, [selectedPolicy, isFleetServerPolicySelected]);

const { isK8s } = useIsK8sPolicy(selectedPolicy ? selectedPolicy : undefined);
const { isK8s } = useIsK8sPolicy(selectedPolicy ?? undefined);
const { cloudSecurityIntegration } = useCloudSecurityIntegration(selectedPolicy ?? undefined);

return (
<EuiFlyout data-test-subj="agentEnrollmentFlyout" onClose={onClose} size="m">
Expand Down Expand Up @@ -197,6 +202,7 @@ export const AgentEnrollmentFlyout: React.FunctionComponent<FlyOutProps> = ({
agentPolicies={agentPolicies}
isFleetServerPolicySelected={isFleetServerPolicySelected}
isK8s={isK8s}
cloudSecurityIntegration={cloudSecurityIntegration}
refreshAgentPolicies={refreshAgentPolicies}
isLoadingAgentPolicies={isLoadingAgentPolicies}
mode={mode}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ import { FleetServerRequirementPage } from '../../applications/fleet/sections/ag
import { AGENTS_PREFIX, FLEET_SERVER_PACKAGE, SO_SEARCH_LIMIT } from '../../constants';
import { useFleetServerUnhealthy } from '../../applications/fleet/sections/agents/hooks/use_fleet_server_unhealthy';
import { Loading } from '..';
import {
getCloudFormationTemplateUrlFromPackagePolicy,
policyHasFleetServer,
} from '../../services';
import { policyHasFleetServer } from '../../services';
import { AdvancedTab } from '../../applications/fleet/components/fleet_server_instructions/advanced_tab';

import type { InstructionProps } from './types';
Expand Down Expand Up @@ -82,20 +79,16 @@ export const Instructions = (props: InstructionProps) => {
isFleetServerUnhealthy ||
(fleetStatus.missingRequirements ?? []).some((r) => r === FLEET_SERVER_PACKAGE));

const cloudFormationTemplateUrl = getCloudFormationTemplateUrlFromPackagePolicy(
props.selectedPolicy
);

useEffect(() => {
// If we have a cloudFormationTemplateUrl, we want to hide the selection type
if (cloudFormationTemplateUrl) {
if (props.cloudSecurityIntegration?.cloudformationUrl) {
setSelectionType(undefined);
} else if (!isIntegrationFlow && showAgentEnrollment) {
setSelectionType('radio');
} else {
setSelectionType('tabs');
}
}, [isIntegrationFlow, showAgentEnrollment, setSelectionType, cloudFormationTemplateUrl]);
}, [isIntegrationFlow, showAgentEnrollment, setSelectionType, props.cloudSecurityIntegration]);

if (isLoadingAgents || isLoadingAgentPolicies || isLoadingFleetServerHealth)
return <Loading size="l" />;
Expand Down Expand Up @@ -124,7 +117,10 @@ export const Instructions = (props: InstructionProps) => {
{isFleetServerPolicySelected ? (
<AdvancedTab selectedPolicyId={props.selectedPolicy?.id} onClose={() => undefined} />
) : (
<ManagedSteps {...props} cloudFormationTemplateUrl={cloudFormationTemplateUrl} />
<ManagedSteps
{...props}
cloudFormationTemplateUrl={props.cloudSecurityIntegration?.cloudformationUrl}
/>
)}
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const StandaloneSteps: React.FunctionComponent<InstructionProps> = ({
selectedApiKeyId,
setSelectedAPIKeyId,
isK8s,
cloudSecurityIntegration,
}) => {
const core = useStartServices();
const { notifications } = core;
Expand Down Expand Up @@ -156,13 +157,15 @@ export const StandaloneSteps: React.FunctionComponent<InstructionProps> = ({
InstallStandaloneAgentStep({
installCommand: standaloneInstallCommands,
isK8s,
cloudSecurityIntegration,
})
);

return steps;
}, [
kibanaVersion,
isK8s,
cloudSecurityIntegration,
agentPolicy,
selectedPolicy,
agentPolicies,
Expand Down Expand Up @@ -195,6 +198,7 @@ export const ManagedSteps: React.FunctionComponent<InstructionProps> = ({
selectionType,
onClickViewAgents,
isK8s,
cloudSecurityIntegration,
installedPackagePolicy,
cloudFormationTemplateUrl,
}) => {
Expand Down Expand Up @@ -259,6 +263,7 @@ export const ManagedSteps: React.FunctionComponent<InstructionProps> = ({
apiKeyData,
selectedApiKeyId,
isK8s,
cloudSecurityIntegration,
enrollToken,
})
);
Expand Down Expand Up @@ -297,6 +302,7 @@ export const ManagedSteps: React.FunctionComponent<InstructionProps> = ({
refreshAgentPolicies,
selectionType,
isK8s,
cloudSecurityIntegration,
installManagedCommands,
apiKeyData,
enrolledAgentIds,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ import type { GetOneEnrollmentAPIKeyResponse } from '../../../../common/types/re
import { InstallSection } from '../../enrollment_instructions/install_section';
import type { CommandsByPlatform } from '../../../applications/fleet/components/fleet_server_instructions/utils/install_command_utils';

import type { K8sMode } from '../types';
import type { K8sMode, CloudSecurityIntegration } from '../types';

export const InstallManagedAgentStep = ({
installCommand,
selectedApiKeyId,
apiKeyData,
isK8s,
cloudSecurityIntegration,
enrollToken,
isComplete,
fullCopyButton,
Expand All @@ -31,6 +32,7 @@ export const InstallManagedAgentStep = ({
selectedApiKeyId?: string;
apiKeyData?: GetOneEnrollmentAPIKeyResponse | null;
isK8s?: K8sMode;
cloudSecurityIntegration?: CloudSecurityIntegration | undefined;
enrollToken?: string;
installCommand: CommandsByPlatform;
isComplete?: boolean;
Expand All @@ -49,6 +51,7 @@ export const InstallManagedAgentStep = ({
<InstallSection
installCommand={installCommand}
isK8s={isK8s}
cloudSecurityIntegration={cloudSecurityIntegration}
enrollToken={enrollToken}
onCopy={onCopy}
fullCopyButton={fullCopyButton}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@ import type { CommandsByPlatform } from '../../../applications/fleet/components/

import { InstallSection } from '../../enrollment_instructions/install_section';

import type { K8sMode } from '../types';
import type { CloudSecurityIntegration, K8sMode } from '../types';

export const InstallStandaloneAgentStep = ({
installCommand,
isK8s,
cloudSecurityIntegration,
isComplete,
fullCopyButton,
onCopy,
}: {
installCommand: CommandsByPlatform;
isK8s?: K8sMode;
cloudSecurityIntegration?: CloudSecurityIntegration | undefined;
isComplete?: boolean;
fullCopyButton?: boolean;
onCopy?: () => void;
Expand All @@ -37,6 +39,7 @@ export const InstallStandaloneAgentStep = ({
<InstallSection
installCommand={installCommand}
isK8s={isK8s}
cloudSecurityIntegration={cloudSecurityIntegration}
onCopy={onCopy}
fullCopyButton={fullCopyButton}
isManaged={false}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,17 @@ export type K8sMode =
| 'IS_KUBERNETES'
| 'IS_NOT_KUBERNETES'
| 'IS_KUBERNETES_MULTIPAGE';

export type CloudSecurityIntegrationType = 'kspm' | 'vuln_mgmt' | 'cspm';

export type FlyoutMode = 'managed' | 'standalone';
export type SelectionType = 'tabs' | 'radio' | undefined;

export interface CloudSecurityIntegration {
integrationType: CloudSecurityIntegrationType | undefined;
cloudformationUrl: string | undefined;
}

export interface BaseProps {
/**
* The user selected policy to be used. If this value is `undefined` a value must be provided for `agentPolicies`.
Expand All @@ -27,6 +35,8 @@ export interface BaseProps {

isK8s?: K8sMode;

cloudSecurityIntegration?: CloudSecurityIntegration;

/**
* There is a step in the agent enrollment process that allows users to see the data from an integration represented in the UI
* in some way. This is an area for consumers to render a button and text explaining how data can be viewed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import type { CommandsByPlatform } from '../../applications/fleet/components/fle

import { InstallationMessage } from '../agent_enrollment_flyout/installation_message';

import type { K8sMode } from '../agent_enrollment_flyout/types';
import type { K8sMode, CloudSecurityIntegration } from '../agent_enrollment_flyout/types';
import { PlatformSelector } from '../platform_selector';

interface Props {
installCommand: CommandsByPlatform;
isK8s: K8sMode | undefined;
cloudSecurityIntegration: CloudSecurityIntegration | undefined;
enrollToken?: string;
fullCopyButton?: boolean;
isManaged?: boolean;
Expand All @@ -26,6 +27,7 @@ interface Props {
export const InstallSection: React.FunctionComponent<Props> = ({
installCommand,
isK8s,
cloudSecurityIntegration,
enrollToken,
fullCopyButton = false,
isManaged = true,
Expand All @@ -44,6 +46,7 @@ export const InstallSection: React.FunctionComponent<Props> = ({
linuxRpmCommand={installCommand.rpm}
k8sCommand={installCommand.kubernetes}
hasK8sIntegration={isK8s === 'IS_KUBERNETES' || isK8s === 'IS_KUBERNETES_MULTIPAGE'}
cloudSecurityIntegration={cloudSecurityIntegration}
hasK8sIntegrationMultiPage={isK8s === 'IS_KUBERNETES_MULTIPAGE'}
isManaged={isManaged}
enrollToken={enrollToken}
Expand Down
Loading

0 comments on commit fc5a39a

Please sign in to comment.