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

Better wazuh-monitoring management #441

Merged
merged 11 commits into from
May 10, 2018
48 changes: 29 additions & 19 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,60 +21,70 @@
# ------------------------------- Index patterns -------------------------------
#
# Default index pattern to use.
#pattern: wazuh-alerts-3.x-*
#pattern: wazuh-alerts-3.x-*
#
# ----------------------------------- Checks -----------------------------------
#
# Defines which checks must to be consider by the healthcheck
# step once the Wazuh app starts. Values must to be true or false.
#checks.pattern : true
#checks.template: true
#checks.api : true
#checks.setup : true
#checks.pattern : true
#checks.template: true
#checks.api : true
#checks.setup : true
#
# --------------------------------- Extensions ---------------------------------
#
# Defines which extensions should be activated when you add a new API entry.
# You can change them after Wazuh app starts.
# Values must to be true or false.
#extensions.pci : true
#extensions.audit : true
#extensions.oscap : true
#extensions.aws : false
#extensions.virustotal: false
#extensions.pci : true
#extensions.audit : true
#extensions.oscap : true
#extensions.aws : false
#extensions.virustotal: false
#
# ---------------------------- Basic authentication ----------------------------
#
# Defines if authentication is enabled or not.
# Field enabled could be true or false, it means login is enabled/disabled.
# Field password is the password used to authenticate on the Wazuh app.
#login.enabled : false
#login.password: changeme
#login.enabled : false
#login.password: changeme
#
# ---------------------------------- Time out ----------------------------------
#
# Defines maximum timeout to be used on the Wazuh app requests.
# Default value is 8000. It will be ignored if it is bellow 1500.
# It means milliseconds before we consider a request as failed.
#timeout: 8000
#timeout: 8000
#
# ------------------------------ Advanced indices ------------------------------
#
# Configure .wazuh and .wazuh-version indices shards and replicas.
#wazuh.shards : 1
#wazuh.replicas : 1
#wazuh-version.shards : 1
#wazuh-version.replicas : 1
#wazuh.shards : 1
#wazuh.replicas : 1
#wazuh-version.shards : 1
#wazuh-version.replicas: 1
#
#
# --------------------------- Index pattern selector ---------------------------
#
# Defines if the user is allowed to change the selected index
# pattern directly from the Wazuh app top menu. Default: yes
#ip.selector: true
#ip.selector: true
#
#---------------------------- RBAC X-Pack -------------------------------------
#
# Custom setting to enable/disable RBAC capabilities included on X-Pack (security)
# Default: enabled
#xpack.rbac.enabled: true
#xpack.rbac.enabled: true
#
#---------------------------- wazuh-monitoring --------------------------------
# Custom setting to enable/disable wazuh-monitoring indices.
# Default: enabled
#wazuh.monitoring.enabled: true
#
# Custom setting to set the frequency for wazuh-monitoring indices cron task.
# Default: 3600 (s)
#wazuh.monitoring.frequency: 3600
#
34 changes: 33 additions & 1 deletion public/controllers/overview.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import * as modules from 'ui/modules'

const app = modules.get('app/wazuh', []);

