Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a33e353
initial groundwork for cloud_defend footprint in security manage page
mitodrummer Feb 8, 2023
06b9a0d
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 8, 2023
c417d41
boilerplate fun
mitodrummer Feb 10, 2023
bd960c9
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 10, 2023
494f0d8
policies page working, empty states working, docs link and add/edit l…
mitodrummer Feb 15, 2023
eb073da
manage link moved into same category as csp (looks cleaner). logo and…
mitodrummer Feb 16, 2023
f430b98
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 16, 2023
2d83259
frontend unit tests passing
mitodrummer Feb 16, 2023
218556b
policies and status route tests passing.
mitodrummer Feb 16, 2023
4d22933
backend tests and subscription check code working
mitodrummer Feb 16, 2023
4d54430
cleanup
mitodrummer Feb 16, 2023
3bc725e
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Feb 16, 2023
277c441
fixed type errors
mitodrummer Feb 20, 2023
052076d
Merge branch 'cloud_defend_manage_ui_bootstrap' of github.com:mitodru…
mitodrummer Feb 20, 2023
38f7056
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 20, 2023
3cde78a
type check fixes
mitodrummer Feb 20, 2023
f94a54f
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 21, 2023
2c08fdd
fixed dep
mitodrummer Feb 21, 2023
7df9a71
cleanup
mitodrummer Feb 21, 2023
daeca16
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Feb 21, 2023
d9223e6
further cleanup
mitodrummer Feb 21, 2023
2fcc52a
Merge branch 'cloud_defend_manage_ui_bootstrap' of github.com:mitodru…
mitodrummer Feb 21, 2023
a9ae9c5
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 21, 2023
f0ad5f4
removed commented out code
mitodrummer Feb 23, 2023
0f22123
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 23, 2023
b57dc22
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 27, 2023
6a867c0
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 27, 2023
ceb506f
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 27, 2023
7e67cc9
tsconfig fix
mitodrummer Feb 27, 2023
9c54ebc
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 27, 2023
7aaf635
tsconfig fix
mitodrummer Feb 28, 2023
ac60975
Merge branch 'cloud_defend_manage_ui_bootstrap' of github.com:mitodru…
mitodrummer Feb 28, 2023
fe3ec04
clean up, per PR comments
mitodrummer Feb 28, 2023
7b7c606
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 28, 2023
d196205
Merge branch 'main' into cloud_defend_manage_ui_bootstrap
mitodrummer Feb 28, 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
5 changes: 4 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -1158,12 +1158,15 @@ x-pack/test/threat_intelligence_cypress @elastic/protections-experience
/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions @elastic/security-defend-workflows
/x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions @elastic/security-defend-workflows

# Cloud Defend
/x-pack/plugins/cloud_defend/ @elastic/sec-cloudnative-integrations
/x-pack/plugins/security_solution/public/cloud_defend @elastic/sec-cloudnative-integrations

# Cloud Security Posture
/x-pack/plugins/security_solution/public/cloud_security_posture @elastic/kibana-cloud-security-posture
/x-pack/test/api_integration/apis/cloud_security_posture/ @elastic/kibana-cloud-security-posture
/x-pack/test/cloud_security_posture_functional/ @elastic/kibana-cloud-security-posture


# Security Solution onboarding tour
/x-pack/plugins/security_solution/public/common/components/guided_onboarding @elastic/security-threat-hunting-explore
/x-pack/plugins/security_solution/cypress/e2e/guided_onboarding @elastic/security-threat-hunting-explore
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/cloud_defend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ responses:

```
node scripts/type_check.js --project x-pack/plugins/cloud_defend/tsconfig.json
node scripts/eslint.js x-pack/plugins/cloud_defend
yarn test:jest x-pack/plugins/cloud_defend
```

Expand Down
9 changes: 8 additions & 1 deletion x-pack/plugins/cloud_defend/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common';

export const PLUGIN_ID = 'cloudDefend';
export const PLUGIN_NAME = 'cloudDefend';
export const PLUGIN_NAME = 'Cloud Defend';
export const INTEGRATION_PACKAGE_NAME = 'cloud_defend';
export const INPUT_CONTROL = 'cloud_defend/control';
export const ALERTS_DATASET = 'cloud_defend.alerts';
export const ALERTS_INDEX_PATTERN = 'cloud_defend.alerts*';

export const POLICIES_ROUTE_PATH = '/internal/cloud_defend/policies';
export const STATUS_ROUTE_PATH = '/internal/cloud_defend/status';

export const CLOUD_DEFEND_FLEET_PACKAGE_KUERY = `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:${INTEGRATION_PACKAGE_NAME}`;
62 changes: 62 additions & 0 deletions x-pack/plugins/cloud_defend/common/schemas/policy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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 { type TypeOf, schema } from '@kbn/config-schema';

