Skip to content

Commit

Permalink
[Cloud Security] Azure integration manual fields (#171069)
Browse files Browse the repository at this point in the history
  • Loading branch information
JordanSh authored Nov 29, 2023
1 parent d3e9ab7 commit 3437e6d
Show file tree
Hide file tree
Showing 8 changed files with 574 additions and 28 deletions.
23 changes: 20 additions & 3 deletions x-pack/plugins/cloud_security_posture/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
VulnSeverity,
AwsCredentialsTypeFieldMap,
GcpCredentialsTypeFieldMap,
AzureCredentialsTypeFieldMap,
} from './types';

export const STATUS_ROUTE_PATH = '/internal/cloud_security_posture/status';
Expand Down Expand Up @@ -161,7 +160,25 @@ export const GCP_CREDENTIALS_TYPE_TO_FIELDS_MAP: GcpCredentialsTypeFieldMap = {
'credentials-json': ['gcp.credentials.json'],
};

export const AZURE_CREDENTIALS_TYPE_TO_FIELDS_MAP: AzureCredentialsTypeFieldMap = {
manual: [],
export const AZURE_CREDENTIALS_TYPE_TO_FIELDS_MAP = {
arm_template: [],
service_principal_with_client_secret: [
'azure.credentials.tenant_id',
'azure.credentials.client_id',
'azure.credentials.client_secret',
],
service_principal_with_client_certificate: [
'azure.credentials.tenant_id',
'azure.credentials.client_id',
'azure.credentials.client_certificate_path',
'azure.credentials.client_certificate_password',
],
service_principal_with_client_username_and_password: [
'azure.credentials.tenant_id',
'azure.credentials.client_id',
'azure.credentials.client_username',
'azure.credentials.client_password',
],
managed_identity: [],
manual: [],
};
8 changes: 7 additions & 1 deletion x-pack/plugins/cloud_security_posture/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ export type GcpCredentialsTypeFieldMap = {
[key in GcpCredentialsType]: string[];
};

export type AzureCredentialsType = 'arm_template' | 'manual';
export type AzureCredentialsType =
| 'arm_template'
| 'service_principal_with_client_secret'
| 'service_principal_with_client_certificate'
| 'service_principal_with_client_username_and_password'
| 'managed_identity'
| 'manual';

export type AzureCredentialsTypeFieldMap = {
[key in AzureCredentialsType]: string[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export const cleanupCredentials = (packagePolicy: NewPackagePolicy | UpdatePacka
const azureCredentialType: AzureCredentialsType | undefined =
enabledInput?.streams?.[0].vars?.['azure.credentials.type']?.value;

if (awsCredentialType || gcpCredentialType) {
if (awsCredentialType || gcpCredentialType || azureCredentialType) {
let credsToKeep: string[] = [' '];
let credFields: string[] = [' '];
if (awsCredentialType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,18 @@
* 2.0.
*/
import React, { useEffect } from 'react';
import { EuiLink, EuiSpacer, EuiText, EuiTitle, EuiCallOut, EuiHorizontalRule } from '@elastic/eui';
import {
EuiLink,
EuiSpacer,
EuiText,
EuiTitle,
EuiCallOut,
EuiHorizontalRule,
EuiFormRow,
EuiSelect,
EuiFieldPassword,
EuiFieldText,
} from '@elastic/eui';
import type { NewPackagePolicy } from '@kbn/fleet-plugin/public';
import { NewPackagePolicyInput, PackageInfo } from '@kbn/fleet-plugin/common';
import { FormattedMessage } from '@kbn/i18n-react';
Expand All @@ -14,8 +25,13 @@ import { i18n } from '@kbn/i18n';
import semverValid from 'semver/functions/valid';
import semverCoerce from 'semver/functions/coerce';
import semverLt from 'semver/functions/lt';
import {
AzureOptions,
getAzureCredentialsFormManualOptions,
} from './get_azure_credentials_form_options';
import { AzureCredentialsType } from '../../../../common/types';
import { SetupFormat, useAzureCredentialsForm } from './hooks';
import { NewPackagePolicyPostureInput } from '../utils';
import { getPosturePolicy, NewPackagePolicyPostureInput } from '../utils';
import { CspRadioOption, RadioGroup } from '../csp_boxed_radio_group';

interface AzureSetupInfoContentProps {
Expand Down Expand Up @@ -161,7 +177,31 @@ const ArmTemplateSetup = ({
);
};

const ManualSetup = ({ integrationLink }: { integrationLink: string }) => {
const AzureCredentialTypeSelector = ({
type,
onChange,
}: {
onChange(type: AzureCredentialsType): void;
type: AzureCredentialsType;
}) => (
<EuiFormRow
fullWidth
label={i18n.translate('xpack.csp.azureIntegration.azureCredentialTypeSelectorLabel', {
defaultMessage: 'Preferred manual method',
})}
>
<EuiSelect
fullWidth
options={getAzureCredentialsFormManualOptions()}
value={type}
onChange={(optionElem) => {
onChange(optionElem.target.value as AzureCredentialsType);
}}
/>
</EuiFormRow>
);

const TemporaryManualSetup = ({ integrationLink }: { integrationLink: string }) => {
return (
<>
<EuiText color="subdued" size="s">
Expand Down Expand Up @@ -206,6 +246,53 @@ const ManualSetup = ({ integrationLink }: { integrationLink: string }) => {
};

const AZURE_MINIMUM_PACKAGE_VERSION = '1.6.0';
const AZURE_MANUAL_FIELDS_PACKAGE_VERSION = '1.7.0';

export const getDefaultAzureManualCredentialType = (packageInfo: PackageInfo) => {
const packageSemanticVersion = semverValid(packageInfo.version);
const cleanPackageVersion = semverCoerce(packageSemanticVersion) || '';

const isPackageVersionValidForManualFields = !semverLt(
cleanPackageVersion,
AZURE_MANUAL_FIELDS_PACKAGE_VERSION
);

return isPackageVersionValidForManualFields ? 'managed_identity' : 'manual';
};

const AzureInputVarFields = ({
fields,
onChange,
}: {
fields: Array<AzureOptions[keyof AzureOptions]['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>
);

export const AzureCredentialsForm = ({
input,
Expand All @@ -216,15 +303,22 @@ export const AzureCredentialsForm = ({
setIsValid,
disabled,
}: Props) => {
const { setupFormat, onSetupFormatChange, integrationLink, hasArmTemplateUrl } =
useAzureCredentialsForm({
newPolicy,
input,
packageInfo,
onChange,
setIsValid,
updatePolicy,
});
const {
group,
fields,
azureCredentialsType,
setupFormat,
onSetupFormatChange,
integrationLink,
hasArmTemplateUrl,
} = useAzureCredentialsForm({
newPolicy,
input,
packageInfo,
onChange,
setIsValid,
updatePolicy,
});

useEffect(() => {
if (!setupFormat) {
Expand All @@ -238,6 +332,10 @@ export const AzureCredentialsForm = ({
cleanPackageVersion,
AZURE_MINIMUM_PACKAGE_VERSION
);
const isPackageVersionValidForManualFields = !semverLt(
cleanPackageVersion,
AZURE_MANUAL_FIELDS_PACKAGE_VERSION
);

useEffect(() => {
setIsValid(isPackageVersionValidForAzure);
Expand Down Expand Up @@ -280,8 +378,52 @@ export const AzureCredentialsForm = ({
{setupFormat === AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE && (
<ArmTemplateSetup hasArmTemplateUrl={hasArmTemplateUrl} input={input} />
)}
{setupFormat === AZURE_MANUAL_CREDENTIAL_TYPE && (
<ManualSetup integrationLink={integrationLink} />
{setupFormat === AZURE_MANUAL_CREDENTIAL_TYPE && !isPackageVersionValidForManualFields && (
<TemporaryManualSetup integrationLink={integrationLink} />
)}
{setupFormat === AZURE_MANUAL_CREDENTIAL_TYPE && isPackageVersionValidForManualFields && (
<>
<AzureCredentialTypeSelector
type={azureCredentialsType}
onChange={(optionId) => {
updatePolicy(
getPosturePolicy(newPolicy, input.type, {
'azure.credentials.type': { value: optionId },
})
);
}}
/>
<EuiSpacer size="m" />
<AzureInputVarFields
fields={fields}
onChange={(key, value) => {
updatePolicy(getPosturePolicy(newPolicy, input.type, { [key]: { value } }));
}}
/>
<EuiSpacer size="m" />
{group.info}
<EuiSpacer size="m" />
<EuiText color="subdued" size="s">
<FormattedMessage
id="xpack.csp.azureIntegration.manualCredentialType.documentaion"
defaultMessage="Read the {documentation} for more details"
values={{
documentation: (
<EuiLink
href={ARM_TEMPLATE_EXTERNAL_DOC_URL}
target="_blank"
rel="noopener nofollow noreferrer"
data-test-subj="externalLink"
>
{i18n.translate('xpack.csp.azureIntegration.documentationLinkText', {
defaultMessage: 'documentation',
})}
</EuiLink>
),
}}
/>
</EuiText>
</>
)}
<EuiSpacer />
</>
Expand Down
Loading

0 comments on commit 3437e6d

Please sign in to comment.