app.controller('overviewController', function ($scope, $location, $rootScope, appState, genericReq, errorHandler) {
app.controller('overviewController', function ($scope, $location, $rootScope, appState, genericReq, errorHandler, apiReq) {
$rootScope.rawVisualizations = null;

$rootScope.page = 'overview';
$scope.extensions = appState.getExtensions().extensions;

$scope.wzMonitoringEnabled = false;

// Metrics General
const metricsGeneral = {
totalAlerts: '[vis-id="\'Wazuh-App-Overview-General-Metric-alerts\'"]',
Expand Down Expand Up @@ -292,4 +294,34 @@ app.controller('overviewController', function ($scope, $location, $rootScope, ap

$scope.tabs = tabs;
$scope.selectedIndex = 0;

genericReq.request('GET', '/api/wazuh-api/configuration', {})
.then(configuration => {
if(configuration && configuration.data && configuration.data.data) {
$scope.wzMonitoringEnabled = typeof configuration.data.data['wazuh.monitoring.enabled'] !== 'undefined' ?
!!configuration.data.data['wazuh.monitoring.enabled'] :
true;
if(!$scope.wzMonitoringEnabled){
apiReq.request('GET', '/agents/summary', { })
.then(data => {
if(data && data.data && data.data.data){
$scope.agentsCountActive = data.data.data.Active;
$scope.agentsCountDisconnected = data.data.data.Disconnected;
$scope.agentsCountNeverConnected = data.data.data['Never connected'];
$scope.agentsCountTotal = data.data.data.Total;
$scope.agentsCoverity = (data.data.data.Active / data.data.data.Total) * 100;
} else {
throw new Error('Error fetching /agents/summary from Wazuh API')
}
})
.catch(error => {
errorHandler.handle(error, 'Overview - Monitoring');
if (!$rootScope.$$phase) $rootScope.$digest();
})
}
} else {
$scope.wzMonitoringEnabled = true;
}
})
.catch(error => {console.log(error.message || error);$scope.wzMonitoringEnabled = true});
});
32 changes: 31 additions & 1 deletion public/templates/overview/overview-general.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,41 @@
</md-card-content>
</md-card>
<md-card flex="35" class="wz-md-card">
<md-card-content class="wazuh-column">
<md-card-content class="wazuh-column" ng-show="wzMonitoringEnabled">
<span class="wz-headline-title">Agents status</span>
<md-divider class="wz-margin-top-10"></md-divider>
<kbn-vis vis-id="'Wazuh-App-Overview-General-Agents-status'"></kbn-vis>
</md-card-content>
<md-card-content class="wazuh-column" ng-show="!wzMonitoringEnabled">
<span class="wz-headline-title">Agents status</span>
<md-divider class="wz-margin-top-10"></md-divider>
<div layout="row">
<div flex layout="column">
<div layout="row" class="wz-padding-top-10"></div>
<div layout="row" class="wz-padding-top-10">
<p flex="50" class="wz-text-bold">Total</p>
<p class="wz-text-right color-grey wz-text-bold">{{agentsCountTotal}}</p>
</div>
<div layout="row" class="wz-padding-top-10"></div>
<div layout="row" class="wz-padding-top-10">
<p flex="50">Active</p>
<p class="wz-text-right color-grey">{{agentsCountActive}}</p>
</div>
<div layout="row" class="wz-padding-top-10">
<p flex="50">Disconnected</p>
<p class="wz-text-right color-grey">{{agentsCountDisconnected}}</p>
</div>
<div layout="row" class="wz-padding-top-10">
<p flex="50">Never connected</p>
<p class="wz-text-right color-grey">{{agentsCountNeverConnected}}</p>
</div>
<div layout="row" class="wz-padding-top-10">
<p flex="50">Agents coverage</p>
<p class="wz-text-right color-grey">{{(agentsCoverity | number:2)}}%</p>
</div>
</div>
</div>
</md-card-content>
</md-card>
</div>

Expand Down
7 changes: 3 additions & 4 deletions server/controllers/wazuh-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@

// Require some libraries
import needle from 'needle'
import fs from 'fs'
import yml from 'js-yaml'
import path from 'path'
import colors from 'ansicolors'
import pciRequirementsFile from '../integration-files/pci-requirements'
Expand All @@ -23,6 +21,7 @@ import packageInfo from '../../package.json'
import monitoring from '../monitoring'
import ErrorResponse from './error-response'
import { Parser } from 'json2csv';
import getConfiguration from '../lib/get-configuration'

const blueWazuh = colors.blue('wazuh');

Expand Down Expand Up @@ -344,7 +343,7 @@ export default class WazuhApi {

getConfigurationFile (req,reply) {
try{
const configFile = yml.load(fs.readFileSync(path.join(__dirname,'../../config.yml'), {encoding: 'utf-8'}));
const configFile = getConfiguration();

if(configFile && configFile['login.password']){
delete configFile['login.password'];
Expand All @@ -364,7 +363,7 @@ export default class WazuhApi {
login(req,reply) {
try{

const configFile = yml.load(fs.readFileSync(path.join(__dirname,'../../config.yml'), {encoding: 'utf-8'}));
const configFile = getConfiguration();

if(!configFile){
throw new Error('Configuration file not found');
Expand Down
7 changes: 2 additions & 5 deletions server/controllers/wazuh-elastic.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@
*
* Find more information about this on the LICENSE file.
*/
import ElasticWrapper from '../lib/elastic-wrapper';
import fs from 'fs';
import yml from 'js-yaml';
import path from 'path';
import ErrorResponse from './error-response'
import ElasticWrapper from '../lib/elastic-wrapper';
import ErrorResponse from './error-response'

import { AgentsVisualizations, OverviewVisualizations } from '../integration-files/visualizations'

Expand Down
6 changes: 2 additions & 4 deletions server/initialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@
*/
import needle from 'needle'
import colors from 'ansicolors'
import fs from 'fs'
import yml from 'js-yaml'
import path from 'path'
import log from './logger'
import knownFields from './integration-files/known-fields'
import ElasticWrapper from './lib/elastic-wrapper'
import packageJSON from '../package.json'
import kibana_template from './integration-files/kibana-template'
import getConfiguration from './lib/get-configuration'

export default (server, options) => {
const blueWazuh = colors.blue('wazuh');
Expand All @@ -36,7 +34,7 @@ export default (server, options) => {
let pattern = null;
// Read config from package.json and config.yml
try {
configurationFile = yml.load(fs.readFileSync(path.join(__dirname, '../config.yml'), { encoding: 'utf-8' }));
configurationFile = getConfiguration();

global.loginEnabled = (configurationFile && typeof configurationFile['login.enabled'] !== 'undefined') ? configurationFile['login.enabled'] : false;
pattern = (configurationFile && typeof configurationFile.pattern !== 'undefined') ? configurationFile.pattern : 'wazuh-alerts-3.x-*';
Expand Down
25 changes: 25 additions & 0 deletions server/lib/get-configuration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Wazuh app - Module to parse the configuration file
* Copyright (C) 2018 Wazuh, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Find more information about this on the LICENSE file.
*/
import fs from 'fs'
import yml from 'js-yaml'
import path from 'path'

export default () => {
try {
const customPath = path.join(__dirname, '../../config.yml');
const raw = fs.readFileSync(customPath, { encoding: 'utf-8' })
const file = yml.load(raw);
return file;
} catch (error) {
return false;
}
}
37 changes: 37 additions & 0 deletions server/lib/parse-cron.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Wazuh app - Module to transform seconds interval to cron readable format
* Copyright (C) 2018 Wazuh, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Find more information about this on the LICENSE file.
*/
import log from '../logger'
import cron from 'node-cron'

export default interval => {
try {
if(!interval) throw new Error('Interval not found');

const parsed = parseInt(interval);

if(!parsed || typeof parsed !== 'number') throw new Error('Interval not valid');
if(parsed < 60) throw new Error('Interval too low');
if(parsed >= 84600) throw new Error('Interval too high');

const minutes = parseInt(parsed / 60);

const cronstr = `0 */${minutes} * * * *`

if(!cron.validate(cronstr)) throw new Error('Generated cron expression not valid for node-cron module')

return cronstr;

} catch (error) {
log('[cron][parse-interval]',`Using default value due to: ${error.message || error}`);
return '0 1 * * * *';
}
}
37 changes: 34 additions & 3 deletions server/monitoring.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,38 @@ import log from './logger'
import ElasticWrapper from './lib/elastic-wrapper'
import monitoringTemplate from './integration-files/monitoring-template'
import packageJSON from '../package.json'
import getConfiguration from './lib/get-configuration'
import parseCron from './lib/parse-cron'

export default (server, options) => {
const blueWazuh = colors.blue('wazuh');
const blueWazuh = colors.blue('wazuh');

let ENABLED = true;
let FREQUENCY = 3600;
let CRON_FREQ = '0 1 * * * *';
try {
const configFile = getConfiguration();

ENABLED = configFile && typeof configFile['wazuh.monitoring.enabled'] !== 'undefined' ?
configFile['wazuh.monitoring.enabled'] :
ENABLED;
FREQUENCY = configFile && typeof configFile['wazuh.monitoring.frequency'] !== 'undefined' ?
configFile['wazuh.monitoring.frequency'] :
FREQUENCY;

CRON_FREQ = parseCron(FREQUENCY);

!options && log('[monitoring][configuration]', `wazuh.monitoring.enabled: ${ENABLED}`,'info');
!options && server.log([blueWazuh, 'monitoring', 'info'], `wazuh.monitoring.enabled: ${ENABLED}`);

!options && log('[monitoring][configuration]', `wazuh.monitoring.frequency: ${FREQUENCY} (${CRON_FREQ}) `,'info');
!options && server.log([blueWazuh, 'monitoring', 'info'], `wazuh.monitoring.frequency: ${FREQUENCY} (${CRON_FREQ})`);

} catch (error) {
log('[monitoring][configuration]', error.message || error);
server.log([blueWazuh, 'monitoring', 'error'], error.message || error);
}

const index_pattern = "wazuh-monitoring-3.x-*";
const index_prefix = "wazuh-monitoring-3.x-";

Expand Down Expand Up @@ -206,6 +235,7 @@ export default (server, options) => {
// Creating wazuh-monitoring index
const createIndex = async (todayIndex,clusterName) => {
try {
if(!ENABLED) return;
await wzWrapper.createIndexByName(todayIndex);
log('[monitoring][createIndex]', 'Successfully created today index.', 'info');
server.log([blueWazuh, 'monitoring', 'info'], 'Successfully created today index.');
Expand Down Expand Up @@ -247,6 +277,7 @@ export default (server, options) => {
// Save agent status into elasticsearch, create index and/or insert document
const saveStatus = async clusterName => {
try {
if(!ENABLED) return;
fDate = new Date().toISOString().replace(/T/, '-').replace(/\..+/, '').replace(/-/g, '.').replace(/:/g, '').slice(0, -7);
todayIndex = index_prefix + fDate;

Expand Down Expand Up @@ -393,8 +424,8 @@ export default (server, options) => {
server.log([blueWazuh, 'monitoring [cronTask]', 'error'], error.message || error)
}
}
if(!options) cronTask()
if(!options && ENABLED) cronTask()
// Cron tab for getting agent status.
if(!options) cron.schedule('0 */10 * * * *', cronTask, true);
if(!options && ENABLED) cron.schedule(CRON_FREQ, cronTask, true);
return fetchAgentsExternal;
};