export const DEFAULT_POLICIES_PER_PAGE = 20;
export const POLICIES_PACKAGE_POLICY_PREFIX = 'package_policy.';
export const policiesQueryParamsSchema = schema.object({
/**
* The page of objects to return
*/
page: schema.number({ defaultValue: 1, min: 1 }),
/**
* The number of objects to include in each page
*/
per_page: schema.number({ defaultValue: DEFAULT_POLICIES_PER_PAGE, min: 0 }),
/**
* Once of PackagePolicy fields for sorting the found objects.
* Sortable fields:
* - package_policy.id
* - package_policy.name
* - package_policy.policy_id
* - package_policy.namespace
* - package_policy.updated_at
* - package_policy.updated_by
* - package_policy.created_at
* - package_policy.created_by,
* - package_policy.package.name
* - package_policy.package.title
* - package_policy.package.version
*/
sort_field: schema.oneOf(
[
schema.literal('package_policy.id'),
schema.literal('package_policy.name'),
schema.literal('package_policy.policy_id'),
schema.literal('package_policy.namespace'),
schema.literal('package_policy.updated_at'),
schema.literal('package_policy.updated_by'),
schema.literal('package_policy.created_at'),
schema.literal('package_policy.created_by'),
schema.literal('package_policy.package.name'),
schema.literal('package_policy.package.title'),
],
{ defaultValue: 'package_policy.name' }
),
/**
* The order to sort by
*/
sort_order: schema.oneOf([schema.literal('asc'), schema.literal('desc')], {
defaultValue: 'asc',
}),
/**
* Policy filter
*/
policy_name: schema.maybe(schema.string()),
});

export type PoliciesQueryParams = TypeOf<typeof policiesQueryParamsSchema>;
54 changes: 54 additions & 0 deletions x-pack/plugins/cloud_defend/common/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* 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 type { PackagePolicy, AgentPolicy } from '@kbn/fleet-plugin/common';

export type IndexStatus =
| 'not-empty' // Index contains documents
| 'empty' // Index doesn't contain documents (or doesn't exist)
| 'unprivileged'; // User doesn't have access to query the index

export type CloudDefendStatusCode =
| 'indexed' // alerts index exists and has results
| 'indexing' // index timeout was not surpassed since installation, assumes data is being indexed
| 'unprivileged' // user lacks privileges for the alerts index
| 'index-timeout' // index timeout was surpassed since installation
| 'not-deployed' // no healthy agents were deployed
| 'not-installed'; // number of installed integrations is 0;

export interface IndexDetails {
index: string;
status: IndexStatus;
}

interface BaseCloudDefendSetupStatus {
indicesDetails: IndexDetails[];
latestPackageVersion: string;
installedPackagePolicies: number;
healthyAgents: number;
}

interface CloudDefendSetupNotInstalledStatus extends BaseCloudDefendSetupStatus {
status: Extract<CloudDefendStatusCode, 'not-installed'>;
}

interface CloudDefendSetupInstalledStatus extends BaseCloudDefendSetupStatus {
status: Exclude<CloudDefendStatusCode, 'not-installed'>;
// status can be `indexed` but return with undefined package information in this case
installedPackageVersion: string | undefined;
}

export type CloudDefendSetupStatus =
| CloudDefendSetupInstalledStatus
| CloudDefendSetupNotInstalledStatus;

export type AgentPolicyStatus = Pick<AgentPolicy, 'id' | 'name'> & { agents: number };

export interface CloudDefendPolicy {
package_policy: PackagePolicy;
agent_policy: AgentPolicyStatus;
}
35 changes: 35 additions & 0 deletions x-pack/plugins/cloud_defend/common/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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 { Truthy } from 'lodash';
import { INTEGRATION_PACKAGE_NAME } from '../constants';

/**
* @example
* declare const foo: Array<string | undefined | null>
* foo.filter(isNonNullable) // foo is Array<string>
*/
export const isNonNullable = <T extends unknown>(v: T): v is NonNullable<T> =>
v !== null && v !== undefined;

export const truthy = <T>(value: T): value is Truthy<T> => !!value;

export const extractErrorMessage = (e: unknown, defaultMessage = 'Unknown Error'): string => {
if (e instanceof Error) return e.message;
if (typeof e === 'string') return e;

return defaultMessage; // TODO: i18n
};

export function assert(condition: any, msg?: string): asserts condition {
if (!condition) {
throw new Error(msg);
}
}

export const isCloudDefendPackage = (packageName?: string) =>
packageName === INTEGRATION_PACKAGE_NAME;
44 changes: 44 additions & 0 deletions x-pack/plugins/cloud_defend/common/utils/subscription.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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 type { LicenseType } from '@kbn/licensing-plugin/common/types';
import { isSubscriptionAllowed } from './subscription';
import { licenseMock } from '@kbn/licensing-plugin/common/licensing.mock';

