@ebowwa/hetzner 0.1.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/actions.js +802 -0
- package/actions.ts +1053 -0
- package/auth.js +35 -0
- package/auth.ts +37 -0
- package/bootstrap/FIREWALL.md +326 -0
- package/bootstrap/KERNEL-HARDENING.md +258 -0
- package/bootstrap/SECURITY-INTEGRATION.md +281 -0
- package/bootstrap/TESTING.md +301 -0
- package/bootstrap/cloud-init.js +279 -0
- package/bootstrap/cloud-init.ts +394 -0
- package/bootstrap/firewall.js +279 -0
- package/bootstrap/firewall.ts +342 -0
- package/bootstrap/genesis.js +406 -0
- package/bootstrap/genesis.ts +518 -0
- package/bootstrap/index.js +35 -0
- package/bootstrap/index.ts +71 -0
- package/bootstrap/kernel-hardening.js +266 -0
- package/bootstrap/kernel-hardening.test.ts +230 -0
- package/bootstrap/kernel-hardening.ts +272 -0
- package/bootstrap/security-audit.js +118 -0
- package/bootstrap/security-audit.ts +124 -0
- package/bootstrap/ssh-hardening.js +182 -0
- package/bootstrap/ssh-hardening.ts +192 -0
- package/client.js +137 -0
- package/client.ts +177 -0
- package/config.js +5 -0
- package/config.ts +5 -0
- package/errors.js +270 -0
- package/errors.ts +371 -0
- package/index.js +28 -0
- package/index.ts +55 -0
- package/package.json +56 -0
- package/pricing.js +284 -0
- package/pricing.ts +422 -0
- package/schemas.js +660 -0
- package/schemas.ts +765 -0
- package/server-status.ts +81 -0
- package/servers.js +424 -0
- package/servers.ts +568 -0
- package/ssh-keys.js +90 -0
- package/ssh-keys.ts +122 -0
- package/ssh-setup.ts +218 -0
- package/types.js +96 -0
- package/types.ts +389 -0
- package/volumes.js +172 -0
- package/volumes.ts +229 -0
|
@@ -0,0 +1,279 @@
|
|
|
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
|
+
import { sshdHardeningPackages, sshdHardeningWriteFiles, sshdHardeningRunCmd, } from "./ssh-hardening";
|
|
15
|
+
import { ufwFirewallPackages, ufwFirewallWriteFiles, ufwFirewallRunCmd, DEFAULT_UFW_WORKER_OPTIONS, } from "./firewall";
|
|
16
|
+
import { kernelHardeningPackages, kernelHardeningWriteFiles, kernelHardeningRunCmd, } from "./kernel-hardening";
|
|
17
|
+
import { securityAuditPackages, securityAuditWriteFiles, securityAuditRunCmd, } from "./security-audit";
|
|
18
|
+
/**
|
|
19
|
+
* Generate a cloud-init YAML script for seed installation
|
|
20
|
+
*
|
|
21
|
+
* @param options - Bootstrap configuration options
|
|
22
|
+
* @returns Cloud-init YAML string
|
|
23
|
+
*/
|
|
24
|
+
export function generateSeedBootstrap(options = {}) {
|
|
25
|
+
const { seedRepo = "https://github.com/ebowwa/seed", seedBranch = "dev", seedPath = "/root/seed", runSetup = true, setupEnv = {}, packages = [], additionalCommands = [], enableSecurity = true, } = options;
|
|
26
|
+
const lines = [];
|
|
27
|
+
// Cloud-config header
|
|
28
|
+
lines.push("#cloud-config");
|
|
29
|
+
lines.push("");
|
|
30
|
+
// System updates
|
|
31
|
+
lines.push("# Update system packages");
|
|
32
|
+
lines.push("package_update: true");
|
|
33
|
+
lines.push("package_upgrade: true");
|
|
34
|
+
lines.push("");
|
|
35
|
+
// Required packages
|
|
36
|
+
lines.push("# Install required packages");
|
|
37
|
+
lines.push("packages:");
|
|
38
|
+
lines.push(" - git");
|
|
39
|
+
lines.push(" - curl");
|
|
40
|
+
lines.push(" - jq");
|
|
41
|
+
lines.push(" - unzip");
|
|
42
|
+
lines.push(" - tmux");
|
|
43
|
+
// Security Module 1: UFW Firewall packages
|
|
44
|
+
if (enableSecurity) {
|
|
45
|
+
lines.push(" # Security: UFW Firewall");
|
|
46
|
+
lines.push(...ufwFirewallPackages());
|
|
47
|
+
}
|
|
48
|
+
// Security Module 2: Kernel hardening packages
|
|
49
|
+
if (enableSecurity) {
|
|
50
|
+
lines.push(" # Security: Kernel hardening");
|
|
51
|
+
lines.push(...kernelHardeningPackages());
|
|
52
|
+
}
|
|
53
|
+
// Security Module 3: SSH hardening packages (fail2ban)
|
|
54
|
+
if (enableSecurity) {
|
|
55
|
+
lines.push(" # Security: SSH hardening");
|
|
56
|
+
lines.push(...sshdHardeningPackages());
|
|
57
|
+
}
|
|
58
|
+
// Security Module 4: Security audit packages (lynis)
|
|
59
|
+
if (enableSecurity) {
|
|
60
|
+
lines.push(" # Security: Security audit");
|
|
61
|
+
lines.push(...securityAuditPackages());
|
|
62
|
+
}
|
|
63
|
+
// Add additional packages
|
|
64
|
+
for (const pkg of packages) {
|
|
65
|
+
lines.push(` - ${pkg}`);
|
|
66
|
+
}
|
|
67
|
+
lines.push("");
|
|
68
|
+
// Status tracking file
|
|
69
|
+
lines.push("# Write bootstrap status file");
|
|
70
|
+
lines.push("write_files:");
|
|
71
|
+
lines.push(" - path: /root/.bootstrap-status");
|
|
72
|
+
lines.push(" owner: root:root");
|
|
73
|
+
lines.push(" permissions: '0644'");
|
|
74
|
+
lines.push(" content: |");
|
|
75
|
+
lines.push(" status=started");
|
|
76
|
+
lines.push(" started_at=$(date -Iseconds)");
|
|
77
|
+
lines.push(" source=cloud-init");
|
|
78
|
+
if (enableSecurity) {
|
|
79
|
+
lines.push(" security=enabled");
|
|
80
|
+
}
|
|
81
|
+
lines.push("");
|
|
82
|
+
// Add bun to system-wide PATH via /etc/environment
|
|
83
|
+
// NOTE: /etc/environment uses simple KEY="value" format (no variables, no comments)
|
|
84
|
+
// We need to replace PATH rather than append, and include all standard paths
|
|
85
|
+
lines.push(" # Add bun to /etc/environment for all users/shells");
|
|
86
|
+
lines.push(" # Format: Simple KEY=\"value\" pairs, no variable expansion");
|
|
87
|
+
lines.push(" - path: /etc/environment");
|
|
88
|
+
lines.push(" owner: root:root");
|
|
89
|
+
lines.push(" permissions: '0644'");
|
|
90
|
+
lines.push(" content: |");
|
|
91
|
+
lines.push(" PATH=\"/root/.bun/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"");
|
|
92
|
+
lines.push("");
|
|
93
|
+
// Security Module 1: UFW Firewall configuration files
|
|
94
|
+
if (enableSecurity) {
|
|
95
|
+
lines.push(" # Security Module 1: UFW Firewall configuration");
|
|
96
|
+
lines.push(...ufwFirewallWriteFiles(DEFAULT_UFW_WORKER_OPTIONS));
|
|
97
|
+
}
|
|
98
|
+
// Security Module 2: Kernel hardening configuration files
|
|
99
|
+
if (enableSecurity) {
|
|
100
|
+
lines.push(" # Security Module 2: Kernel hardening");
|
|
101
|
+
lines.push(...kernelHardeningWriteFiles());
|
|
102
|
+
}
|
|
103
|
+
// Security Module 3: SSH hardening configuration files
|
|
104
|
+
if (enableSecurity) {
|
|
105
|
+
lines.push(" # Security Module 3: SSH hardening");
|
|
106
|
+
lines.push(...sshdHardeningWriteFiles());
|
|
107
|
+
}
|
|
108
|
+
// Security Module 4: Security audit script
|
|
109
|
+
if (enableSecurity) {
|
|
110
|
+
lines.push(" # Security Module 4: Security audit");
|
|
111
|
+
lines.push(...securityAuditWriteFiles());
|
|
112
|
+
}
|
|
113
|
+
// Node-agent systemd service
|
|
114
|
+
lines.push(" # Node-agent systemd service for Ralph Loop orchestration");
|
|
115
|
+
lines.push(" - path: /etc/systemd/system/node-agent.service");
|
|
116
|
+
lines.push(" owner: root:root");
|
|
117
|
+
lines.push(" permissions: '0644'");
|
|
118
|
+
lines.push(" content: |");
|
|
119
|
+
lines.push(" [Unit]");
|
|
120
|
+
lines.push(" Description=Node Agent for Ralph Loop Orchestration");
|
|
121
|
+
lines.push(" Documentation=https://github.com/ebowwa/seed");
|
|
122
|
+
lines.push(" After=network-online.target");
|
|
123
|
+
lines.push(" Wants=network-online.target");
|
|
124
|
+
lines.push("");
|
|
125
|
+
lines.push(" [Service]");
|
|
126
|
+
lines.push(" Type=simple");
|
|
127
|
+
lines.push(" User=root");
|
|
128
|
+
lines.push(` WorkingDirectory=${seedPath}/node-agent`);
|
|
129
|
+
lines.push(" ExecStart=/root/.bun/bin/bun run src/index.ts");
|
|
130
|
+
lines.push(` EnvironmentFile=-${seedPath}/node-agent/.env`);
|
|
131
|
+
lines.push(" Environment=PORT=8911");
|
|
132
|
+
lines.push(" Restart=always");
|
|
133
|
+
lines.push(" RestartSec=10");
|
|
134
|
+
lines.push(" StandardOutput=journal");
|
|
135
|
+
lines.push(" StandardError=journal");
|
|
136
|
+
lines.push(" SyslogIdentifier=node-agent");
|
|
137
|
+
lines.push("");
|
|
138
|
+
// Security hardening for node-agent service
|
|
139
|
+
if (enableSecurity) {
|
|
140
|
+
lines.push(" # Security hardening");
|
|
141
|
+
lines.push(" NoNewPrivileges=true");
|
|
142
|
+
lines.push(" PrivateTmp=true");
|
|
143
|
+
lines.push(" ProtectSystem=strict");
|
|
144
|
+
lines.push(" ProtectHome=true");
|
|
145
|
+
lines.push(" ReadOnlyPaths=/");
|
|
146
|
+
lines.push(" ReadWritePaths=/var/log " + seedPath + "/node-agent");
|
|
147
|
+
}
|
|
148
|
+
lines.push("");
|
|
149
|
+
lines.push(" [Install]");
|
|
150
|
+
lines.push(" WantedBy=multi-user.target");
|
|
151
|
+
lines.push("");
|
|
152
|
+
// Run commands
|
|
153
|
+
lines.push("# Bootstrap commands");
|
|
154
|
+
lines.push("runcmd:");
|
|
155
|
+
// Install Bun and create node symlink
|
|
156
|
+
lines.push(" # Install Bun");
|
|
157
|
+
lines.push(" - curl -fsSL https://bun.sh/install | bash");
|
|
158
|
+
lines.push(" - ln -sf /root/.bun/bin/bun /root/.bun/bin/node # Create 'node' symlink to bun");
|
|
159
|
+
lines.push("");
|
|
160
|
+
// Clone seed repository
|
|
161
|
+
lines.push(` # Clone seed repository`);
|
|
162
|
+
lines.push(` - git clone --depth 1 --branch ${seedBranch} ${seedRepo} ${seedPath}`);
|
|
163
|
+
lines.push("");
|
|
164
|
+
if (runSetup) {
|
|
165
|
+
// Build environment variables
|
|
166
|
+
const envVars = ["NONINTERACTIVE=1", ...Object.entries(setupEnv).map(([k, v]) => `${k}=${v}`)];
|
|
167
|
+
const envString = envVars.join(" ");
|
|
168
|
+
lines.push(` # Run seed setup non-interactively`);
|
|
169
|
+
lines.push(` - cd ${seedPath} && ${envString} bash ./setup.sh 2>&1 | tee /var/log/seed-setup.log`);
|
|
170
|
+
lines.push("");
|
|
171
|
+
// Create completion marker
|
|
172
|
+
lines.push(` # Mark setup complete`);
|
|
173
|
+
lines.push(` - touch ${seedPath}/.seed-setup-complete`);
|
|
174
|
+
lines.push("");
|
|
175
|
+
}
|
|
176
|
+
// Additional commands
|
|
177
|
+
if (additionalCommands.length > 0) {
|
|
178
|
+
lines.push(` # Additional custom commands`);
|
|
179
|
+
for (const cmd of additionalCommands) {
|
|
180
|
+
lines.push(` - ${cmd}`);
|
|
181
|
+
}
|
|
182
|
+
lines.push("");
|
|
183
|
+
}
|
|
184
|
+
// Security Module 1: UFW Firewall activation (runs first)
|
|
185
|
+
if (enableSecurity) {
|
|
186
|
+
lines.push(" # Security Module 1: Activate UFW Firewall");
|
|
187
|
+
lines.push(...ufwFirewallRunCmd(DEFAULT_UFW_WORKER_OPTIONS));
|
|
188
|
+
}
|
|
189
|
+
// Security Module 2: Kernel hardening activation
|
|
190
|
+
if (enableSecurity) {
|
|
191
|
+
lines.push(" # Security Module 2: Apply kernel hardening");
|
|
192
|
+
lines.push(...kernelHardeningRunCmd());
|
|
193
|
+
}
|
|
194
|
+
// Security Module 3: SSH hardening activation
|
|
195
|
+
if (enableSecurity) {
|
|
196
|
+
lines.push(" # Security Module 3: Activate SSH hardening");
|
|
197
|
+
lines.push(...sshdHardeningRunCmd());
|
|
198
|
+
}
|
|
199
|
+
// Security Module 4: Security audit (runs last)
|
|
200
|
+
if (enableSecurity) {
|
|
201
|
+
lines.push(" # Security Module 4: Run security audit");
|
|
202
|
+
lines.push(...securityAuditRunCmd());
|
|
203
|
+
}
|
|
204
|
+
// Mark bootstrap complete
|
|
205
|
+
lines.push(` # Mark bootstrap complete`);
|
|
206
|
+
lines.push(` - echo "status=complete" >> /root/.bootstrap-status`);
|
|
207
|
+
lines.push(` - echo "completed_at=$(date -Iseconds)" >> /root/.bootstrap-status`);
|
|
208
|
+
if (enableSecurity) {
|
|
209
|
+
lines.push(` - echo "security_hardening=applied" >> /root/.bootstrap-status`);
|
|
210
|
+
}
|
|
211
|
+
lines.push("");
|
|
212
|
+
lines.push(" # Start node-agent service");
|
|
213
|
+
lines.push(" - systemctl daemon-reload");
|
|
214
|
+
lines.push(" - systemctl enable node-agent");
|
|
215
|
+
lines.push(" - systemctl start node-agent");
|
|
216
|
+
return lines.join("\n");
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Generate a minimal cloud-init script that uses #include to fetch from a URL
|
|
220
|
+
*
|
|
221
|
+
* This is useful for larger bootstrap scripts or when you want to update
|
|
222
|
+
* the bootstrap without code changes.
|
|
223
|
+
*
|
|
224
|
+
* @param url - URL to fetch the cloud-init config from
|
|
225
|
+
* @returns Cloud-init YAML string with #include directive
|
|
226
|
+
*/
|
|
227
|
+
export function generateRemoteBootstrap(url) {
|
|
228
|
+
return `#include\n${url}`;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Bootstrap configuration presets for common scenarios
|
|
232
|
+
*/
|
|
233
|
+
export const BootstrapPresets = {
|
|
234
|
+
/**
|
|
235
|
+
* Default seed installation with setup.sh and full security hardening
|
|
236
|
+
*/
|
|
237
|
+
default: () => generateSeedBootstrap(),
|
|
238
|
+
/**
|
|
239
|
+
* Seed installation with full security hardening and verbose logging
|
|
240
|
+
*/
|
|
241
|
+
secure: () => generateSeedBootstrap({
|
|
242
|
+
setupEnv: {
|
|
243
|
+
DEBUG: "1",
|
|
244
|
+
VERBOSE: "1",
|
|
245
|
+
},
|
|
246
|
+
}),
|
|
247
|
+
/**
|
|
248
|
+
* Seed installation without running setup.sh (useful for debugging)
|
|
249
|
+
*/
|
|
250
|
+
cloneOnly: () => generateSeedBootstrap({ runSetup: false }),
|
|
251
|
+
/**
|
|
252
|
+
* Development bootstrap without security hardening (for testing)
|
|
253
|
+
*/
|
|
254
|
+
development: () => generateSeedBootstrap({
|
|
255
|
+
enableSecurity: false,
|
|
256
|
+
packages: ["htop", "vim", "strace"],
|
|
257
|
+
}),
|
|
258
|
+
/**
|
|
259
|
+
* Verbose bootstrap with logging enabled
|
|
260
|
+
*/
|
|
261
|
+
verbose: () => generateSeedBootstrap({
|
|
262
|
+
setupEnv: {
|
|
263
|
+
DEBUG: "1",
|
|
264
|
+
VERBOSE: "1",
|
|
265
|
+
},
|
|
266
|
+
}),
|
|
267
|
+
};
|
|
268
|
+
// Re-export Genesis bootstrap functions
|
|
269
|
+
export { generateGenesisBootstrap, generateRemoteGenesisBootstrap, GenesisBootstrapPresets, } from "./genesis";
|
|
270
|
+
// Re-export SSH hardening components so callers can compose custom
|
|
271
|
+
// cloud-init scripts with hardening baked in (e.g. for non-standard node types)
|
|
272
|
+
export { sshdHardeningPackages, sshdHardeningWriteFiles, sshdHardeningRunCmd, } from "./ssh-hardening";
|
|
273
|
+
// Re-export UFW firewall components
|
|
274
|
+
export { ufwFirewallPackages, ufwFirewallWriteFiles, ufwFirewallRunCmd, DEFAULT_UFW_WORKER_OPTIONS, DEFAULT_UFW_GENESIS_OPTIONS, generateUFWFirewallForGenesis, generateUFWFirewallForWorker, } from "./firewall";
|
|
275
|
+
// Re-export kernel hardening components
|
|
276
|
+
export { kernelHardeningPackages, kernelHardeningWriteFiles, kernelHardeningRunCmd, } from "./kernel-hardening";
|
|
277
|
+
// Re-export security audit components
|
|
278
|
+
export { securityAuditPackages, securityAuditWriteFiles, securityAuditRunCmd, } from "./security-audit";
|
|
279
|
+
//# sourceMappingURL=cloud-init.js.map
|
|
@@ -0,0 +1,394 @@
|
|
|
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";
|