wazuh-kibana-app/server/monitoring.js

406 lines
15 KiB
JavaScript
Raw Normal View History

2017-10-27 07:03:53 +00:00
// External libraries
const cron = require('node-cron');
const needle = require('needle');
const getPath = require('../util/get-path');
2017-10-27 07:03:53 +00:00
// Colors for console logging
const colors = require('ansicolors');
const blueWazuh = colors.blue('wazuh');
const APP_OBJECTS_FILE = './integration-files/app-objects-file-monitoring.json';
module.exports = (server, options) => {
2017-12-11 10:45:32 +00:00
// Elastic JS Client
const elasticRequest = server.plugins.elasticsearch.getCluster('admin');
// Initialize
let agentsArray = [];
let index_pattern = "wazuh-monitoring-3.x-*";
let index_prefix = "wazuh-monitoring-3.x-";
let fDate = new Date().toISOString().replace(/T/, '-').replace(/\..+/, '').replace(/-/g, '.').replace(/:/g, '').slice(0, -7);
let todayIndex = index_prefix + fDate;
let packageJSON = {};
let app_objects = {};
2017-12-11 10:45:32 +00:00
// Read Wazuh App package file
try {
packageJSON = require('../package.json');
} catch (e) {
server.log([blueWazuh, 'monitoring', 'error'], 'Could not read the Wazuh package file due to ' + e);
}
// Check status and get agent status array
const checkStatus = (apiEntry, maxSize, offset) => {
if (!maxSize) {
server.log([blueWazuh, 'monitoring', 'error'], 'You must provide a max size');
}
let payload = {
'offset': offset ? offset: 0,
'limit': (250 < maxSize) ? 250 : maxSize
};
let options = {
headers: {
'wazuh-app-version': packageJSON.version
},
username: apiEntry.user,
password: apiEntry.password,
rejectUnauthorized: !apiEntry.insecure
};
needle.request('get', `${getPath(apiEntry)}/agents`, payload, options, (error, response) => {
if (!error && !response.error && response.body.data.items) {
agentsArray = agentsArray.concat(response.body.data.items);
if ((payload.limit + payload.offset) < maxSize) {
checkStatus(apiEntry, response.body.data.totalItems, payload.limit + payload.offset);
} else {
saveStatus();
}
} else {
server.log([blueWazuh, 'monitoring', 'error'], 'Can not access Wazuh API');
}
});
};
// Check API status twice and get agents total items
const checkAndSaveStatus = (apiEntry) => {
let payload = {
'offset': 0,
'limit': 1
};
let options = {
headers: {
'wazuh-app-version': packageJSON.version
},
username: apiEntry.user,
password: apiEntry.password,
rejectUnauthorized: !apiEntry.insecure
};
needle('get', `${getPath(apiEntry)}/agents`, payload, options)
.then((response) => {
if (!response.error && response.body.data && response.body.data.totalItems) {
checkStatus(apiEntry, response.body.data.totalItems);
} else {
server.log([blueWazuh, 'monitoring', 'error'], 'Wazuh API credentials not found or are not correct. Open the app in your browser and configure it to start monitoring agents.');
}
});
};
// Load Wazuh API credentials from Elasticsearch document
const loadCredentials = (apiEntries) => {
if (typeof apiEntries === 'undefined' || !('hits' in apiEntries)) return;
const filteredApis = apiEntries.hits.filter((element, index, self) =>
index === self.findIndex((t) => (
t._source.api_user === element._source.api_user &&
t._source.api_password === element._source.api_password &&
t._source.url === element._source.url &&
t._source.api_port === element._source.api_port
))
);
for(let element of filteredApis) {
2017-12-11 10:45:32 +00:00
let apiEntry = {
'user': element._source.api_user,
'password': Buffer.from(element._source.api_password, 'base64').toString("ascii"),
'url': element._source.url,
'port': element._source.api_port,
'insecure': element._source.insecure
};
if (apiEntry.error) {
2018-03-12 10:27:19 +00:00
wazuhlogger.log({
date: new Date(),
level: 'error',
location: 'monitoring.js loadCredentials',
message: apiEntry.error || apiEntry
});
2017-12-11 10:45:32 +00:00
server.log([blueWazuh, 'monitoring', 'error'], `Error getting wazuh-api data: ${apiEntry.error}`);
break;
}
checkAndSaveStatus(apiEntry);
}
};
// Get API configuration from elastic and callback to loadCredentials
const getConfig = (callback) => {
elasticRequest.callWithInternalUser('search', {
index: '.wazuh',
type: 'wazuh-configuration'
})
.then(data => {
if (data.hits.total > 0) {
2017-12-11 10:45:32 +00:00
callback(data.hits);
} else {
callback({
'error': 'no credentials',
'error_code': 1
});
}
})
2018-03-11 16:58:57 +00:00
.catch(error => {
wazuhlogger.log({
date: new Date(),
level: 'error',
location: 'monitoring.js getConfig',
message: error.message || error
});
2017-12-11 10:45:32 +00:00
callback({
'error': 'no elasticsearch',
'error_code': 2
});
});
};
// Importing Wazuh app visualizations and dashboards
const importAppObjects = (id) => {
server.log([blueWazuh, 'monitoring', 'info'], 'Importing Wazuh app visualizations...');
try {
app_objects = require(APP_OBJECTS_FILE);
} catch (e) {
server.log([blueWazuh, 'monitoring', 'error'], 'Could not read the objects file.');
server.log([blueWazuh, 'monitoring', 'error'], 'Path: ' + APP_OBJECTS_FILE);
server.log([blueWazuh, 'monitoring', 'error'], 'Exception: ' + e);
}
let body = '';
for(let element of app_objects){
body += '{ "index": { "_index": ".kibana", "_type": "doc", ' +
'"_id": "' + element._type + ':' + element._id + '" } }\n';
let temp = {};
let aux = JSON.stringify(element._source);
aux = aux.replace("wazuh-monitoring", id);
aux = JSON.parse(aux);
temp[element._type] = aux;
if (temp[element._type].kibanaSavedObjectMeta.searchSourceJSON.index) {
temp[element._type].kibanaSavedObjectMeta.searchSourceJSON.index = id;
}
temp["type"] = element._type;
body += JSON.stringify(temp) + "\n";
}
elasticRequest.callWithInternalUser('bulk', {
index: '.kibana',
body: body
})
.then(() => elasticRequest.callWithInternalUser('indices.refresh', {
index: ['.kibana', index_pattern]
}))
.then(() => {
server.log([blueWazuh, 'monitoring', 'info'], 'Wazuh app visualizations were successfully installed. App ready to be used.');
})
2018-03-11 16:58:57 +00:00
.catch(error => {
wazuhlogger.log({
date: new Date(),
level: 'error',
location: 'monitoring.js importAppObjects',
message: error.message || error
});
2017-12-11 10:45:32 +00:00
server.log([blueWazuh, 'server', 'error'], 'Error importing objects into elasticsearch. Bulk request failed.');
});
};
// fetchAgents on demand
const fetchAgents = () => getConfig(loadCredentials);
// Configure Kibana patterns.
const configureKibana = () => {
server.log([blueWazuh, 'monitoring', 'info'], `Creating index pattern: ${index_pattern}`);
2017-12-26 17:50:18 +00:00
let patternId = 'index-pattern:' + index_pattern;
elasticRequest.callWithInternalUser('create', {
2017-12-11 10:45:32 +00:00
index: '.kibana',
type: 'doc',
2017-12-26 17:50:18 +00:00
id: patternId,
2017-12-11 10:45:32 +00:00
body: {
"type": 'index-pattern',
"index-pattern": {
"title": index_pattern,
"timeFieldName": '@timestamp'
}
}
})
2018-03-11 16:58:57 +00:00
.then(resp => {
2017-12-11 10:45:32 +00:00
server.log([blueWazuh, 'monitoring', 'info'], 'Created index pattern: ' + index_pattern);
2017-12-26 17:50:18 +00:00
importAppObjects(index_pattern);
2017-12-11 10:45:32 +00:00
})
2018-03-11 16:58:57 +00:00
.catch(error => {
wazuhlogger.log({
date: new Date(),
level: 'error',
location: 'monitoring.js configureKibana',
message: error.message || error
});
2017-12-11 10:45:32 +00:00
server.log([blueWazuh, 'monitoring', 'error'], 'Error creating index-pattern due to ' + error);
});;
};
// Creating wazuh-monitoring index
const createIndex = (todayIndex) => {
elasticRequest.callWithInternalUser('indices.create', { index: todayIndex })
.then(() => {
server.log([blueWazuh, 'monitoring', 'info'], 'Successfully created today index.');
insertDocument(todayIndex);
})
2018-03-11 16:58:57 +00:00
.catch(error => {
wazuhlogger.log({
date: new Date(),
level: 'error',
location: 'monitoring.js createIndex',
message: error.message || error
});
2017-12-11 10:45:32 +00:00
server.log([blueWazuh, 'monitoring', 'error'], `Could not create ${todayIndex} index on elasticsearch due to ` + error);
});
};
// Inserting one document per agent into Elastic. Bulk.
const insertDocument = (todayIndex) => {
let body = '';
if (agentsArray.length > 0) {
let managerName = agentsArray[0].name;
for(let element of agentsArray) {
body += '{ "index": { "_index": "' + todayIndex + '", "_type": "wazuh-agent" } }\n';
let date = new Date(Date.now()).toISOString();
element["@timestamp"] = date;
element["host"] = managerName;
body += JSON.stringify(element) + "\n";
}
if (body === '') return;
elasticRequest.callWithInternalUser('bulk', {
index: todayIndex,
type: 'agent',
body: body
})
.then((response) => agentsArray.length = 0)
2018-03-11 16:58:57 +00:00
.catch(error => {
wazuhlogger.log({
date: new Date(),
level: 'error',
location: 'monitoring.js insertDocument',
message: error.message || error
});
2017-12-11 10:45:32 +00:00
server.log([blueWazuh, 'monitoring', 'error'], 'Error inserting agent data into elasticsearch. Bulk request failed due to ' + error);
});
}
};
// Save agent status into elasticsearch, create index and/or insert document
const saveStatus = () => {
fDate = new Date().toISOString().replace(/T/, '-').replace(/\..+/, '').replace(/-/g, '.').replace(/:/g, '').slice(0, -7);
todayIndex = index_prefix + fDate;
elasticRequest.callWithInternalUser('indices.exists', { index: todayIndex })
.then((result) => {
if (result) insertDocument(todayIndex);
else createIndex(todayIndex);
})
2018-03-11 16:58:57 +00:00
.catch(error => {
wazuhlogger.log({
date: new Date(),
level: 'error',
location: 'monitoring.js saveStatus',
message: error.message || error
});
2017-12-11 10:45:32 +00:00
server.log([blueWazuh, 'monitoring', 'error'], `Could not check if the index ${todayIndex} exists due to ` + error);
});
};
// Main. First execution when installing / loading App.
const init = () => {
server.log([blueWazuh, 'monitoring', 'info'], 'Creating today index...');
saveStatus();
2017-12-26 17:50:18 +00:00
let patternId = 'index-pattern:' + index_pattern;
2017-12-11 10:45:32 +00:00
elasticRequest.callWithInternalUser('get', {
index: '.kibana',
type: 'doc',
2017-12-26 17:50:18 +00:00
id: patternId
2017-12-11 10:45:32 +00:00
})
2018-03-11 16:58:57 +00:00
.then(data => {
2017-12-11 10:45:32 +00:00
server.log([blueWazuh, 'monitoring', 'info'], 'Skipping index-pattern creation. Already exists.');
})
2018-03-11 16:58:57 +00:00
.catch(error => {
wazuhlogger.log({
date: new Date(),
level: 'error',
location: 'monitoring.js init',
message: error.message || error
});
2017-12-11 10:45:32 +00:00
server.log([blueWazuh, 'monitoring', 'info'], "Didn't find wazuh-monitoring pattern for Kibana v6.x. Proceeding to create it...");
elasticRequest.callWithInternalUser('delete', {
index: '.kibana',
type: 'doc',
id: 'index-pattern:wazuh-monitoring-*'
})
2018-03-11 16:58:57 +00:00
.then(resp => {
2017-12-11 10:45:32 +00:00
server.log([blueWazuh, 'monitoring', 'info'], "Successfully deleted old wazuh-monitoring pattern.");
})
2018-03-11 16:58:57 +00:00
.catch(error => {
wazuhlogger.log({
date: new Date(),
level: 'error',
location: 'monitoring.js init',
message: error.message || error
});
server.log([blueWazuh, 'monitoring', 'info'], "Didn't find old wazuh-monitoring pattern. Skipping deletion.");
2017-12-11 10:45:32 +00:00
});
configureKibana();
});
};
2017-06-01 15:08:10 +00:00
// Check Elasticsearch Server status and .kibana index presence
const checkElasticsearchServer = () => {
return new Promise(function (resolve, reject) {
2017-12-11 10:45:32 +00:00
elasticRequest.callWithInternalUser('indices.exists', { index: ".kibana" })
2018-03-11 16:58:57 +00:00
.then(data => {
if (data) server.plugins.elasticsearch.waitUntilReady().then(data => { resolve(data); });
2017-12-11 10:45:32 +00:00
else reject(data);
})
2018-03-11 16:58:57 +00:00
.catch(error => {
wazuhlogger.log({
date: new Date(),
level: 'error',
location: 'monitoring.js checkElasticsearchServer',
message: error.message || error
});
reject(error);
});
})
}
2017-12-11 10:45:32 +00:00
// Wait until Kibana server is ready
const checkKibanaStatus = () => {
2018-03-11 16:58:57 +00:00
checkElasticsearchServer().then(data => { init() })
.catch(error => {
wazuhlogger.log({
date: new Date(),
level: 'error',
location: 'monitoring.js checkKibanaStatus',
message: error.message || error
});
2017-12-11 10:45:32 +00:00
server.log([blueWazuh, 'monitoring', 'info'], 'Waiting for Kibana and Elasticsearch servers to be ready...');
setTimeout(() => checkKibanaStatus(), 3000);
});
2017-12-11 10:45:32 +00:00
};
2017-06-01 15:08:10 +00:00
2017-12-11 10:45:32 +00:00
// Check Kibana index and if it is prepared, start the initialization of Wazuh App.
checkKibanaStatus();
2017-06-01 15:08:10 +00:00
2017-12-11 10:45:32 +00:00
// Cron tab for getting agent status.
cron.schedule('0 */10 * * * *', () => {
agentsArray.length = 0;
getConfig(loadCredentials);
}, true);
2017-06-01 15:08:10 +00:00
2017-12-11 10:45:32 +00:00
module.exports = fetchAgents;
};