@ebowwa/hetzner 0.2.2 → 0.3.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.
Files changed (61) hide show
  1. package/dist/bootstrap/index.js +1126 -0
  2. package/dist/bootstrap/index.js.map +15 -0
  3. package/dist/index.js +3540 -0
  4. package/dist/index.js.map +31 -0
  5. package/dist/onboarding/index.js +460 -0
  6. package/dist/onboarding/index.js.map +14 -0
  7. package/package.json +53 -16
  8. package/actions.js +0 -1084
  9. package/actions.ts +0 -1053
  10. package/auth.js +0 -39
  11. package/auth.ts +0 -37
  12. package/bootstrap/FIREWALL.md +0 -326
  13. package/bootstrap/KERNEL-HARDENING.md +0 -258
  14. package/bootstrap/SECURITY-INTEGRATION.md +0 -281
  15. package/bootstrap/TESTING.md +0 -301
  16. package/bootstrap/cloud-init.js +0 -323
  17. package/bootstrap/cloud-init.ts +0 -394
  18. package/bootstrap/firewall.js +0 -292
  19. package/bootstrap/firewall.ts +0 -342
  20. package/bootstrap/genesis.js +0 -424
  21. package/bootstrap/genesis.ts +0 -518
  22. package/bootstrap/index.js +0 -59
  23. package/bootstrap/index.ts +0 -71
  24. package/bootstrap/kernel-hardening.js +0 -270
  25. package/bootstrap/kernel-hardening.test.js +0 -182
  26. package/bootstrap/kernel-hardening.test.ts +0 -230
  27. package/bootstrap/kernel-hardening.ts +0 -272
  28. package/bootstrap/security-audit.js +0 -122
  29. package/bootstrap/security-audit.ts +0 -124
  30. package/bootstrap/ssh-hardening.js +0 -186
  31. package/bootstrap/ssh-hardening.ts +0 -192
  32. package/client.js +0 -234
  33. package/client.ts +0 -177
  34. package/config.js +0 -7
  35. package/config.ts +0 -5
  36. package/errors.js +0 -345
  37. package/errors.ts +0 -371
  38. package/index.js +0 -73
  39. package/index.ts +0 -59
  40. package/onboarding/doppler.ts +0 -116
  41. package/onboarding/git.ts +0 -133
  42. package/onboarding/index.ts +0 -18
  43. package/onboarding/onboarding.ts +0 -193
  44. package/onboarding/tailscale.ts +0 -159
  45. package/onboarding/types.ts +0 -115
  46. package/pricing.js +0 -387
  47. package/pricing.ts +0 -422
  48. package/schemas.js +0 -667
  49. package/schemas.ts +0 -765
  50. package/server-status.js +0 -122
  51. package/server-status.ts +0 -81
  52. package/servers.js +0 -667
  53. package/servers.ts +0 -568
  54. package/ssh-keys.js +0 -180
  55. package/ssh-keys.ts +0 -122
  56. package/ssh-setup.js +0 -253
  57. package/ssh-setup.ts +0 -218
  58. package/types.js +0 -99
  59. package/types.ts +0 -389
  60. package/volumes.js +0 -295
  61. package/volumes.ts +0 -229
