mirror of
https://github.com/valitydev/wazuh-kibana-app.git
synced 2024-11-06 18:05:20 +00:00
363 lines
12 KiB
JavaScript
363 lines
12 KiB
JavaScript
module.exports = function (server, options) {
|
|
|
|
// Colors for console logging
|
|
const colors = require('ansicolors');
|
|
const blueWazuh = colors.blue('wazuh');
|
|
|
|
// Elastic JS Client
|
|
const serverConfig = server.config();
|
|
const elasticsearch = require('elasticsearch');
|
|
const elasticRequest = server.plugins.elasticsearch.getCluster('data');
|
|
|
|
var index_pattern = "wazuh-alerts-*";
|
|
var index_pattern_wazuh_monitoring = "wazuh-monitoring-*";
|
|
var index_prefix = "wazuh-alerts-";
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const KIBANA_FIELDS_FILE = '../startup/integration_files/kibana_fields_file.json';
|
|
var kibana_fields_data = {};
|
|
|
|
const payloads = {
|
|
getFieldTop: { "size": 1, "query": { "bool": { "must": [{ "query_string": { "query": "*", "analyze_wildcard": true } }, { "range": { "@timestamp": { "gte": '', "format": "epoch_millis" } } }], "must_not": [] } }, "aggs": { "2": { "terms": { "field": '', "size": 1, "order": { "_count": "desc" } } } } },
|
|
getLastField: { "size": 1, "query": { "bool": { "must": [{ "exists": { "field": '' } }, { "query_string": { "query": "*" } }], "must_not": [{}] } }, "sort": [{ "@timestamp": { "order": "desc", "unmapped_type": "boolean" } }] }
|
|
};
|
|
|
|
//Handlers
|
|
|
|
var fetchElastic = function (req, payload) {
|
|
return elasticRequest.callWithRequest(req, 'search', { index: 'wazuh-alerts-*', type: 'wazuh', body: payload });
|
|
};
|
|
|
|
// Returns alerts count for fields/value array between timeGTE and timeLT
|
|
var alertsCount = function (req, reply) {
|
|
|
|
var payload = {"size": 1,"query": {"bool": {"must": [], "filter": {"range": {"@timestamp": {}}}}}};
|
|
|
|
// Set up time interval, default to Last 24h
|
|
const timeGTE = req.payload.timeinterval.gte ? req.payload.timeinterval.gte : "now-1d";
|
|
const timeLT = req.payload.timeinterval.lt ? req.payload.timeinterval.lt : "now";
|
|
payload.query.bool.filter.range['@timestamp']["gte"] = timeGTE;
|
|
if(timeLT != "now")
|
|
payload.query.bool.filter.range['@timestamp']["lte"] = timeLT;
|
|
else
|
|
payload.query.bool.filter.range['@timestamp']["lt"] = timeLT;
|
|
|
|
// Set up match for default manager name
|
|
payload.query.bool.must.push({"match": {"manager.name": req.payload.manager}});
|
|
|
|
// Set up match for different pairs field/value
|
|
req.payload.fields.forEach(function(item) {
|
|
var obj = {};
|
|
obj[item.field] = item.value;
|
|
payload.query.bool.must.push({"match": obj});
|
|
})
|
|
|
|
|
|
fetchElastic(req, payload).then(function (data) {
|
|
reply({ 'statusCode': 200, 'data': data.hits.total });
|
|
}, function () {
|
|
reply({ 'statusCode': 500, 'error': 9, 'message': 'Could not get data from elasticsearch' }).code(500);
|
|
});
|
|
};
|
|
|
|
var getFieldTop = function (req, reply) {
|
|
|
|
// Top field payload
|
|
var payload = {"size":1,"query":{"bool":{"must":[],"filter":{"range":{"@timestamp":{}}}}},"aggs":{"2":{"terms":{"field":"","size":1,"order":{"_count":"desc"}}}}}
|
|
|
|
// Set up time interval, default to Last 24h
|
|
const timeGTE = "now-1d";
|
|
const timeLT = "now";
|
|
payload.query.bool.filter.range['@timestamp']["gte"] = timeGTE;
|
|
payload.query.bool.filter.range['@timestamp']["lt"] = timeLT;
|
|
|
|
// Set up match for default manager name
|
|
payload.query.bool.must.push({"match": {"manager.name": req.params.manager}});
|
|
payload.aggs['2'].terms.field = req.params.field;
|
|
|
|
fetchElastic(req, payload).then(function (data) {
|
|
|
|
if (data.hits.total == 0 || typeof data.aggregations['2'].buckets[0] === 'undefined')
|
|
reply({ 'statusCode': 200, 'data': '' });
|
|
else
|
|
reply({ 'statusCode': 200, 'data': data.aggregations['2'].buckets[0].key });
|
|
}, function () {
|
|
reply({ 'statusCode': 500, 'error': 9, 'message': 'Could not get data from elasticsearch' }).code(500);
|
|
});
|
|
};
|
|
|
|
var getLastField = function (req, reply) {
|
|
var filtering = false;
|
|
var filterArray = {};
|
|
var termArray = {};
|
|
|
|
if (req.params.fieldValue && req.params.fieldFilter)
|
|
filtering = true;
|
|
|
|
var payload = JSON.parse(JSON.stringify(payloads.getLastField));
|
|
payload.query.bool.must[0].exists.field = req.params.field;
|
|
|
|
filterArray["host"]["manager.name"] = req.params.manager;
|
|
termArray = { "term": filterArray };
|
|
payload.query.bool.must.push(termArray);
|
|
filterArray = {};
|
|
termArray = {};
|
|
|
|
if (filtering) {
|
|
filterArray[req.params.fieldFilter] = req.params.fieldValue;
|
|
termArray = { "term": filterArray };
|
|
payload.query.bool.must.push(termArray);
|
|
}
|
|
|
|
fetchElastic(req, payload).then(function (data) {
|
|
|
|
if (data.hits.total == 0 || typeof data.hits.hits[0] === 'undefined')
|
|
reply({ 'statusCode': 200, 'data': '' });
|
|
else
|
|
reply({ 'statusCode': 200, 'data': data.hits.hits[0]._source[req.params.field] });
|
|
}, function () {
|
|
reply({ 'statusCode': 500, 'error': 9, 'message': 'Could not get data from elasticsearch' }).code(500);
|
|
});
|
|
};
|
|
|
|
var getSetupInfo = function (req, reply) {
|
|
elasticRequest.callWithRequest(req, 'search', { index: '.wazuh', type: 'wazuh-setup' })
|
|
.then(function (data) {
|
|
if (data.hits.total == 0) {
|
|
reply({ 'statusCode': 200, 'data': '' });
|
|
}
|
|
else {
|
|
reply({ 'statusCode': 200, 'data': data.hits.hits[0]._source });
|
|
}
|
|
}, function (error) {
|
|
console.log(error);
|
|
reply({ 'statusCode': 500, 'error': 9, 'message': 'Could not get data from elasticsearch' }).code(500);
|
|
});
|
|
};
|
|
|
|
var putWazuhAlertsPattern = function (req, reply) {
|
|
|
|
try {
|
|
kibana_fields_data = JSON.parse(fs.readFileSync(path.resolve(__dirname, KIBANA_FIELDS_FILE), 'utf8'));
|
|
// Get fields index pattern template (wazuh-alerts-*)
|
|
var wazuhAlerts_indexPattern_template = JSON.parse(kibana_fields_data.wazuh_alerts)
|
|
var wazuhAlerts_indexPattern_current = {};
|
|
var responseBack = {};
|
|
var fields = [];
|
|
for (var i = 0, len = wazuhAlerts_indexPattern_template.length; i < len; i++) {
|
|
fields.push(wazuhAlerts_indexPattern_template[i].name);
|
|
}
|
|
|
|
// Get current fields index pattern (wazuh-alerts-*)
|
|
elasticRequest.callWithInternalUser('get', {
|
|
index: '.kibana',
|
|
type: 'index-pattern',
|
|
id: index_pattern
|
|
}).then(
|
|
function (response) {
|
|
wazuhAlerts_indexPattern_current = JSON.parse(response._source.fields);
|
|
// Compare and update fields properties
|
|
for (var i = 0, len = wazuhAlerts_indexPattern_current.length; i < len; i++) {
|
|
if (fields.indexOf(wazuhAlerts_indexPattern_current[i].name) >= 0) {
|
|
wazuhAlerts_indexPattern_current[i].searchable = true;
|
|
wazuhAlerts_indexPattern_current[i].aggregatable = true;
|
|
}
|
|
}
|
|
// Update index pattern (wazuh-alerts-*)
|
|
elasticRequest.callWithInternalUser('update', {
|
|
index: '.kibana',
|
|
type: 'index-pattern',
|
|
id: index_pattern,
|
|
body: {
|
|
doc: {
|
|
fields: JSON.stringify((wazuhAlerts_indexPattern_current))
|
|
}
|
|
}
|
|
}).then(
|
|
function (response) {
|
|
reply({ 'response': response}).code(200);
|
|
}, function (error) {
|
|
reply({ 'response': error, 'error' : '1'}).code(error.statusCode);
|
|
}
|
|
);
|
|
}, function (error) {
|
|
// Create index pattern
|
|
elasticRequest.callWithInternalUser('create', {
|
|
index: '.kibana',
|
|
type: 'index-pattern',
|
|
id: index_pattern,
|
|
body: {
|
|
title: index_pattern,
|
|
timeFieldName: '@timestamp',
|
|
fields: kibana_fields_data.wazuh_alerts
|
|
}
|
|
}).then(
|
|
function (response) {
|
|
reply({ 'response': response}).code(200);
|
|
}, function (error) {
|
|
reply({ 'response': error, 'error' : '2'}).code(error.statusCode);
|
|
});
|
|
}
|
|
);
|
|
|
|
} catch (e) {
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Could not read the mapping file.');
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Path: ' + KIBANA_FIELDS_FILE);
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Exception: ' + e);
|
|
};
|
|
};
|
|
var putWazuhMonitoringPattern = function (req, reply) {
|
|
|
|
try {
|
|
kibana_fields_data = JSON.parse(fs.readFileSync(path.resolve(__dirname, KIBANA_FIELDS_FILE), 'utf8'));
|
|
// Check if wazuh-monitoring-* exists
|
|
elasticRequest.callWithInternalUser('get', {
|
|
index: '.kibana',
|
|
type: 'index-pattern',
|
|
id: index_pattern_wazuh_monitoring
|
|
}).then(
|
|
function (response) {
|
|
// Update index pattern (wazuh-monitoring-*)
|
|
elasticRequest.callWithInternalUser('update', {
|
|
index: '.kibana',
|
|
type: 'index-pattern',
|
|
id: index_pattern_wazuh_monitoring,
|
|
body: {
|
|
doc: {
|
|
fields: kibana_fields_data.wazuh_monitoring
|
|
}
|
|
}
|
|
}).then(
|
|
function (response) {
|
|
reply({ 'response': response}).code(200);
|
|
}, function (error) {
|
|
reply({ 'response': error }).code(error.statusCode);
|
|
}
|
|
);
|
|
}, function (error) {
|
|
// Create index pattern
|
|
elasticRequest.callWithInternalUser('create', {
|
|
index: '.kibana',
|
|
type: 'index-pattern',
|
|
id: index_pattern_wazuh_monitoring,
|
|
body: {
|
|
title: index_pattern_wazuh_monitoring,
|
|
timeFieldName: '@timestamp',
|
|
fields: kibana_fields_data.wazuh_monitoring
|
|
}
|
|
}).then(
|
|
function (response) {
|
|
reply({ 'response': response}).code(200);
|
|
}, function (error) {
|
|
reply({ 'response': error, 'error' : '2'}).code(error.statusCode);
|
|
});
|
|
}
|
|
);
|
|
} catch (e) {
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Could not read the mapping file.');
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Path: ' + KIBANA_FIELDS_FILE);
|
|
server.log([blueWazuh, 'initialize', 'error'], 'Exception: ' + e);
|
|
};
|
|
}
|
|
|
|
//Server routes
|
|
|
|
/*
|
|
* GET /api/wazuh-elastic/top/{manager}/{field}/{time?}
|
|
* Returns the agent with most alerts
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-elastic/top/{manager}/{field}/{time?}',
|
|
handler: getFieldTop
|
|
});
|
|
|
|
/*
|
|
* GET /api/wazuh-elastic/top/{manager}/{field}/{fieldFilter}/{fieldValue}/{time?}
|
|
* Returns the agent with most alerts
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-elastic/top/{manager}/{field}/{fieldFilter}/{fieldValue}/{time?}',
|
|
handler: getFieldTop
|
|
});
|
|
|
|
/*
|
|
* GET /api/wazuh-elastic/top/{manager}/{field}/{fieldFilter}/{fieldValue}/{fieldFilter}/{fieldValue}/{time?}
|
|
* Returns the agent with most alerts
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-elastic/top/{manager}/{field}/{fieldFilter}/{fieldValue}/{fieldFilter2}/{fieldValue2}/{time?}',
|
|
handler: getFieldTop
|
|
});
|
|
|
|
/*
|
|
* /api/wazuh-elastic/alerts-count
|
|
* Returns alerts count for fields/value array between timeGTE and timeLT
|
|
* @params: fields[{field,value}], manager, timeinterval{gte,lte}
|
|
**/
|
|
server.route({
|
|
method: 'POST',
|
|
path: '/api/wazuh-elastic/alerts-count/',
|
|
handler: alertsCount
|
|
});
|
|
/*
|
|
* GET /api/wazuh-elastic/last/{manager}/{field}
|
|
* Return last field value
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-elastic/last/{manager}/{field}',
|
|
handler: getLastField
|
|
});
|
|
/*
|
|
|
|
/*
|
|
* GET /api/wazuh-elastic/last/{manager}/{field}/{fieldFilter}/{fieldValue}
|
|
* Return last field value
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-elastic/last/{manager}/{field}/{fieldFilter}/{fieldValue}',
|
|
handler: getLastField
|
|
});
|
|
|
|
/*
|
|
* GET /api/wazuh-elastic/setup
|
|
* Return Wazuh Appsetup info
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'GET',
|
|
path: '/api/wazuh-elastic/setup',
|
|
handler: getSetupInfo
|
|
});
|
|
|
|
/*
|
|
* PUT /api/wazuh-elastic/wazuh-pattern
|
|
* Set wazuh index pattern
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'PUT',
|
|
path: '/api/wazuh-elastic/wazuh-alerts-pattern',
|
|
handler: putWazuhAlertsPattern
|
|
});
|
|
|
|
/*
|
|
* PUT /api/wazuh-elastic/wazuh-pattern
|
|
* Set wazuh index pattern
|
|
*
|
|
**/
|
|
server.route({
|
|
method: 'PUT',
|
|
path: '/api/wazuh-elastic/wazuh-monitoring-pattern',
|
|
handler: putWazuhMonitoringPattern
|
|
});
|
|
}; |