defense-mcp-server 0.6.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/CHANGELOG.md +471 -0
- package/LICENSE +21 -0
- package/README.md +242 -0
- package/build/core/auto-installer.d.ts +102 -0
- package/build/core/auto-installer.d.ts.map +1 -0
- package/build/core/auto-installer.js +833 -0
- package/build/core/backup-manager.d.ts +63 -0
- package/build/core/backup-manager.d.ts.map +1 -0
- package/build/core/backup-manager.js +189 -0
- package/build/core/changelog.d.ts +75 -0
- package/build/core/changelog.d.ts.map +1 -0
- package/build/core/changelog.js +123 -0
- package/build/core/command-allowlist.d.ts +129 -0
- package/build/core/command-allowlist.d.ts.map +1 -0
- package/build/core/command-allowlist.js +849 -0
- package/build/core/config.d.ts +79 -0
- package/build/core/config.d.ts.map +1 -0
- package/build/core/config.js +193 -0
- package/build/core/dependency-validator.d.ts +106 -0
- package/build/core/dependency-validator.d.ts.map +1 -0
- package/build/core/dependency-validator.js +405 -0
- package/build/core/distro-adapter.d.ts +177 -0
- package/build/core/distro-adapter.d.ts.map +1 -0
- package/build/core/distro-adapter.js +481 -0
- package/build/core/distro.d.ts +68 -0
- package/build/core/distro.d.ts.map +1 -0
- package/build/core/distro.js +457 -0
- package/build/core/encrypted-state.d.ts +76 -0
- package/build/core/encrypted-state.d.ts.map +1 -0
- package/build/core/encrypted-state.js +209 -0
- package/build/core/executor.d.ts +56 -0
- package/build/core/executor.d.ts.map +1 -0
- package/build/core/executor.js +350 -0
- package/build/core/installer.d.ts +92 -0
- package/build/core/installer.d.ts.map +1 -0
- package/build/core/installer.js +1072 -0
- package/build/core/logger.d.ts +102 -0
- package/build/core/logger.d.ts.map +1 -0
- package/build/core/logger.js +132 -0
- package/build/core/parsers.d.ts +151 -0
- package/build/core/parsers.d.ts.map +1 -0
- package/build/core/parsers.js +479 -0
- package/build/core/policy-engine.d.ts +170 -0
- package/build/core/policy-engine.d.ts.map +1 -0
- package/build/core/policy-engine.js +656 -0
- package/build/core/preflight.d.ts +157 -0
- package/build/core/preflight.d.ts.map +1 -0
- package/build/core/preflight.js +638 -0
- package/build/core/privilege-manager.d.ts +108 -0
- package/build/core/privilege-manager.d.ts.map +1 -0
- package/build/core/privilege-manager.js +363 -0
- package/build/core/rate-limiter.d.ts +67 -0
- package/build/core/rate-limiter.d.ts.map +1 -0
- package/build/core/rate-limiter.js +129 -0
- package/build/core/rollback.d.ts +73 -0
- package/build/core/rollback.d.ts.map +1 -0
- package/build/core/rollback.js +278 -0
- package/build/core/safeguards.d.ts +58 -0
- package/build/core/safeguards.d.ts.map +1 -0
- package/build/core/safeguards.js +448 -0
- package/build/core/sanitizer.d.ts +118 -0
- package/build/core/sanitizer.d.ts.map +1 -0
- package/build/core/sanitizer.js +459 -0
- package/build/core/secure-fs.d.ts +67 -0
- package/build/core/secure-fs.d.ts.map +1 -0
- package/build/core/secure-fs.js +143 -0
- package/build/core/spawn-safe.d.ts +55 -0
- package/build/core/spawn-safe.d.ts.map +1 -0
- package/build/core/spawn-safe.js +146 -0
- package/build/core/sudo-guard.d.ts +145 -0
- package/build/core/sudo-guard.d.ts.map +1 -0
- package/build/core/sudo-guard.js +349 -0
- package/build/core/sudo-session.d.ts +100 -0
- package/build/core/sudo-session.d.ts.map +1 -0
- package/build/core/sudo-session.js +319 -0
- package/build/core/tool-dependencies.d.ts +61 -0
- package/build/core/tool-dependencies.d.ts.map +1 -0
- package/build/core/tool-dependencies.js +571 -0
- package/build/core/tool-registry.d.ts +111 -0
- package/build/core/tool-registry.d.ts.map +1 -0
- package/build/core/tool-registry.js +656 -0
- package/build/core/tool-wrapper.d.ts +73 -0
- package/build/core/tool-wrapper.d.ts.map +1 -0
- package/build/core/tool-wrapper.js +296 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +247 -0
- package/build/tools/access-control.d.ts +9 -0
- package/build/tools/access-control.d.ts.map +1 -0
- package/build/tools/access-control.js +1818 -0
- package/build/tools/api-security.d.ts +12 -0
- package/build/tools/api-security.d.ts.map +1 -0
- package/build/tools/api-security.js +901 -0
- package/build/tools/app-hardening.d.ts +11 -0
- package/build/tools/app-hardening.d.ts.map +1 -0
- package/build/tools/app-hardening.js +768 -0
- package/build/tools/backup.d.ts +8 -0
- package/build/tools/backup.d.ts.map +1 -0
- package/build/tools/backup.js +381 -0
- package/build/tools/cloud-security.d.ts +17 -0
- package/build/tools/cloud-security.d.ts.map +1 -0
- package/build/tools/cloud-security.js +739 -0
- package/build/tools/compliance.d.ts +10 -0
- package/build/tools/compliance.d.ts.map +1 -0
- package/build/tools/compliance.js +1225 -0
- package/build/tools/container-security.d.ts +14 -0
- package/build/tools/container-security.d.ts.map +1 -0
- package/build/tools/container-security.js +788 -0
- package/build/tools/deception.d.ts +13 -0
- package/build/tools/deception.d.ts.map +1 -0
- package/build/tools/deception.js +763 -0
- package/build/tools/dns-security.d.ts +93 -0
- package/build/tools/dns-security.d.ts.map +1 -0
- package/build/tools/dns-security.js +745 -0
- package/build/tools/drift-detection.d.ts +8 -0
- package/build/tools/drift-detection.d.ts.map +1 -0
- package/build/tools/drift-detection.js +326 -0
- package/build/tools/ebpf-security.d.ts +15 -0
- package/build/tools/ebpf-security.d.ts.map +1 -0
- package/build/tools/ebpf-security.js +294 -0
- package/build/tools/encryption.d.ts +9 -0
- package/build/tools/encryption.d.ts.map +1 -0
- package/build/tools/encryption.js +1667 -0
- package/build/tools/firewall.d.ts +9 -0
- package/build/tools/firewall.d.ts.map +1 -0
- package/build/tools/firewall.js +1398 -0
- package/build/tools/hardening.d.ts +10 -0
- package/build/tools/hardening.d.ts.map +1 -0
- package/build/tools/hardening.js +2654 -0
- package/build/tools/ids.d.ts +9 -0
- package/build/tools/ids.d.ts.map +1 -0
- package/build/tools/ids.js +624 -0
- package/build/tools/incident-response.d.ts +10 -0
- package/build/tools/incident-response.d.ts.map +1 -0
- package/build/tools/incident-response.js +1180 -0
- package/build/tools/logging.d.ts +12 -0
- package/build/tools/logging.d.ts.map +1 -0
- package/build/tools/logging.js +454 -0
- package/build/tools/malware.d.ts +10 -0
- package/build/tools/malware.d.ts.map +1 -0
- package/build/tools/malware.js +532 -0
- package/build/tools/meta.d.ts +11 -0
- package/build/tools/meta.d.ts.map +1 -0
- package/build/tools/meta.js +2278 -0
- package/build/tools/network-defense.d.ts +12 -0
- package/build/tools/network-defense.d.ts.map +1 -0
- package/build/tools/network-defense.js +760 -0
- package/build/tools/patch-management.d.ts +3 -0
- package/build/tools/patch-management.d.ts.map +1 -0
- package/build/tools/patch-management.js +708 -0
- package/build/tools/process-security.d.ts +12 -0
- package/build/tools/process-security.d.ts.map +1 -0
- package/build/tools/process-security.js +784 -0
- package/build/tools/reporting.d.ts +11 -0
- package/build/tools/reporting.d.ts.map +1 -0
- package/build/tools/reporting.js +559 -0
- package/build/tools/secrets.d.ts +9 -0
- package/build/tools/secrets.d.ts.map +1 -0
- package/build/tools/secrets.js +596 -0
- package/build/tools/siem-integration.d.ts +18 -0
- package/build/tools/siem-integration.d.ts.map +1 -0
- package/build/tools/siem-integration.js +754 -0
- package/build/tools/sudo-management.d.ts +18 -0
- package/build/tools/sudo-management.d.ts.map +1 -0
- package/build/tools/sudo-management.js +737 -0
- package/build/tools/supply-chain-security.d.ts +8 -0
- package/build/tools/supply-chain-security.d.ts.map +1 -0
- package/build/tools/supply-chain-security.js +256 -0
- package/build/tools/threat-intel.d.ts +22 -0
- package/build/tools/threat-intel.d.ts.map +1 -0
- package/build/tools/threat-intel.js +749 -0
- package/build/tools/vulnerability-management.d.ts +11 -0
- package/build/tools/vulnerability-management.d.ts.map +1 -0
- package/build/tools/vulnerability-management.js +667 -0
- package/build/tools/waf.d.ts +12 -0
- package/build/tools/waf.d.ts.map +1 -0
- package/build/tools/waf.js +843 -0
- package/build/tools/wireless-security.d.ts +19 -0
- package/build/tools/wireless-security.d.ts.map +1 -0
- package/build/tools/wireless-security.js +826 -0
- package/build/tools/zero-trust-network.d.ts +8 -0
- package/build/tools/zero-trust-network.d.ts.map +1 -0
- package/build/tools/zero-trust-network.js +367 -0
- package/docs/SAFEGUARDS.md +518 -0
- package/docs/TOOLS-REFERENCE.md +665 -0
- package/package.json +87 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-trust network tools.
|
|
3
|
+
*
|
|
4
|
+
* Registers 1 tool: zero_trust (actions: wireguard, wg_peers, mtls, microsegment).
|
|
5
|
+
*/
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
export declare function registerZeroTrustNetworkTools(server: McpServer): void;
|
|
8
|
+
//# sourceMappingURL=zero-trust-network.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zero-trust-network.d.ts","sourceRoot":"","sources":["../../src/tools/zero-trust-network.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6BpE,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+XrE"}
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-trust network tools.
|
|
3
|
+
*
|
|
4
|
+
* Registers 1 tool: zero_trust (actions: wireguard, wg_peers, mtls, microsegment).
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { executeCommand } from "../core/executor.js";
|
|
8
|
+
import { createErrorContent, formatToolOutput } from "../core/parsers.js";
|
|
9
|
+
import { logChange, createChangeEntry, backupFile } from "../core/changelog.js";
|
|
10
|
+
import { SafeguardRegistry } from "../core/safeguards.js";
|
|
11
|
+
import { validateTarget, validatePort } from "../core/sanitizer.js";
|
|
12
|
+
import { existsSync } from "node:fs";
|
|
13
|
+
// ── Input validation helpers (TOOL-003 remediation) ────────────────────────
|
|
14
|
+
/** Validate a service name for use in iptables comments — alphanumeric, dash, underscore only */
|
|
15
|
+
const SERVICE_NAME_RE = /^[a-zA-Z0-9._-]+$/;
|
|
16
|
+
function validateServiceName(name) {
|
|
17
|
+
if (!name || !SERVICE_NAME_RE.test(name)) {
|
|
18
|
+
throw new Error(`Invalid service name: '${name}'. Only [a-zA-Z0-9._-] allowed.`);
|
|
19
|
+
}
|
|
20
|
+
return name;
|
|
21
|
+
}
|
|
22
|
+
/** Validate an interface name */
|
|
23
|
+
const INTERFACE_NAME_RE = /^[a-zA-Z0-9._-]+$/;
|
|
24
|
+
function validateInterfaceName(name) {
|
|
25
|
+
if (!name || !INTERFACE_NAME_RE.test(name)) {
|
|
26
|
+
throw new Error(`Invalid interface name: '${name}'. Only [a-zA-Z0-9._-] allowed.`);
|
|
27
|
+
}
|
|
28
|
+
return name;
|
|
29
|
+
}
|
|
30
|
+
export function registerZeroTrustNetworkTools(server) {
|
|
31
|
+
server.tool("zero_trust", "Zero-trust networking: set up WireGuard VPN, manage WG peers, generate mTLS certificates, or configure microsegmentation.", {
|
|
32
|
+
action: z.enum(["wireguard", "wg_peers", "mtls", "microsegment"]).describe("Action: wireguard=setup VPN, wg_peers=manage peers, mtls=generate certs, microsegment=firewall rules"),
|
|
33
|
+
// wireguard params
|
|
34
|
+
interfaceName: z.string().optional().default("wg0").describe("WireGuard interface name (wireguard/wg_peers action)"),
|
|
35
|
+
listenPort: z.number().optional().default(51820).describe("UDP listen port (wireguard action)"),
|
|
36
|
+
address: z.string().optional().describe("Interface address with CIDR e.g. 10.0.0.1/24 (wireguard action)"),
|
|
37
|
+
// wg_peers params
|
|
38
|
+
peer_action: z.enum(["add", "remove", "list"]).optional().describe("Peer action (wg_peers action)"),
|
|
39
|
+
publicKey: z.string().optional().describe("Peer public key (wg_peers add/remove)"),
|
|
40
|
+
allowedIps: z.string().optional().describe("Allowed IPs for peer (wg_peers add)"),
|
|
41
|
+
endpoint: z.string().optional().describe("Peer endpoint ip:port (wg_peers add)"),
|
|
42
|
+
// mtls params
|
|
43
|
+
outputDir: z.string().optional().describe("Directory to write certificates (mtls action)"),
|
|
44
|
+
commonName: z.string().optional().default("kali-defense-ca").describe("CA common name (mtls action)"),
|
|
45
|
+
serverCN: z.string().optional().default("server.local").describe("Server common name (mtls action)"),
|
|
46
|
+
clientCN: z.string().optional().default("client.local").describe("Client common name (mtls action)"),
|
|
47
|
+
validDays: z.number().optional().default(365).describe("Certificate validity in days (mtls action)"),
|
|
48
|
+
// microsegment params
|
|
49
|
+
service: z.string().optional().describe("Service name e.g. nginx, postgres (microsegment action)"),
|
|
50
|
+
allowPorts: z.array(z.number()).optional().describe("Ports to allow (microsegment action)"),
|
|
51
|
+
allowSources: z.array(z.string()).optional().default([]).describe("Source IPs/CIDRs to allow (microsegment action)"),
|
|
52
|
+
denyAll: z.boolean().optional().default(true).describe("Add deny-all rule for other ports (microsegment action)"),
|
|
53
|
+
// shared
|
|
54
|
+
dryRun: z.boolean().optional().default(true).describe("Preview only"),
|
|
55
|
+
}, async (params) => {
|
|
56
|
+
const { action } = params;
|
|
57
|
+
switch (action) {
|
|
58
|
+
// ── wireguard ───────────────────────────────────────────────
|
|
59
|
+
case "wireguard": {
|
|
60
|
+
const { interfaceName, listenPort, address, dryRun } = params;
|
|
61
|
+
try {
|
|
62
|
+
if (!address) {
|
|
63
|
+
return { content: [createErrorContent("address is required for wireguard action (e.g. 10.0.0.1/24)")], isError: true };
|
|
64
|
+
}
|
|
65
|
+
const safety = await SafeguardRegistry.getInstance().checkSafety("setup_wireguard", { interfaceName });
|
|
66
|
+
if (!safety.safe) {
|
|
67
|
+
return { content: [formatToolOutput({ blocked: true, ...safety })], isError: true };
|
|
68
|
+
}
|
|
69
|
+
// Generate keys
|
|
70
|
+
const privKeyResult = await executeCommand({ command: "wg", args: ["genkey"], timeout: 5000 });
|
|
71
|
+
if (privKeyResult.exitCode !== 0) {
|
|
72
|
+
return { content: [createErrorContent("WireGuard tools not installed. Install wireguard-tools.")], isError: true };
|
|
73
|
+
}
|
|
74
|
+
const privateKey = privKeyResult.stdout.trim();
|
|
75
|
+
const pubKeyResult = await executeCommand({
|
|
76
|
+
command: "wg",
|
|
77
|
+
args: ["pubkey"],
|
|
78
|
+
stdin: privateKey,
|
|
79
|
+
timeout: 5000,
|
|
80
|
+
});
|
|
81
|
+
const publicKey = pubKeyResult.stdout.trim();
|
|
82
|
+
const config = `[Interface]
|
|
83
|
+
PrivateKey = ${privateKey}
|
|
84
|
+
Address = ${address}
|
|
85
|
+
ListenPort = ${listenPort}
|
|
86
|
+
`;
|
|
87
|
+
const configPath = `/etc/wireguard/${interfaceName}.conf`;
|
|
88
|
+
if (dryRun) {
|
|
89
|
+
return {
|
|
90
|
+
content: [formatToolOutput({
|
|
91
|
+
dryRun: true,
|
|
92
|
+
publicKey,
|
|
93
|
+
configPath,
|
|
94
|
+
configPreview: config.replace(privateKey, "[REDACTED]"),
|
|
95
|
+
warnings: safety.warnings,
|
|
96
|
+
nextSteps: [`wg-quick up ${interfaceName}`],
|
|
97
|
+
})],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// Backup existing config if present
|
|
101
|
+
if (existsSync(configPath)) {
|
|
102
|
+
backupFile(configPath);
|
|
103
|
+
}
|
|
104
|
+
const writeResult = await executeCommand({
|
|
105
|
+
command: "tee",
|
|
106
|
+
args: [configPath],
|
|
107
|
+
stdin: config,
|
|
108
|
+
timeout: 5000,
|
|
109
|
+
});
|
|
110
|
+
// Set permissions
|
|
111
|
+
await executeCommand({ command: "chmod", args: ["600", configPath], timeout: 5000 });
|
|
112
|
+
const entry = createChangeEntry({
|
|
113
|
+
tool: "zero_trust",
|
|
114
|
+
action: `Create WireGuard config for ${interfaceName}`,
|
|
115
|
+
target: configPath,
|
|
116
|
+
dryRun: false,
|
|
117
|
+
success: writeResult.exitCode === 0,
|
|
118
|
+
rollbackCommand: `rm ${configPath}`,
|
|
119
|
+
});
|
|
120
|
+
logChange(entry);
|
|
121
|
+
return {
|
|
122
|
+
content: [formatToolOutput({
|
|
123
|
+
success: writeResult.exitCode === 0,
|
|
124
|
+
publicKey,
|
|
125
|
+
configPath,
|
|
126
|
+
interfaceName,
|
|
127
|
+
listenPort,
|
|
128
|
+
nextSteps: [`wg-quick up ${interfaceName}`],
|
|
129
|
+
})],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
return { content: [createErrorContent(`WireGuard setup failed: ${err instanceof Error ? err.message : String(err)}`)], isError: true };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// ── wg_peers ────────────────────────────────────────────────
|
|
137
|
+
case "wg_peers": {
|
|
138
|
+
const { peer_action, interfaceName, publicKey, allowedIps, endpoint, dryRun } = params;
|
|
139
|
+
try {
|
|
140
|
+
if (!peer_action) {
|
|
141
|
+
return { content: [createErrorContent("peer_action is required for wg_peers action (add/remove/list)")], isError: true };
|
|
142
|
+
}
|
|
143
|
+
if (peer_action === "list") {
|
|
144
|
+
const result = await executeCommand({
|
|
145
|
+
command: "wg",
|
|
146
|
+
args: ["show", interfaceName],
|
|
147
|
+
timeout: 10000,
|
|
148
|
+
});
|
|
149
|
+
return {
|
|
150
|
+
content: [formatToolOutput({
|
|
151
|
+
interface: interfaceName,
|
|
152
|
+
output: result.stdout || result.stderr,
|
|
153
|
+
exitCode: result.exitCode,
|
|
154
|
+
})],
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (!publicKey) {
|
|
158
|
+
return { content: [createErrorContent("publicKey is required for add/remove actions")], isError: true };
|
|
159
|
+
}
|
|
160
|
+
if (peer_action === "add") {
|
|
161
|
+
if (!allowedIps) {
|
|
162
|
+
return { content: [createErrorContent("allowedIps is required for add action")], isError: true };
|
|
163
|
+
}
|
|
164
|
+
const args = ["set", interfaceName, "peer", publicKey, "allowed-ips", allowedIps];
|
|
165
|
+
if (endpoint)
|
|
166
|
+
args.push("endpoint", endpoint);
|
|
167
|
+
if (dryRun) {
|
|
168
|
+
return { content: [formatToolOutput({ dryRun: true, command: `wg ${args.join(" ")}` })] };
|
|
169
|
+
}
|
|
170
|
+
const result = await executeCommand({ command: "wg", args, timeout: 10000 });
|
|
171
|
+
const entry = createChangeEntry({
|
|
172
|
+
tool: "zero_trust",
|
|
173
|
+
action: `Add peer ${publicKey.slice(0, 12)}...`,
|
|
174
|
+
target: interfaceName,
|
|
175
|
+
dryRun: false,
|
|
176
|
+
success: result.exitCode === 0,
|
|
177
|
+
rollbackCommand: `wg set ${interfaceName} peer ${publicKey} remove`,
|
|
178
|
+
});
|
|
179
|
+
logChange(entry);
|
|
180
|
+
return { content: [formatToolOutput({ success: result.exitCode === 0, output: result.stdout || result.stderr })] };
|
|
181
|
+
}
|
|
182
|
+
if (peer_action === "remove") {
|
|
183
|
+
const args = ["set", interfaceName, "peer", publicKey, "remove"];
|
|
184
|
+
if (dryRun) {
|
|
185
|
+
return { content: [formatToolOutput({ dryRun: true, command: `wg ${args.join(" ")}` })] };
|
|
186
|
+
}
|
|
187
|
+
const result = await executeCommand({ command: "wg", args, timeout: 10000 });
|
|
188
|
+
const entry = createChangeEntry({
|
|
189
|
+
tool: "zero_trust",
|
|
190
|
+
action: `Remove peer ${publicKey.slice(0, 12)}...`,
|
|
191
|
+
target: interfaceName,
|
|
192
|
+
dryRun: false,
|
|
193
|
+
success: result.exitCode === 0,
|
|
194
|
+
});
|
|
195
|
+
logChange(entry);
|
|
196
|
+
return { content: [formatToolOutput({ success: result.exitCode === 0, output: result.stdout || result.stderr })] };
|
|
197
|
+
}
|
|
198
|
+
return { content: [createErrorContent(`Unknown peer_action: ${peer_action}`)], isError: true };
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
return { content: [createErrorContent(`WireGuard peer management failed: ${err instanceof Error ? err.message : String(err)}`)], isError: true };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// ── mtls ────────────────────────────────────────────────────
|
|
205
|
+
case "mtls": {
|
|
206
|
+
const { outputDir, commonName, serverCN, clientCN, validDays, dryRun } = params;
|
|
207
|
+
try {
|
|
208
|
+
if (!outputDir) {
|
|
209
|
+
return { content: [createErrorContent("outputDir is required for mtls action")], isError: true };
|
|
210
|
+
}
|
|
211
|
+
if (dryRun) {
|
|
212
|
+
return {
|
|
213
|
+
content: [formatToolOutput({
|
|
214
|
+
dryRun: true,
|
|
215
|
+
outputDir,
|
|
216
|
+
files: ["ca.key", "ca.crt", "server.key", "server.crt", "client.key", "client.crt"],
|
|
217
|
+
commonName,
|
|
218
|
+
serverCN,
|
|
219
|
+
clientCN,
|
|
220
|
+
validDays,
|
|
221
|
+
})],
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
// Create output directory
|
|
225
|
+
await executeCommand({ command: "mkdir", args: ["-p", outputDir], timeout: 5000 });
|
|
226
|
+
// Generate CA key and cert
|
|
227
|
+
await executeCommand({
|
|
228
|
+
command: "openssl",
|
|
229
|
+
args: ["req", "-x509", "-newkey", "rsa:4096", "-keyout", `${outputDir}/ca.key`,
|
|
230
|
+
"-out", `${outputDir}/ca.crt`, "-days", String(validDays), "-nodes",
|
|
231
|
+
"-subj", `/CN=${commonName}`],
|
|
232
|
+
timeout: 30000,
|
|
233
|
+
});
|
|
234
|
+
// Generate server key, CSR, and sign with CA
|
|
235
|
+
await executeCommand({
|
|
236
|
+
command: "openssl",
|
|
237
|
+
args: ["req", "-newkey", "rsa:4096", "-keyout", `${outputDir}/server.key`,
|
|
238
|
+
"-out", `${outputDir}/server.csr`, "-nodes", "-subj", `/CN=${serverCN}`],
|
|
239
|
+
timeout: 30000,
|
|
240
|
+
});
|
|
241
|
+
await executeCommand({
|
|
242
|
+
command: "openssl",
|
|
243
|
+
args: ["x509", "-req", "-in", `${outputDir}/server.csr`, "-CA", `${outputDir}/ca.crt`,
|
|
244
|
+
"-CAkey", `${outputDir}/ca.key`, "-CAcreateserial", "-out", `${outputDir}/server.crt`,
|
|
245
|
+
"-days", String(validDays)],
|
|
246
|
+
timeout: 30000,
|
|
247
|
+
});
|
|
248
|
+
// Generate client key, CSR, and sign with CA
|
|
249
|
+
await executeCommand({
|
|
250
|
+
command: "openssl",
|
|
251
|
+
args: ["req", "-newkey", "rsa:4096", "-keyout", `${outputDir}/client.key`,
|
|
252
|
+
"-out", `${outputDir}/client.csr`, "-nodes", "-subj", `/CN=${clientCN}`],
|
|
253
|
+
timeout: 30000,
|
|
254
|
+
});
|
|
255
|
+
await executeCommand({
|
|
256
|
+
command: "openssl",
|
|
257
|
+
args: ["x509", "-req", "-in", `${outputDir}/client.csr`, "-CA", `${outputDir}/ca.crt`,
|
|
258
|
+
"-CAkey", `${outputDir}/ca.key`, "-CAcreateserial", "-out", `${outputDir}/client.crt`,
|
|
259
|
+
"-days", String(validDays)],
|
|
260
|
+
timeout: 30000,
|
|
261
|
+
});
|
|
262
|
+
// Set permissions on keys
|
|
263
|
+
await executeCommand({ command: "chmod", args: ["600", `${outputDir}/ca.key`, `${outputDir}/server.key`, `${outputDir}/client.key`], timeout: 5000 });
|
|
264
|
+
const entry = createChangeEntry({
|
|
265
|
+
tool: "zero_trust",
|
|
266
|
+
action: "Generate mTLS certificate chain",
|
|
267
|
+
target: outputDir,
|
|
268
|
+
dryRun: false,
|
|
269
|
+
success: true,
|
|
270
|
+
});
|
|
271
|
+
logChange(entry);
|
|
272
|
+
return {
|
|
273
|
+
content: [formatToolOutput({
|
|
274
|
+
success: true,
|
|
275
|
+
outputDir,
|
|
276
|
+
filesCreated: ["ca.key", "ca.crt", "server.key", "server.crt", "client.key", "client.crt"],
|
|
277
|
+
validDays,
|
|
278
|
+
})],
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
catch (err) {
|
|
282
|
+
return { content: [createErrorContent(`mTLS setup failed: ${err instanceof Error ? err.message : String(err)}`)], isError: true };
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// ── microsegment ────────────────────────────────────────────
|
|
286
|
+
case "microsegment": {
|
|
287
|
+
const { service, allowPorts, allowSources, denyAll, dryRun } = params;
|
|
288
|
+
try {
|
|
289
|
+
if (!service) {
|
|
290
|
+
return { content: [createErrorContent("service is required for microsegment action")], isError: true };
|
|
291
|
+
}
|
|
292
|
+
if (!allowPorts || allowPorts.length === 0) {
|
|
293
|
+
return { content: [createErrorContent("allowPorts is required for microsegment action")], isError: true };
|
|
294
|
+
}
|
|
295
|
+
// TOOL-003 remediation: validate all user-supplied inputs
|
|
296
|
+
const validatedService = validateServiceName(service);
|
|
297
|
+
const validatedPorts = allowPorts.map(p => validatePort(p));
|
|
298
|
+
const validatedSources = allowSources.map(s => validateTarget(s));
|
|
299
|
+
const safety = await SafeguardRegistry.getInstance().checkSafety("configure_microsegmentation", { service: validatedService, ports: validatedPorts });
|
|
300
|
+
// Build rules as structured {command, args} arrays — no string interpolation/splitting
|
|
301
|
+
const rules = [];
|
|
302
|
+
for (const port of validatedPorts) {
|
|
303
|
+
if (validatedSources.length > 0) {
|
|
304
|
+
for (const src of validatedSources) {
|
|
305
|
+
rules.push({
|
|
306
|
+
description: `iptables -A INPUT -p tcp --dport ${port} -s ${src} -j ACCEPT -m comment --comment "microseg-${validatedService}"`,
|
|
307
|
+
command: "iptables",
|
|
308
|
+
args: ["-A", "INPUT", "-p", "tcp", "--dport", String(port), "-s", src, "-j", "ACCEPT", "-m", "comment", "--comment", `microseg-${validatedService}`],
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
rules.push({
|
|
314
|
+
description: `iptables -A INPUT -p tcp --dport ${port} -j ACCEPT -m comment --comment "microseg-${validatedService}"`,
|
|
315
|
+
command: "iptables",
|
|
316
|
+
args: ["-A", "INPUT", "-p", "tcp", "--dport", String(port), "-j", "ACCEPT", "-m", "comment", "--comment", `microseg-${validatedService}`],
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (denyAll) {
|
|
321
|
+
for (const port of validatedPorts) {
|
|
322
|
+
rules.push({
|
|
323
|
+
description: `iptables -A INPUT -p tcp --dport ${port} -j DROP -m comment --comment "microseg-${validatedService}-deny"`,
|
|
324
|
+
command: "iptables",
|
|
325
|
+
args: ["-A", "INPUT", "-p", "tcp", "--dport", String(port), "-j", "DROP", "-m", "comment", "--comment", `microseg-${validatedService}-deny`],
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (dryRun) {
|
|
330
|
+
return {
|
|
331
|
+
content: [formatToolOutput({
|
|
332
|
+
dryRun: true,
|
|
333
|
+
service: validatedService,
|
|
334
|
+
rules: rules.map(r => r.description),
|
|
335
|
+
warnings: safety.warnings,
|
|
336
|
+
})],
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
const results = [];
|
|
340
|
+
for (const rule of rules) {
|
|
341
|
+
// Execute directly with parameterized arrays — no shell string splitting
|
|
342
|
+
const result = await executeCommand({
|
|
343
|
+
command: rule.command,
|
|
344
|
+
args: rule.args,
|
|
345
|
+
timeout: 10000,
|
|
346
|
+
});
|
|
347
|
+
results.push({ rule: rule.description, success: result.exitCode === 0, error: result.exitCode !== 0 ? result.stderr : undefined });
|
|
348
|
+
}
|
|
349
|
+
const entry = createChangeEntry({
|
|
350
|
+
tool: "zero_trust",
|
|
351
|
+
action: `Microsegment ${service}`,
|
|
352
|
+
target: service,
|
|
353
|
+
dryRun: false,
|
|
354
|
+
success: results.every((r) => r.success),
|
|
355
|
+
});
|
|
356
|
+
logChange(entry);
|
|
357
|
+
return { content: [formatToolOutput({ service, results })] };
|
|
358
|
+
}
|
|
359
|
+
catch (err) {
|
|
360
|
+
return { content: [createErrorContent(`Microsegmentation failed: ${err instanceof Error ? err.message : String(err)}`)], isError: true };
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
default:
|
|
364
|
+
return { content: [createErrorContent(`Unknown action: ${action}`)], isError: true };
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
}
|