[Cloud Security] AWS Organization form (#162571)

This commit is contained in:
Jordan 2023-07-26 21:29:13 +03:00 committed by GitHub
parent 09ed3fc8a0
commit 4654a5244d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 20 deletions

View file

@ -6,7 +6,11 @@
*/
import React from 'react';
import { render } from '@testing-library/react';
import { CspPolicyTemplateForm } from './policy_template_form';
import {
CspPolicyTemplateForm,
AWS_ORGANIZATION_ACCOUNT,
AWS_SINGLE_ACCOUNT,
} from './policy_template_form';
import { TestProvider } from '../../test/test_provider';
import {
getMockPackageInfoCspmAWS,
@ -712,10 +716,10 @@ describe('<CspPolicyTemplateForm />', () => {
});
describe('AWS Credentials input fields', () => {
it(`renders ${CLOUDBEAT_AWS} Account Type field`, () => {
it(`renders ${CLOUDBEAT_AWS} Account Type field, AWS Organization is enabled for supported versions`, () => {
let policy = getMockPolicyAWS();
policy = getPosturePolicy(policy, CLOUDBEAT_AWS, {
'aws.account_type': { value: 'single_account' },
'aws.account_type': { value: AWS_ORGANIZATION_ACCOUNT },
});
const { getByLabelText } = render(
@ -724,13 +728,14 @@ describe('<CspPolicyTemplateForm />', () => {
expect(getByLabelText('Single Account')).toBeInTheDocument();
expect(getByLabelText('AWS Organization')).toBeInTheDocument();
expect(getByLabelText('AWS Organization')).toBeEnabled();
});
it(`${CLOUDBEAT_AWS} form displays upgrade message for unsupported versions and aws organization option is disabled`, () => {
let policy = getMockPolicyAWS();
policy = getPosturePolicy(policy, CLOUDBEAT_AWS, {
'aws.credentials.type': { value: 'cloud_formation' },
'aws.account_type': { value: 'single_account' },
'aws.account_type': { value: AWS_SINGLE_ACCOUNT },
});
const { getByText, getByLabelText } = render(
@ -743,13 +748,14 @@ describe('<CspPolicyTemplateForm />', () => {
)
).toBeInTheDocument();
expect(getByLabelText('AWS Organization')).toBeDisabled();
expect(getByLabelText('Single Account')).toBeEnabled();
});
it(`${CLOUDBEAT_AWS} form do not displays upgrade message for supported versions and aws organization option is enabled`, () => {
let policy = getMockPolicyAWS();
policy = getPosturePolicy(policy, CLOUDBEAT_AWS, {
'aws.credentials.type': { value: 'cloud_formation' },
'aws.account_type': { value: 'single_account' },
'aws.account_type': { value: AWS_ORGANIZATION_ACCOUNT },
});
const { queryByText, getByLabelText } = render(

View file

@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { memo, useCallback, useEffect, useState } from 'react';
import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
import semverCompare from 'semver/functions/compare';
import semverValid from 'semver/functions/valid';
import {
@ -79,17 +79,13 @@ interface IntegrationInfoFieldsProps {
onChange(field: string, value: string): void;
}
type AwsAccountType = 'single_account' | 'organization_account';
export const AWS_SINGLE_ACCOUNT = 'single-account';
export const AWS_ORGANIZATION_ACCOUNT = 'organization-account';
type AwsAccountType = typeof AWS_SINGLE_ACCOUNT | typeof AWS_ORGANIZATION_ACCOUNT;
const getAwsAccountTypeOptions = (isAwsOrgDisabled: boolean): CspRadioGroupProps['options'] => [
{
id: 'single_account',
label: i18n.translate('xpack.csp.fleetIntegration.awsAccountType.singleAccountLabel', {
defaultMessage: 'Single Account',
}),
},
{
id: 'organization_account',
id: AWS_ORGANIZATION_ACCOUNT,
label: i18n.translate('xpack.csp.fleetIntegration.awsAccountType.awsOrganizationLabel', {
defaultMessage: 'AWS Organization',
}),
@ -100,13 +96,19 @@ const getAwsAccountTypeOptions = (isAwsOrgDisabled: boolean): CspRadioGroupProps
})
: undefined,
},
{
id: AWS_SINGLE_ACCOUNT,
label: i18n.translate('xpack.csp.fleetIntegration.awsAccountType.singleAccountLabel', {
defaultMessage: 'Single Account',
}),
},
];
const getAwsAccountType = (
input: Extract<NewPackagePolicyPostureInput, { type: 'cloudbeat/cis_aws' }>
): AwsAccountType | undefined => input.streams[0].vars?.['aws.account_type']?.value;
const AWS_ORG_MINIMUM_PACKAGE_VERSION = '1.5.0';
const AWS_ORG_MINIMUM_PACKAGE_VERSION = '1.5.0-preview20';
const AwsAccountTypeSelect = ({
input,
@ -119,28 +121,30 @@ const AwsAccountTypeSelect = ({
updatePolicy: (updatedPolicy: NewPackagePolicy) => void;
packageInfo: PackageInfo;
}) => {
// This will disable the aws org option for any version LOWER than 1.5.0
// This will disable the aws org option for any version below 1.5.0-preview20 which introduced support for account_type. https://github.com/elastic/integrations/pull/6682
const isValidSemantic = semverValid(packageInfo.version);
const isAwsOrgDisabled = isValidSemantic
? semverCompare(packageInfo.version, AWS_ORG_MINIMUM_PACKAGE_VERSION) < 0
: true;
const awsAccountTypeOptions = getAwsAccountTypeOptions(isAwsOrgDisabled);
const awsAccountTypeOptions = useMemo(
() => getAwsAccountTypeOptions(isAwsOrgDisabled),
[isAwsOrgDisabled]
);
useEffect(() => {
if (!getAwsAccountType(input)) {
updatePolicy(
getPosturePolicy(newPolicy, input.type, {
'aws.account_type': {
value: awsAccountTypeOptions[0].id,
value: isAwsOrgDisabled ? AWS_SINGLE_ACCOUNT : AWS_ORGANIZATION_ACCOUNT,
type: 'text',
},
})
);
}
// we only wish to call this once on mount
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [input]);
return (
<>
@ -177,6 +181,28 @@ const AwsAccountTypeSelect = ({
}}
size="m"
/>
{getAwsAccountType(input) === AWS_ORGANIZATION_ACCOUNT && (
<>
<EuiSpacer size="l" />
<EuiText color="subdued" size="s">
<FormattedMessage
id="xpack.csp.fleetIntegration.awsAccountType.awsOrganizationDescription"
defaultMessage="Connect Elastic to every AWS Account (current and future) in your environment by providing Elastic with read-only (configuration) access to your AWS organization."
/>
</EuiText>
</>
)}
{getAwsAccountType(input) === AWS_SINGLE_ACCOUNT && (
<>
<EuiSpacer size="l" />
<EuiText color="subdued" size="s">
<FormattedMessage
id="xpack.csp.fleetIntegration.awsAccountType.singleAccountDescription"
defaultMessage="Deploying to a single account is suitable for an initial POC. To ensure complete coverage, it is strongly recommended to deploy CSPM at the organization-level, which automatically connects all accounts (both current and future)."
/>
</EuiText>
</>
)}
<EuiSpacer size="l" />
</>
);