mirror of
https://github.com/valitydev/wazuh-kibana-app.git
synced 2024-11-07 10:18:57 +00:00
Merge branch '3.2' into 3.2-dev-new-menu
This commit is contained in:
commit
37b9b367f1
@ -34,6 +34,14 @@ All notable changes to the Wazuh app project will be documented in this file.
|
||||
- Now every index-pattern is **dynamically formatted** (for example, to enable the URLs in the *Vulnerabilities* tab).
|
||||
- Several **code refactoring** for a better handling of possible use cases.
|
||||
- And the best thing, **it's no longer needed to insert the sample alert**!
|
||||
- **Improvements and changes to index-patterns** ([#320](https://github.com/wazuh/wazuh-kibana-app/pull/320)):
|
||||
- There's a new route, `/get-list`, to fetch the index pattern list.
|
||||
- We've removed and changes several functions for a proper management of index-patterns.
|
||||
- We've improved the compatibility with user-created index-patterns, known to have unpredictable IDs.
|
||||
- **Improvements to monitoring module** ([#322](https://github.com/wazuh/wazuh-kibana-app/pull/322)):
|
||||
- We don't need the monitoring template insertion step anymore.
|
||||
- Minor refactor to the whole module.
|
||||
- Regenerate the index pattern if it's missing.
|
||||
- Now the app healthcheck system only checks if the API and app **have the same `major.minor` version** ([#311](https://github.com/wazuh/wazuh-kibana-app/pull/311)):
|
||||
- Previously, the API and app had to be on the same `major.minor.patch` version.
|
||||
- Adjusted space between title and value in some cards showing Manager or Agent configurations ([#315](https://github.com/wazuh/wazuh-kibana-app/pull/315)).
|
||||
|
@ -42,27 +42,7 @@ app.controller('settingsController', function ($scope, $rootScope, $http, $route
|
||||
const portRegEx = new RegExp(/^[0-9]{2,5}$/);
|
||||
|
||||
$scope.indexPatterns = [];
|
||||
|
||||
// Getting the index pattern list into the scope, but selecting only "valid" ones
|
||||
for (let i = 0; i < $route.current.locals.ips.list.length; i ++) {
|
||||
courier.indexPatterns.get($route.current.locals.ips.list[i].id)
|
||||
.then((data) => {
|
||||
let minimum = ["@timestamp", "full_log", "manager.name", "agent.id"];
|
||||
let minimumCount = 0;
|
||||
|
||||
for (let j = 0; j < data.fields.length; j++) {
|
||||
if (minimum.includes(data.fields[j].name)) {
|
||||
minimumCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (minimumCount == minimum.length) {
|
||||
$scope.indexPatterns.push($route.current.locals.ips.list[i]);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
$scope.apiEntries = [];
|
||||
if ($routeParams.tab){
|
||||
$scope.submenuNavItem = $routeParams.tab;
|
||||
}
|
||||
@ -147,6 +127,8 @@ app.controller('settingsController', function ($scope, $rootScope, $http, $route
|
||||
// Get settings function
|
||||
const getSettings = async () => {
|
||||
try {
|
||||
const patternList = await genericReq.request('GET','/get-list',{});
|
||||
$scope.indexPatterns = patternList.data.data;
|
||||
const data = await genericReq.request('GET', '/api/wazuh-api/apiEntries');
|
||||
for(const entry of data.data) $scope.showEditForm[entry._id] = false;
|
||||
|
||||
@ -259,7 +241,7 @@ app.controller('settingsController', function ($scope, $rootScope, $http, $route
|
||||
extensions : tmpData.extensions
|
||||
}
|
||||
};
|
||||
|
||||
console.log($scope.apiEntries)
|
||||
$scope.apiEntries.push(newEntry);
|
||||
$scope.apiEntries = $scope.apiEntries.sort(sortByTimestamp);
|
||||
|
||||
|
@ -51,7 +51,7 @@
|
||||
|
||||
<!-- Case 2b - There's pattern and there's only one-->
|
||||
<span ng-if="showSelector" ng-show="theresPattern && patternList && patternList.length === 1" tooltip="Selected index pattern" tooltip-placement="bottom">
|
||||
{{patternList[0].attributes.title}}
|
||||
{{patternList[0].title}}
|
||||
</span>
|
||||
|
||||
<!-- Settings tab button -->
|
||||
|
@ -3,25 +3,8 @@ require('ui/modules').get('app/wazuh', [])
|
||||
return {
|
||||
getPatternList: async () => {
|
||||
try {
|
||||
let patternList = [];
|
||||
|
||||
// Getting the index pattern list into the array,
|
||||
// but selecting only "valid" ones
|
||||
const len = $route.current.locals.ips.list.length;
|
||||
let data;
|
||||
for (let i = 0; i < len; i ++) {
|
||||
data = await courier.indexPatterns.get($route.current.locals.ips.list[i].id)
|
||||
|
||||
let minimum = ["@timestamp", "full_log", "manager.name", "agent.id"];
|
||||
let minimumCount = 0;
|
||||
data.fields.filter(element => minimumCount += (minimum.includes(element.name)) ? 1 : 0);
|
||||
|
||||
if (minimumCount === minimum.length) {
|
||||
patternList.push($route.current.locals.ips.list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return patternList;
|
||||
const patternList = await genericReq.request('GET','/get-list',{});
|
||||
return patternList.data.data;
|
||||
} catch (error) {
|
||||
errorHandler.handle(error,'Pattern Handler (getPatternList)');
|
||||
if(!$rootScope.$$phase) $rootScope.$digest();
|
||||
|
@ -239,49 +239,6 @@ const getIp = (Promise, courier, config, $q, $rootScope, $window, $location, Pri
|
||||
|
||||
};
|
||||
|
||||
const getAllIp = (Promise, $q, $window, $rootScope, courier, config, $location, Private) => {
|
||||
|
||||
if (healthCheck($window, $rootScope) && !$location.path().includes("/settings")) {
|
||||
let deferred = $q.defer();
|
||||
$location.path('/health-check');
|
||||
deferred.reject();
|
||||
return deferred.promise;
|
||||
} else {
|
||||
const State = Private(StateProvider);
|
||||
const savedObjectsClient = Private(SavedObjectsClientProvider);
|
||||
|
||||
return savedObjectsClient.find({
|
||||
type: 'index-pattern',
|
||||
fields: ['title'],
|
||||
perPage: 10000
|
||||
})
|
||||
.then(({ savedObjects }) => {
|
||||
/**
|
||||
* In making the indexPattern modifiable it was placed in appState. Unfortunately,
|
||||
* the load order of AppState conflicts with the load order of many other things
|
||||
* so in order to get the name of the index we should use, and to switch to the
|
||||
* default if necessary, we parse the appState with a temporary State object and
|
||||
* then destroy it immediatly after we're done
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
const state = new State('_a', {});
|
||||
|
||||
const specified = !!state.index;
|
||||
const exists = _.findIndex(savedObjects, o => o.id === state.index) > -1;
|
||||
const id = exists ? state.index : config.get('defaultIndex');
|
||||
state.destroy();
|
||||
|
||||
return Promise.props({
|
||||
list: savedObjects,
|
||||
loaded: courier.indexPatterns.get(id),
|
||||
stateVal: state.index,
|
||||
stateValFound: specified && exists
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const getSavedSearch = (courier, $q, $window, $rootScope, savedSearches, $route) => {
|
||||
if (healthCheck($window, $rootScope)) {
|
||||
let deferred = $q.defer();
|
||||
@ -311,15 +268,13 @@ routes
|
||||
resolve: {
|
||||
"checkAPI": settingsWizard,
|
||||
"ip": getIp,
|
||||
"ips": getAllIp,
|
||||
"savedSearch": getSavedSearch
|
||||
}
|
||||
})
|
||||
.when('/agents-preview', {
|
||||
template: require('plugins/wazuh/templates/agents-prev/agents-prev.jade'),
|
||||
resolve: {
|
||||
"checkAPI": settingsWizard,
|
||||
"ips": getAllIp
|
||||
"checkAPI": settingsWizard
|
||||
}
|
||||
})
|
||||
.when('/manager/:tab?/', {
|
||||
@ -327,7 +282,6 @@ routes
|
||||
resolve: {
|
||||
"checkAPI": settingsWizard,
|
||||
"ip": getIp,
|
||||
"ips": getAllIp,
|
||||
"savedSearch": getSavedSearch
|
||||
}
|
||||
})
|
||||
@ -336,7 +290,6 @@ routes
|
||||
resolve: {
|
||||
"checkAPI": settingsWizard,
|
||||
"ip": getIp,
|
||||
"ips": getAllIp,
|
||||
"savedSearch": getSavedSearch
|
||||
}
|
||||
})
|
||||
@ -345,15 +298,11 @@ routes
|
||||
resolve: {
|
||||
"checkAPI": settingsWizard,
|
||||
"ip": getIp,
|
||||
"ips": getAllIp,
|
||||
"savedSearch": getSavedSearch
|
||||
}
|
||||
})
|
||||
.when('/settings/:tab?/', {
|
||||
template: require('plugins/wazuh/templates/settings/settings.html'),
|
||||
resolve: {
|
||||
"ips": getAllIp
|
||||
}
|
||||
})
|
||||
.when('/visualize/create?', {
|
||||
redirectTo: function () {},
|
||||
|
@ -284,7 +284,7 @@
|
||||
|
||||
<div flex="20" layout="column" class="height-41 md-block wz-margin-top-17 wz-margin-right-15 wz-select-input">
|
||||
<select flex class="kuiSelect wz-border-none cursor-pointer" ng-model="selectedIndexPattern" ng-change="changeIndexPattern(selectedIndexPattern)" aria-label="Select index pattern">
|
||||
<option ng-repeat="indexPattern in indexPatterns" value="{{indexPattern.id}}">{{indexPattern.attributes.title}}</option>
|
||||
<option ng-repeat="indexPattern in indexPatterns" value="{{indexPattern.id}}">{{indexPattern.title}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</md-card-content>
|
||||
|
@ -329,6 +329,59 @@ module.exports = (server, options) => {
|
||||
|
||||
module.exports = getConfig;
|
||||
|
||||
|
||||
const getlist = async (req,res) => {
|
||||
try {
|
||||
const data = await elasticRequest
|
||||
.callWithInternalUser('search', {
|
||||
index: '.kibana',
|
||||
type: 'doc',
|
||||
body: {
|
||||
"query":{
|
||||
"match":{
|
||||
"type": "index-pattern"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
if(data && data.hits && data.hits.hits){
|
||||
const minimum = ["@timestamp", "full_log", "manager.name", "agent.id"];
|
||||
let list = [];
|
||||
if(data.hits.hits.length === 0) throw new Error('There is no index pattern');
|
||||
for(const index of data.hits.hits){
|
||||
let valid, parsed;
|
||||
try{
|
||||
parsed = JSON.parse(index._source['index-pattern'].fields)
|
||||
} catch (error){
|
||||
continue;
|
||||
}
|
||||
|
||||
valid = parsed.filter(item => minimum.includes(item.name));
|
||||
if(valid.length === 4){
|
||||
list.push({
|
||||
id: index._id.split('index-pattern:')[1],
|
||||
title: index._source['index-pattern'].title
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
return res({data: list});
|
||||
}
|
||||
|
||||
throw new Error('The Elasticsearch request didn\'t fetch the expected data');
|
||||
|
||||
} catch(error){
|
||||
return res({error: error.message}).code(500)
|
||||
}
|
||||
}
|
||||
|
||||
// Get index patterns list
|
||||
server.route({
|
||||
method: 'GET',
|
||||
path: '/get-list',
|
||||
handler: getlist
|
||||
});
|
||||
//Server routes
|
||||
|
||||
/*
|
||||
|
@ -147,7 +147,13 @@ module.exports = (server, options) => {
|
||||
.callWithInternalUser('search', {
|
||||
index: '.kibana',
|
||||
type: 'doc',
|
||||
q: `index-pattern.title:"${id}"`
|
||||
body: {
|
||||
"query": {
|
||||
"match": {
|
||||
"_id":"index-pattern:" + id
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return data;
|
||||
} catch (error) {
|
||||
|
32
server/integration-files/monitoring-template.js
Normal file
32
server/integration-files/monitoring-template.js
Normal file
@ -0,0 +1,32 @@
|
||||
module.exports = {
|
||||
"order": 0,
|
||||
"template": "wazuh-monitoring*",
|
||||
"settings": {
|
||||
"index.refresh_interval": "5s"
|
||||
},
|
||||
"mappings": {
|
||||
"wazuh-agent": {
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date",
|
||||
"format": "dateOptionalTime"
|
||||
},
|
||||
"status": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"ip": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"host": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -33,324 +33,394 @@ module.exports = (server, options) => {
|
||||
}
|
||||
|
||||
// Check status and get agent status array
|
||||
const checkStatus = (apiEntry, maxSize, offset) => {
|
||||
if (!maxSize) {
|
||||
log('monitoring.js', 'You must provide a max size');
|
||||
server.log([blueWazuh, 'monitoring', 'error'], 'You must provide a max size');
|
||||
}
|
||||
const checkStatus = async (apiEntry, maxSize, offset) => {
|
||||
try {
|
||||
if (!maxSize) {
|
||||
throw new Error('You must provide a max size')
|
||||
}
|
||||
|
||||
const payload = {
|
||||
offset: offset ? offset: 0,
|
||||
limit : (250 < maxSize) ? 250 : maxSize
|
||||
};
|
||||
|
||||
const options = {
|
||||
headers: {
|
||||
'wazuh-app-version': packageJSON.version
|
||||
},
|
||||
username: apiEntry.user,
|
||||
password: apiEntry.password,
|
||||
rejectUnauthorized: !apiEntry.insecure
|
||||
};
|
||||
|
||||
const response = await needle('get', `${getPath(apiEntry)}/agents`, payload, options);
|
||||
|
||||
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) {
|
||||
if (!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);
|
||||
return checkStatus(apiEntry, response.body.data.totalItems, payload.limit + payload.offset);
|
||||
} else {
|
||||
saveStatus();
|
||||
await saveStatus();
|
||||
}
|
||||
} else {
|
||||
log('monitoring.js', 'Can not access Wazuh API');
|
||||
server.log([blueWazuh, 'monitoring', 'error'], 'Can not access Wazuh API');
|
||||
throw new Error('Can not access Wazuh API')
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
|
||||
} catch (error) {
|
||||
log('monitoring.js', 'Can not access Wazuh API ' + error.message || error);
|
||||
server.log([blueWazuh, 'monitoring', 'error'], 'Can not access Wazuh API ' + error.message || error);
|
||||
}
|
||||
};
|
||||
|
||||
// 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) => {
|
||||
const checkAndSaveStatus = async apiEntry => {
|
||||
try{
|
||||
const payload = {
|
||||
'offset': 0,
|
||||
'limit': 1
|
||||
};
|
||||
|
||||
const options = {
|
||||
headers: {
|
||||
'wazuh-app-version': packageJSON.version
|
||||
},
|
||||
username: apiEntry.user,
|
||||
password: apiEntry.password,
|
||||
rejectUnauthorized: !apiEntry.insecure
|
||||
};
|
||||
|
||||
const response = await needle('get', `${getPath(apiEntry)}/agents`, payload, options)
|
||||
|
||||
if (!response.error && response.body.data && response.body.data.totalItems) {
|
||||
checkStatus(apiEntry, response.body.data.totalItems);
|
||||
} else {
|
||||
log('monitoring.js', 'Wazuh API credentials not found or are not correct. Open the app in your browser and configure it to start monitoring agents.');
|
||||
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.');
|
||||
}
|
||||
});
|
||||
return;
|
||||
} catch(error){
|
||||
log('monitoring.js',error.message || error);
|
||||
server.log([blueWazuh, 'monitoring', 'error'], error.message || error);
|
||||
}
|
||||
};
|
||||
|
||||
// Load Wazuh API credentials from Elasticsearch document
|
||||
const loadCredentials = (apiEntries) => {
|
||||
if (typeof apiEntries === 'undefined' || !('hits' in apiEntries)) return;
|
||||
const loadCredentials = async apiEntries => {
|
||||
try {
|
||||
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) {
|
||||
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) {
|
||||
log('monitoring.js loadCredentials', apiEntry.error || apiEntry);
|
||||
server.log([blueWazuh, 'monitoring', 'error'], `Error getting wazuh-api data: ${apiEntry.error}`);
|
||||
break;
|
||||
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) {
|
||||
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) {
|
||||
log('monitoring.js loadCredentials', apiEntry.error || apiEntry);
|
||||
server.log([blueWazuh, 'monitoring', 'error'], `Error getting wazuh-api data: ${apiEntry.error}`);
|
||||
break;
|
||||
}
|
||||
await checkAndSaveStatus(apiEntry);
|
||||
}
|
||||
checkAndSaveStatus(apiEntry);
|
||||
} catch(error){
|
||||
log('monitoring.js',error.message || error);
|
||||
server.log([blueWazuh, 'monitoring', 'error'], error.message || error);
|
||||
}
|
||||
};
|
||||
|
||||
// Get API configuration from elastic and callback to loadCredentials
|
||||
const getConfig = (callback) => {
|
||||
elasticRequest.callWithInternalUser('search', {
|
||||
index: '.wazuh',
|
||||
type: 'wazuh-configuration'
|
||||
})
|
||||
.then(data => {
|
||||
const getConfig = async callback => {
|
||||
try {
|
||||
const data = await elasticRequest.callWithInternalUser('search', {
|
||||
index: '.wazuh',
|
||||
type: 'wazuh-configuration'
|
||||
})
|
||||
|
||||
if (data.hits.total > 0) {
|
||||
callback(data.hits);
|
||||
} else {
|
||||
log('monitoring.js getConfig','no credentials');
|
||||
callback({
|
||||
'error': 'no credentials',
|
||||
'error_code': 1
|
||||
});
|
||||
return callback(data.hits);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
log('monitoring.js getConfig','no credentials');
|
||||
return callback({
|
||||
'error': 'no credentials',
|
||||
'error_code': 1
|
||||
});
|
||||
|
||||
} catch (error){
|
||||
log('monitoring.js getConfig',error.message || error);
|
||||
callback({
|
||||
return callback({
|
||||
'error': 'no elasticsearch',
|
||||
'error_code': 2
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Importing Wazuh app visualizations and dashboards
|
||||
const importAppObjects = (id) => {
|
||||
log('monitoring.js importAppObjects','Importing Wazuh app visualizations...','info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], 'Importing Wazuh app visualizations...');
|
||||
|
||||
const importAppObjects = async id => {
|
||||
try {
|
||||
app_objects = require(APP_OBJECTS_FILE);
|
||||
} catch (error) {
|
||||
log('monitoring.js importAppObjects', error.message || error);
|
||||
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: ' + error.message || error);
|
||||
}
|
||||
|
||||
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;
|
||||
log('monitoring.js importAppObjects','Importing Wazuh app visualizations...','info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], 'Importing Wazuh app visualizations...');
|
||||
|
||||
try {
|
||||
app_objects = require(APP_OBJECTS_FILE);
|
||||
} catch (error) {
|
||||
log('monitoring.js importAppObjects', error.message || error);
|
||||
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: ' + error.message || error);
|
||||
}
|
||||
|
||||
temp["type"] = element._type;
|
||||
body += JSON.stringify(temp) + "\n";
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
await elasticRequest.callWithInternalUser('bulk', {
|
||||
index: '.kibana',
|
||||
body: body
|
||||
})
|
||||
|
||||
elasticRequest.callWithInternalUser('bulk', {
|
||||
index: '.kibana',
|
||||
body: body
|
||||
})
|
||||
.then(() => elasticRequest.callWithInternalUser('indices.refresh', {
|
||||
index: ['.kibana', index_pattern]
|
||||
}))
|
||||
.then(() => {
|
||||
await elasticRequest.callWithInternalUser('indices.refresh', {
|
||||
index: ['.kibana', index_pattern]
|
||||
})
|
||||
|
||||
|
||||
log('monitoring.js importAppObjects', 'Wazuh app visualizations were successfully installed. App ready to be used.', 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], 'Wazuh app visualizations were successfully installed. App ready to be used.');
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
return;
|
||||
|
||||
} catch (error) {
|
||||
log('monitoring.js importAppObjects',error.message || error);
|
||||
server.log([blueWazuh, 'server', 'error'], 'Error importing objects into elasticsearch. Bulk request failed.');
|
||||
});
|
||||
server.log([blueWazuh, 'server', 'error'], 'Error importing objects into elasticsearch. Bulk request failed.' + error.message || error);
|
||||
}
|
||||
};
|
||||
|
||||
// fetchAgents on demand
|
||||
const fetchAgents = () => getConfig(loadCredentials);
|
||||
|
||||
// Configure Kibana patterns.
|
||||
const configureKibana = () => {
|
||||
log('monitoring.js configureKibana', `Creating index pattern: ${index_pattern}`, 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], `Creating index pattern: ${index_pattern}`);
|
||||
|
||||
let patternId = 'index-pattern:' + index_pattern;
|
||||
elasticRequest.callWithInternalUser('create', {
|
||||
index: '.kibana',
|
||||
type: 'doc',
|
||||
id: patternId,
|
||||
body: {
|
||||
"type": 'index-pattern',
|
||||
"index-pattern": {
|
||||
"title": index_pattern,
|
||||
"timeFieldName": '@timestamp'
|
||||
const configureKibana = async () => {
|
||||
try {
|
||||
log('monitoring.js configureKibana', `Creating index pattern: ${index_pattern}`, 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], `Creating index pattern: ${index_pattern}`);
|
||||
|
||||
let patternId = 'index-pattern:' + index_pattern;
|
||||
await elasticRequest.callWithInternalUser('create', {
|
||||
index: '.kibana',
|
||||
type: 'doc',
|
||||
id: patternId,
|
||||
body: {
|
||||
"type": 'index-pattern',
|
||||
"index-pattern": {
|
||||
"title": index_pattern,
|
||||
"timeFieldName": '@timestamp'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(resp => {
|
||||
})
|
||||
log('monitoring.js configureKibana', `Created index pattern: ${index_pattern}`, 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], `Created index pattern: ${index_pattern}`);
|
||||
importAppObjects(index_pattern);
|
||||
})
|
||||
.catch(error => {
|
||||
await importAppObjects(index_pattern);
|
||||
return;
|
||||
} catch(error) {
|
||||
log('monitoring.js configureKibana',error.message || error);
|
||||
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(() => {
|
||||
const createIndex = async todayIndex => {
|
||||
try {
|
||||
await elasticRequest.callWithInternalUser('indices.create', { index: todayIndex });
|
||||
log('monitoring.js createIndex', 'Successfully created today index.', 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], 'Successfully created today index.');
|
||||
insertDocument(todayIndex);
|
||||
})
|
||||
.catch(error => {
|
||||
await insertDocument(todayIndex);
|
||||
return;
|
||||
} catch (error) {
|
||||
log('monitoring.js createIndex', error.message || error);
|
||||
server.log([blueWazuh, 'monitoring', 'error'], `Could not create ${todayIndex} index on elasticsearch due to ` + error);
|
||||
});
|
||||
server.log([blueWazuh, 'monitoring', 'error'], `Could not create ${todayIndex} index on elasticsearch due to ` + error.message || error);
|
||||
}
|
||||
};
|
||||
|
||||
// Inserting one document per agent into Elastic. Bulk.
|
||||
const insertDocument = (todayIndex) => {
|
||||
let body = '';
|
||||
if (agentsArray.length > 0) {
|
||||
let managerName = agentsArray[0].name;
|
||||
const insertDocument = async todayIndex => {
|
||||
try {
|
||||
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;
|
||||
|
||||
const response = await elasticRequest.callWithInternalUser('bulk', {
|
||||
index: todayIndex,
|
||||
type: 'agent',
|
||||
body: body
|
||||
})
|
||||
|
||||
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";
|
||||
agentsArray.length = 0;
|
||||
}
|
||||
|
||||
if (body === '') return;
|
||||
|
||||
elasticRequest.callWithInternalUser('bulk', {
|
||||
index: todayIndex,
|
||||
type: 'agent',
|
||||
body: body
|
||||
})
|
||||
.then((response) => agentsArray.length = 0)
|
||||
.catch(error => {
|
||||
log('monitoring.js insertDocument', error.message || error);
|
||||
server.log([blueWazuh, 'monitoring', 'error'], 'Error inserting agent data into elasticsearch. Bulk request failed due to ' + error);
|
||||
});
|
||||
return;
|
||||
} catch (error) {
|
||||
log('monitoring.js insertDocument', error.message || error);
|
||||
server.log([blueWazuh, 'monitoring', 'error'], 'Error inserting agent data into elasticsearch. Bulk request failed due to ' + error.message || 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;
|
||||
const saveStatus = async () => {
|
||||
try {
|
||||
fDate = new Date().toISOString().replace(/T/, '-').replace(/\..+/, '').replace(/-/g, '.').replace(/:/g, '').slice(0, -7);
|
||||
todayIndex = index_prefix + fDate;
|
||||
|
||||
const result = await elasticRequest.callWithInternalUser('indices.exists', { index: todayIndex })
|
||||
|
||||
result ? await insertDocument(todayIndex) : await createIndex(todayIndex);
|
||||
|
||||
elasticRequest.callWithInternalUser('indices.exists', { index: todayIndex })
|
||||
.then((result) => {
|
||||
if (result) insertDocument(todayIndex);
|
||||
else createIndex(todayIndex);
|
||||
})
|
||||
.catch(error => {
|
||||
return;
|
||||
|
||||
} catch (error) {
|
||||
log('monitoring.js saveStatus', `Could not check if the index ${todayIndex} exists due to ${error.message || error}`);
|
||||
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 = () => {
|
||||
log('monitoring.js init', 'Creating today index...', 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], 'Creating today index...');
|
||||
saveStatus();
|
||||
|
||||
let patternId = 'index-pattern:' + index_pattern;
|
||||
elasticRequest.callWithInternalUser('get', {
|
||||
index: '.kibana',
|
||||
type: 'doc',
|
||||
id: patternId
|
||||
})
|
||||
.then(data => {
|
||||
log('monitoring.js init', 'Skipping index-pattern creation. Already exists.', 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], 'Skipping index-pattern creation. Already exists.');
|
||||
})
|
||||
.catch(error => {
|
||||
log('monitoring.js init', 'Didn\'t find wazuh-monitoring pattern for Kibana v6.x. Proceeding to create it...');
|
||||
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-*'
|
||||
})
|
||||
.then(resp => {
|
||||
const createWazuhMonitoring = async () => {
|
||||
try{
|
||||
|
||||
const patternId = 'index-pattern:' + index_pattern;
|
||||
try{
|
||||
await elasticRequest.callWithInternalUser('delete', {
|
||||
index: '.kibana',
|
||||
type: 'doc',
|
||||
id: 'index-pattern:wazuh-monitoring-*'
|
||||
})
|
||||
log('monitoring.js init', 'Successfully deleted old wazuh-monitoring pattern.', 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], "Successfully deleted old wazuh-monitoring pattern.");
|
||||
})
|
||||
.catch(error => {
|
||||
log('monitoring.js init', 'Didn\'t find old wazuh-monitoring pattern. Skipping deletion.');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], "Didn't find old wazuh-monitoring pattern. Skipping deletion.");
|
||||
} catch (error) {
|
||||
log('monitoring.js init', 'No need to delete old wazuh-monitoring pattern.', 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], "No need to delete old wazuh-monitoring pattern.");
|
||||
}
|
||||
|
||||
await configureKibana();
|
||||
return;
|
||||
}catch(error){
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
const checkTemplate = async () => {
|
||||
try {
|
||||
log('monitoring.js checkTemplate', 'Updating wazuh-monitoring template...', 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], "Updating wazuh-monitoring template...");
|
||||
const monitoringTemplate = require('./integration-files/monitoring-template');
|
||||
const data = await elasticRequest.callWithInternalUser('indices.putTemplate', {
|
||||
name : 'wazuh-agent',
|
||||
body : monitoringTemplate
|
||||
});
|
||||
configureKibana();
|
||||
});
|
||||
return;
|
||||
} catch(error){
|
||||
log('monitoring.js checkTemplate', 'Something went wrong updating wazuh-monitoring template...' + error.message || error);
|
||||
server.log([blueWazuh, 'monitoring', 'info'], "Something went wrong updating wazuh-monitoring template..." + error.message || error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Main. First execution when installing / loading App.
|
||||
const init = async () => {
|
||||
try {
|
||||
|
||||
log('monitoring.js init', 'Creating/Updating wazuh-agent template...', 'info');
|
||||
await checkTemplate();
|
||||
|
||||
log('monitoring.js init', 'Creating today index...', 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], 'Creating today index...');
|
||||
|
||||
await saveStatus();
|
||||
|
||||
const patternId = 'index-pattern:' + index_pattern;
|
||||
await elasticRequest.callWithInternalUser('get', {
|
||||
index: '.kibana',
|
||||
type: 'doc',
|
||||
id: patternId
|
||||
});
|
||||
|
||||
log('monitoring.js init', 'Skipping index-pattern creation. Already exists.', 'info');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], 'Skipping index-pattern creation. Already exists.');
|
||||
|
||||
return;
|
||||
|
||||
} catch (error) {
|
||||
server.log([blueWazuh, 'monitoring', 'error'], error.message);
|
||||
log('monitoring.js init', 'Didn\'t find wazuh-monitoring pattern for Kibana v6.x. Proceeding to create it...');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], "Didn't find wazuh-monitoring pattern for Kibana v6.x. Proceeding to create it...");
|
||||
return createWazuhMonitoring();
|
||||
}
|
||||
};
|
||||
|
||||
// Check Elasticsearch Server status and .kibana index presence
|
||||
const checkElasticsearchServer = () => {
|
||||
return new Promise(function (resolve, reject) {
|
||||
elasticRequest.callWithInternalUser('indices.exists', { index: ".kibana" })
|
||||
.then(data => {
|
||||
if (data) server.plugins.elasticsearch.waitUntilReady().then(data => { resolve(data); });
|
||||
else reject(data);
|
||||
})
|
||||
.catch(error => {
|
||||
log('monitoring.js checkElasticsearchServer',error.message || error);
|
||||
reject(error);
|
||||
});
|
||||
})
|
||||
const checkElasticsearchServer = async () => {
|
||||
try {
|
||||
const data = await elasticRequest.callWithInternalUser('indices.exists', { index: ".kibana" });
|
||||
if (data) {
|
||||
const pluginsData = await server.plugins.elasticsearch.waitUntilReady();
|
||||
return pluginsData;
|
||||
}
|
||||
return Promise.reject(data);
|
||||
} catch(error){
|
||||
log('monitoring.js checkElasticsearchServer',error.message || error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until Kibana server is ready
|
||||
const checkKibanaStatus = () => {
|
||||
checkElasticsearchServer().then(data => { init() })
|
||||
.catch(error => {
|
||||
const checkKibanaStatus = async () => {
|
||||
try {
|
||||
log('monitoring.js checkKibanaStatus','Waiting for Kibana and Elasticsearch servers to be ready...');
|
||||
server.log([blueWazuh, 'monitoring', 'info'], 'Waiting for Kibana and Elasticsearch servers to be ready...');
|
||||
await checkElasticsearchServer();
|
||||
await init();
|
||||
return;
|
||||
} catch(error) {
|
||||
log('monitoring.js checkKibanaStatus',error.message || error);
|
||||
server.log([blueWazuh, 'monitoring', 'info'], 'Waiting for Kibana and Elasticsearch servers to be ready...');
|
||||
setTimeout(() => checkKibanaStatus(), 3000);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Check Kibana index and if it is prepared, start the initialization of Wazuh App.
|
||||
|
Loading…
Reference in New Issue
Block a user