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

[Endpoint] Show Policy Status on Host Details using Policy Response API #64116

Merged
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
117 changes: 116 additions & 1 deletion x-pack/plugins/endpoint/common/generate_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@

import uuid from 'uuid';
import seedrandom from 'seedrandom';
import { AlertEvent, EndpointEvent, HostMetadata, OSFields, HostFields, PolicyData } from './types';
import {
AlertEvent,
EndpointEvent,
HostFields,
HostMetadata,
OSFields,
PolicyData,
HostPolicyResponse,
HostPolicyResponseActionStatus,
} from './types';
import { factory as policyFactory } from './models/policy_config';

export type Event = AlertEvent | EndpointEvent;
Expand Down Expand Up @@ -486,6 +495,112 @@ export class EndpointDocGenerator {
};
}

/**
* Generates a Host Policy response message
*/
generatePolicyResponse(): HostPolicyResponse {
return {
'@timestamp': new Date().toISOString(),
elastic: {
agent: {
id: 'c2a9093e-e289-4c0a-aa44-8c32a414fa7a',
},
},
ecs: {
version: '1.0.0',
},
event: {
created: '2015-01-01T12:10:30Z',
kind: 'policy_response',
},
agent: {
version: '6.0.0-rc2',
id: '8a4f500d',
},
endpoint: {
artifacts: {
'global-manifest': {
version: '1.2.3',
sha256: 'abcdef',
},
'endpointpe-v4-windows': {
version: '1.2.3',
sha256: 'abcdef',
},
'user-whitelist-windows': {
version: '1.2.3',
sha256: 'abcdef',
},
'global-whitelist-windows': {
version: '1.2.3',
sha256: 'abcdef',
},
},
policy: {
applied: {
version: '1.0.0',
id: '17d4b81d-9940-4b64-9de5-3e03ef1fb5cf',
status: HostPolicyResponseActionStatus.success,
response: {
configurations: {
malware: {
status: HostPolicyResponseActionStatus.success,
concerned_actions: ['download_model', 'workflow', 'a_custom_future_action'],
},
events: {
status: HostPolicyResponseActionStatus.success,
concerned_actions: ['ingest_events_config', 'workflow'],
},
logging: {
status: HostPolicyResponseActionStatus.success,
concerned_actions: ['configure_elasticsearch_connection'],
},
streaming: {
status: HostPolicyResponseActionStatus.success,
concerned_actions: [
'detect_file_open_events',
'download_global_artifacts',
'a_custom_future_action',
],
},
},
actions: {
download_model: {
status: HostPolicyResponseActionStatus.success,
message: 'model downloaded',
},
ingest_events_config: {
status: HostPolicyResponseActionStatus.success,
message: 'no action taken',
},
workflow: {
status: HostPolicyResponseActionStatus.success,
message: 'the flow worked well',
},
a_custom_future_action: {
status: HostPolicyResponseActionStatus.success,
message: 'future message',
},
configure_elasticsearch_connection: {
status: HostPolicyResponseActionStatus.success,
message: 'some message',
},
detect_file_open_events: {
status: HostPolicyResponseActionStatus.success,
message: 'some message',
},
download_global_artifacts: {
status: HostPolicyResponseActionStatus.success,
message: 'some message',
},
},
},
},
},
},
};
}

private randomN(n: number): number {
return Math.floor(this.random() * n);
}
Expand Down
100 changes: 100 additions & 0 deletions x-pack/plugins/endpoint/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -573,3 +573,103 @@ export type NewPolicyData = NewDatasource & {
}
];
};

/**
* the possible status for actions, configurations and overall Policy Response
*/
export enum HostPolicyResponseActionStatus {
success = 'success',
failure = 'failure',
warning = 'warning',
}

/**
* The details of a given action
*/
interface HostPolicyResponseActionDetails {
status: HostPolicyResponseActionStatus;
message: string;
}

/**
* A known list of possible Endpoint actions
*/
interface HostPolicyResponseActions {
download_model: HostPolicyResponseActionDetails;
ingest_events_config: HostPolicyResponseActionDetails;
workflow: HostPolicyResponseActionDetails;
configure_elasticsearch_connection: HostPolicyResponseActionDetails;
configure_kernel: HostPolicyResponseActionDetails;
configure_logging: HostPolicyResponseActionDetails;
configure_malware: HostPolicyResponseActionDetails;
connect_kernel: HostPolicyResponseActionDetails;
detect_file_open_events: HostPolicyResponseActionDetails;
detect_file_write_events: HostPolicyResponseActionDetails;
detect_image_load_events: HostPolicyResponseActionDetails;
detect_process_events: HostPolicyResponseActionDetails;
download_global_artifacts: HostPolicyResponseActionDetails;
load_config: HostPolicyResponseActionDetails;
load_malware_model: HostPolicyResponseActionDetails;
read_elasticsearch_config: HostPolicyResponseActionDetails;
read_events_config: HostPolicyResponseActionDetails;
read_kernel_config: HostPolicyResponseActionDetails;
read_logging_config: HostPolicyResponseActionDetails;
read_malware_config: HostPolicyResponseActionDetails;
// The list of possible Actions will change rapidly, so the below entry will allow
// them without us defining them here statically
[key: string]: HostPolicyResponseActionDetails;
}

