2017-10-27 07:03:53 +00:00
// External libraries
2017-10-27 10:03:05 +00:00
const cron = require ( 'node-cron' ) ;
const needle = require ( 'needle' ) ;
2017-10-27 07:22:10 +00:00
const getPath = require ( '../util/get-path' ) ;
2017-10-27 10:03:05 +00:00
2017-10-27 07:03:53 +00:00
// Colors for console logging
const colors = require ( 'ansicolors' ) ;
const blueWazuh = colors . blue ( 'wazuh' ) ;
2018-02-15 14:45:56 +00:00
const APP _OBJECTS _FILE = './integration-files/app-objects-file-monitoring.json' ;
2017-11-15 14:58:53 +00:00
2018-03-12 11:29:24 +00:00
const { log } = require ( './logger' ) ;
2017-10-27 10:03:05 +00:00
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 = { } ;
2018-01-29 12:57:28 +00:00
let app _objects = { } ;
2017-12-11 10:45:32 +00:00
// Read Wazuh App package file
try {
packageJSON = require ( '../package.json' ) ;
2018-03-12 11:57:14 +00:00
} catch ( error ) {
log ( 'monitoring.js' , error . message || error ) ;
server . log ( [ blueWazuh , 'monitoring' , 'error' ] , 'Could not read the Wazuh package file due to ' + error . message || error ) ;
2017-12-11 10:45:32 +00:00
}
// Check status and get agent status array
2018-03-19 11:21:44 +00:00
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
} ;
2018-03-19 12:18:56 +00:00
const response = await needle ( 'get' , ` ${ getPath ( apiEntry ) } /agents ` , payload , options ) ;
2017-12-11 10:45:32 +00:00
2018-03-19 11:21:44 +00:00
if ( ! response . error && response . body . data . items ) {
2017-12-11 10:45:32 +00:00
agentsArray = agentsArray . concat ( response . body . data . items ) ;
if ( ( payload . limit + payload . offset ) < maxSize ) {
2018-03-19 11:21:44 +00:00
return checkStatus ( apiEntry , response . body . data . totalItems , payload . limit + payload . offset ) ;
2017-12-11 10:45:32 +00:00
} else {
2018-03-19 11:21:44 +00:00
await saveStatus ( ) ;
2017-12-11 10:45:32 +00:00
}
} else {
2018-03-19 11:21:44 +00:00
throw new Error ( 'Can not access Wazuh API' )
2017-12-11 10:45:32 +00:00
}
2018-03-19 11:21:44 +00:00
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 ) ;
}
2017-12-11 10:45:32 +00:00
} ;
// Check API status twice and get agents total items
2018-03-19 11:21:44 +00:00
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 )
2017-12-11 10:45:32 +00:00
if ( ! response . error && response . body . data && response . body . data . totalItems ) {
checkStatus ( apiEntry , response . body . data . totalItems ) ;
} else {
2018-03-12 11:57:14 +00:00
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.' ) ;
2017-12-11 10:45:32 +00:00
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.' ) ;
}
2018-03-19 11:21:44 +00:00
return ;
} catch ( error ) {
log ( 'monitoring.js' , error . message || error ) ;
server . log ( [ blueWazuh , 'monitoring' , 'error' ] , error . message || error ) ;
}
2017-12-11 10:45:32 +00:00
} ;
// Load Wazuh API credentials from Elasticsearch document
2018-03-19 11:21:44 +00:00
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 ;
}
await checkAndSaveStatus ( apiEntry ) ;
2017-12-11 10:45:32 +00:00
}
2018-03-19 11:21:44 +00:00
} catch ( error ) {
log ( 'monitoring.js' , error . message || error ) ;
server . log ( [ blueWazuh , 'monitoring' , 'error' ] , error . message || error ) ;
2017-12-11 10:45:32 +00:00
}
} ;
// Get API configuration from elastic and callback to loadCredentials
2018-03-19 11:21:44 +00:00
const getConfig = async callback => {
try {
const data = await elasticRequest . callWithInternalUser ( 'search' , {
index : '.wazuh' ,
type : 'wazuh-configuration'
} )
2017-12-21 16:15:13 +00:00
if ( data . hits . total > 0 ) {
2018-03-19 11:21:44 +00:00
return callback ( data . hits ) ;
2017-12-11 10:45:32 +00:00
}
2018-03-19 11:21:44 +00:00
log ( 'monitoring.js getConfig' , 'no credentials' ) ;
return callback ( {
'error' : 'no credentials' ,
'error_code' : 1
} ) ;
} catch ( error ) {
2018-03-12 11:57:14 +00:00
log ( 'monitoring.js getConfig' , error . message || error ) ;
2018-03-19 11:21:44 +00:00
return callback ( {
2017-12-11 10:45:32 +00:00
'error' : 'no elasticsearch' ,
'error_code' : 2
} ) ;
2018-03-19 11:21:44 +00:00
}
2017-12-11 10:45:32 +00:00
} ;
// Importing Wazuh app visualizations and dashboards
2018-03-19 11:21:44 +00:00
const importAppObjects = async id => {
2017-12-11 10:45:32 +00:00
try {
2018-03-19 11:21:44 +00:00
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 ) ;
2017-12-11 10:45:32 +00:00
}
2018-03-19 11:21:44 +00:00
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
} )
2017-12-11 10:45:32 +00:00
2018-03-19 11:21:44 +00:00
await elasticRequest . callWithInternalUser ( 'indices.refresh' , {
index : [ '.kibana' , index _pattern ]
} )
2018-03-12 11:57:14 +00:00
log ( 'monitoring.js importAppObjects' , 'Wazuh app visualizations were successfully installed. App ready to be used.' , 'info' ) ;
2017-12-11 10:45:32 +00:00
server . log ( [ blueWazuh , 'monitoring' , 'info' ] , 'Wazuh app visualizations were successfully installed. App ready to be used.' ) ;
2018-03-19 11:21:44 +00:00
return ;
} catch ( error ) {
2018-03-12 11:57:14 +00:00
log ( 'monitoring.js importAppObjects' , error . message || error ) ;
2018-03-19 11:21:44 +00:00
server . log ( [ blueWazuh , 'server' , 'error' ] , 'Error importing objects into elasticsearch. Bulk request failed.' + error . message || error ) ;
}
2017-12-11 10:45:32 +00:00
} ;
// fetchAgents on demand
const fetchAgents = ( ) => getConfig ( loadCredentials ) ;
// Configure Kibana patterns.
2018-03-19 11:21:44 +00:00
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'
}
2017-12-11 10:45:32 +00:00
}
2018-03-19 11:21:44 +00:00
} )
2018-03-12 11:57:14 +00:00
log ( 'monitoring.js configureKibana' , ` Created index pattern: ${ index _pattern } ` , 'info' ) ;
server . log ( [ blueWazuh , 'monitoring' , 'info' ] , ` Created index pattern: ${ index _pattern } ` ) ;
2018-03-19 11:21:44 +00:00
await importAppObjects ( index _pattern ) ;
return ;
} catch ( error ) {
2018-03-12 11:57:14 +00:00
log ( 'monitoring.js configureKibana' , error . message || error ) ;
2017-12-11 10:45:32 +00:00
server . log ( [ blueWazuh , 'monitoring' , 'error' ] , 'Error creating index-pattern due to ' + error ) ;
2018-03-19 11:21:44 +00:00
}
2017-12-11 10:45:32 +00:00
} ;
// Creating wazuh-monitoring index
2018-03-19 11:21:44 +00:00
const createIndex = async todayIndex => {
try {
await elasticRequest . callWithInternalUser ( 'indices.create' , { index : todayIndex } ) ;
2018-03-12 11:57:14 +00:00
log ( 'monitoring.js createIndex' , 'Successfully created today index.' , 'info' ) ;
2017-12-11 10:45:32 +00:00
server . log ( [ blueWazuh , 'monitoring' , 'info' ] , 'Successfully created today index.' ) ;
2018-03-19 11:21:44 +00:00
await insertDocument ( todayIndex ) ;
return ;
} catch ( error ) {
2018-03-12 11:57:14 +00:00
log ( 'monitoring.js createIndex' , error . message || error ) ;
2018-03-19 11:21:44 +00:00
server . log ( [ blueWazuh , 'monitoring' , 'error' ] , ` Could not create ${ todayIndex } index on elasticsearch due to ` + error . message || error ) ;
}
2017-12-11 10:45:32 +00:00
} ;
// Inserting one document per agent into Elastic. Bulk.
2018-03-19 11:21:44 +00:00
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
} )
2017-12-11 10:45:32 +00:00
2018-03-19 11:21:44 +00:00
agentsArray . length = 0 ;
}
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 ) ;
2017-12-11 10:45:32 +00:00
}
} ;
// Save agent status into elasticsearch, create index and/or insert document
2018-03-19 11:21:44 +00:00
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 ) ;
return ;
} catch ( error ) {
2018-03-12 11:57:14 +00:00
log ( 'monitoring.js saveStatus' , ` Could not check if the index ${ todayIndex } exists due to ${ 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 ) ;
2018-03-19 11:21:44 +00:00
}
2017-12-11 10:45:32 +00:00
} ;
2018-03-19 11:21:44 +00:00
const createWazuhMonitoring = async ( ) => {
try {
2018-03-19 11:56:31 +00:00
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' , 'No need to delete old wazuh-monitoring pattern.' , 'info' ) ;
server . log ( [ blueWazuh , 'monitoring' , 'info' ] , "No need to delete old wazuh-monitoring pattern." ) ;
}
2018-03-19 11:21:44 +00:00
await configureKibana ( ) ;
return ;
} catch ( error ) {
return Promise . reject ( error ) ;
}
}
const checkTemplate = async ( ) => {
try {
2018-03-19 14:11:36 +00:00
log ( 'monitoring.js checkTemplate' , 'Updating wazuh-monitoring template...' , 'info' ) ;
server . log ( [ blueWazuh , 'monitoring' , 'info' ] , "Updating wazuh-monitoring template..." ) ;
2018-03-19 11:21:44 +00:00
const monitoringTemplate = require ( './integration-files/monitoring-template' ) ;
const data = await elasticRequest . callWithInternalUser ( 'indices.putTemplate' , {
name : 'wazuh-agent' ,
body : monitoringTemplate
2017-12-11 10:45:32 +00:00
} ) ;
2018-03-19 11:21:44 +00:00
return ;
} catch ( error ) {
2018-03-19 14:11:36 +00:00
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 ) ;
2018-03-19 11:21:44 +00:00
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 ;
2018-03-19 11:56:31 +00:00
2018-03-21 15:03:33 +00:00
// Checks if wazuh-monitoring index pattern is already created, if it fails create it
try {
log ( 'monitoring.js init' , 'Checking if wazuh-monitoring pattern exists...' , 'info' ) ;
server . log ( [ blueWazuh , 'monitoring' , 'info' ] , 'Checking if wazuh-monitoring pattern exists...' ) ;
await elasticRequest . callWithInternalUser ( 'get' , {
index : '.kibana' ,
type : 'doc' ,
id : patternId
} ) ;
} 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..." ) ;
return createWazuhMonitoring ( ) ;
}
log ( 'monitoring.js init' , 'Skipping wazuh-monitoring pattern creation. Already exists.' , 'info' ) ;
server . log ( [ blueWazuh , 'monitoring' , 'info' ] , 'Skipping wazuh-monitoring creation. Already exists.' ) ;
2018-03-19 11:21:44 +00:00
return ;
} catch ( error ) {
2018-03-21 15:03:33 +00:00
server . log ( [ blueWazuh , 'monitoring' , 'error' ] , error . message || error ) ;
log ( 'monitoring.js init' , error . message || error ) ;
return ;
2018-03-19 11:21:44 +00:00
}
2017-12-11 10:45:32 +00:00
} ;
2017-06-01 15:08:10 +00:00
2017-11-15 09:35:23 +00:00
// Check Elasticsearch Server status and .kibana index presence
2018-03-19 11:21:44 +00:00
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 ) ;
}
2017-11-15 09:35:23 +00:00
}
2017-12-11 10:45:32 +00:00
// Wait until Kibana server is ready
2018-03-19 11:21:44 +00:00
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 ) {
2018-03-12 11:57:14 +00:00
log ( 'monitoring.js checkKibanaStatus' , 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...' ) ;
2017-11-15 09:35:23 +00:00
setTimeout ( ( ) => checkKibanaStatus ( ) , 3000 ) ;
2018-03-19 11:21:44 +00:00
}
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 ;
} ;