Notify policy updates to open-appsec container.

UI labels in log.
This commit is contained in:
Rami Winestock
2023-12-13 21:51:43 +02:00
parent dbd78e5e03
commit ce84a865f1
13 changed files with 102 additions and 120 deletions

View File

@@ -1,3 +1,6 @@
const util = require('util');
const execPromise = util.promisify(require('child_process').exec);
const { exec } = require('child_process');
const _ = require('lodash'); const _ = require('lodash');
const fs = require('fs'); const fs = require('fs');
const logger = require('../logger').nginx; const logger = require('../logger').nginx;
@@ -100,7 +103,24 @@ const internalNginxOpenappsec = {
(err) => { (err) => {
logger.error('Error generating openappsec config:', err); logger.error('Error generating openappsec config:', err);
return Promise.reject(err); return Promise.reject(err);
})
.then(() => {
// Return the notifyPolicyUpdate promise chain
// notify openappsec to apply the policy
return internalNginxOpenappsec.notifyPolicyUpdate().catch((errorMessage) => {
console.error('Error:', errorMessage);
const errorMessageForUI = `Error: Policy couldnt be applied, open-appsec-agent container is not responding.
Check if open-appec-agent container is running, then apply open-appsec Configuration
again by clicking here:
<br>Settings -> open-appsec Advanced -> Save Settings`;
return Promise.reject(new Error(errorMessageForUI));
}); });
})
.catch((err) => {
logger.error('Error generating openappsec config:', err);
throw err; // Propagate the error to the caller
});
}, },
/** /**
@@ -122,9 +142,22 @@ const internalNginxOpenappsec = {
internalNginxOpenappsec.removeMatchingNodes(openappsecConfig, pattern); internalNginxOpenappsec.removeMatchingNodes(openappsecConfig, pattern);
fs.writeFileSync(configFilePath, yaml.dump(openappsecConfig)); fs.writeFileSync(configFilePath, yaml.dump(openappsecConfig));
}) })
.catch(err => { .then(() => {
// Return the notifyPolicyUpdate promise chain
// notify openappsec to apply the policy
return internalNginxOpenappsec.notifyPolicyUpdate().catch((errorMessage) => {
console.error('---Error:', errorMessage);
const errorMessageForUI = `Error: Policy couldnt be applied, open-appsec-agent container is not responding.
Check if open-appec-agent container is running, then apply open-appsec Configuration
again by clicking here:
<br>Settings -> open-appsec Advanced -> Save Settings`;
return Promise.reject(new Error(errorMessageForUI));
});
})
.catch((err) => {
logger.error('Error deleting openappsec config:', err); logger.error('Error deleting openappsec config:', err);
return Promise.reject(err); throw err; // Propagate the error to the caller
}); });
}, },
@@ -180,6 +213,38 @@ const internalNginxOpenappsec = {
} }
}, },
notifyPolicyUpdate: async function() {
if (!constants.USE_NOTIFY_POLICY) {
console.log('USE_NOTIFY_POLICY is false');
return;
}
let ports = constants.PORTS;
console.log(`Notifying openappsec to apply the policy on ports ${ports}`);
let lastError = null;
for (let port of ports) {
try {
const command = `curl -s -o /dev/null -w "%{http_code}" ${constants.HOSTURL}:${port}/openappsec/apply-policy`;
console.log(`command: ${command}`);
let { stdout } = await execPromise(command);
if (stdout === '200') {
console.log(`Policy applied successfully on port ${port}`);
return;
} else {
console.log(`Policy Unexpected response code: ${stdout}`);
lastError = new Error(`Unexpected response code: ${stdout}`);
}
} catch (error) {
console.log(`Error notifying openappsec to apply the policy on port ${port}: ${error.message}`);
lastError = error;
}
}
if (lastError) {
throw lastError;
}
},
/** /**
* Recursively removes nodes from a JavaScript object based on a pattern. * Recursively removes nodes from a JavaScript object based on a pattern.
* *

View File

@@ -100,7 +100,6 @@ const internalOpenappsecLog = {
.then(async () => { .then(async () => {
const directoryPath = APPSEC_LOG_DIR; const directoryPath = APPSEC_LOG_DIR;
let totalDataLines = await this.countTotalLines(directoryPath); let totalDataLines = await this.countTotalLines(directoryPath);
console.log("totalLineCount: " + totalDataLines);
const files = await fs.promises.readdir(directoryPath); const files = await fs.promises.readdir(directoryPath);
const logFiles = files.filter(file => path.extname(file).startsWith('.log')); const logFiles = files.filter(file => path.extname(file).startsWith('.log'));

View File

@@ -95,9 +95,14 @@ const internalProxyHost = {
}); });
}) })
.then(row => { .then(row => {
internalNginxOpenappsec.generateConfig(access, row, data) return internalNginxOpenappsec.generateConfig(access, row, data)
return row; .then(() => {
}) return row;
})
.catch((err) => {
throw new error.ConfigurationError(err.message);
});
})
.then((row) => { .then((row) => {
// Audit log // Audit log
data.meta = _.assign({}, data.meta || {}, row.meta); data.meta = _.assign({}, data.meta || {}, row.meta);
@@ -174,10 +179,14 @@ const internalProxyHost = {
} }
}) })
.then(row => { .then(row => {
internalNginxOpenappsec.generateConfig(access, row, data); return internalNginxOpenappsec.generateConfig(access, row, data)
// internalNginxOpenappsec.updateConfig(row, data) .then(() => {
return row; return row;
}) })
.catch((err) => {
throw new error.ConfigurationError(err.message);
});
})
.then((row) => { .then((row) => {
// Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here. // Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here.
data = _.assign({}, { data = _.assign({}, {
@@ -316,7 +325,11 @@ const internalProxyHost = {
}) })
.then(() => { .then(() => {
// Delete openappsec config // Delete openappsec config
internalNginxOpenappsec.deleteConfig(access, row); return internalNginxOpenappsec.deleteConfig(access, row)
.catch((err) => {
throw new error.ConfigurationError(err.message);
});
}) })
.then(() => { .then(() => {
// Delete Nginx Config // Delete Nginx Config

View File

@@ -2,4 +2,8 @@ module.exports = {
APPSEC_CONFIG_FILE_NAME: 'local_policy.yaml', APPSEC_CONFIG_FILE_NAME: 'local_policy.yaml',
APPSEC_EXT_DIR: '/ext/appsec', APPSEC_EXT_DIR: '/ext/appsec',
APPSEC_LOG_DIR: '/ext/appsec-logs', APPSEC_LOG_DIR: '/ext/appsec-logs',
USE_NOTIFY_POLICY: true,
PORTS: [7777, 7778],
HOSTURL: 'http://127.0.0.1',
POLICY_PATH: '/etc/cp/conf/local_policy.yaml',
}; };

View File

@@ -1,29 +1,6 @@
<td> <td><%- formatDbDate(eventTime, 'D-M-YY, H:mm') %></td>
<%- formatDbDate(eventTime, 'D-M-YYYY, H:mm') %> <td><%- eventSeverity %></td>
</td>
<td>
<div class="text-nowrap">
<% var sevirityClass = 'bg-success';
switch (eventSeverity) {
case 'Critical':
sevirityClass = 'bg-danger';
break;
case 'Warning':
sevirityClass = 'bg-warning';
break;
case 'Info':
sevirityClass = 'bg-success';
//sevirityClass = 'bg-info';
break;
case 'Debug':
sevirityClass = 'bg-success';
break;
}
%>
<span class="status-icon <%- sevirityClass %>"></span> <%- eventSeverity %>
</div>
</td>
<td><%- assetName %></td> <td><%- assetName %></td>
<td><%- securityAction %></td> <td><%- securityAction %></td>
<td><%- waapIncidentType %></td> <td><%- waapIncidentType %></td>
@@ -34,7 +11,7 @@
<td><%- httpMethod %></td> <td><%- httpMethod %></td>
<td><%- httpResponseCode %></td> <td><%- httpResponseCode %></td>
<td><%- httpUriPath %></td> <td><%- httpUriPath %></td>
<td><%- protectionName %></td> <td><%- eventTopic %></td>
<td><%- matchedLocation %></td> <td><%- matchedLocation %></td>
<td><%- matchedParameter %></td> <td><%- matchedParameter %></td>
<td><%- matchedSample %></td> <td><%- matchedSample %></td>

View File

@@ -11,7 +11,7 @@
<th>HTTP Method</th> <th>HTTP Method</th>
<th>HTTP Response Code</th> <th>HTTP Response Code</th>
<th>HTTP URI Path</th> <th>HTTP URI Path</th>
<th>Protection Name</th> <th>Event Topic</th>
<th>Matched Location</th> <th>Matched Location</th>
<th>Matched Parameter</th> <th>Matched Parameter</th>
<th>Matched Sample</th> <th>Matched Sample</th>

View File

@@ -8,7 +8,6 @@ let TableBody = Mn.CollectionView.extend({
initialize: function (options) { initialize: function (options) {
this.options = new Backbone.Model(options); this.options = new Backbone.Model(options);
console.log("options: ", options);
// this.page = options.page; // this.page = options.page;
// this.perPage = options.perPage; // this.perPage = options.perPage;
this.updatePage(); this.updatePage();
@@ -20,22 +19,12 @@ let TableBody = Mn.CollectionView.extend({
let page = this.page || 1; let page = this.page || 1;
let models; let models;
if (this.perPage && this.page) { if (this.perPage && this.page) {
console.log('updatePage2');
models = this.collection.models.slice((page - 1) * perPage, page * perPage); models = this.collection.models.slice((page - 1) * perPage, page * perPage);
} else { } else {
console.log('updatePage3');
models = this.collection.models; models = this.collection.models;
} }
this.collection.reset(models); this.collection.reset(models);
} }
// updatePage: function () {
// let perPage = this.perPage || this.collection.length;
// let page = this.page || 1;
// let models = this.collection.models.slice((page - 1) * perPage, page * perPage);
// this.collection.reset(models);
// }
}); });
module.exports = Mn.View.extend({ module.exports = Mn.View.extend({

View File

@@ -1,29 +1,6 @@
<td> <td><%- formatDbDate(eventTime, 'D-M-YY, H:mm') %></td>
<%- formatDbDate(eventTime, 'D-M-YY, H:mm') %> <td><%- eventSeverity %></td>
</td>
<td>
<div class="text-nowrap">
<% var sevirityClass = 'bg-success';
switch (eventSeverity) {
case 'Critical':
sevirityClass = 'bg-danger';
break;
case 'Warning':
sevirityClass = 'bg-warning';
break;
case 'Info':
sevirityClass = 'bg-success';
//sevirityClass = 'bg-info';
break;
case 'Debug':
sevirityClass = 'bg-success';
break;
}
%>
<span class="status-icon <%- sevirityClass %>"></span> <%- eventSeverity %>
</div>
</td>
<td><%- assetName %></td> <td><%- assetName %></td>
<td><%- securityAction %></td> <td><%- securityAction %></td>
<td><%- waapIncidentType %></td> <td><%- waapIncidentType %></td>
@@ -34,7 +11,7 @@
<td><%- httpMethod %></td> <td><%- httpMethod %></td>
<td><%- httpResponseCode %></td> <td><%- httpResponseCode %></td>
<td><%- httpUriPath %></td> <td><%- httpUriPath %></td>
<td><%- protectionName %></td> <td><%- eventTopic %></td>
<td><%- matchedLocation %></td> <td><%- matchedLocation %></td>
<td><%- matchedParameter %></td> <td><%- matchedParameter %></td>
<td><%- matchedSample %></td> <td><%- matchedSample %></td>

View File

@@ -11,7 +11,7 @@
<th>HTTP Method</th> <th>HTTP Method</th>
<th>HTTP Response Code</th> <th>HTTP Response Code</th>
<th>HTTP URI Path</th> <th>HTTP URI Path</th>
<th>Protection Name</th> <th>Event Topic</th>
<th>Matched Location</th> <th>Matched Location</th>
<th>Matched Parameter</th> <th>Matched Parameter</th>
<th>Matched Sample</th> <th>Matched Sample</th>

View File

@@ -15,7 +15,6 @@ let TableBody = Mn.CollectionView.extend({
}, },
updatePage: function () { updatePage: function () {
console.log('updatePage');
let models = this.collection.models.slice((this.page - 1) * this.perPage, this.page * this.perPage); let models = this.collection.models.slice((this.page - 1) * this.perPage, this.page * this.perPage);
this.collection.reset(models); this.collection.reset(models);
} }

View File

@@ -1,27 +1,5 @@
<td><%- formatDbDate(eventTime, 'D-M-YY, H:mm') %></td> <td><%- formatDbDate(eventTime, 'D-M-YY, H:mm') %></td>
<td> <td><%- eventSeverity %></td>
<div class="text-nowrap">
<% var sevirityClass = 'bg-success';
switch (eventSeverity) {
case 'Critical':
sevirityClass = 'bg-danger';
break;
case 'Warning':
sevirityClass = 'bg-warning';
break;
case 'Info':
sevirityClass = 'bg-success';
//sevirityClass = 'bg-info';
break;
case 'Debug':
sevirityClass = 'bg-success';
break;
}
%>
<span class="status-icon <%- sevirityClass %>"></span> <%- eventSeverity %>
</div>
</td>
<td><%- eventPriority %></td> <td><%- eventPriority %></td>
<td><%- eventTopic %></td> <td><%- eventTopic %></td>
<td><%- eventName %></td> <td><%- eventName %></td>

View File

@@ -15,7 +15,6 @@ let TableBody = Mn.CollectionView.extend({
}, },
updatePage: function () { updatePage: function () {
console.log('updatePage');
let models = this.collection.models.slice((this.page - 1) * this.perPage, this.page * this.perPage); let models = this.collection.models.slice((this.page - 1) * this.perPage, this.page * this.perPage);
this.collection.reset(models); this.collection.reset(models);
} }

View File

@@ -182,24 +182,6 @@ module.exports = Mn.View.extend({
onTabClick: function(event) { onTabClick: function(event) {
event.preventDefault(); event.preventDefault();
const selectedTab = event.target.id; const selectedTab = event.target.id;
console.log("selectedTab: ", selectedTab);
// let ListView;
// switch (selectedTab) {
// case 'tab1':
// ListView = ListViewTab1;
// break;
// case 'tab2':
// ListView = ListViewTab2;
// break;
// case 'tab3':
// ListView = ListViewTab3;
// break;
// default:
// ListView = ListViewTab1;
// }
let view = this; let view = this;
let query = this.ui.query.val() || ''; let query = this.ui.query.val() || '';