securenow 5.10.2 → 5.11.0
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/CONSUMING-APPS-GUIDE.md +30 -0
- package/NPM_README.md +65 -0
- package/README.md +13 -0
- package/cidr.js +83 -0
- package/cli/auth.js +208 -208
- package/cli/config.js +117 -117
- package/cli/firewall.js +81 -0
- package/cli/fp.js +638 -0
- package/cli/security.js +4 -8
- package/cli.js +28 -1
- package/console-instrumentation.js +147 -147
- package/docs/ALL-FRAMEWORKS-QUICKSTART.md +40 -1
- package/docs/API-KEYS-GUIDE.md +215 -0
- package/docs/ENVIRONMENT-VARIABLES.md +880 -697
- package/docs/FIREWALL-GUIDE.md +388 -0
- package/docs/INDEX.md +8 -1
- package/firewall-cloud.js +212 -0
- package/firewall-iptables.js +139 -0
- package/firewall-tcp.js +58 -0
- package/firewall.js +235 -0
- package/free-trial-banner.js +174 -174
- package/nextjs-auto-capture.js +199 -199
- package/nextjs-middleware.js +186 -186
- package/nextjs-wrapper.js +158 -158
- package/nuxt-server-plugin.mjs +400 -400
- package/package.json +30 -3
- package/resolve-ip.js +77 -0
- package/tracing.js +31 -56
- package/web-vite.mjs +239 -239
package/cli.js
CHANGED
|
@@ -119,6 +119,32 @@ const COMMANDS = {
|
|
|
119
119
|
},
|
|
120
120
|
defaultSub: 'rules',
|
|
121
121
|
},
|
|
122
|
+
fp: {
|
|
123
|
+
desc: 'Manage false-positive exclusion rules',
|
|
124
|
+
usage: 'securenow fp <subcommand> [options]',
|
|
125
|
+
flags: { json: 'Output as JSON', conditions: 'JSON array of conditions', 'match-mode': 'Match mode: all (AND) or any (OR)', 'rule-scope': 'Scope: this_rule | specific_rules | all_existing | any_rule', 'target-rules': 'Comma-separated rule IDs (when --rule-scope specific_rules)', 'path-safe': 'Add path_safe_values condition (standard|strict)', 'query-safe': 'Add query_safe_values condition (standard|strict)', 'query-keys': 'Allowed query param names (comma-separated)', 'ua-safe': 'Add ua_safe_values condition (standard|strict)', 'headers-safe': 'Add headers_safe_values condition (standard|strict)', 'headers-keys': 'Allowed header names (comma-separated)' },
|
|
126
|
+
sub: {
|
|
127
|
+
list: { desc: 'List all exclusion rules', run: (a, f) => require('./cli/fp').list(a, f) },
|
|
128
|
+
show: { desc: 'Show exclusion rule details', usage: 'securenow fp show <id>', run: (a, f) => require('./cli/fp').show(a, f) },
|
|
129
|
+
create: { desc: 'Create an exclusion rule', usage: 'securenow fp create [--conditions \'[...]\'] [--path /api/event] [--method POST] [--path-safe standard] [--ua-safe standard] [--headers-safe standard] [--query-keys page,limit] [--headers-keys host,content-type] [--reason "..."] [--rule-scope any_rule|specific_rules|all_existing] [--target-rules id1,id2]', run: (a, f) => require('./cli/fp').create(a, f) },
|
|
130
|
+
edit: { desc: 'Edit an exclusion rule', usage: 'securenow fp edit <id> [--active true/false] [--conditions \'[...]\']', run: (a, f) => require('./cli/fp').edit(a, f) },
|
|
131
|
+
delete: { desc: 'Delete an exclusion rule', usage: 'securenow fp delete <id> [--yes]', run: (a, f) => require('./cli/fp').remove(a, f) },
|
|
132
|
+
'test-body': { desc: 'Test a request body against conditions', usage: 'securenow fp test-body <body|@file> --conditions \'[...]\'', run: (a, f) => require('./cli/fp').testBody(a, f) },
|
|
133
|
+
'dry-run': { desc: 'Dry-run conditions against live traces (last 3 days)', usage: 'securenow fp dry-run --conditions \'[...]\'', run: (a, f) => require('./cli/fp').dryRun(a, f) },
|
|
134
|
+
'ai-fill': { desc: 'AI-generate exclusion conditions', usage: 'securenow fp ai-fill [--description "..."] [--context \'{"method":"POST",...}\']', run: (a, f) => require('./cli/fp').aiFill(a, f) },
|
|
135
|
+
mark: { desc: 'Mark an IP as false positive on a notification', usage: 'securenow fp mark <notification-id> <ip> [--conditions \'[...]\'] [--reason "..."] [--rule-scope this_rule|specific_rules|all_existing|any_rule] [--target-rules id1,id2]', run: (a, f) => require('./cli/fp').mark(a, f) },
|
|
136
|
+
},
|
|
137
|
+
defaultSub: 'list',
|
|
138
|
+
},
|
|
139
|
+
firewall: {
|
|
140
|
+
desc: 'Firewall status and IP testing',
|
|
141
|
+
usage: 'securenow firewall <subcommand> [options]',
|
|
142
|
+
sub: {
|
|
143
|
+
status: { desc: 'Show firewall status, layers, and blocklist info', run: (a, f) => require('./cli/firewall').status(a, f) },
|
|
144
|
+
'test-ip': { desc: 'Check if an IP would be blocked', usage: 'securenow firewall test-ip <ip>', run: (a, f) => require('./cli/firewall').testIp(a, f) },
|
|
145
|
+
},
|
|
146
|
+
defaultSub: 'status',
|
|
147
|
+
},
|
|
122
148
|
blocklist: {
|
|
123
149
|
desc: 'Manage IP blocklist',
|
|
124
150
|
usage: 'securenow blocklist <subcommand> [options]',
|
|
@@ -305,8 +331,9 @@ function showHelp(commandName) {
|
|
|
305
331
|
'Authentication': ['login', 'logout', 'whoami'],
|
|
306
332
|
'Applications': ['apps', 'init', 'status'],
|
|
307
333
|
'Observe': ['traces', 'logs', 'analytics'],
|
|
308
|
-
'Detect & Respond': ['issues', 'notifications', 'alerts'],
|
|
334
|
+
'Detect & Respond': ['issues', 'notifications', 'alerts', 'fp'],
|
|
309
335
|
'Investigate': ['ip', 'forensics', 'api-map'],
|
|
336
|
+
'Firewall': ['firewall'],
|
|
310
337
|
'Remediation': ['blocklist', 'trusted'],
|
|
311
338
|
'Settings': ['instances', 'config', 'version'],
|
|
312
339
|
};
|
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Console instrumentation helper for securenow
|
|
5
|
-
*
|
|
6
|
-
* This module wraps the default console methods (log, info, warn, error, debug)
|
|
7
|
-
* to automatically send logs to OpenTelemetry / any OTLP-compatible backend.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* 1. Enable logging: SECURENOW_LOGGING_ENABLED=1
|
|
11
|
-
* 2. Import this file AFTER securenow is initialized
|
|
12
|
-
* 3. Use console.log/info/warn/error as normal
|
|
13
|
-
*
|
|
14
|
-
* Example:
|
|
15
|
-
* // At the top of your app.js or index.js
|
|
16
|
-
* require('securenow/register'); // or use NODE_OPTIONS
|
|
17
|
-
* require('securenow/console-instrumentation');
|
|
18
|
-
*
|
|
19
|
-
* // Now all console calls are captured
|
|
20
|
-
* console.log('Application started');
|
|
21
|
-
* console.error('An error occurred');
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
const tracing = require('./tracing');
|
|
25
|
-
|
|
26
|
-
if (!tracing.isLoggingEnabled()) {
|
|
27
|
-
console.warn('[securenow] Console instrumentation loaded but logging is not enabled. Set SECURENOW_LOGGING_ENABLED=1 to enable.');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Get a logger instance
|
|
31
|
-
const logger = tracing.getLogger('console', '1.0.0');
|
|
32
|
-
|
|
33
|
-
if (!logger) {
|
|
34
|
-
console.warn('[securenow] Console instrumentation: No logger available. Logging will not work.');
|
|
35
|
-
module.exports = {};
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (console.__securenow_patched) {
|
|
40
|
-
console.warn('[securenow] Console already instrumented by tracing.js — skipping to avoid duplicate logs.');
|
|
41
|
-
module.exports = {};
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Store original console methods
|
|
46
|
-
const originalConsole = {
|
|
47
|
-
log: console.log,
|
|
48
|
-
info: console.info,
|
|
49
|
-
warn: console.warn,
|
|
50
|
-
error: console.error,
|
|
51
|
-
debug: console.debug,
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
// Map severity levels (OpenTelemetry standard)
|
|
55
|
-
const SeverityNumber = {
|
|
56
|
-
DEBUG: 5,
|
|
57
|
-
INFO: 9,
|
|
58
|
-
WARN: 13,
|
|
59
|
-
ERROR: 17,
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Format arguments into a log message
|
|
64
|
-
*/
|
|
65
|
-
function formatMessage(args) {
|
|
66
|
-
return args
|
|
67
|
-
.map((arg) => {
|
|
68
|
-
if (typeof arg === 'object' && arg !== null) {
|
|
69
|
-
try {
|
|
70
|
-
return JSON.stringify(arg);
|
|
71
|
-
} catch (e) {
|
|
72
|
-
return String(arg);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return String(arg);
|
|
76
|
-
})
|
|
77
|
-
.join(' ');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const { context, trace } = require('@opentelemetry/api');
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Emit a log record, correlating with the active trace/span when available
|
|
84
|
-
*/
|
|
85
|
-
function emitLog(severityNumber, severityText, args) {
|
|
86
|
-
const message = formatMessage(args);
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
const activeCtx = context.active();
|
|
90
|
-
const spanCtx = trace.getSpanContext(activeCtx);
|
|
91
|
-
logger.emit({
|
|
92
|
-
severityNumber,
|
|
93
|
-
severityText,
|
|
94
|
-
body: message,
|
|
95
|
-
attributes: {
|
|
96
|
-
'log.source': 'console',
|
|
97
|
-
'log.method': severityText.toLowerCase(),
|
|
98
|
-
},
|
|
99
|
-
...(spanCtx && { context: activeCtx }),
|
|
100
|
-
});
|
|
101
|
-
} catch (e) {
|
|
102
|
-
// Silently fail to avoid breaking the application
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Override console.log
|
|
107
|
-
console.log = function (...args) {
|
|
108
|
-
emitLog(SeverityNumber.INFO, 'INFO', args);
|
|
109
|
-
originalConsole.log.apply(console, args);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
// Override console.info
|
|
113
|
-
console.info = function (...args) {
|
|
114
|
-
emitLog(SeverityNumber.INFO, 'INFO', args);
|
|
115
|
-
originalConsole.info.apply(console, args);
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
// Override console.warn
|
|
119
|
-
console.warn = function (...args) {
|
|
120
|
-
emitLog(SeverityNumber.WARN, 'WARN', args);
|
|
121
|
-
originalConsole.warn.apply(console, args);
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
// Override console.error
|
|
125
|
-
console.error = function (...args) {
|
|
126
|
-
emitLog(SeverityNumber.ERROR, 'ERROR', args);
|
|
127
|
-
originalConsole.error.apply(console, args);
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
// Override console.debug
|
|
131
|
-
console.debug = function (...args) {
|
|
132
|
-
emitLog(SeverityNumber.DEBUG, 'DEBUG', args);
|
|
133
|
-
originalConsole.debug.apply(console, args);
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
console.log('[securenow] Console instrumentation installed - all console logs will be sent to any OTLP-compatible backend');
|
|
137
|
-
|
|
138
|
-
module.exports = {
|
|
139
|
-
originalConsole,
|
|
140
|
-
restoreConsole: () => {
|
|
141
|
-
console.log = originalConsole.log;
|
|
142
|
-
console.info = originalConsole.info;
|
|
143
|
-
console.warn = originalConsole.warn;
|
|
144
|
-
console.error = originalConsole.error;
|
|
145
|
-
console.debug = originalConsole.debug;
|
|
146
|
-
},
|
|
147
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Console instrumentation helper for securenow
|
|
5
|
+
*
|
|
6
|
+
* This module wraps the default console methods (log, info, warn, error, debug)
|
|
7
|
+
* to automatically send logs to OpenTelemetry / any OTLP-compatible backend.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* 1. Enable logging: SECURENOW_LOGGING_ENABLED=1
|
|
11
|
+
* 2. Import this file AFTER securenow is initialized
|
|
12
|
+
* 3. Use console.log/info/warn/error as normal
|
|
13
|
+
*
|
|
14
|
+
* Example:
|
|
15
|
+
* // At the top of your app.js or index.js
|
|
16
|
+
* require('securenow/register'); // or use NODE_OPTIONS
|
|
17
|
+
* require('securenow/console-instrumentation');
|
|
18
|
+
*
|
|
19
|
+
* // Now all console calls are captured
|
|
20
|
+
* console.log('Application started');
|
|
21
|
+
* console.error('An error occurred');
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const tracing = require('./tracing');
|
|
25
|
+
|
|
26
|
+
if (!tracing.isLoggingEnabled()) {
|
|
27
|
+
console.warn('[securenow] Console instrumentation loaded but logging is not enabled. Set SECURENOW_LOGGING_ENABLED=1 to enable.');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Get a logger instance
|
|
31
|
+
const logger = tracing.getLogger('console', '1.0.0');
|
|
32
|
+
|
|
33
|
+
if (!logger) {
|
|
34
|
+
console.warn('[securenow] Console instrumentation: No logger available. Logging will not work.');
|
|
35
|
+
module.exports = {};
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (console.__securenow_patched) {
|
|
40
|
+
console.warn('[securenow] Console already instrumented by tracing.js — skipping to avoid duplicate logs.');
|
|
41
|
+
module.exports = {};
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Store original console methods
|
|
46
|
+
const originalConsole = {
|
|
47
|
+
log: console.log,
|
|
48
|
+
info: console.info,
|
|
49
|
+
warn: console.warn,
|
|
50
|
+
error: console.error,
|
|
51
|
+
debug: console.debug,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Map severity levels (OpenTelemetry standard)
|
|
55
|
+
const SeverityNumber = {
|
|
56
|
+
DEBUG: 5,
|
|
57
|
+
INFO: 9,
|
|
58
|
+
WARN: 13,
|
|
59
|
+
ERROR: 17,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Format arguments into a log message
|
|
64
|
+
*/
|
|
65
|
+
function formatMessage(args) {
|
|
66
|
+
return args
|
|
67
|
+
.map((arg) => {
|
|
68
|
+
if (typeof arg === 'object' && arg !== null) {
|
|
69
|
+
try {
|
|
70
|
+
return JSON.stringify(arg);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
return String(arg);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return String(arg);
|
|
76
|
+
})
|
|
77
|
+
.join(' ');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const { context, trace } = require('@opentelemetry/api');
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Emit a log record, correlating with the active trace/span when available
|
|
84
|
+
*/
|
|
85
|
+
function emitLog(severityNumber, severityText, args) {
|
|
86
|
+
const message = formatMessage(args);
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const activeCtx = context.active();
|
|
90
|
+
const spanCtx = trace.getSpanContext(activeCtx);
|
|
91
|
+
logger.emit({
|
|
92
|
+
severityNumber,
|
|
93
|
+
severityText,
|
|
94
|
+
body: message,
|
|
95
|
+
attributes: {
|
|
96
|
+
'log.source': 'console',
|
|
97
|
+
'log.method': severityText.toLowerCase(),
|
|
98
|
+
},
|
|
99
|
+
...(spanCtx && { context: activeCtx }),
|
|
100
|
+
});
|
|
101
|
+
} catch (e) {
|
|
102
|
+
// Silently fail to avoid breaking the application
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Override console.log
|
|
107
|
+
console.log = function (...args) {
|
|
108
|
+
emitLog(SeverityNumber.INFO, 'INFO', args);
|
|
109
|
+
originalConsole.log.apply(console, args);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Override console.info
|
|
113
|
+
console.info = function (...args) {
|
|
114
|
+
emitLog(SeverityNumber.INFO, 'INFO', args);
|
|
115
|
+
originalConsole.info.apply(console, args);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Override console.warn
|
|
119
|
+
console.warn = function (...args) {
|
|
120
|
+
emitLog(SeverityNumber.WARN, 'WARN', args);
|
|
121
|
+
originalConsole.warn.apply(console, args);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// Override console.error
|
|
125
|
+
console.error = function (...args) {
|
|
126
|
+
emitLog(SeverityNumber.ERROR, 'ERROR', args);
|
|
127
|
+
originalConsole.error.apply(console, args);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Override console.debug
|
|
131
|
+
console.debug = function (...args) {
|
|
132
|
+
emitLog(SeverityNumber.DEBUG, 'DEBUG', args);
|
|
133
|
+
originalConsole.debug.apply(console, args);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
console.log('[securenow] Console instrumentation installed - all console logs will be sent to any OTLP-compatible backend');
|
|
137
|
+
|
|
138
|
+
module.exports = {
|
|
139
|
+
originalConsole,
|
|
140
|
+
restoreConsole: () => {
|
|
141
|
+
console.log = originalConsole.log;
|
|
142
|
+
console.info = originalConsole.info;
|
|
143
|
+
console.warn = originalConsole.warn;
|
|
144
|
+
console.error = originalConsole.error;
|
|
145
|
+
console.debug = originalConsole.debug;
|
|
146
|
+
},
|
|
147
|
+
};
|
|
@@ -24,7 +24,7 @@ Protect any Node.js app in minutes. This guide covers **installation, CLI comman
|
|
|
24
24
|
5. [Verify It Works](#step-4--verify-it-works)
|
|
25
25
|
6. [CLI Command Reference](#step-5--cli-command-reference)
|
|
26
26
|
7. [Forensics Chat — Ask Questions in Plain English](#step-6--forensics-chat--ask-questions-in-plain-english)
|
|
27
|
-
8. [Block & Manage IPs](#step-7--block--manage-ips)
|
|
27
|
+
8. [Block & Manage IPs + Firewall](#step-7--block--manage-ips)
|
|
28
28
|
9. [Monitor, Detect & Respond](#step-8--monitor-detect--respond)
|
|
29
29
|
10. [PM2 / Docker Deployment](#deployment)
|
|
30
30
|
11. [Compatibility Matrix](#compatibility-matrix)
|
|
@@ -1087,6 +1087,45 @@ npx securenow blocklist add 185.220.101.1 --reason "brute force login attempts"
|
|
|
1087
1087
|
npx securenow blocklist
|
|
1088
1088
|
```
|
|
1089
1089
|
|
|
1090
|
+
### Enforce the Blocklist on Your App (Firewall)
|
|
1091
|
+
|
|
1092
|
+
Once you've built a blocklist, enforce it at your application layer — automatically, with zero code changes:
|
|
1093
|
+
|
|
1094
|
+
```bash
|
|
1095
|
+
# Add your API key to .env
|
|
1096
|
+
SECURENOW_API_KEY=snk_live_abc123...
|
|
1097
|
+
```
|
|
1098
|
+
|
|
1099
|
+
Restart your app. The firewall syncs the blocklist every 60 seconds and blocks matching IPs with a 403 response:
|
|
1100
|
+
|
|
1101
|
+
```
|
|
1102
|
+
[securenow] Firewall: ENABLED
|
|
1103
|
+
[securenow] Firewall: Layer 1 (HTTP 403) active
|
|
1104
|
+
[securenow] Firewall: synced 142 blocked IPs
|
|
1105
|
+
```
|
|
1106
|
+
|
|
1107
|
+
Enable additional layers for defense in depth:
|
|
1108
|
+
|
|
1109
|
+
```bash
|
|
1110
|
+
# TCP-level blocking (zero bytes sent back)
|
|
1111
|
+
SECURENOW_FIREWALL_TCP=1
|
|
1112
|
+
|
|
1113
|
+
# OS-level blocking (iptables/nftables, Linux only)
|
|
1114
|
+
SECURENOW_FIREWALL_IPTABLES=1
|
|
1115
|
+
|
|
1116
|
+
# Cloud WAF blocking (Cloudflare, AWS WAF, GCP Cloud Armor)
|
|
1117
|
+
SECURENOW_FIREWALL_CLOUD=cloudflare
|
|
1118
|
+
```
|
|
1119
|
+
|
|
1120
|
+
Check firewall status:
|
|
1121
|
+
|
|
1122
|
+
```bash
|
|
1123
|
+
npx securenow firewall status
|
|
1124
|
+
npx securenow firewall test-ip 185.220.101.1
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
See the [Firewall Guide](FIREWALL-GUIDE.md) for the full reference.
|
|
1128
|
+
|
|
1090
1129
|
---
|
|
1091
1130
|
|
|
1092
1131
|
## Step 8 — Monitor, Detect & Respond
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# SecureNow API Keys
|
|
2
|
+
|
|
3
|
+
API keys provide programmatic access to the SecureNow platform. They support granular feature-level permissions, application scoping, IP allowlisting, and secure one-time-copy generation.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Creating an API Key
|
|
8
|
+
|
|
9
|
+
### From the Dashboard
|
|
10
|
+
|
|
11
|
+
1. Go to **Settings → API Keys**
|
|
12
|
+
2. Click **Create API Key**
|
|
13
|
+
3. Enter a name (e.g., "Production Firewall", "CI/CD Pipeline")
|
|
14
|
+
4. Select the scopes (permissions) you need
|
|
15
|
+
5. Optionally restrict to specific applications and IP addresses
|
|
16
|
+
6. Click **Create**
|
|
17
|
+
7. **Copy the key immediately** — it will only be shown once
|
|
18
|
+
|
|
19
|
+
### From the CLI
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx securenow login
|
|
23
|
+
npx securenow firewall status
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The `securenow init` and `securenow login` commands can automatically provision a firewall API key for you.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Key Format
|
|
31
|
+
|
|
32
|
+
All API keys use the format:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
snk_live_<64 hex characters>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Example: `snk_live_a1b2c3d4e5f6...`
|
|
39
|
+
|
|
40
|
+
The `snk_live_` prefix makes it easy to identify SecureNow keys in your codebase and credential scanners.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Scopes (Permissions)
|
|
45
|
+
|
|
46
|
+
Each API key has a set of scopes that control what it can access. Scopes follow the `resource:action` pattern.
|
|
47
|
+
|
|
48
|
+
| Scope | Description |
|
|
49
|
+
|-------|-------------|
|
|
50
|
+
| `firewall:read` | Read the blocklist (used by the firewall SDK) |
|
|
51
|
+
| `blocklist:read` | List and check blocked IPs |
|
|
52
|
+
| `blocklist:write` | Add and remove blocked IPs |
|
|
53
|
+
| `applications:read` | List and view applications |
|
|
54
|
+
| `applications:write` | Create and delete applications |
|
|
55
|
+
| `traces:read` | Query traces |
|
|
56
|
+
| `logs:read` | Query logs |
|
|
57
|
+
| `issues:read` | List and view security issues |
|
|
58
|
+
| `issues:write` | Resolve and manage issues |
|
|
59
|
+
| `alerts:read` | View alert rules, channels, and history |
|
|
60
|
+
| `alerts:write` | Create and manage alert rules |
|
|
61
|
+
| `analytics:read` | View analytics data |
|
|
62
|
+
| `forensics:read` | Run forensic queries |
|
|
63
|
+
| `ip:read` | IP intelligence lookups |
|
|
64
|
+
| `trusted:read` | List trusted IPs |
|
|
65
|
+
| `trusted:write` | Manage trusted IPs |
|
|
66
|
+
| `notifications:read` | List notifications |
|
|
67
|
+
| `notifications:write` | Mark notifications as read |
|
|
68
|
+
| `api-map:read` | View API map |
|
|
69
|
+
| `instances:read` | List instances |
|
|
70
|
+
| `false-positives:read` | List false positive rules |
|
|
71
|
+
| `false-positives:write` | Create and manage false positive rules |
|
|
72
|
+
|
|
73
|
+
### Principle of Least Privilege
|
|
74
|
+
|
|
75
|
+
Only grant the scopes your use case requires:
|
|
76
|
+
|
|
77
|
+
- **Firewall SDK:** `firewall:read`
|
|
78
|
+
- **CI/CD monitoring:** `issues:read`, `traces:read`
|
|
79
|
+
- **Automated remediation:** `blocklist:read`, `blocklist:write`
|
|
80
|
+
- **Dashboard integration:** all `*:read` scopes
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Application Scoping
|
|
85
|
+
|
|
86
|
+
Restrict an API key to specific applications. When set, the key can only access data for those applications.
|
|
87
|
+
|
|
88
|
+
Leave empty to allow access to all applications on your account.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## IP Allowlisting
|
|
93
|
+
|
|
94
|
+
Restrict an API key to specific client IPs or CIDR ranges. When set, requests from other IPs are rejected with 403.
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
34.56.78.90
|
|
98
|
+
10.0.0.0/24
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Leave empty to allow from any IP.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Using API Keys
|
|
106
|
+
|
|
107
|
+
### In HTTP Requests
|
|
108
|
+
|
|
109
|
+
Pass the API key in the `Authorization` header:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
curl -s https://api.securenow.ai/api/v1/blocklist \
|
|
113
|
+
-H "Authorization: Bearer snk_live_abc123..."
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### In the Firewall SDK
|
|
117
|
+
|
|
118
|
+
Set the `SECURENOW_API_KEY` environment variable:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
SECURENOW_API_KEY=snk_live_abc123...
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The firewall SDK reads this automatically on startup.
|
|
125
|
+
|
|
126
|
+
### In CI/CD
|
|
127
|
+
|
|
128
|
+
```yaml
|
|
129
|
+
# GitHub Actions example
|
|
130
|
+
env:
|
|
131
|
+
SECURENOW_API_KEY: ${{ secrets.SECURENOW_API_KEY }}
|
|
132
|
+
|
|
133
|
+
steps:
|
|
134
|
+
- run: |
|
|
135
|
+
ISSUES=$(curl -s https://api.securenow.ai/api/v1/issues \
|
|
136
|
+
-H "Authorization: Bearer $SECURENOW_API_KEY")
|
|
137
|
+
echo "$ISSUES" | jq '.issues | length'
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Key Management
|
|
143
|
+
|
|
144
|
+
### Viewing Keys
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# From the CLI
|
|
148
|
+
npx securenow api-keys list
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Or go to **Settings → API Keys** in the dashboard. You'll see the key name, last 4 characters, status, scopes, and last used timestamp.
|
|
152
|
+
|
|
153
|
+
### Revoking a Key
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
npx securenow api-keys revoke <key-id>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Or click **Revoke** in the dashboard. Revoked keys immediately stop working. This cannot be undone.
|
|
160
|
+
|
|
161
|
+
### Regenerating a Key
|
|
162
|
+
|
|
163
|
+
Regeneration creates a new key with the same name, scopes, and settings. The old key is automatically revoked.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Rate Limits
|
|
168
|
+
|
|
169
|
+
API keys are subject to rate limiting:
|
|
170
|
+
|
|
171
|
+
| Endpoint | Limit |
|
|
172
|
+
|----------|-------|
|
|
173
|
+
| General API (`/api/*`) | 600 requests/minute |
|
|
174
|
+
| Firewall sync (`/api/firewall/*`) | 120 requests/minute |
|
|
175
|
+
|
|
176
|
+
Rate limit headers are included in every response:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
X-RateLimit-Limit: 600
|
|
180
|
+
X-RateLimit-Remaining: 597
|
|
181
|
+
X-RateLimit-Reset: 1712534400
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Security Best Practices
|
|
187
|
+
|
|
188
|
+
1. **Never commit API keys to source control.** Use `.env` files or secret managers.
|
|
189
|
+
2. **Use the minimum scopes required.** A firewall key only needs `firewall:read`.
|
|
190
|
+
3. **Restrict by IP when possible.** Server keys should be locked to your server IPs.
|
|
191
|
+
4. **Rotate keys periodically.** Use the regenerate feature to rotate without downtime.
|
|
192
|
+
5. **Monitor usage.** Check the "last used" timestamp and known IPs in the dashboard.
|
|
193
|
+
6. **Revoke unused keys.** Delete keys that are no longer in use.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## API Versioning
|
|
198
|
+
|
|
199
|
+
All API endpoints are available at both `/api/` and `/api/v1/`. We recommend using the versioned path for stability:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Recommended
|
|
203
|
+
https://api.securenow.ai/api/v1/blocklist
|
|
204
|
+
|
|
205
|
+
# Also works (unversioned)
|
|
206
|
+
https://api.securenow.ai/api/blocklist
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Related Documentation
|
|
212
|
+
|
|
213
|
+
- [Firewall Guide](./FIREWALL-GUIDE.md) — Automatic IP blocking setup
|
|
214
|
+
- [Environment Variables Reference](./ENVIRONMENT-VARIABLES.md) — All configuration options
|
|
215
|
+
- [All Frameworks Quick Start](./ALL-FRAMEWORKS-QUICKSTART.md) — Framework setup guides
|