@newrelic/security-agent 0.0.8 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/index.js +1 -1
- package/lib/instrumentation-security/core/constants.js +2 -2
- package/lib/instrumentation-security/core/request-manager.js +24 -1
- package/lib/instrumentation-security/core/sec-trace.js +4 -1
- package/lib/instrumentation-security/core/sec-utils.js +12 -2
- package/lib/instrumentation-security/hooks/http/nr-http.js +10 -6
- package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +38 -14
- package/lib/nr-security-agent/index.js +4 -4
- package/lib/nr-security-agent/lib/core/Policy.js +4 -1
- package/lib/nr-security-agent/lib/core/agent-status.js +2 -1
- package/lib/nr-security-agent/lib/core/applicationinfo.js +2 -4
- package/lib/nr-security-agent/lib/core/commonUtils.js +46 -22
- package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +2 -2
- package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +31 -19
- package/lib/nr-security-agent/lib/core/logging.js +10 -5
- package/lib/nr-security-agent/lib/core/sec-agent-constants.js +5 -4
- package/lib/nr-security-agent/lib/core/sec-util.js +2 -2
- package/lib/nr-security-agent/lib/core/sha-size-util.js +3 -16
- package/lib/nr-security-agent/lib/core/statusUtils.js +36 -32
- package/lib/nr-security-agent/lib/core/websocket-client.js +3 -3
- package/lib/nr-security-agent/resources/config.js +7 -1
- package/package.json +1 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
###v0.1.1
|
|
2
|
+
* Fix in mysql instrumentation on getConnection to check if callback is wrapped
|
|
3
|
+
* NR-123832: Support for fire and forget vulnerability detection
|
|
4
|
+
* Fixes for snapshot file.
|
|
5
|
+
* Handling for high_security config.
|
|
6
|
+
### v0.1.0
|
|
7
|
+
* Handling to use OS specific path separator.
|
|
8
|
+
* Functionality to create directories in windows environment.
|
|
9
|
+
* IAST support for windows.
|
|
10
|
+
* Log file permission fix.
|
|
1
11
|
### v0.0.8
|
|
2
12
|
* Handling for IP resolving to IPV4 as Node.js v17 and above no longer re-sorts results of IP address lookups and returns them as-is.
|
|
3
13
|
* Third Party Notices update
|
package/index.js
CHANGED
|
@@ -13,7 +13,7 @@ function start(NRAgentObject) {
|
|
|
13
13
|
const agent = NRAgentObject.agent;
|
|
14
14
|
API.newrelic = NRAgentObject;
|
|
15
15
|
API.setNRAgent(agent);
|
|
16
|
-
if (
|
|
16
|
+
if (agent.config.high_security) {
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
require('./lib/nr-security-agent');
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
const AWS_LAMBDA_NODE_EXEC_ENV_IDENTIFIER = /^AWS_Lambda_nodejs.*$/g;
|
|
10
10
|
const AWS_EXECUTION_ENV_VAR = 'AWS_EXECUTION_ENV';
|
|
11
|
+
const sep = require('path').sep;
|
|
11
12
|
|
|
12
13
|
module.exports = {
|
|
13
14
|
|
|
@@ -33,7 +34,7 @@ module.exports = {
|
|
|
33
34
|
COLON: ':',
|
|
34
35
|
OPEN_PARANTHESIS: '(',
|
|
35
36
|
CLOSE_PARANTHESIS: ')',
|
|
36
|
-
SLASH:
|
|
37
|
+
SLASH: sep,
|
|
37
38
|
INCOMING_MSG: 'IncomingMessage',
|
|
38
39
|
OBJECT: 'object',
|
|
39
40
|
STRING: 'string',
|
|
@@ -59,7 +60,6 @@ module.exports = {
|
|
|
59
60
|
SLASHDOTDOT: '/..',
|
|
60
61
|
UNDEFINED: 'undefined',
|
|
61
62
|
SELF_FD_PATH: '/proc/self/fd/',
|
|
62
|
-
SLASH: '/',
|
|
63
63
|
CSEC_LAST_FUZZ_REQUEST_TIME: 'CSEC_LAST_FUZZ_REQUEST_TIME',
|
|
64
64
|
NR_CSEC_FUZZ_REQUEST_ID: 'nr-csec-fuzz-request-id',
|
|
65
65
|
|
|
@@ -34,6 +34,13 @@ function getRequest(shim) {
|
|
|
34
34
|
const transactionId = segment.transaction.id;
|
|
35
35
|
return getRequestFromId(transactionId);
|
|
36
36
|
}
|
|
37
|
+
else if (shim.agent.getLinkingMetadata()) {
|
|
38
|
+
let linkingMetadata = shim.agent.getLinkingMetadata();
|
|
39
|
+
if (linkingMetadata['trace.id']) {
|
|
40
|
+
let traceId = linkingMetadata['trace.id'];
|
|
41
|
+
return getRequestFromId(traceId);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
/**
|
|
@@ -51,16 +58,32 @@ function updateRequestBody(shim, data) {
|
|
|
51
58
|
setRequest(transactionId, requestData);
|
|
52
59
|
}
|
|
53
60
|
}
|
|
61
|
+
if (shim.agent.getLinkingMetadata()) {
|
|
62
|
+
let linkingMetadata = shim.agent.getLinkingMetadata();
|
|
63
|
+
if (linkingMetadata['trace.id']) {
|
|
64
|
+
let traceId = linkingMetadata['trace.id'];
|
|
65
|
+
const requestData = getRequestFromId(traceId);
|
|
66
|
+
if (requestData) {
|
|
67
|
+
requestData.body = data;
|
|
68
|
+
setRequest(traceId, requestData)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
54
72
|
}
|
|
55
73
|
|
|
56
74
|
/**
|
|
57
75
|
* Utility to clear data based on transaction Id
|
|
58
76
|
* @param {*} transactionId
|
|
59
77
|
*/
|
|
60
|
-
function gcRequestMap(
|
|
78
|
+
function gcRequestMap(transaction) {
|
|
79
|
+
let transactionId = transaction.id;
|
|
80
|
+
let traceId = transaction._traceId;
|
|
61
81
|
if (requestMap.has(transactionId)) {
|
|
62
82
|
requestMap.delete(transactionId);
|
|
63
83
|
}
|
|
84
|
+
if (requestMap.has(traceId)) {
|
|
85
|
+
requestMap.delete(traceId);
|
|
86
|
+
}
|
|
64
87
|
}
|
|
65
88
|
|
|
66
89
|
module.exports = {
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const API = require("../../nr-security-api");
|
|
8
8
|
const NRAgent = API.getNRAgent();
|
|
9
|
-
|
|
9
|
+
let AGENT_DIR = path.join(__dirname, '../../');
|
|
10
|
+
if(process.platform == 'win32'){
|
|
11
|
+
AGENT_DIR = path.join(__dirname, "..\\..\\..\\");
|
|
12
|
+
}
|
|
10
13
|
const NR_LIB = '/newrelic/lib';
|
|
11
14
|
let LOAD_LIST;
|
|
12
15
|
const { IS_LAMBDA_ENV, LAMBDA_RUNTIME_DIR_VAR } = require('./constants');
|
|
@@ -10,8 +10,11 @@ const requestManager = require('./request-manager');
|
|
|
10
10
|
const routeManager = require('./route-manager');
|
|
11
11
|
const async_hooks = require('async_hooks');
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
let AGENT_DIR = path.join(__dirname, '../../');
|
|
14
14
|
|
|
15
|
+
if(process.platform == 'win32'){
|
|
16
|
+
AGENT_DIR = path.join(__dirname, "..\\..\\");
|
|
17
|
+
}
|
|
15
18
|
const NR_LIB = '/newrelic/lib';
|
|
16
19
|
|
|
17
20
|
const ANONYMOUS_FUNCTION = '<anonymous>';
|
|
@@ -123,7 +126,7 @@ function traceElementForRoute () {
|
|
|
123
126
|
const trace = stackTraceModule.get();
|
|
124
127
|
let methodName = null;
|
|
125
128
|
|
|
126
|
-
for (let i = 0; i
|
|
129
|
+
for (let i = 0; i <= trace.length - 1; i++) {
|
|
127
130
|
const funcName = trace[i].getFunctionName();
|
|
128
131
|
const fileName = trace[i].getFileName();
|
|
129
132
|
const lineNumber = trace[i].getLineNumber();
|
|
@@ -195,6 +198,13 @@ function addRequestData(shim, request) {
|
|
|
195
198
|
data.parameterMap = storedRequest.parameterMap;
|
|
196
199
|
}
|
|
197
200
|
requestManager.setRequest(transactionId, data);
|
|
201
|
+
if(shim.agent.getLinkingMetadata()){
|
|
202
|
+
let linkingMetadata = shim.agent.getLinkingMetadata();
|
|
203
|
+
if(linkingMetadata['trace.id']){
|
|
204
|
+
let traceId = linkingMetadata['trace.id'];
|
|
205
|
+
requestManager.setRequest(traceId, data)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
198
208
|
}
|
|
199
209
|
} catch (error) {
|
|
200
210
|
logger.debug("Error while preparing incoming request:", error);
|
|
@@ -72,7 +72,9 @@ function setupRequestMapCleanup() {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
// Here removing request data corresponding to transactionId
|
|
75
|
-
|
|
75
|
+
setTimeout(() => {
|
|
76
|
+
requestManager.gcRequestMap(transaction);
|
|
77
|
+
}, 5000);
|
|
76
78
|
})
|
|
77
79
|
}
|
|
78
80
|
}
|
|
@@ -88,7 +90,6 @@ function outboundHook(shim, mod, method, moduleName) {
|
|
|
88
90
|
shim.wrap(mod, method, function makeRequestWrapper(shim, fn) {
|
|
89
91
|
return function requestWrapper() {
|
|
90
92
|
const request = requestManager.getRequest(shim);
|
|
91
|
-
|
|
92
93
|
const data = {};
|
|
93
94
|
data.headers = {};
|
|
94
95
|
data.method = arguments[0].method;
|
|
@@ -96,7 +97,6 @@ function outboundHook(shim, mod, method, moduleName) {
|
|
|
96
97
|
data.protocol = arguments[0].protocol ? arguments[0].protocol : 'http:';
|
|
97
98
|
data.headers.host = arguments[0].hostname ? arguments[0].hostname : arguments[0].host;
|
|
98
99
|
data.port = arguments[0].port;
|
|
99
|
-
|
|
100
100
|
if (method === 'get') {
|
|
101
101
|
data.method = 'GET';
|
|
102
102
|
data.path = '/';
|
|
@@ -107,13 +107,11 @@ function outboundHook(shim, mod, method, moduleName) {
|
|
|
107
107
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
|
|
111
110
|
let completeURL = data.protocol + '//' + data.headers.host + (data.port ? (':' + data.port) : '') + data.path;
|
|
112
111
|
completeURL = completeURL.split(QUESTION_MARK)[0];
|
|
113
112
|
|
|
114
113
|
if (request && !lodash.isEmpty(data.headers.host) && !lodash.isEmpty(data.path)) {
|
|
115
114
|
const appUUID = API.getSecAgent().applicationInfo.applicationUUID;
|
|
116
|
-
|
|
117
115
|
const id = secUtils.getExecutionId().toString();
|
|
118
116
|
let generateFlag = false;
|
|
119
117
|
if (arguments[0] && arguments[0].headers && arguments[0].headers.SECHOOK === id) {
|
|
@@ -130,7 +128,6 @@ function outboundHook(shim, mod, method, moduleName) {
|
|
|
130
128
|
}
|
|
131
129
|
|
|
132
130
|
let traceHeader = EMPTY_STRING;
|
|
133
|
-
|
|
134
131
|
if (request.headers['nr-csec-tracing-data']) {
|
|
135
132
|
traceHeader = request.headers['nr-csec-tracing-data'];
|
|
136
133
|
}
|
|
@@ -235,6 +232,13 @@ function addRequestData(shim, request) {
|
|
|
235
232
|
data.parameterMap = storedRequest.parameterMap;
|
|
236
233
|
}
|
|
237
234
|
requestManager.setRequest(transactionId, data);
|
|
235
|
+
if (shim.agent.getLinkingMetadata()) {
|
|
236
|
+
let linkingMetadata = shim.agent.getLinkingMetadata();
|
|
237
|
+
if (linkingMetadata['trace.id']) {
|
|
238
|
+
let traceId = linkingMetadata['trace.id'];
|
|
239
|
+
requestManager.setRequest(traceId, data)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
238
242
|
parseFuzzheaders(data, transactionId);
|
|
239
243
|
}
|
|
240
244
|
} catch (error) {
|
|
@@ -5,13 +5,19 @@
|
|
|
5
5
|
|
|
6
6
|
const requestManager = require("../../core/request-manager");
|
|
7
7
|
|
|
8
|
-
const async_hooks = require("async_hooks");
|
|
9
8
|
const secUtils = require('../../core/sec-utils');
|
|
10
9
|
const API = require("../../../nr-security-api");
|
|
11
10
|
const securityMetaData = require('../../core/security-metadata');
|
|
12
11
|
const { EVENT_TYPE, EVENT_CATEGORY } = require('../../core/event-constants');
|
|
13
12
|
const { NR_CSEC_FUZZ_REQUEST_ID } = require('../../core/constants');
|
|
14
13
|
const logger = API.getLogger();
|
|
14
|
+
const symbols = {
|
|
15
|
+
unwrapConnection: Symbol('unwrapConnection'),
|
|
16
|
+
unwrapPool: Symbol('unwrapPool'),
|
|
17
|
+
clusterOf: Symbol('clusterOf'),
|
|
18
|
+
createPoolCluster: Symbol('createPoolCluster'),
|
|
19
|
+
wrappedPoolConnection: Symbol('wrappedPoolConnection')
|
|
20
|
+
}
|
|
15
21
|
|
|
16
22
|
module.exports = initialize;
|
|
17
23
|
|
|
@@ -34,37 +40,53 @@ function initialize(shim, mysql, moduleName) {
|
|
|
34
40
|
* Wrapper for mysql module hooks
|
|
35
41
|
* @param {*} shim
|
|
36
42
|
* @param {*} mysql
|
|
37
|
-
* @param {*} moduleName
|
|
38
43
|
*/
|
|
39
|
-
function callbackInitialize(shim, mysql
|
|
40
|
-
shim.
|
|
44
|
+
function callbackInitialize(shim, mysql) {
|
|
45
|
+
shim[symbols.wrappedPoolConnection] = false
|
|
41
46
|
|
|
42
47
|
shim.wrapReturn(mysql, "createConnection", wrapCreateConnection);
|
|
43
48
|
function wrapCreateConnection(shim, fn, fnName, connection) {
|
|
49
|
+
if (shim[symbols.unwrapConnection]) {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
if (wrapQueryable(shim, connection, false)) {
|
|
45
54
|
const connProto = Object.getPrototypeOf(connection);
|
|
46
|
-
shim.
|
|
55
|
+
shim[symbols.unwrapConnection] = true
|
|
47
56
|
}
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
shim.wrapReturn(mysql, "createPool", wrapCreatePool);
|
|
51
60
|
function wrapCreatePool(shim, fn, fnName, pool) {
|
|
61
|
+
if (shim[symbols.unwrapPool]) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
52
65
|
if (wrapQueryable(shim, pool, true) && wrapGetConnection(shim, pool)) {
|
|
53
|
-
shim.
|
|
66
|
+
shim[symbols.unwrapPool] = true
|
|
54
67
|
}
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
shim.wrapReturn(mysql, "createPoolCluster", wrapCreatePoolCluster);
|
|
58
71
|
function wrapCreatePoolCluster(shim, fn, fnName, poolCluster) {
|
|
72
|
+
if (shim[symbols.createPoolCluster]) {
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
59
76
|
const proto = Object.getPrototypeOf(poolCluster);
|
|
60
77
|
shim.wrapReturn(proto, "of", wrapPoolClusterOf);
|
|
61
78
|
function wrapPoolClusterOf(shim, of, _n, poolNamespace) {
|
|
62
|
-
if (
|
|
63
|
-
|
|
79
|
+
if (poolNamespace[symbols.clusterOf]) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (wrapGetConnection(shim, poolNamespace) && wrapQueryable(shim, poolNamespace, false)) {
|
|
84
|
+
poolNamespace[symbols.clusterOf] = true
|
|
64
85
|
}
|
|
86
|
+
|
|
65
87
|
}
|
|
66
88
|
if (wrapGetConnection(shim, poolCluster)) {
|
|
67
|
-
shim.
|
|
89
|
+
shim[symbols.createPoolCluster] = true
|
|
68
90
|
}
|
|
69
91
|
}
|
|
70
92
|
}
|
|
@@ -101,9 +123,12 @@ function wrapGetConnection(shim, connectable) {
|
|
|
101
123
|
const args = shim.toArray(arguments);
|
|
102
124
|
const cbIdx = args.length - 1;
|
|
103
125
|
|
|
104
|
-
|
|
126
|
+
// avoid an infinite loop and check both the cb and the "original" cb before re-wrapping
|
|
127
|
+
// this is only applicable now with the security agent + us doing the same thing
|
|
128
|
+
const original = shim.getOriginalOnce(args[cbIdx])
|
|
129
|
+
if (shim.isFunction(args[cbIdx]) && !(shim.isWrapped(args[cbIdx]) || shim.isWrapped(original))) {
|
|
105
130
|
let cb = args[cbIdx];
|
|
106
|
-
if (!shim.
|
|
131
|
+
if (!shim[symbols.wrappedPoolConnection]) {
|
|
107
132
|
cb = shim.wrap(cb, wrapGetConnectionCallback);
|
|
108
133
|
}
|
|
109
134
|
args[cbIdx] = shim.bindSegment(cb);
|
|
@@ -121,7 +146,7 @@ function wrapGetConnectionCallback(shim, cb) {
|
|
|
121
146
|
if (!err && wrapQueryable(shim, conn, false)) {
|
|
122
147
|
// Leave getConnection wrapped in order to maintain TX state, but we can
|
|
123
148
|
// simplify the wrapping of its callback in future calls.
|
|
124
|
-
shim.
|
|
149
|
+
shim[symbols.wrappedPoolConnection] = true
|
|
125
150
|
}
|
|
126
151
|
} catch (_err) { }
|
|
127
152
|
return cb.apply(this, arguments);
|
|
@@ -186,7 +211,6 @@ function extractQueryArgs(shim, args) {
|
|
|
186
211
|
* @param {*} method
|
|
187
212
|
*/
|
|
188
213
|
function queryHook(shim, mod, method, isPoolQuery) {
|
|
189
|
-
|
|
190
214
|
shim.wrap(mod, method, function makeQueryWrapper(shim, fn) {
|
|
191
215
|
return function queryWrapper() {
|
|
192
216
|
const parameters = extractQueryArgs(shim, arguments);
|
|
@@ -229,4 +253,4 @@ function callbackHook(shim, mod, fun, secEvent) {
|
|
|
229
253
|
return fn.apply(this, arguments);
|
|
230
254
|
}
|
|
231
255
|
})
|
|
232
|
-
}
|
|
256
|
+
}
|
|
@@ -18,12 +18,12 @@ const {
|
|
|
18
18
|
IS_LAMBDA_ENV,
|
|
19
19
|
AWS_LAMBDA_FUNCTION_NAME_ENV_IDENTIFIER,
|
|
20
20
|
LAMBDA_TASK_ROOT_ENV_IDENTIFIER,
|
|
21
|
-
LOG_MESSAGES } = njsAgentConstants;
|
|
21
|
+
LOG_MESSAGES, SLASH } = njsAgentConstants;
|
|
22
22
|
const commonUtils = require('./lib/core/commonUtils');
|
|
23
23
|
|
|
24
24
|
const { AGENT_DIR } = agentConfig;
|
|
25
25
|
// eslint-disable-next-line no-unused-vars
|
|
26
|
-
const DIR_IDENTIFIER =
|
|
26
|
+
const DIR_IDENTIFIER = SLASH;
|
|
27
27
|
const SPACE_CHARACTER = ' ';
|
|
28
28
|
// eslint-disable-next-line no-control-regex
|
|
29
29
|
const NULL_CHAR_REGEX = /\u0000/g;
|
|
@@ -106,10 +106,10 @@ function initialize() {
|
|
|
106
106
|
initLogger.info("[STEP-3] => Gathering information about the application :", JSON.stringify(applicationInfo));
|
|
107
107
|
if (NRAgent) {
|
|
108
108
|
NRAgent.on('started', () => {
|
|
109
|
-
if (NRAgent.config.security.enabled) {
|
|
109
|
+
if (NRAgent.config.security.enabled || !NRAgent.config.high_security) {
|
|
110
110
|
wsClient.initialize();
|
|
111
111
|
logger.info('NR Agent started with agent_run_id:', NRAgent.config.run_id, NRAgent.config.account_id);
|
|
112
|
-
Agent.getAgent().status.setStatus('
|
|
112
|
+
Agent.getAgent().status.setStatus('connecting');
|
|
113
113
|
Agent.setNRAgent(NRAgent);
|
|
114
114
|
}
|
|
115
115
|
else {
|
|
@@ -61,7 +61,10 @@ function setPolicyData(data) {
|
|
|
61
61
|
|
|
62
62
|
// function to setup default policy provided in resources directory
|
|
63
63
|
function setDefaultPolicy() {
|
|
64
|
-
|
|
64
|
+
let default_policy_file = path.resolve(__dirname, '../../resources/default-policy.yaml');
|
|
65
|
+
if(process.platform == 'win32'){
|
|
66
|
+
default_policy_file = path.resolve(__dirname, '..\\..\\resources\\default-policy.yaml');
|
|
67
|
+
}
|
|
65
68
|
// Get document, or throw exception on error
|
|
66
69
|
try {
|
|
67
70
|
const default_policy = yaml.load(fs.readFileSync(default_policy_file, 'utf8'));
|
|
@@ -34,7 +34,7 @@ const SELF_PROC_DIR = '/proc/self';
|
|
|
34
34
|
const CGROUP_FILE_NAME = '/proc/self/cgroup';
|
|
35
35
|
const STAT = '/stat';
|
|
36
36
|
const CMD_LINE_FILE = '/cmdline';
|
|
37
|
-
const DIR_IDENTIFIER =
|
|
37
|
+
const DIR_IDENTIFIER = SLASH;
|
|
38
38
|
const NEW_LINE_SEPERATOR = '\n';
|
|
39
39
|
const CGROUP_FILE = '/cgroup';
|
|
40
40
|
const ESCAPED_DOT = '.';
|
|
@@ -425,7 +425,7 @@ function getProcStartTime () {
|
|
|
425
425
|
function setBuildDetails (agentDir, applicationInfo) {
|
|
426
426
|
const jsonFileHandler = new JsonHandler(PACKAGE_JSON_FILE, agentDir);
|
|
427
427
|
const pkg = jsonFileHandler.getJSON();
|
|
428
|
-
applicationInfo.collectorVersion = pkg.
|
|
428
|
+
applicationInfo.collectorVersion = pkg.version;
|
|
429
429
|
applicationInfo.jsonVersion = pkg.jsonVersion;
|
|
430
430
|
applicationInfo.buildNumber = pkg.version;
|
|
431
431
|
}
|
|
@@ -440,8 +440,6 @@ function isK8S () {
|
|
|
440
440
|
|
|
441
441
|
function getHostName () {
|
|
442
442
|
try {
|
|
443
|
-
// const hostFile = fs.readFileSync("/etc/hostname");
|
|
444
|
-
// return hostFile.toString().trim();
|
|
445
443
|
return OS.hostname();
|
|
446
444
|
} catch (err) {
|
|
447
445
|
return EMPTY_STRING;
|
|
@@ -8,12 +8,11 @@ const fs = require('fs');
|
|
|
8
8
|
const uuidv4 = require('uuid/v4');
|
|
9
9
|
const logs = require('./logging');
|
|
10
10
|
const logger = logs.getLogger();
|
|
11
|
-
const cp = require('child_process');
|
|
12
11
|
const OS = require('os');
|
|
13
12
|
const path = require('path');
|
|
14
13
|
const checkDiskSpace = require('check-disk-space').default;
|
|
15
14
|
const AgentStatus = require('../core/agent-status');
|
|
16
|
-
const { LOG_MESSAGES, CSEC_HOME } = require('./sec-agent-constants');
|
|
15
|
+
const { LOG_MESSAGES, CSEC_HOME, SLASH } = require('./sec-agent-constants');
|
|
17
16
|
|
|
18
17
|
const prettyBytes = require('pretty-bytes');
|
|
19
18
|
const njsAgentConstants = require('./sec-agent-constants');
|
|
@@ -22,7 +21,7 @@ const API = require('../../../nr-security-api');
|
|
|
22
21
|
const NRAgent = API.getNRAgent();
|
|
23
22
|
const lodash = require('lodash')
|
|
24
23
|
const backupLogFileRegex = /.log.\d/gm;
|
|
25
|
-
|
|
24
|
+
let websocketHealth;
|
|
26
25
|
/**
|
|
27
26
|
* Utility to generate UUID
|
|
28
27
|
* @returns UUID
|
|
@@ -120,15 +119,15 @@ function getOS () {
|
|
|
120
119
|
* Utility to create directories
|
|
121
120
|
*/
|
|
122
121
|
function createDirectories () {
|
|
123
|
-
createPathIfNotExist(`${CSEC_HOME}
|
|
124
|
-
createPathIfNotExist(`${CSEC_HOME}
|
|
125
|
-
createPathIfNotExist(`${CSEC_HOME}
|
|
126
|
-
createPathIfNotExist(`${CSEC_HOME}
|
|
127
|
-
createPathIfNotExist(`${CSEC_HOME}
|
|
128
|
-
createPathIfNotExist(`${CSEC_HOME}
|
|
129
|
-
createPathIfNotExist(`${CSEC_HOME}
|
|
122
|
+
createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home`);
|
|
123
|
+
createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home${SLASH}logs`);
|
|
124
|
+
createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home${SLASH}logs${SLASH}snapshots`);
|
|
125
|
+
createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home${SLASH}tmp`);
|
|
126
|
+
createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home${SLASH}tmp${SLASH}language-agent`);
|
|
127
|
+
createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home${SLASH}tmp${SLASH}language-agent${SLASH}${getUUID()}`);
|
|
128
|
+
createPathIfNotExist(`${CSEC_HOME}${SLASH}nr-security-home${SLASH}tmp${SLASH}language-agent${SLASH}${getUUID()}${SLASH}ds-tmp`);
|
|
130
129
|
try {
|
|
131
|
-
fs.chmodSync(`${CSEC_HOME}
|
|
130
|
+
fs.chmodSync(`${CSEC_HOME}${SLASH}nr-security-home`, 0o777);
|
|
132
131
|
} catch (error) {
|
|
133
132
|
}
|
|
134
133
|
}
|
|
@@ -238,8 +237,7 @@ async function getHCStats () {
|
|
|
238
237
|
* Utility to check Agent status
|
|
239
238
|
*/
|
|
240
239
|
function isAgentActiveState () {
|
|
241
|
-
|
|
242
|
-
if (AgentStatus.getInstance().getStatus() === AgentStatus.CSECAgentStatus.codes.ACTIVE && (NRAgent ? (NRAgent.config.security.enabled && NRAgent.canCollectData()) : true)) {
|
|
240
|
+
if (AgentStatus.getInstance().getStatus() === AgentStatus.CSECAgentStatus.codes.ACTIVE && (NRAgent ? (NRAgent.config.security.enabled && NRAgent.canCollectData()) : true) && getWSHealthStatus()=='OK') {
|
|
243
241
|
return 'OK';
|
|
244
242
|
} else {
|
|
245
243
|
return 'Error';
|
|
@@ -254,14 +252,14 @@ function iastRestClientStatus () {
|
|
|
254
252
|
*/
|
|
255
253
|
function removeOlderSnapshots () {
|
|
256
254
|
try {
|
|
257
|
-
const basePath = njsAgentConstants.LOG_DIR + 'snapshots
|
|
255
|
+
const basePath = njsAgentConstants.LOG_DIR + 'snapshots'+ SLASH;
|
|
258
256
|
const directoryContent = fs.readdirSync(basePath);
|
|
259
257
|
const files = directoryContent.filter((filename) => {
|
|
260
|
-
return fs.statSync(`${basePath}
|
|
258
|
+
return fs.statSync(`${basePath}${SLASH}${filename}`).isFile();
|
|
261
259
|
});
|
|
262
260
|
const sorted = files.sort((a, b) => {
|
|
263
|
-
const firstStat = fs.statSync(`${basePath}
|
|
264
|
-
const secondStat = fs.statSync(`${basePath}
|
|
261
|
+
const firstStat = fs.statSync(`${basePath}${SLASH}${a}`);
|
|
262
|
+
const secondStat = fs.statSync(`${basePath}${SLASH}${b}`);
|
|
265
263
|
return new Date(secondStat.mtime).getTime() - new Date(firstStat.mtime).getTime();
|
|
266
264
|
});
|
|
267
265
|
for (let i = 99; i < sorted.length; i++) {
|
|
@@ -292,12 +290,12 @@ function removeOlderlogfiles () {
|
|
|
292
290
|
// eslint-disable-next-line array-callback-return
|
|
293
291
|
const files = directoryContent.filter((filename) => {
|
|
294
292
|
if (filename.match(backupLogFileRegex)) {
|
|
295
|
-
return fs.statSync(`${basePath}
|
|
293
|
+
return fs.statSync(`${basePath}${SLASH}${filename}`).isFile();
|
|
296
294
|
}
|
|
297
295
|
});
|
|
298
296
|
const sorted = files.sort((a, b) => {
|
|
299
|
-
const firstStat = fs.statSync(`${basePath}
|
|
300
|
-
const secondStat = fs.statSync(`${basePath}
|
|
297
|
+
const firstStat = fs.statSync(`${basePath}${SLASH}${a}`);
|
|
298
|
+
const secondStat = fs.statSync(`${basePath}${SLASH}${b}`);
|
|
301
299
|
return new Date(secondStat.mtime).getTime() - new Date(firstStat.mtime).getTime();
|
|
302
300
|
});
|
|
303
301
|
|
|
@@ -384,9 +382,33 @@ function getCSECmode(){
|
|
|
384
382
|
* @returns
|
|
385
383
|
*/
|
|
386
384
|
function getPathOfCACert(){
|
|
387
|
-
|
|
385
|
+
let relativePath = path.resolve(__dirname, '../../resources/cert.pem');
|
|
386
|
+
if(process.platform == 'win32'){
|
|
387
|
+
relativePath = path.resolve(__dirname, '..\\..\\resources\\cert.pem');
|
|
388
|
+
}
|
|
389
|
+
const certPath = NRAgent && NRAgent.config.security.ca_bundle_path ? NRAgent.config.security.ca_bundle_path : relativePath;
|
|
388
390
|
return certPath
|
|
389
391
|
}
|
|
392
|
+
/**
|
|
393
|
+
* Setting ws health status
|
|
394
|
+
* @param {*} status
|
|
395
|
+
*/
|
|
396
|
+
function setWSHealthStatus(status){
|
|
397
|
+
websocketHealth = status;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Returns value of websocketHealth
|
|
402
|
+
* @returns websocketHealth
|
|
403
|
+
*/
|
|
404
|
+
function getWSHealthStatus(){
|
|
405
|
+
if(!websocketHealth){
|
|
406
|
+
return 'Error';
|
|
407
|
+
}
|
|
408
|
+
else{
|
|
409
|
+
return websocketHealth;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
390
412
|
|
|
391
413
|
module.exports = {
|
|
392
414
|
getUUID,
|
|
@@ -407,5 +429,7 @@ module.exports = {
|
|
|
407
429
|
logRollOver,
|
|
408
430
|
getValidatorServiceEndpointURL,
|
|
409
431
|
getCSECmode,
|
|
410
|
-
getPathOfCACert
|
|
432
|
+
getPathOfCACert,
|
|
433
|
+
getWSHealthStatus,
|
|
434
|
+
setWSHealthStatus
|
|
411
435
|
};
|
package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js
CHANGED
|
@@ -10,7 +10,7 @@ const restClient = require('../../restclient');
|
|
|
10
10
|
const { Agent } = require('../../../agent');
|
|
11
11
|
const { FuzzFailEvent } = require('../../../FuzzFailEvent');
|
|
12
12
|
const { hasWorker: isWorkerSupported } = require('../../../commonUtils');
|
|
13
|
-
const { CSEC_HOME_TMP, COLON, NR_CSEC_FUZZ_REQUEST_ID } = require('../../../sec-agent-constants');
|
|
13
|
+
const { CSEC_HOME_TMP, COLON, NR_CSEC_FUZZ_REQUEST_ID, SLASH } = require('../../../sec-agent-constants');
|
|
14
14
|
const LOCALHOST = 'localhost';
|
|
15
15
|
const COLON_SLASH_SLASH = '://';
|
|
16
16
|
const http = require('http');
|
|
@@ -24,7 +24,7 @@ const {
|
|
|
24
24
|
} = require('../../../sec-agent-constants');
|
|
25
25
|
const statusUtils = require('../../../statusUtils');
|
|
26
26
|
|
|
27
|
-
const find =
|
|
27
|
+
const find = `${SLASH}{{NR_CSEC_VALIDATOR_HOME_TMP}}`;
|
|
28
28
|
const CSEC_HOME_TMP_CONST = new RegExp(find, 'g');
|
|
29
29
|
|
|
30
30
|
let logger;
|
|
@@ -14,7 +14,6 @@ const { Agent } = require('../../agent');
|
|
|
14
14
|
const logs = require('../../logging');
|
|
15
15
|
const hc = require('../../health-check');
|
|
16
16
|
const fs = require('fs');
|
|
17
|
-
const path = require('path');
|
|
18
17
|
const { promisify } = require('../../sec-util');
|
|
19
18
|
const ResponseHandler = require('./response');
|
|
20
19
|
const { EMPTY_APPLICATION_UUID, LOG_MESSAGES } = require('../../sec-agent-constants');
|
|
@@ -27,6 +26,7 @@ const CONNECTING = 'connecting';
|
|
|
27
26
|
const WS_ON_OPEN = 'open';
|
|
28
27
|
const WS_ON_MSG = 'message';
|
|
29
28
|
const WS_ON_ERR = 'error';
|
|
29
|
+
const WS_ON_PONG = 'pong';
|
|
30
30
|
const ACK = 'ACK';
|
|
31
31
|
const INIT_PING_RETRY_DELAY_ON_FAIL = 200; // in ms
|
|
32
32
|
const RECONNECTION_DELAY = 500; // ms
|
|
@@ -39,6 +39,7 @@ const initLogger = logs.getInitLogger();
|
|
|
39
39
|
let webSocket;
|
|
40
40
|
let pingIntervalConst;
|
|
41
41
|
let initTimeOut;
|
|
42
|
+
let lastPongtime;
|
|
42
43
|
|
|
43
44
|
/**
|
|
44
45
|
* defines the WebSocket callbacks object
|
|
@@ -107,11 +108,14 @@ SecWebSocket.prototype.init = function init() {
|
|
|
107
108
|
logger.error("Error in reading certificate:", error);
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
webSocket = new WebSocket(validatorService, null, { headers: authHeaders, cert: cert });
|
|
111
|
+
webSocket = new WebSocket(validatorService, null, { headers: authHeaders, cert: cert, handshakeTimeout: 10000 });
|
|
111
112
|
|
|
112
113
|
webSocket.on(WS_ON_OPEN, this.openCB);
|
|
113
114
|
webSocket.on(WS_ON_MSG, this.msgCB);
|
|
114
115
|
webSocket.on(WS_ON_ERR, this.errCB);
|
|
116
|
+
webSocket.on(WS_ON_PONG, () => {
|
|
117
|
+
lastPongtime = Date.now();
|
|
118
|
+
})
|
|
115
119
|
this.instance = webSocket;
|
|
116
120
|
};
|
|
117
121
|
|
|
@@ -121,7 +125,6 @@ SecWebSocket.prototype.init = function init() {
|
|
|
121
125
|
*/
|
|
122
126
|
SecWebSocket.prototype.reconnect = function reconnect() {
|
|
123
127
|
const { instance } = this;
|
|
124
|
-
|
|
125
128
|
if (instance.readyState === WebSocket.CONNECTING &&
|
|
126
129
|
process.env.CSEC_WS_STATE === CONNECTING) {
|
|
127
130
|
return;
|
|
@@ -133,7 +136,7 @@ SecWebSocket.prototype.reconnect = function reconnect() {
|
|
|
133
136
|
this.openCB();
|
|
134
137
|
return;
|
|
135
138
|
}
|
|
136
|
-
|
|
139
|
+
commonUtils.setWSHealthStatus('Error');
|
|
137
140
|
logger.debug(LOG_MESSAGES.DETECTED_BROKEN_CONN);
|
|
138
141
|
this.obeyReconnect();
|
|
139
142
|
|
|
@@ -141,10 +144,10 @@ SecWebSocket.prototype.reconnect = function reconnect() {
|
|
|
141
144
|
|
|
142
145
|
SecWebSocket.prototype.obeyReconnect = function obeyReconnect() {
|
|
143
146
|
const { instance } = this;
|
|
144
|
-
if(initTimeOut){
|
|
147
|
+
if (initTimeOut) {
|
|
145
148
|
clearTimeout(initTimeOut);
|
|
146
149
|
}
|
|
147
|
-
|
|
150
|
+
|
|
148
151
|
initTimeOut = setTimeout(() => {
|
|
149
152
|
logger.debug("Terminating ws instance and reconnecting");
|
|
150
153
|
try {
|
|
@@ -159,16 +162,26 @@ SecWebSocket.prototype.obeyReconnect = function obeyReconnect() {
|
|
|
159
162
|
|
|
160
163
|
SecWebSocket.prototype.pingWS = async function pingWS() {
|
|
161
164
|
const self = this;
|
|
165
|
+
let currentTime = Date.now();
|
|
166
|
+
let timeDiffInPing = (currentTime - lastPongtime) / 1000;
|
|
167
|
+
if (timeDiffInPing > 40 && lastPongtime != 0) {
|
|
168
|
+
self.obeyReconnect();
|
|
169
|
+
lastPongtime = 0;
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
162
172
|
try {
|
|
163
173
|
await promisify(self.instance, self.instance.ping)(ACK, true, function (err) {
|
|
164
174
|
if (err) {
|
|
165
175
|
logger.debug("Error while pinging:", err);
|
|
176
|
+
commonUtils.setWSHealthStatus('Error');
|
|
177
|
+
statusUtils.addErrortoBuffer(err);
|
|
166
178
|
self.obeyReconnect();
|
|
167
179
|
}
|
|
168
180
|
});
|
|
169
181
|
} catch (err) {
|
|
170
182
|
logger.debug("error in ping:", err);
|
|
171
183
|
statusUtils.addErrortoBuffer(err);
|
|
184
|
+
commonUtils.setWSHealthStatus('Error');
|
|
172
185
|
return;
|
|
173
186
|
}
|
|
174
187
|
}
|
|
@@ -188,16 +201,19 @@ SecWebSocket.prototype.dispatch = async function dispatch(event) {
|
|
|
188
201
|
!this.isICReadyForEvents
|
|
189
202
|
) {
|
|
190
203
|
handleDispatchFailure(this, event, eventStr);
|
|
204
|
+
commonUtils.setWSHealthStatus('Error')
|
|
191
205
|
return;
|
|
192
206
|
}
|
|
193
207
|
try {
|
|
194
208
|
aquireWebSocket();
|
|
195
|
-
|
|
196
|
-
|
|
209
|
+
await promisify(this.instance, this.instance.send)(eventStr, { mask: true }, () => {
|
|
210
|
+
logger.debug(LOG_MESSAGES.EVENT_SENT + eventStr);
|
|
211
|
+
});
|
|
197
212
|
releaseWebSocket();
|
|
198
213
|
} catch (error) {
|
|
199
214
|
logger.debug(LOG_MESSAGES.ERROR_WHILE_SEND_EVENT, eventStr, error);
|
|
200
215
|
statusUtils.addErrortoBuffer(error);
|
|
216
|
+
commonUtils.setWSHealthStatus('Error')
|
|
201
217
|
handleDispatchFailure(this, event, eventStr);
|
|
202
218
|
}
|
|
203
219
|
};
|
|
@@ -278,10 +294,6 @@ const handleDispatchFailure = (self, event, eventStr) => {
|
|
|
278
294
|
hc.getInstance().registerEventDrop();
|
|
279
295
|
queue.enq(eventStr);
|
|
280
296
|
}
|
|
281
|
-
process.env.WS_HEALTH = 'Error';
|
|
282
|
-
// If the reconnection is not already in progress
|
|
283
|
-
// we would want to reconnect to IC
|
|
284
|
-
// self.reconnect();
|
|
285
297
|
};
|
|
286
298
|
|
|
287
299
|
/**
|
|
@@ -316,8 +328,8 @@ const defaultOnOpenCB = () => async function onOpen() {
|
|
|
316
328
|
try {
|
|
317
329
|
|
|
318
330
|
this.wsRetryCount = 0;
|
|
319
|
-
|
|
320
|
-
|
|
331
|
+
commonUtils.setWSHealthStatus('OK')
|
|
332
|
+
Agent.getAgent().status.setStatus('active');
|
|
321
333
|
const applicationInfo = APP_INFO || Agent.getAgent().applicationInfo;
|
|
322
334
|
await self.dispatchApplicationInfo(applicationInfo);
|
|
323
335
|
|
|
@@ -328,11 +340,11 @@ const defaultOnOpenCB = () => async function onOpen() {
|
|
|
328
340
|
await self.flushEventQueue();
|
|
329
341
|
ResponseHandler.FuzzRequestHandler.setLastFuzzEnventTime();
|
|
330
342
|
releaseWebSocket();
|
|
331
|
-
initLogger.info(LOG_MESSAGES.SENDING_APPINFO_COMPLETE, JSON.stringify(applicationInfo));
|
|
343
|
+
initLogger.info(LOG_MESSAGES.SENDING_APPINFO_COMPLETE, JSON.stringify(applicationInfo));
|
|
332
344
|
} catch (err) {
|
|
333
345
|
logger.error(`Connection broken: ${err.message}`);
|
|
334
346
|
statusUtils.addErrortoBuffer(err);
|
|
335
|
-
|
|
347
|
+
commonUtils.setWSHealthStatus('Error')
|
|
336
348
|
setWebSocketConn();
|
|
337
349
|
self.setValidatorNotReadyForEvents();
|
|
338
350
|
setTimeout(self.openCB, INIT_PING_RETRY_DELAY_ON_FAIL);
|
|
@@ -362,7 +374,9 @@ const defaultOnMsgCB = () => function onMessage(data) {
|
|
|
362
374
|
*
|
|
363
375
|
* @param {SecWebSocket} self
|
|
364
376
|
*/
|
|
365
|
-
const defaultOnErrCB = (
|
|
377
|
+
const defaultOnErrCB = () => function onClose(error) {
|
|
378
|
+
commonUtils.setWSHealthStatus('Error');
|
|
379
|
+
statusUtils.addErrortoBuffer(error);
|
|
366
380
|
const self = this;
|
|
367
381
|
if (error && error.code && (error.code === 'ECONNREFUSED' || error.code === 'EPIPE' || error.code === 'ECONNRESET')) {
|
|
368
382
|
logger.debug("WS Client Error callback called:", error);
|
|
@@ -372,8 +386,6 @@ const defaultOnErrCB = (error) => function onClose(error) {
|
|
|
372
386
|
aquireWebSocket(true);
|
|
373
387
|
self.reconnect();
|
|
374
388
|
}
|
|
375
|
-
statusUtils.addErrortoBuffer(new Error('Error connecting to websocket'));
|
|
376
|
-
process.env.WS_HEALTH = 'Error';
|
|
377
389
|
};
|
|
378
390
|
|
|
379
391
|
SecWebSocket.Events = {
|
|
@@ -9,7 +9,6 @@ const fs = require('fs');
|
|
|
9
9
|
|
|
10
10
|
const log4js = require('log4js');
|
|
11
11
|
const { ENV: env } = require('../../resources/config');
|
|
12
|
-
const cp = require('child_process');
|
|
13
12
|
|
|
14
13
|
const INFO = 'info';
|
|
15
14
|
const LOG_FILE_SIZE = 50485760 * 10000;
|
|
@@ -17,11 +16,14 @@ const LOG_PATTERN_OBJ = {
|
|
|
17
16
|
type: 'pattern',
|
|
18
17
|
pattern: '%[%d[%p][%c][%h][%z]%] %m'
|
|
19
18
|
};
|
|
20
|
-
const {
|
|
19
|
+
const { LOG_DIR } = require('./sec-agent-constants');
|
|
21
20
|
let logger;
|
|
22
21
|
const API = require('../../../nr-security-api');
|
|
23
22
|
const NRAgent = API.getNRAgent();
|
|
24
23
|
|
|
24
|
+
const logFileName = `${LOG_DIR}node-security-collector.log`;
|
|
25
|
+
const initLogFileName = `${LOG_DIR}node-security-collector-init.log`;
|
|
26
|
+
|
|
25
27
|
function createLogPathIfNotExist (dir) {
|
|
26
28
|
try {
|
|
27
29
|
if (!fs.existsSync(dir)) {
|
|
@@ -57,9 +59,6 @@ function initialize (applicationUUID) {
|
|
|
57
59
|
} catch (error) {
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
const logFileName = `${LOG_DIR}node-security-collector.log`;
|
|
61
|
-
const initLogFileName = `${LOG_DIR}node-security-collector-init.log`;
|
|
62
|
-
|
|
63
62
|
Object.assign(appenders.NR_CSEC, {
|
|
64
63
|
filename: logFileName,
|
|
65
64
|
maxLogSize: LOG_FILE_SIZE,
|
|
@@ -143,6 +142,12 @@ function getLogger (applicationUUID = process.env.applicationUUID) {
|
|
|
143
142
|
initialize(applicationUUID);
|
|
144
143
|
logger = log4js.getLogger('NR_CSEC');
|
|
145
144
|
const initLogger = getInitLogger();
|
|
145
|
+
try {
|
|
146
|
+
fs.chmodSync(`${logFileName}`, 0o777);
|
|
147
|
+
fs.chmodSync(`${initLogFileName}`, 0o777);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
logger.error("Error while setting up permissions on log files", error);
|
|
150
|
+
}
|
|
146
151
|
initLogger.info("[STEP-2] => Generating unique identifier:",applicationUUID )
|
|
147
152
|
if (NRAgent) {
|
|
148
153
|
setLevel(NRAgent.config.logging.level);
|
|
@@ -10,6 +10,7 @@ const AWS_EXECUTION_ENV_VAR = 'AWS_EXECUTION_ENV';
|
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const API = require('../../../nr-security-api');
|
|
12
12
|
const NRAgent = API.getNRAgent();
|
|
13
|
+
const sep = require('path').sep;
|
|
13
14
|
|
|
14
15
|
let CSEC_HOME = NRAgent && NRAgent.config.newrelic_home ? NRAgent.config.newrelic_home : require('path').join(process.cwd());
|
|
15
16
|
const CSEC_GROUP_NAME = NRAgent ? NRAgent.config.security.mode : 'IAST';
|
|
@@ -19,11 +20,11 @@ const agentStartTime = new Date().toString();
|
|
|
19
20
|
module.exports = {
|
|
20
21
|
CSEC_HOME: CSEC_HOME,
|
|
21
22
|
CSEC_GROUP_NAME: CSEC_GROUP_NAME,
|
|
22
|
-
LOG_DIR: `${CSEC_HOME}
|
|
23
|
-
CSEC_HOME_TMP: `${CSEC_HOME}
|
|
23
|
+
LOG_DIR: `${CSEC_HOME}${sep}nr-security-home${sep}logs${sep}`,
|
|
24
|
+
CSEC_HOME_TMP: `${CSEC_HOME}${sep}nr-security-home${sep}tmp${sep}language-agent${sep}${process.env.applicationUUID}`,
|
|
24
25
|
AGENT_START_TIME: agentStartTime,
|
|
25
26
|
FRAMEWORK: '',
|
|
26
|
-
STATUS_LOG_FILE: `${CSEC_HOME}
|
|
27
|
+
STATUS_LOG_FILE: `${CSEC_HOME}${sep}nr-security-home${sep}logs${sep}snapshots${sep}node-security-collector-status-${process.env.applicationUUID}.log`,
|
|
27
28
|
|
|
28
29
|
DB_LIST: {
|
|
29
30
|
MYSQL: 'MYSQL',
|
|
@@ -83,7 +84,7 @@ module.exports = {
|
|
|
83
84
|
COLON: ':',
|
|
84
85
|
OPEN_PARANTHESIS: '(',
|
|
85
86
|
CLOSE_PARANTHESIS: ')',
|
|
86
|
-
SLASH:
|
|
87
|
+
SLASH: sep,
|
|
87
88
|
INCOMING_MSG: 'IncomingMessage',
|
|
88
89
|
OBJECT: 'object',
|
|
89
90
|
STRING: 'string',
|
|
@@ -133,9 +133,9 @@ function generateExitEvent(secEvent) {
|
|
|
133
133
|
|
|
134
134
|
function sendEvent(secEvent) {
|
|
135
135
|
const agentModule = Agent.getAgent();
|
|
136
|
-
if (agentModule.status.getStatus()
|
|
136
|
+
if (agentModule.status.getStatus() != 'connecting' && NRAgent.config.security.enabled) {
|
|
137
137
|
agentModule.client.dispatcher(secEvent);
|
|
138
|
-
if (!firstEventSent) {
|
|
138
|
+
if (!firstEventSent && agentModule.status.getStatus() === 'active') {
|
|
139
139
|
initLogger.info("[STEP-8] => First event sent for validation. Security Agent started successfully", JSON.stringify(secEvent));
|
|
140
140
|
firstEventSent = true;
|
|
141
141
|
}
|
|
@@ -264,23 +264,10 @@ function getSHA256ForFileSync (filePath) {
|
|
|
264
264
|
*/
|
|
265
265
|
function getSHA256ForData (data) {
|
|
266
266
|
try {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
270
|
-
const cachedSha = process.traceMap.get(data);
|
|
271
|
-
|
|
272
|
-
if (cachedSha) {
|
|
273
|
-
return cachedSha;
|
|
274
|
-
} else {
|
|
275
|
-
const calSha = hash.sha256().update(data).digest(HEX_DIGEST);
|
|
276
|
-
if (process.traceMap.size < 2000 && (httpreq && httpreq.data)) {
|
|
277
|
-
process.traceMap.set(data, calSha);
|
|
278
|
-
}
|
|
279
|
-
return calSha;
|
|
280
|
-
}
|
|
267
|
+
const calSha = hash.sha256().update(data).digest(HEX_DIGEST);
|
|
268
|
+
return calSha;
|
|
281
269
|
} catch (err) {
|
|
282
|
-
logger.
|
|
283
|
-
logger.debug(err);
|
|
270
|
+
logger.debug('Unable to calculate SHA256 for data.',err);
|
|
284
271
|
return null;
|
|
285
272
|
}
|
|
286
273
|
}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
/* eslint-disable new-cap */
|
|
7
7
|
|
|
8
8
|
const njsAgentConstants = require('./sec-agent-constants');
|
|
9
|
-
const
|
|
9
|
+
const agentConfig = require('../../resources/config');
|
|
10
|
+
const { AGENT_DIR } = agentConfig;
|
|
10
11
|
const lodash = require('lodash');
|
|
11
12
|
|
|
12
13
|
let errors = [];
|
|
@@ -24,33 +25,33 @@ const logger = logs.getLogger();
|
|
|
24
25
|
const statusFile = njsAgentConstants.STATUS_LOG_FILE;
|
|
25
26
|
|
|
26
27
|
const statusTemplate = 'Snapshot timestamp: : %s\n' +
|
|
27
|
-
`CSEC Agent start timestamp: ${njsAgentConstants.AGENT_START_TIME} with application uuid:${commonUtils.getUUID()}\n` +
|
|
28
|
-
`SEC_HOME: ${njsAgentConstants.CSEC_HOME}\n` +
|
|
29
|
-
`Agent location: ${
|
|
30
|
-
`Using CSEC Agent for Node.js, Node version:${process.version}, PID:${process.pid}\n` +
|
|
31
|
-
`Process title: ${process.title}\n` +
|
|
32
|
-
`Process binary: ${process.execPath}\n` +
|
|
33
|
-
'Application location: %s\n' +
|
|
34
|
-
`Current working directory: ${process.cwd()}\n` +
|
|
35
|
-
`Agent mode: ${commonUtils.getCSECmode()}\n` +
|
|
36
|
-
'Application server: %s\n' +
|
|
37
|
-
'Application Framework: %s\n' +
|
|
38
|
-
`Websocket connection to Prevent Web: ${commonUtils.getValidatorServiceEndpointURL()}, Status: %s\n` +
|
|
39
|
-
'Instrumentation successful:\n' +
|
|
40
|
-
'Tracking loaded modules in the application:\n' +
|
|
41
|
-
'Policy applied successfully. Policy version is: %s\n' +
|
|
42
|
-
'Started Health Check for Agent\n' +
|
|
43
|
-
'Started Inbound and Outbound monitoring \n' +
|
|
44
|
-
'\nProcess stats:\n%s\n' +
|
|
45
|
-
'\nService stats:\n%s\n' +
|
|
46
|
-
'\nLast 5 errors: \n%s\n' +
|
|
47
|
-
'\nLast 5 Health Checks are:\n %s \n';
|
|
28
|
+
`CSEC Agent start timestamp: ${njsAgentConstants.AGENT_START_TIME} with application uuid:${commonUtils.getUUID()}\n` +
|
|
29
|
+
`SEC_HOME: ${njsAgentConstants.CSEC_HOME}\n` +
|
|
30
|
+
`Agent location: ${AGENT_DIR}\n` +
|
|
31
|
+
`Using CSEC Agent for Node.js, Node version:${process.version}, PID:${process.pid}\n` +
|
|
32
|
+
`Process title: ${process.title}\n` +
|
|
33
|
+
`Process binary: ${process.execPath}\n` +
|
|
34
|
+
'Application location: %s\n' +
|
|
35
|
+
`Current working directory: ${process.cwd()}\n` +
|
|
36
|
+
`Agent mode: ${commonUtils.getCSECmode()}\n` +
|
|
37
|
+
'Application server: %s\n' +
|
|
38
|
+
'Application Framework: %s\n' +
|
|
39
|
+
`Websocket connection to Prevent Web: ${commonUtils.getValidatorServiceEndpointURL()}, Status: %s\n` +
|
|
40
|
+
'Instrumentation successful:\n' +
|
|
41
|
+
'Tracking loaded modules in the application:\n' +
|
|
42
|
+
'Policy applied successfully. Policy version is: %s\n' +
|
|
43
|
+
'Started Health Check for Agent\n' +
|
|
44
|
+
'Started Inbound and Outbound monitoring \n' +
|
|
45
|
+
'\nProcess stats:\n%s\n' +
|
|
46
|
+
'\nService stats:\n%s\n' +
|
|
47
|
+
'\nLast 5 errors: \n%s\n' +
|
|
48
|
+
'\nLast 5 Health Checks are:\n %s \n';
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* Utility to add hc in hc buffer
|
|
51
52
|
* @param {*} healthCheck
|
|
52
53
|
*/
|
|
53
|
-
function addHCtoBuffer
|
|
54
|
+
function addHCtoBuffer(healthCheck) {
|
|
54
55
|
try {
|
|
55
56
|
bufferedHC.enq(healthCheck);
|
|
56
57
|
lastHC = healthCheck;
|
|
@@ -63,9 +64,12 @@ function addHCtoBuffer (healthCheck) {
|
|
|
63
64
|
* Utility to add error object in error buffer
|
|
64
65
|
* @param {*} error
|
|
65
66
|
*/
|
|
66
|
-
function addErrortoBuffer
|
|
67
|
+
function addErrortoBuffer(error) {
|
|
67
68
|
try {
|
|
68
|
-
|
|
69
|
+
let errorObj = {
|
|
70
|
+
'error': error.stack
|
|
71
|
+
}
|
|
72
|
+
bufferedErrors.enq(errorObj);
|
|
69
73
|
} catch (error) {
|
|
70
74
|
logger.debug(error);
|
|
71
75
|
}
|
|
@@ -74,19 +78,19 @@ function addErrortoBuffer (error) {
|
|
|
74
78
|
/**
|
|
75
79
|
* utility to format status template with dynamic values
|
|
76
80
|
*/
|
|
77
|
-
function getFormattedData
|
|
81
|
+
function getFormattedData() {
|
|
78
82
|
const Agent = require('./agent').Agent.getAgent();
|
|
79
83
|
const appInfo = Agent.applicationInfo;
|
|
80
84
|
const deployedApplications = appInfo && appInfo.serverInfo && appInfo.serverInfo.deployedApplications;
|
|
81
85
|
const appLoc = deployedApplications[0].deployedPath;
|
|
82
|
-
const formattedSnapshot = util.format(statusTemplate, new Date().toString(), appLoc, appInfo.serverInfo.name, njsAgentConstants.FRAMEWORK,
|
|
86
|
+
const formattedSnapshot = util.format(statusTemplate, new Date().toString(), appLoc, appInfo.serverInfo.name, njsAgentConstants.FRAMEWORK,commonUtils.getWSHealthStatus(), appInfo.policyVersion, getKeyValPairs(lastHC.stats), getKeyValPairs(lastHC.serviceStatus), JSON.stringify(getBufferedErrors()), JSON.stringify(getBufferedHC()));
|
|
83
87
|
return formattedSnapshot;
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
/**
|
|
87
91
|
* utility to write snapshot in snapshot file
|
|
88
92
|
*/
|
|
89
|
-
function writeSnapshot
|
|
93
|
+
function writeSnapshot() {
|
|
90
94
|
const snapshot = getFormattedData();
|
|
91
95
|
commonUtils.removeOlderSnapshots();
|
|
92
96
|
fs.writeFile(statusFile, snapshot, { mode: 0o777 }, function (err) {
|
|
@@ -105,14 +109,14 @@ function writeSnapshot () {
|
|
|
105
109
|
/**
|
|
106
110
|
* return buffered error instance.
|
|
107
111
|
*/
|
|
108
|
-
function getRingBufferedErrors
|
|
112
|
+
function getRingBufferedErrors() {
|
|
109
113
|
return bufferedErrors;
|
|
110
114
|
}
|
|
111
115
|
|
|
112
116
|
/**
|
|
113
117
|
* return buffered HC list without null, undefined
|
|
114
118
|
*/
|
|
115
|
-
function getBufferedHC
|
|
119
|
+
function getBufferedHC() {
|
|
116
120
|
try {
|
|
117
121
|
HC = lodash.compact(bufferedHC._elements);
|
|
118
122
|
} catch (error) {
|
|
@@ -124,7 +128,7 @@ function getBufferedHC () {
|
|
|
124
128
|
/**
|
|
125
129
|
* returns buffered error list without null, undefined
|
|
126
130
|
*/
|
|
127
|
-
function getBufferedErrors
|
|
131
|
+
function getBufferedErrors() {
|
|
128
132
|
try {
|
|
129
133
|
errors = lodash.compact(bufferedErrors._elements);
|
|
130
134
|
} catch (error) {
|
|
@@ -137,7 +141,7 @@ function getBufferedErrors () {
|
|
|
137
141
|
* Utility to get key val pairs from json object
|
|
138
142
|
* @param {*} jsonObject
|
|
139
143
|
*/
|
|
140
|
-
function getKeyValPairs
|
|
144
|
+
function getKeyValPairs(jsonObject) {
|
|
141
145
|
let statStr = njsAgentConstants.EMPTY_STR;
|
|
142
146
|
for (const key in jsonObject) {
|
|
143
147
|
statStr = statStr + key + ': ' + jsonObject[key] + '\n';
|
|
@@ -195,7 +195,7 @@ function handleWorkerMessage(json) {
|
|
|
195
195
|
break;
|
|
196
196
|
}
|
|
197
197
|
case WorkerMessage.TYPE.ERROR: {
|
|
198
|
-
statusUtils.addErrortoBuffer(msg.getPayload()
|
|
198
|
+
statusUtils.addErrortoBuffer(msg.getPayload());
|
|
199
199
|
break;
|
|
200
200
|
}
|
|
201
201
|
default:
|
|
@@ -206,7 +206,7 @@ function handleWorkerMessage(json) {
|
|
|
206
206
|
* Sends Agent HelthCheck to Validator.
|
|
207
207
|
*/
|
|
208
208
|
const sendHC = async function () {
|
|
209
|
-
if (AgentStatus.getInstance().getStatus()
|
|
209
|
+
if (AgentStatus.getInstance().getStatus() != AgentStatus.CSECAgentStatus.codes.DISABLED && (NRAgent ? (NRAgent.config.security.enabled && NRAgent.canCollectData()) : true)) {
|
|
210
210
|
let json = hc.getInstance().get();
|
|
211
211
|
json = JSON.parse(json);
|
|
212
212
|
json.policyVersion = applicationInfo.policyVersion;
|
|
@@ -218,7 +218,7 @@ const sendHC = async function () {
|
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
json.serviceStatus = {};
|
|
221
|
-
json.serviceStatus.websocket =
|
|
221
|
+
json.serviceStatus.websocket = commonUtils.getWSHealthStatus();
|
|
222
222
|
json.serviceStatus.logWriter = await commonUtils.isLogAccessible(`${LOG_DIR}node-security-collector.log`);
|
|
223
223
|
json.serviceStatus.initLogWriter = await commonUtils.isLogAccessible(`${LOG_DIR}node-security-collector-init.log`);
|
|
224
224
|
json.serviceStatus.statusLogWriter = await commonUtils.isLogAccessible(njsAgentConstants.STATUS_LOG_FILE);
|
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
3
|
* SPDX-License-Identifier: New Relic Pre-Release
|
|
4
4
|
*/
|
|
5
|
+
const { platform } = require('os');
|
|
5
6
|
const path = require('path');
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
let AGENT_DIR = path.join(__dirname, '../../../');
|
|
9
|
+
|
|
10
|
+
if(process.platform == 'win32'){
|
|
11
|
+
AGENT_DIR = path.join(__dirname, "..\\..\\..\\");
|
|
12
|
+
}
|
|
13
|
+
|
|
8
14
|
const uuidv4 = require('uuid/v4');
|
|
9
15
|
process.env.applicationUUID = process.env.applicationUUID || uuidv4();
|
|
10
16
|
|
package/package.json
CHANGED