@@ -1,394 +0,0 @@
1
- /**
2
- * Cloud-Init Bootstrap Generator
3
- *
4
- * Generates cloud-init YAML scripts for first-boot server provisioning.
5
- * Handles seed repository installation and initial setup.
6
- *
7
- * Security Integration:
8
- * This module integrates all security modules in the correct order:
9
- * 1. UFW Firewall (network-level defense)
10
- * 2. Kernel Hardening (system-level hardening)
11
- * 3. SSH Hardening (service-level hardening)
12
- * 4. Security Audit (verification and reporting)
13
- */
14
-
15
- import {
16
- sshdHardeningPackages,
17
- sshdHardeningWriteFiles,
18
- sshdHardeningRunCmd,
19
- } from "./ssh-hardening";
20
- import {
21
- ufwFirewallPackages,
22
- ufwFirewallWriteFiles,
23
- ufwFirewallRunCmd,
24
- DEFAULT_UFW_WORKER_OPTIONS,
25
- } from "./firewall";
26
- import {
27
- kernelHardeningPackages,
28
- kernelHardeningWriteFiles,
29
- kernelHardeningRunCmd,
30
- } from "./kernel-hardening";
31
- import {
32
- securityAuditPackages,
33
- securityAuditWriteFiles,
34
- securityAuditRunCmd,
35
- } from "./security-audit";
36
-
37
- export interface BootstrapOptions {
38
- /** Seed repository URL (default: https://github.com/ebowwa/seed) */
39
- seedRepo?: string;
40
- /** Seed repository branch (default: dev) */
41
- seedBranch?: string;
42
- /** Installation path (default: /root/seed) */
43
- seedPath?: string;
44
- /** Whether to run setup.sh non-interactively (default: true) */
45
- runSetup?: boolean;
46
- /** Additional environment variables for setup.sh */
47
- setupEnv?: Record<string, string>;
48
- /** Additional packages to install */
49
- packages?: string[];
50
- /** Additional commands to run after seed installation */
51
- additionalCommands?: string[];
52
- /** Enable security hardening (default: true) */
53
- enableSecurity?: boolean;
54
- }
55
-
56
- /**
57
- * Generate a cloud-init YAML script for seed installation
58
- *
59
- * @param options - Bootstrap configuration options
60
- * @returns Cloud-init YAML string
61
- */
62
- export function generateSeedBootstrap(options: BootstrapOptions = {}): string {
63
- const {
64
- seedRepo = "https://github.com/ebowwa/seed",
65
- seedBranch = "dev",
66
- seedPath = "/root/seed",
67
- runSetup = true,
68
- setupEnv = {},
69
- packages = [],
70
- additionalCommands = [],
71
- enableSecurity = true,
72
- } = options;
73
-
74
- const lines: string[] = [];
75
-
76
- // Cloud-config header
77
- lines.push("#cloud-config");
78
- lines.push("");
79
-
80
- // System updates
81
- lines.push("# Update system packages");
82
- lines.push("package_update: true");
83
- lines.push("package_upgrade: true");
84
- lines.push("");
85
-
86
- // Required packages
87
- lines.push("# Install required packages");
88
- lines.push("packages:");
89
- lines.push(" - git");
90
- lines.push(" - curl");
91
- lines.push(" - jq");
92
- lines.push(" - unzip");
93
- lines.push(" - tmux");
94
-
95
- // Security Module 1: UFW Firewall packages
96
- if (enableSecurity) {
97
- lines.push(" # Security: UFW Firewall");
98
- lines.push(...ufwFirewallPackages());
99
- }
100
-
101
- // Security Module 2: Kernel hardening packages
102
- if (enableSecurity) {
103
- lines.push(" # Security: Kernel hardening");
104
- lines.push(...kernelHardeningPackages());
105
- }
106
-
107
- // Security Module 3: SSH hardening packages (fail2ban)
108
- if (enableSecurity) {
109
- lines.push(" # Security: SSH hardening");
110
- lines.push(...sshdHardeningPackages());
111
- }
112
-
113
- // Security Module 4: Security audit packages (lynis)
114
- if (enableSecurity) {
115
- lines.push(" # Security: Security audit");
116
- lines.push(...securityAuditPackages());
117
- }
118
-
119
- // Add additional packages
120
- for (const pkg of packages) {
121
- lines.push(` - ${pkg}`);
122
- }
123
- lines.push("");
124
-
125
- // Status tracking file
126
- lines.push("# Write bootstrap status file");
127
- lines.push("write_files:");
128
- lines.push(" - path: /root/.bootstrap-status");
129
- lines.push(" owner: root:root");
130
- lines.push(" permissions: '0644'");
131
- lines.push(" content: |");
132
- lines.push(" status=started");
133
- lines.push(" started_at=$(date -Iseconds)");
134
- lines.push(" source=cloud-init");
135
- if (enableSecurity) {
136
- lines.push(" security=enabled");
137
- }
138
- lines.push("");
139
-
140
- // Add bun to system-wide PATH via /etc/environment
141
- // NOTE: /etc/environment uses simple KEY="value" format (no variables, no comments)
142
- // We need to replace PATH rather than append, and include all standard paths
143
- lines.push(" # Add bun to /etc/environment for all users/shells");
144
- lines.push(" # Format: Simple KEY=\"value\" pairs, no variable expansion");
145
- lines.push(" - path: /etc/environment");
146
- lines.push(" owner: root:root");
147
- lines.push(" permissions: '0644'");
148
- lines.push(" content: |");
149
- lines.push(" PATH=\"/root/.bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"");
150
- lines.push("");
151
-
152
- // Security Module 1: UFW Firewall configuration files
153
- if (enableSecurity) {
154
- lines.push(" # Security Module 1: UFW Firewall configuration");
155
- lines.push(...ufwFirewallWriteFiles(DEFAULT_UFW_WORKER_OPTIONS));
156
- }
157
-
158
- // Security Module 2: Kernel hardening configuration files
159
- if (enableSecurity) {
160
- lines.push(" # Security Module 2: Kernel hardening");
161
- lines.push(...kernelHardeningWriteFiles());
162
- }
163
-
164
- // Security Module 3: SSH hardening configuration files
165
- if (enableSecurity) {
166
- lines.push(" # Security Module 3: SSH hardening");
167
- lines.push(...sshdHardeningWriteFiles());
168
- }
169
-
170
- // Security Module 4: Security audit script
171
- if (enableSecurity) {
172
- lines.push(" # Security Module 4: Security audit");
173
- lines.push(...securityAuditWriteFiles());
174
- }
175
-
176
- // Node-agent systemd service
177
- lines.push(" # Node-agent systemd service for Ralph Loop orchestration");
178
- lines.push(" - path: /etc/systemd/system/node-agent.service");
179
- lines.push(" owner: root:root");
180
- lines.push(" permissions: '0644'");
181
- lines.push(" content: |");
182
- lines.push(" [Unit]");
183
- lines.push(" Description=Node Agent for Ralph Loop Orchestration");
184
- lines.push(" Documentation=https://github.com/ebowwa/seed");
185
- lines.push(" After=network-online.target");
186
- lines.push(" Wants=network-online.target");
187
- lines.push("");
188
- lines.push(" [Service]");
189
- lines.push(" Type=simple");
190
- lines.push(" User=root");
191
- lines.push(` WorkingDirectory=${seedPath}/node-agent`);
192
- lines.push(" ExecStart=/root/.bun/bin/bun run src/index.ts");
193
- lines.push(` EnvironmentFile=-${seedPath}/node-agent/.env`);
194
- lines.push(" Environment=PORT=8911");
195
- lines.push(" Restart=always");
196
- lines.push(" RestartSec=10");
197
- lines.push(" StandardOutput=journal");
198
- lines.push(" StandardError=journal");
199
- lines.push(" SyslogIdentifier=node-agent");
200
- lines.push("");
201
- // Security hardening for node-agent service
202
- if (enableSecurity) {
203
- lines.push(" # Security hardening");
204
- lines.push(" NoNewPrivileges=true");
205
- lines.push(" PrivateTmp=true");
206
- lines.push(" ProtectSystem=strict");
207
- lines.push(" ProtectHome=true");
208
- lines.push(" ReadOnlyPaths=/");
209
- lines.push(" ReadWritePaths=/var/log " + seedPath + "/node-agent");
210
- }
211
- lines.push("");
212
- lines.push(" [Install]");
213
- lines.push(" WantedBy=multi-user.target");
214
- lines.push("");
215
-
216
- // Run commands
217
- lines.push("# Bootstrap commands");
218
- lines.push("runcmd:");
219
-
220
- // Install Bun and create node symlink
221
- lines.push(" # Install Bun");
222
- lines.push(" - curl -fsSL https://bun.sh/install | bash");
223
- lines.push(" - ln -sf /root/.bun/bin/bun /root/.bun/bin/node # Create 'node' symlink to bun");
224
- lines.push("");
225
-
226
- // Clone seed repository
227
- lines.push(` # Clone seed repository`);
228
- lines.push(` - git clone --depth 1 --branch ${seedBranch} ${seedRepo} ${seedPath}`);
229
- lines.push("");
230
-
231
- if (runSetup) {
232
- // Build environment variables
233
- const envVars = ["NONINTERACTIVE=1", ...Object.entries(setupEnv).map(([k, v]) => `${k}=${v}`)];
234
- const envString = envVars.join(" ");
235
-
236
- lines.push(` # Run seed setup non-interactively`);
237
- lines.push(` - cd ${seedPath} && ${envString} bash ./setup.sh 2>&1 | tee /var/log/seed-setup.log`);
238
- lines.push("");
239
-
240
- // Create completion marker
241
- lines.push(` # Mark setup complete`);
242
- lines.push(` - touch ${seedPath}/.seed-setup-complete`);
243
- lines.push("");
244
- }
245
-
246
- // Additional commands
247
- if (additionalCommands.length > 0) {
248
- lines.push(` # Additional custom commands`);
249
- for (const cmd of additionalCommands) {
250
- lines.push(` - ${cmd}`);
251
- }
252
- lines.push("");
253
- }
254
-
255
- // Security Module 1: UFW Firewall activation (runs first)
256
- if (enableSecurity) {
257
- lines.push(" # Security Module 1: Activate UFW Firewall");
258
- lines.push(...ufwFirewallRunCmd(DEFAULT_UFW_WORKER_OPTIONS));
259
- }
260
-
261
- // Security Module 2: Kernel hardening activation
262
- if (enableSecurity) {
263
- lines.push(" # Security Module 2: Apply kernel hardening");
264
- lines.push(...kernelHardeningRunCmd());
265
- }
266
-
267
- // Security Module 3: SSH hardening activation
268
- if (enableSecurity) {
269
- lines.push(" # Security Module 3: Activate SSH hardening");
270
- lines.push(...sshdHardeningRunCmd());
271
- }
272
-
273
- // Security Module 4: Security audit (runs last)
274
- if (enableSecurity) {
275
- lines.push(" # Security Module 4: Run security audit");
276
- lines.push(...securityAuditRunCmd());
277
- }
278
-
279
- // Mark bootstrap complete
280
- lines.push(` # Mark bootstrap complete`);
281
- lines.push(` - echo "status=complete" >> /root/.bootstrap-status`);
282
- lines.push(` - echo "completed_at=$(date -Iseconds)" >> /root/.bootstrap-status`);
283
- if (enableSecurity) {
284
- lines.push(` - echo "security_hardening=applied" >> /root/.bootstrap-status`);
285
- }
286
- lines.push("");
287
- lines.push(" # Start node-agent service");
288
- lines.push(" - systemctl daemon-reload");
289
- lines.push(" - systemctl enable node-agent");
290
- lines.push(" - systemctl start node-agent");
291
-
292
- return lines.join("\n");
293
- }
294
-
295
- /**
296
- * Generate a minimal cloud-init script that uses #include to fetch from a URL
297
- *
298
- * This is useful for larger bootstrap scripts or when you want to update
299
- * the bootstrap without code changes.
300
- *
301
- * @param url - URL to fetch the cloud-init config from
302
- * @returns Cloud-init YAML string with #include directive
303
- */
304
- export function generateRemoteBootstrap(url: string): string {
305
- return `#include\n${url}`;
306
- }
307
-
308
- /**
309
- * Bootstrap configuration presets for common scenarios
310
- */
311
- export const BootstrapPresets = {
312
- /**
313
- * Default seed installation with setup.sh and full security hardening
314
- */
315
- default: () => generateSeedBootstrap(),
316
-
317
- /**
318
- * Seed installation with full security hardening and verbose logging
319
- */
320
- secure: () =>
321
- generateSeedBootstrap({
322
- setupEnv: {
323
- DEBUG: "1",
324
- VERBOSE: "1",
325
- },
326
- }),
327
-
328
- /**
329
- * Seed installation without running setup.sh (useful for debugging)
330
- */
331
- cloneOnly: () => generateSeedBootstrap({ runSetup: false }),
332
-
333
- /**
334
- * Development bootstrap without security hardening (for testing)
335
- */
336
- development: () =>
337
- generateSeedBootstrap({
338
- enableSecurity: false,
339
- packages: ["htop", "vim", "strace"],
340
- }),
341
-
342
- /**
343
- * Verbose bootstrap with logging enabled
344
- */
345
- verbose: () =>
346
- generateSeedBootstrap({
347
- setupEnv: {
348
- DEBUG: "1",
349
- VERBOSE: "1",
350
- },
351
- }),
352
- } as const;
353
-
354
- // Re-export Genesis bootstrap functions
355
- export {
356
- generateGenesisBootstrap,
357
- generateRemoteGenesisBootstrap,
358
- GenesisBootstrapPresets,
359
- type GenesisBootstrapOptions,
360
- } from "./genesis";
361
-
362
- // Re-export SSH hardening components so callers can compose custom
363
- // cloud-init scripts with hardening baked in (e.g. for non-standard node types)
364
- export {
365
- sshdHardeningPackages,
366
- sshdHardeningWriteFiles,
367
- sshdHardeningRunCmd,
368
- } from "./ssh-hardening";
369
-
370
- // Re-export UFW firewall components
371
- export {
372
- ufwFirewallPackages,
373
- ufwFirewallWriteFiles,
374
- ufwFirewallRunCmd,
375
- DEFAULT_UFW_WORKER_OPTIONS,
376
- DEFAULT_UFW_GENESIS_OPTIONS,
377
- generateUFWFirewallForGenesis,
378
- generateUFWFirewallForWorker,
379
- type UFWFirewallOptions,
380
- } from "./firewall";
381
-
382
- // Re-export kernel hardening components
383
- export {
384
- kernelHardeningPackages,
385
- kernelHardeningWriteFiles,
386
- kernelHardeningRunCmd,
387
- } from "./kernel-hardening";
388
-
389
- // Re-export security audit components
390
- export {
391
- securityAuditPackages,
392
- securityAuditWriteFiles,
393
- securityAuditRunCmd,
394
- } from "./security-audit";
@@ -1,292 +0,0 @@
1
- "use strict";
2
- /**
3
- * UFW Firewall Cloud-Init Components
4
- *
5
- * Composable cloud-init blocks for securing servers with UFW (Uncomplicated Firewall).
6
- * Includes: default deny incoming, allow outgoing, rate limiting, and logging.
7
- *
8
- * Background: Hetzner public IPs face constant scanning and brute-force attacks.
9
- * UFW provides a simple interface to iptables/nftables with secure defaults.
10
- *
11
- * This module is imported by cloud-init.ts (seed/worker nodes) and genesis.ts
12
- * (control plane) so every new server gets firewall protection at first boot.
13
- *
14
- * Three composable functions return cloud-init line arrays for splicing into
15
- * the appropriate YAML sections:
16
- * - ufwFirewallPackages() → packages: section
17
- * - ufwFirewallWriteFiles() → write_files: section
18
- * - ufwFirewallRunCmd() → runcmd: section
19
- *
20
- * Security Policy:
21
- * - Default: deny incoming, allow outgoing (stateful)
22
- * - SSH (22): rate limited to prevent brute-force
23
- * - HTTP/HTTPS (80/443): allowed for web services
24
- * - Node Agent (8911): allowed for internal communication
25
- * - Tailscale (41641): allowed for VPN
26
- * - Logging: enabled with rate limiting to prevent log flooding
27
- */
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.DEFAULT_UFW_WORKER_OPTIONS = exports.DEFAULT_UFW_GENESIS_OPTIONS = void 0;
30
- exports.ufwFirewallPackages = ufwFirewallPackages;
31
- exports.ufwFirewallWriteFiles = ufwFirewallWriteFiles;
32
- exports.ufwFirewallRunCmd = ufwFirewallRunCmd;
33
- exports.generateUFWFirewallForGenesis = generateUFWFirewallForGenesis;
34
- exports.generateUFWFirewallForWorker = generateUFWFirewallForWorker;
35
- /**
36
- * Default firewall options for Genesis control plane servers.
37
- */
38
- exports.DEFAULT_UFW_GENESIS_OPTIONS = {
39
- allowSSHFrom: [], // Empty = allow from anywhere
40
- allowHTTP: true,
41
- allowHTTPS: true,
42
- allowNodeAgent: false, // Genesis doesn't run node-agent
43
- verboseLogging: false,
44
- };
45
- /**
46
- * Default firewall options for worker/seed servers.
47
- */
48
- exports.DEFAULT_UFW_WORKER_OPTIONS = {
49
- allowSSHFrom: [], // Empty = allow from anywhere
50
- allowHTTP: false,
51
- allowHTTPS: false,
52
- allowNodeAgent: true, // Workers run node-agent on port 8911
53
- verboseLogging: false,
54
- };
55
- /**
56
- * Packages required for UFW firewall.
57
- * Returns cloud-init YAML lines for the `packages:` section.
58
- *
59
- * - ufw: Uncomplicated Firewall interface to iptables/nftables
60
- */
61
- function ufwFirewallPackages() {
62
- return [
63
- " - ufw",
64
- ];
65
- }
66
- /**
67
- * Files to write at first boot for UFW firewall configuration.
68
- * Returns cloud-init YAML lines for the `write_files:` section.
69
- *
70
- * Drops 2 files onto the server:
71
- *
72
- * 1. /etc/ufw/before.rules
73
- * - Custom before rules for stateful firewall behavior
74
- * - Allows loopback, established/related connections
75
- * - Drops invalid packets early
76
- *
77
- * 2. /etc/ufw/sysctl.conf
78
- * - Enables kernel network security parameters
79
- * - IP spoofing protection
80
- * - ICMP redirect protection
81
- * - Log martian packets
82
- */
83
- function ufwFirewallWriteFiles(options) {
84
- if (options === void 0) { options = {}; }
85
- var lines = [];
86
- // 1. UFW before.rules - stateful firewall rules applied before UFW rules
87
- lines.push(" # UFW before.rules - stateful firewall and network security");
88
- lines.push(" - path: /etc/ufw/before.rules");
89
- lines.push(" owner: root:root");
90
- lines.push(" permissions: '0644'");
91
- lines.push(" content: |");
92
- lines.push(" #");
93
- lines.push(" # UFW before.rules - applied before UFW rules");
94
- lines.push(" #");
95
- lines.push(" # Start with the standard configuration");
96
- lines.push(" *filter");
97
- lines.push(" :ufw-before-input - [0:0]");
98
- lines.push(" :ufw-before-output - [0:0]");
99
- lines.push(" :ufw-before-forward - [0:0]");
100
- lines.push(" :ufw-not-local - [0:0]");
101
- lines.push(" # End of lines to adjust");
102
- lines.push("");
103
- lines.push(" # Allow all on loopback");
104
- lines.push(" -A ufw-before-input -i lo -j ACCEPT");
105
- lines.push(" -A ufw-before-output -o lo -j ACCEPT");
106
- lines.push("");
107
- lines.push(" # Drop invalid packets");
108
- lines.push(" -A ufw-before-input -m conntrack --ctstate INVALID -j DROP");
109
- lines.push("");
110
- lines.push(" # Allow established and related connections");
111
- lines.push(" -A ufw-before-input -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT");
112
- lines.push(" -A ufw-before-output -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT");
113
- lines.push("");
114
- lines.push(" # Allow ICMP messages (required for PMTU discovery)");
115
- lines.push(" -A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT");
116
- lines.push(" -A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT");
117
- lines.push(" -A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT");
118
- lines.push(" -A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT");
119
- lines.push("");
120
- lines.push(" # Drop packets with bogus TCP flags (potential scan)");
121
- lines.push(" -A ufw-before-input -p tcp --tcp-flags ALL NONE -j DROP");
122
- lines.push(" -A ufw-before-input -p tcp --tcp-flags ALL ALL -j DROP");
123
- lines.push("");
124
- lines.push(" # Commit changes");
125
- lines.push(" COMMIT");
126
- lines.push("");
127
- // 2. UFW sysctl.conf - kernel network security parameters
128
- lines.push(" # UFW sysctl.conf - kernel network hardening");
129
- lines.push(" - path: /etc/ufw/sysctl.conf");
130
- lines.push(" owner: root:root");
131
- lines.push(" permissions: '0644'");
132
- lines.push(" content: |");
133
- lines.push(" #");
134
- lines.push(" # UFW sysctl.conf - kernel network security parameters");
135
- lines.push(" #");
136
- lines.push("");
137
- lines.push(" # IP spoofing protection");
138
- lines.push(" net/ipv4/conf/all/rp_filter=1");
139
- lines.push(" net/ipv4/conf/default/rp_filter=1");
140
- lines.push("");
141
- lines.push(" # Ignore ICMP redirect messages");
142
- lines.push(" net/ipv4/conf/all/accept_redirects=0");
143
- lines.push(" net/ipv6/conf/all/accept_redirects=0");
144
- lines.push(" net/ipv4/conf/default/accept_redirects=0");
145
- lines.push(" net/ipv6/conf/default/accept_redirects=0");
146
- lines.push("");
147
- lines.push(" # Ignore send redirects");
148
- lines.push(" net/ipv4/conf/all/send_redirects=0");
149
- lines.push(" net/ipv4/conf/default/send_redirects=0");
150
- lines.push("");
151
- lines.push(" # Log martian packets (packets with impossible addresses)");
152
- lines.push(" net/ipv4/conf/all/log_martians=1");
153
- lines.push(" net/ipv4/conf/default/log_martians=1");
154
- lines.push("");
155
- lines.push(" # SYN cookies protection (SYN flood mitigation)");
156
- lines.push(" net/ipv4/tcp_syncookies=1");
157
- lines.push("");
158
- lines.push(" # Source address verification (spoofing protection)");
159
- lines.push(" net/ipv4/conf/all/secure_redirects=1");
160
- lines.push(" net/ipv4/conf/default/secure_redirects=1");
161
- lines.push("");
162
- return lines;
163
- }
164
- /**
165
- * Commands to configure and activate UFW firewall at first boot.
166
- * Returns cloud-init YAML lines for the `runcmd:` section.
167
- *
168
- * Order matters:
169
- * 1. Set default policies (deny incoming, allow outgoing)
170
- * 2. Allow loopback interface
171
- * 3. Allow SSH with rate limiting (prevents brute-force)
172
- * 4. Allow HTTP/HTTPS if enabled
173
- * 5. Allow Node Agent port if enabled
174
- * 6. Allow Tailscale port (required for VPN)
175
- * 7. Enable logging with rate limiting
176
- * 8. Enable and reload UFW
177
- * 9. Display firewall status
178
- */
179
- function ufwFirewallRunCmd(options) {
180
- if (options === void 0) { options = {}; }
181
- var _a = options.allowSSHFrom, allowSSHFrom = _a === void 0 ? [] : _a, _b = options.allowHTTP, allowHTTP = _b === void 0 ? true : _b, _c = options.allowHTTPS, allowHTTPS = _c === void 0 ? true : _c, _d = options.allowNodeAgent, allowNodeAgent = _d === void 0 ? false : _d, _e = options.additionalPorts, additionalPorts = _e === void 0 ? [] : _e, _f = options.verboseLogging, verboseLogging = _f === void 0 ? false : _f;
182
- var lines = [];
183
- lines.push(" # UFW Firewall: Configure and enable secure firewall");
184
- lines.push("");
185
- // Set default policies
186
- lines.push(" # Set default policies: deny incoming, allow outgoing");
187
- lines.push(" - ufw --force reset");
188
- lines.push(" - ufw default deny incoming");
189
- lines.push(" - ufw default allow outgoing");
190
- lines.push(" - ufw default deny forwarded");
191
- lines.push("");
192
- // Allow loopback
193
- lines.push(" # Allow loopback interface");
194
- lines.push(" - ufw allow in on lo");
195
- lines.push("");
196
- // Allow SSH with rate limiting
197
- if (allowSSHFrom.length === 0) {
198
- // Allow SSH from anywhere with rate limiting
199
- lines.push(" # Allow SSH with rate limiting (6 connections in 30 seconds)");
200
- lines.push(" - ufw limit 22/tcp comment 'Rate-limited SSH'");
201
- }
202
- else {
203
- // Allow SSH from specific IPs/CIDRs
204
- for (var _i = 0, allowSSHFrom_1 = allowSSHFrom; _i < allowSSHFrom_1.length; _i++) {
205
- var source = allowSSHFrom_1[_i];
206
- lines.push(" - ufw allow from ".concat(source, " to any port 22 proto tcp comment 'SSH from ").concat(source, "'"));
207
- }
208
- }
209
- lines.push("");
210
- // Allow HTTP if enabled
211
- if (allowHTTP) {
212
- lines.push(" # Allow HTTP");
213
- lines.push(" - ufw allow 80/tcp comment 'HTTP'");
214
- }
215
- // Allow HTTPS if enabled
216
- if (allowHTTPS) {
217
- lines.push(" # Allow HTTPS");
218
- lines.push(" - ufw allow 443/tcp comment 'HTTPS'");
219
- }
220
- lines.push("");
221
- // Allow Node Agent port if enabled
222
- if (allowNodeAgent) {
223
- lines.push(" # Allow Node Agent (internal communication)");
224
- lines.push(" - ufw allow 8911/tcp comment 'Node Agent'");
225
- lines.push("");
226
- }
227
- // Allow Tailscale (required for VPN functionality)
228
- lines.push(" # Allow Tailscale VPN");
229
- lines.push(" - ufw allow 41641/udp comment 'Tailscale'");
230
- lines.push("");
231
- // Additional ports
232
- if (additionalPorts.length > 0) {
233
- lines.push(" # Additional custom ports");
234
- for (var _g = 0, additionalPorts_1 = additionalPorts; _g < additionalPorts_1.length; _g++) {
235
- var portConfig = additionalPorts_1[_g];
236
- var protocol = portConfig.protocol || "tcp";
237
- var comment = portConfig.comment || "Custom port ".concat(portConfig.port);
238
- lines.push(" - ufw allow ".concat(portConfig.port, "/").concat(protocol, " comment '").concat(comment, "'"));
239
- }
240
- lines.push("");
241
- }
242
- // Configure logging
243
- if (verboseLogging) {
244
- lines.push(" # Enable verbose logging");
245
- lines.push(" - ufw logging on");
246
- lines.push(" - ufw logging high");
247
- }
248
- else {
249
- lines.push(" # Enable rate-limited logging (prevent log flooding)");
250
- lines.push(" - ufw logging on");
251
- lines.push(" - ufw logging low");
252
- }
253
- lines.push("");
254
- // Enable and reload UFW
255
- lines.push(" # Enable and reload UFW");
256
- lines.push(" - ufw --force enable");
257
- lines.push(" - ufw reload");
258
- lines.push("");
259
- // Display status
260
- lines.push(" # Display firewall status");
261
- lines.push(" - ufw status verbose > /var/log/ufw-bootstrap-status.log");
262
- lines.push("");
263
- return lines;
264
- }
265
- /**
266
- * Generate complete UFW firewall configuration for Genesis servers.
267
- *
268
- * @param options - UFW firewall options (uses DEFAULT_UFW_GENESIS_OPTIONS if not provided)
269
- * @returns Object with packages, writeFiles, and runCmd arrays
270
- */
271
- function generateUFWFirewallForGenesis(options) {
272
- if (options === void 0) { options = exports.DEFAULT_UFW_GENESIS_OPTIONS; }
273
- return {
274
- packages: ufwFirewallPackages(),
275
- writeFiles: ufwFirewallWriteFiles(options),
276
- runCmd: ufwFirewallRunCmd(options),
277
- };
278
- }
279
- /**
280
- * Generate complete UFW firewall configuration for worker/seed servers.
281
- *
282
- * @param options - UFW firewall options (uses DEFAULT_UFW_WORKER_OPTIONS if not provided)
283
- * @returns Object with packages, writeFiles, and runCmd arrays
284
- */
285
- function generateUFWFirewallForWorker(options) {
286
- if (options === void 0) { options = exports.DEFAULT_UFW_WORKER_OPTIONS; }
287
- return {
288
- packages: ufwFirewallPackages(),
289
- writeFiles: ufwFirewallWriteFiles(options),
290
- runCmd: ufwFirewallRunCmd(options),
291
- };
292
- }