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' ) ;
2017-11-15 14:58:53 +00:00
const APP _OBJECTS _FILE = './integration_files/app_objects_file_monitoring.json' ;
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 = { } ;
let app _objects = { } ;
// 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 ;
2017-12-21 16:15:13 +00:00
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 ) {
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'
} )
2017-12-21 16:15:13 +00:00
. 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
} ) ;
}
} )
. catch ( ( ) => {
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.' ) ;
} )
. catch ( ( error ) => {
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'
}
}
} )
. then ( ( resp ) => {
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
} )
. catch ( ( 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 ( ( ) => {
server . log ( [ blueWazuh , 'monitoring' , 'info' ] , 'Successfully created today index.' ) ;
insertDocument ( todayIndex ) ;
} )
. catch ( ( error ) => {
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 )
. catch ( ( error ) => {
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 ) ;
} )
. catch ( ( 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 = ( ) => {
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
} )
. then ( ( data ) => {
server . log ( [ blueWazuh , 'monitoring' , 'info' ] , 'Skipping index-pattern creation. Already exists.' ) ;
} )
. catch ( ( error ) => {
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 ) => {
server . log ( [ blueWazuh , 'monitoring' , 'info' ] , "Successfully deleted old wazuh-monitoring pattern." ) ;
} )
. catch ( ( error ) => {
server . log ( [ blueWazuh , 'monitoring' , 'error' ] , "Didn't find old wazuh-monitoring pattern. Skipping deletion." ) ;
} ) ;
configureKibana ( ) ;
} ) ;
} ;
2017-06-01 15:08:10 +00:00
2017-11-15 09:35:23 +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" } )
2017-11-15 09:35:23 +00:00
. then ( ( data ) => {
2017-12-11 10:45:32 +00:00
if ( data ) server . plugins . elasticsearch . waitUntilReady ( ) . then ( ( data ) => { resolve ( data ) ; } ) ;
else reject ( data ) ;
2017-11-15 09:35:23 +00:00
} )
. catch ( ( error ) => {
2017-11-30 15:22:31 +00:00
reject ( error ) ;
2017-11-15 09:35:23 +00:00
} ) ;
} )
}
2017-12-11 10:45:32 +00:00
// Wait until Kibana server is ready
const checkKibanaStatus = ( ) => {
checkElasticsearchServer ( ) . then ( ( data ) => { init ( ) } )
2017-11-15 09:35:23 +00:00
. catch ( ( 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 ) ;
} ) ;
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 ;
} ;