Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cloud Security][Fleet] Deployment instructions update for CSP Integrations #155476

Merged
merged 12 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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