interface HostPolicyResponseConfigurationStatus {
status: HostPolicyResponseActionStatus;
concerned_actions: Array<keyof HostPolicyResponseActions>;
}

/**
* Information about the applying of a policy to a given host
*/
export interface HostPolicyResponse {
'@timestamp': string;
elastic: {
agent: {
id: string;
};
};
ecs: {
version: string;
};
event: {
created: string;
kind: string;
};
agent: {
version: string;
id: string;
};
endpoint: {
artifacts: {};
policy: {
applied: {
version: string;
id: string;
status: HostPolicyResponseActionStatus;
response: {
configurations: {
malware: HostPolicyResponseConfigurationStatus;
events: HostPolicyResponseConfigurationStatus;
logging: HostPolicyResponseConfigurationStatus;
streaming: HostPolicyResponseConfigurationStatus;
};
actions: Partial<HostPolicyResponseActions>;
};
};
};
};
}

/**
* REST API response for retrieving a host's Policy Response status
*/
export interface GetHostPolicyResponse {
policy_response: HostPolicyResponse;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import { ServerApiError } from '../../types';
import { HostResultList, HostInfo } from '../../../../../common/types';
import { HostResultList, HostInfo, GetHostPolicyResponse } from '../../../../../common/types';

interface ServerReturnedHostList {
type: 'serverReturnedHostList';
Expand All @@ -27,8 +27,14 @@ interface ServerFailedToReturnHostDetails {
payload: ServerApiError;
}

interface ServerReturnedHostPolicyResponse {
type: 'serverReturnedHostPolicyResponse';
payload: GetHostPolicyResponse;
}

export type HostAction =
| ServerReturnedHostList
| ServerFailedToReturnHostList
| ServerReturnedHostDetails
| ServerFailedToReturnHostDetails;
| ServerFailedToReturnHostDetails
| ServerReturnedHostPolicyResponse;
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { HostResultList } from '../../../../../common/types';
import { isOnHostPage, hasSelectedHost, uiQueryParams, listData } from './selectors';
import { HostState } from '../../types';
import { ImmutableMiddlewareFactory } from '../../types';
import { HostPolicyResponse } from '../../../../../common/types';

export const hostMiddlewareFactory: ImmutableMiddlewareFactory<HostState> = coreStart => {
return ({ getState, dispatch }) => next => async action => {
Expand Down Expand Up @@ -69,6 +70,21 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory<HostState> = core
type: 'serverReturnedHostDetails',
payload: response,
});
// FIXME: once we have the API implementation in place, we should call it parallel with the above api call and then dispatch this with the results of the second call
dispatch({
type: 'serverReturnedHostPolicyResponse',
payload: {
policy_response: ({
endpoint: {
policy: {
applied: {
status: 'success',
},
},
},
} as unknown) as HostPolicyResponse, // Temporary until we get API
},
});
} catch (error) {
dispatch({
type: 'serverFailedToReturnHostDetails',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const initialState = (): HostState => {
details: undefined,
detailsLoading: false,
detailsError: undefined,
policyResponse: undefined,
location: undefined,
};
};
Expand Down Expand Up @@ -63,6 +64,11 @@ export const hostListReducer: ImmutableReducer<HostState, AppAction> = (
detailsError: action.payload,
detailsLoading: false,
};
} else if (action.type === 'serverReturnedHostPolicyResponse') {
return {
...state,
policyResponse: action.payload.policy_response,
};
} else if (action.type === 'userChangedUrl') {
const newState: Immutable<HostState> = {
...state,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,13 @@ export const showView: (state: HostState) => 'policy_response' | 'details' = cre
return searchParams.show === 'policy_response' ? 'policy_response' : 'details';
}
);

/**
* Returns the Policy Response overall status
*/
export const policyResponseStatus: (state: Immutable<HostState>) => string = createSelector(
state => state.policyResponse,
policyResponse => {
return (policyResponse && policyResponse?.endpoint?.policy?.applied?.status) || '';
}
);
3 changes: 3 additions & 0 deletions x-pack/plugins/endpoint/public/applications/endpoint/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
MalwareFields,
UIPolicyConfig,
PolicyData,
HostPolicyResponse,
} from '../../../common/types';
import { EndpointPluginStartDependencies } from '../../plugin';
import { AppAction } from './store/action';
Expand Down Expand Up @@ -107,6 +108,8 @@ export interface HostState {
detailsLoading: boolean;
/** api error from retrieving host details */
detailsError?: ServerApiError;
/** Holds the Policy Response for the Host currently being displayed in the details */
policyResponse?: HostPolicyResponse;
/** current location info */
location?: Immutable<EndpointAppLocation>;
}
Expand Down
Loading