const ON_PREM_ALLOWED_LICENSES: readonly LicenseType[] = ['enterprise', 'trial'];
const ON_PREM_NOT_ALLOWED_LICENSES: readonly LicenseType[] = ['basic', 'gold', 'platinum'];
const ALL_LICENSE_TYPES: readonly LicenseType[] = [
'standard',
...ON_PREM_NOT_ALLOWED_LICENSES,
...ON_PREM_NOT_ALLOWED_LICENSES,
];

describe('isSubscriptionAllowed', () => {
it('should allow any cloud subscription', () => {
const isCloudEnabled = true;
ALL_LICENSE_TYPES.forEach((licenseType) => {
const license = licenseMock.createLicense({ license: { type: licenseType } });
expect(isSubscriptionAllowed(isCloudEnabled, license)).toBeTruthy();
});
});

it('should allow enterprise and trial licenses for on-prem', () => {
const isCloudEnabled = false;
ON_PREM_ALLOWED_LICENSES.forEach((licenseType) => {
const license = licenseMock.createLicense({ license: { type: licenseType } });
expect(isSubscriptionAllowed(isCloudEnabled, license)).toBeTruthy();
});
});

it('should not allow enterprise and trial licenses for on-prem', () => {
const isCloudEnabled = false;
ON_PREM_NOT_ALLOWED_LICENSES.forEach((licenseType) => {
const license = licenseMock.createLicense({ license: { type: licenseType } });
expect(isSubscriptionAllowed(isCloudEnabled, license)).toBeFalsy();
});
});
});
24 changes: 24 additions & 0 deletions x-pack/plugins/cloud_defend/common/utils/subscription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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 type { ILicense, LicenseType } from '@kbn/licensing-plugin/common/types';
import { PLUGIN_NAME } from '../constants';

const MINIMUM_NON_CLOUD_LICENSE_TYPE: LicenseType = 'enterprise';

export const isSubscriptionAllowed = (isCloudEnabled?: boolean, license?: ILicense): boolean => {
if (isCloudEnabled) {
return true;
}

if (!license) {
return false;
}

const licenseCheck = license.check(PLUGIN_NAME, MINIMUM_NON_CLOUD_LICENSE_TYPE);
return licenseCheck.state === 'valid';
};
23 changes: 20 additions & 3 deletions x-pack/plugins/cloud_defend/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,31 @@
"type": "plugin",
"id": "@kbn/cloud-defend-plugin",
"owner": "@elastic/sec-cloudnative-integrations",
"description": "Defend for Containers",
"description": "Defend for containers (D4C)",
"plugin": {
"id": "cloudDefend",
"server": false,
"server": true,
"browser": true,
"configPath": [
"xpack",
"cloudDefend"
],
"requiredPlugins": [
"navigation",
"data",
"fleet",
"kibanaReact"
"unifiedSearch",
"kibanaReact",
"cloud",
"security",
"licensing"
],
"optionalPlugins": [
"usageCollection"
],
"requiredBundles": [
"kibanaReact",
"usageCollection"
]
}
}
50 changes: 50 additions & 0 deletions x-pack/plugins/cloud_defend/public/application/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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 { Route } from '@kbn/shared-ux-router';
import { type RouteProps } from 'react-router-dom';
import { TrackApplicationView } from '@kbn/usage-collection-plugin/public';
import { cloudDefendPages } from '../common/navigation/constants';
import { useSecuritySolutionContext } from './security_solution_context';
import type { CloudDefendPageNavigationItem } from '../common/navigation/types';

type CloudDefendRouteProps = Omit<RouteProps, 'render'> & CloudDefendPageNavigationItem;

// Security SpyRoute can be automatically rendered for pages with static paths, Security will manage everything using the `links` object.
// Pages with dynamic paths are not in the Security `links` object, they must render SpyRoute with the parameters values, if needed.
const STATIC_PATH_PAGE_IDS = Object.fromEntries(
Object.values(cloudDefendPages).map(({ id }) => [id, true])
);

export const CloudDefendRoute: React.FC<CloudDefendRouteProps> = ({
id,
children,
component: Component,
disabled = false,
...cloudDefendRouteProps
}) => {
const SpyRoute = useSecuritySolutionContext()?.getSpyRouteComponent();

if (disabled) {
return null;
}

const routeProps: RouteProps = {
...cloudDefendRouteProps,
...(Component && {
render: (renderProps) => (
<TrackApplicationView viewId={id}>
{STATIC_PATH_PAGE_IDS[id] && SpyRoute && <SpyRoute pageName={id} />}
<Component {...renderProps} />
</TrackApplicationView>
),
}),
};

return <Route {...routeProps}>{children}</Route>;
};
Loading