Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
cb31457
fix modal dismissing bug
opauloh Jun 20, 2023
22f4cb6
cloud formation for cspm
opauloh Jun 20, 2023
5933fc0
fixing modal dismissing bug
opauloh Jun 20, 2023
4a99c08
adding packageinfo
opauloh Jun 20, 2023
8d4e276
getCspmCloudFormationDefaultValue
opauloh Jun 20, 2023
4966ac5
post install cloud formation modal
opauloh Jun 20, 2023
3425405
added SUBMITTED_CLOUD_FORMATION to integrations form
opauloh Jun 20, 2023
7c4ff20
add reusable cloud formation guide
opauloh Jun 20, 2023
5643ebb
updating get cloud formation methods
opauloh Jun 20, 2023
bf9accd
add useCreateCloudFormationUrl hook
opauloh Jun 20, 2023
9d01907
Merge branch 'main' into cspm/add-cloud-formation
opauloh Jun 20, 2023
e83f5d3
updating tests
opauloh Jun 20, 2023
615e504
fixing translations
opauloh Jun 20, 2023
372729c
fixing condition
opauloh Jun 20, 2023
16e56e9
fixing typo
opauloh Jun 20, 2023
fc91a40
adding unit tests
opauloh Jun 20, 2023
8f8aa46
move eks to it own form
opauloh Jun 24, 2023
a2c7e66
update hook parameters
opauloh Jun 24, 2023
91b25d5
updating launch cloud formation texts
opauloh Jun 24, 2023
fcdf7c3
updating utils
opauloh Jun 24, 2023
d17aef4
adding eks form to template selector
opauloh Jun 24, 2023
edaebe2
handling validation state in form
opauloh Jun 24, 2023
6bb7d8e
splitting files
opauloh Jun 26, 2023
2acb170
updating tests
opauloh Jun 26, 2023
2b27573
Merge branch 'main' into cspm/add-cloud-formation
opauloh Jun 26, 2023
e879af2
CI fix: types
opauloh Jun 26, 2023
394e932
Ci fix: exporting type
opauloh Jun 26, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,32 @@ interface PackagePolicyListData {

const PACKAGE_POLICY_LIST_QUERY_KEY = ['packagePolicyList'];

export const usePackagePolicyList = (packageInfoName: string) => {
export const usePackagePolicyList = (packageInfoName: string, { enabled = true }) => {
const { http } = useKibana<CoreStart>().services;

const query = useQuery<PackagePolicyListData, Error>(PACKAGE_POLICY_LIST_QUERY_KEY, async () => {
try {
const res = await http.get<PackagePolicyListData>(packagePolicyRouteService.getListPath(), {
query: {
perPage: SO_SEARCH_LIMIT,
page: 1,
kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${packageInfoName}`,
},
});
const query = useQuery<PackagePolicyListData, Error>(
PACKAGE_POLICY_LIST_QUERY_KEY,
async () => {
try {
const res = await http.get<PackagePolicyListData>(packagePolicyRouteService.getListPath(), {
query: {
perPage: SO_SEARCH_LIMIT,
page: 1,
kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${packageInfoName}`,
},
});

return res;
} catch (error: any) {
throw new Error(`Failed to fetch package policy list: ${error.message}`);
return res;
} catch (error: any) {
throw new Error(`Failed to fetch package policy list: ${error.message}`);
}
},
{
enabled,
refetchOnMount: false,
refetchOnWindowFocus: false,
}
});
);

return query;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
/*
* 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 from 'react';
import {
EuiFieldText,
EuiFieldPassword,
EuiFormRow,
EuiLink,
EuiSpacer,
EuiText,
EuiTitle,
EuiSelect,
EuiCallOut,
} from '@elastic/eui';
import type { NewPackagePolicy } from '@kbn/fleet-plugin/public';
import { PackageInfo } from '@kbn/fleet-plugin/common';
import { FormattedMessage } from '@kbn/i18n-react';
import { css } from '@emotion/react';
import { i18n } from '@kbn/i18n';
import {
getAwsCredentialsFormManualOptions,
AwsCredentialsType,
AwsOptions,
DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE,
} from './get_aws_credentials_form_options';
import { RadioGroup } from '../csp_boxed_radio_group';
import {
getCspmCloudFormationDefaultValue,
getPosturePolicy,
NewPackagePolicyPostureInput,
} from '../utils';
import { SetupFormat, useAwsCredentialsForm } from './hooks';

interface AWSSetupInfoContentProps {
integrationLink: string;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we rename this? the current name suggest its a link to an integration

}

const AWSSetupInfoContent = ({ integrationLink }: AWSSetupInfoContentProps) => {
return (
<>
<EuiSpacer size="l" />
<EuiTitle size="s">
<h2>
<FormattedMessage
id="xpack.csp.awsIntegration.setupInfoContentTitle"
defaultMessage="Setup Access"
/>
</h2>
</EuiTitle>
<EuiSpacer size="l" />
<EuiText color="subdued" size="s">
<FormattedMessage
id="xpack.csp.awsIntegration.gettingStarted.setupInfoContent"
defaultMessage="Utilize AWS CloudFormation (a built-in AWS tool) or a series of manual steps to set up and deploy CSPM for assessing your AWS environment's security posture. Refer to our {gettingStartedLink} guide for details."
values={{
gettingStartedLink: (
<EuiLink href={integrationLink} target="_blank">
<FormattedMessage
id="xpack.csp.awsIntegration.gettingStarted.setupInfoContentLink"
defaultMessage="Getting Started"
/>
</EuiLink>
),
}}
/>
</EuiText>
</>
);
};

const getSetupFormatOptions = (): Array<{ id: SetupFormat; label: string }> => [
{
id: 'cloud_formation',
label: 'CloudFormation',
},
{
id: 'manual',
label: i18n.translate('xpack.csp.awsIntegration.setupFormatOptions.manual', {
defaultMessage: 'Manual',
}),
},
];

export const getDefaultAwsVarsGroup = (packageInfo: PackageInfo): AwsCredentialsType => {
const hasCloudFormationTemplate = !!getCspmCloudFormationDefaultValue(packageInfo);
if (hasCloudFormationTemplate) {
return 'cloud_formation';
}

return DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE;
};

interface Props {
newPolicy: NewPackagePolicy;
input: Extract<NewPackagePolicyPostureInput, { type: 'cloudbeat/cis_aws' }>;
updatePolicy(updatedPolicy: NewPackagePolicy): void;
packageInfo: PackageInfo;
onChange: any;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing type

setIsValid: (isValid: boolean) => void;
}

const CloudFormationSetup = ({
hasCloudFormationTemplate,
}: {
hasCloudFormationTemplate: boolean;
}) => {
if (!hasCloudFormationTemplate) {
return (
<EuiCallOut color="warning">
<FormattedMessage
id="xpack.csp.awsIntegration.cloudFormationSetupStep.notSupported"
defaultMessage="CloudFormation is not supported on the current Integration version, please upgrade your integration to the latest version to use CloudFormation"
/>
</EuiCallOut>
);
}
return (
<>
<EuiText color="subdued" size="s">
<ol
css={css`
list-style: auto;
`}
>
<li>
<FormattedMessage
id="xpack.csp.awsIntegration.cloudFormationSetupStep.login"
defaultMessage="Log in as an admin to the AWS Account you want to onboard"
/>
</li>
<li>
<FormattedMessage
id="xpack.csp.awsIntegration.cloudFormationSetupStep.save"
defaultMessage="Click the Save and continue button on the bottom right of this page"
/>
</li>
<li>
<FormattedMessage
id="xpack.csp.awsIntegration.cloudFormationSetupStep.launch"
defaultMessage="On the subsequent pop-up modal, click the Launch CloudFormation button."
/>
</li>
</ol>
</EuiText>
<EuiSpacer size="l" />
<ReadDocumentation url={CLOUD_FORMATION_EXTERNAL_DOC_URL} />
</>
);
};

const CLOUD_FORMATION_EXTERNAL_DOC_URL =
'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-whatis-howdoesitwork.html';

const Link = ({ children, url }: { children: React.ReactNode; url: string }) => (
<EuiLink
href={url}
target="_blank"
rel="noopener nofollow noreferrer"
data-test-subj="externalLink"
>
{children}
</EuiLink>
);

const ReadDocumentation = ({ url }: { url: string }) => {
return (
<EuiText color="subdued" size="s">
<FormattedMessage
id="xpack.csp.awsIntegration.cloudFormationSetupNote"
defaultMessage="Read the {documentation} for more details"
values={{
documentation: (
<Link url={url}>
{i18n.translate('xpack.csp.awsIntegration.documentationLinkText', {
defaultMessage: 'documentation',
})}
</Link>
),
}}
/>
</EuiText>
);
};

export const AwsCredentialsForm = ({
input,
newPolicy,
updatePolicy,
packageInfo,
onChange,
setIsValid,
}: Props) => {
const {
awsCredentialsType,
setupFormat,
group,
fields,
integrationLink,
hasCloudFormationTemplate,
onSetupFormatChange,
} = useAwsCredentialsForm({
newPolicy,
input,
packageInfo,
onChange,
setIsValid,
updatePolicy,
});

return (
<>
<AWSSetupInfoContent integrationLink={integrationLink} />
<EuiSpacer size="l" />
<RadioGroup
size="m"
options={getSetupFormatOptions()}
idSelected={setupFormat}
onChange={onSetupFormatChange}
/>
<EuiSpacer size="l" />
{setupFormat === 'cloud_formation' && (
<CloudFormationSetup hasCloudFormationTemplate={hasCloudFormationTemplate} />
)}
{setupFormat === 'manual' && (
<>
<AwsCredentialTypeSelector
type={awsCredentialsType}
onChange={(optionId) => {
updatePolicy(
getPosturePolicy(newPolicy, input.type, {
'aws.credentials.type': { value: optionId },
})
);
}}
/>
<EuiSpacer size="m" />
{group.info}
<EuiSpacer size="m" />
<ReadDocumentation url={integrationLink} />
<EuiSpacer size="l" />
<AwsInputVarFields
fields={fields}
onChange={(key, value) => {
updatePolicy(getPosturePolicy(newPolicy, input.type, { [key]: { value } }));
}}
/>
</>
)}
<EuiSpacer />
</>
);
};
const AwsCredentialTypeSelector = ({
type,
onChange,
}: {
onChange(type: AwsCredentialsType): void;
type: AwsCredentialsType;
}) => (
<EuiFormRow
fullWidth
label={i18n.translate('xpack.csp.awsIntegration.awsCredentialTypeSelectorLabel', {
defaultMessage: 'Preferred manual method',
})}
>
<EuiSelect
fullWidth
options={getAwsCredentialsFormManualOptions()}
value={type}
onChange={(optionElem) => {
onChange(optionElem.target.value as AwsCredentialsType);
}}
/>
</EuiFormRow>
);

const AwsInputVarFields = ({
fields,
onChange,
}: {
fields: Array<AwsOptions[keyof AwsOptions]['fields'][number] & { value: string; id: string }>;
onChange: (key: string, value: string) => void;
}) => (
<div>
{fields.map((field) => (
<EuiFormRow key={field.id} label={field.label} fullWidth hasChildLabel={true} id={field.id}>
<>
{field.type === 'password' && (
<EuiFieldPassword
id={field.id}
type="dual"
fullWidth
value={field.value || ''}
onChange={(event) => onChange(field.id, event.target.value)}
/>
)}
{field.type === 'text' && (
<EuiFieldText
id={field.id}
fullWidth
value={field.value || ''}
onChange={(event) => onChange(field.id, event.target.value)}
/>
)}
</>
</EuiFormRow>
))}
</div>
);
Loading