@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.
Files changed (46) hide show
  1. package/actions.js +802 -0
  2. package/actions.ts +1053 -0
  3. package/auth.js +35 -0
  4. package/auth.ts +37 -0
  5. package/bootstrap/FIREWALL.md +326 -0
  6. package/bootstrap/KERNEL-HARDENING.md +258 -0
  7. package/bootstrap/SECURITY-INTEGRATION.md +281 -0
  8. package/bootstrap/TESTING.md +301 -0
  9. package/bootstrap/cloud-init.js +279 -0
  10. package/bootstrap/cloud-init.ts +394 -0
  11. package/bootstrap/firewall.js +279 -0
  12. package/bootstrap/firewall.ts +342 -0
  13. package/bootstrap/genesis.js +406 -0
  14. package/bootstrap/genesis.ts +518 -0
  15. package/bootstrap/index.js +35 -0
  16. package/bootstrap/index.ts +71 -0
  17. package/bootstrap/kernel-hardening.js +266 -0
  18. package/bootstrap/kernel-hardening.test.ts +230 -0
  19. package/bootstrap/kernel-hardening.ts +272 -0
  20. package/bootstrap/security-audit.js +118 -0
  21. package/bootstrap/security-audit.ts +124 -0
  22. package/bootstrap/ssh-hardening.js +182 -0
  23. package/bootstrap/ssh-hardening.ts +192 -0
  24. package/client.js +137 -0
  25. package/client.ts +177 -0
  26. package/config.js +5 -0
  27. package/config.ts +5 -0
  28. package/errors.js +270 -0
  29. package/errors.ts +371 -0
  30. package/index.js +28 -0
  31. package/index.ts +55 -0
  32. package/package.json +56 -0
  33. package/pricing.js +284 -0
  34. package/pricing.ts +422 -0
  35. package/schemas.js +660 -0
  36. package/schemas.ts +765 -0
  37. package/server-status.ts +81 -0
  38. package/servers.js +424 -0
  39. package/servers.ts +568 -0
  40. package/ssh-keys.js +90 -0
  41. package/ssh-keys.ts +122 -0
  42. package/ssh-setup.ts +218 -0
  43. package/types.js +96 -0
  44. package/types.ts +389 -0
  45. package/volumes.js +172 -0
  46. package/volumes.ts +229 -0
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Kernel Hardening Cloud-Init Components
3
+ *
4
+ * Composable cloud-init blocks for securing the Linux kernel on new servers.
5
+ * Implements 2026 best practices for network stack hardening, IP spoofing
6
+ * protection, SYN flood mitigation, and secure core dump policies.
7
+ *
8
+ * Background: Public-facing VPS servers are constantly probed and attacked.
9
+ * Default Linux kernel settings prioritize compatibility over security. This
10
+ * module applies CIS Benchmark-aligned hardening via /etc/sysctl.d/ which
11
+ * persists across reboots and overrides defaults.
12
+ *
13
+ * Three composable functions return cloud-init line arrays for splicing into
14
+ * the appropriate YAML sections:
15
+ * - kernelHardeningPackages() → packages: section (currently empty, reserved)
16
+ * - kernelHardeningWriteFiles() → write_files: section (drops sysctl config)
17
+ * - kernelHardeningRunCmd() → runcmd: section (applies settings immediately)
18
+ *
19
+ * Security Measures Implemented:
20
+ * 1. Network Stack Hardening: SYN cookies, ICMP rate limits, martian packet logging
21
+ * 2. IP Spoofing Protection: Reverse path filtering, source address verification
22
+ * 3. SYN Flood Protection: TCP SYN cookies, reuse time_wait connections
23
+ * 4. Core Dump Restrictions: Disable setuid dumps, limit core dump size to 0
24
+ * 5. File Permissions: Hard links, symlinks, FIFO protection
25
+ * 6. Memory Protection: ASLR, randomize_va_space
26
+ *
27
+ * References:
28
+ * - CIS Benchmark for Ubuntu Linux 24.04
29
+ * - NIST SP 800-53 Revision 5
30
+ * - https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
31
+ */
32
+
33
+ /**
34
+ * Packages required for kernel hardening.
35
+ * Returns cloud-init YAML lines for the `packages:` section.
36
+ *
37
+ * Note: All kernel hardening is done via sysctl configuration, which uses
38
+ * built-in kernel functionality. No additional packages are required.
39
+ * This function is reserved for future expansion (e.g., auditd, kexec-tools).
40
+ */
41
+ export function kernelHardeningPackages(): string[] {
42
+ return [
43
+ // Reserved for future packages (auditd, kexec-tools, etc.)
44
+ // Currently empty - all hardening via sysctl
45
+ ];
46
+ }
47
+
48
+ /**
49
+ * Kernel sysctl configuration file for comprehensive hardening.
50
+ * Returns cloud-init YAML lines for the `write_files:` section.
51
+ *
52
+ * Drops /etc/sysctl.d/99-security-hardening.conf which:
53
+ * - Takes precedence over /etc/sysctl.conf (99- prefix ensures last load)
54
+ * - Persists across reboots (sysctl.d files are applied on boot)
55
+ * - Can be applied immediately via `sysctl --system` (see runcmd)
56
+ *
57
+ * Settings organized by category:
58
+ * 1. IP Spoofing Protection: rp_filter, secure redirects
59
+ * 2. SYN Flood Protection: syncookies, tcp_tw_reuse
60
+ * 3. Network Stack: ICMP rate limits, martian logging, ignore broadcasts
61
+ * 4. Core Dumps: Disabled for setuid programs, limited for all processes
62
+ * 5. Memory Protection: ASLR, randomize_va_space
63
+ * 6. Filesystem: Hard link/symlink protection
64
+ */
65
+ export function kernelHardeningWriteFiles(): string[] {
66
+ const lines: string[] = [];
67
+
68
+ lines.push(" # Kernel hardening: sysctl.d configuration for 2026 best practices");
69
+ lines.push(" # This file persists across reboots and overrides /etc/sysctl.conf");
70
+ lines.push(" - path: /etc/sysctl.d/99-security-hardening.conf");
71
+ lines.push(" owner: root:root");
72
+ lines.push(" permissions: '0644'");
73
+ lines.push(" content: |");
74
+ lines.push(" # =================================================================");
75
+ lines.push(" # Kernel Security Hardening Configuration");
76
+ lines.push(" # =================================================================");
77
+ lines.push(" # Applied via cloud-init for com.hetzner.codespaces");
78
+ lines.push(" # Version: 1.0.0 (2026 best practices)");
79
+ lines.push(" #");
80
+ lines.push(" # This configuration follows CIS Benchmark and NIST guidelines");
81
+ lines.push(" # See: /usr/share/doc/linux-doc/sysctl/ for parameter documentation");
82
+ lines.push("");
83
+ lines.push(" # =================================================================");
84
+ lines.push(" # 1. IP SPOOFING PROTECTION");
85
+ lines.push(" # =================================================================");
86
+ lines.push(" # Enable reverse path filtering (validates source addresses)");
87
+ lines.push(" # Prevents IP spoofing attacks by dropping packets with invalid sources");
88
+ lines.push(" net.ipv4.conf.all.rp_filter = 1");
89
+ lines.push(" net.ipv4.conf.default.rp_filter = 1");
90
+ lines.push("");
91
+ lines.push(" # Log martian packets (packets with impossible addresses)");
92
+ lines.push(" # Helps detect spoofing attempts and network misconfigurations");
93
+ lines.push(" net.ipv4.conf.all.log_martians = 1");
94
+ lines.push("");
95
+ lines.push(" # Disable ICMP redirect acceptance (prevent MITM attacks)");
96
+ lines.push(" net.ipv4.conf.all.accept_redirects = 0");
97
+ lines.push(" net.ipv4.conf.default.accept_redirects = 0");
98
+ lines.push(" net.ipv4.conf.all.secure_redirects = 0");
99
+ lines.push(" net.ipv4.conf.default.secure_redirects = 0");
100
+ lines.push("");
101
+ lines.push(" # Disable sending ICMP redirects");
102
+ lines.push(" net.ipv4.conf.all.send_redirects = 0");
103
+ lines.push(" net.ipv4.conf.default.send_redirects = 0");
104
+ lines.push("");
105
+ lines.push(" # =================================================================");
106
+ lines.push(" # 2. SYN FLOOD PROTECTION");
107
+ lines.push(" # =================================================================");
108
+ lines.push(" # Enable SYN cookies (protects against SYN flood attacks)");
109
+ lines.push(" # Allows server to continue accepting connections under SYN flood");
110
+ lines.push(" net.ipv4.tcp_syncookies = 1");
111
+ lines.push("");
112
+ lines.push(" # Reuse TIME_WAIT sockets for new connections (safer, faster)");
113
+ lines.push(" # Reduces connection table exhaustion under high load");
114
+ lines.push(" net.ipv4.tcp_tw_reuse = 1");
115
+ lines.push("");
116
+ lines.push(" # Reduce SYN backlog and timeouts for faster detection");
117
+ lines.push(" net.ipv4.tcp_max_syn_backlog = 2048");
118
+ lines.push(" net.ipv4.tcp_synack_retries = 2");
119
+ lines.push(" net.ipv4.tcp_syn_retries = 5");
120
+ lines.push("");
121
+ lines.push(" # =================================================================");
122
+ lines.push(" # 3. NETWORK STACK HARDENING");
123
+ lines.push(" # =================================================================");
124
+ lines.push(" # Disable ICMP redirect acceptance (IPv6)");
125
+ lines.push(" net.ipv6.conf.all.accept_redirects = 0");
126
+ lines.push(" net.ipv6.conf.default.accept_redirects = 0");
127
+ lines.push("");
128
+ lines.push(" # Ignore ICMP broadcasts (prevent smurf attacks)");
129
+ lines.push(" net.ipv4.icmp_echo_ignore_broadcasts = 1");
130
+ lines.push("");
131
+ lines.push(" # Ignore bogus ICMP error responses (prevent ICMP attacks)");
132
+ lines.push(" net.ipv4.icmp_ignore_bogus_error_responses = 1");
133
+ lines.push("");
134
+ lines.push(" # Enable TCP timestamps (RFC 1323) for better sequence handling");
135
+ lines.push(" # Also protects against wrapped sequence number attacks");
136
+ lines.push(" net.ipv4.tcp_timestamps = 1");
137
+ lines.push("");
138
+ lines.push(" # Enable TCP selective acknowledgments (better performance)");
139
+ lines.push(" net.ipv4.tcp_sack = 1");
140
+ lines.push("");
141
+ lines.push(" # =================================================================");
142
+ lines.push(" # 4. CORE DUMP RESTRICTIONS");
143
+ lines.push(" # =================================================================");
144
+ lines.push(" # Disable core dumps for setuid programs (prevent privilege escalation)");
145
+ lines.push(" fs.suid_dumpable = 0");
146
+ lines.push("");
147
+ lines.push(" # Limit core dump size to 0 (disable core dumps)");
148
+ lines.push(" # Override in /etc/security/limits.conf if needed for debugging");
149
+ lines.push(" kernel.core_pattern = |/bin/false");
150
+ lines.push("");
151
+ lines.push(" # =================================================================");
152
+ lines.push(" # 5. MEMORY PROTECTION (ASLR)");
153
+ lines.push(" # =================================================================");
154
+ lines.push(" # Enable Address Space Layout Randomization (full)");
155
+ lines.push(" # Makes exploitation of memory corruption vulnerabilities harder");
156
+ lines.push(" # 0: Disabled, 1: Conservative, 2: Full (default)");
157
+ lines.push(" kernel.randomize_va_space = 2");
158
+ lines.push("");
159
+ lines.push(" # =================================================================");
160
+ lines.push(" # 6. FILESYSTEM PROTECTION");
161
+ lines.push(" # =================================================================");
162
+ lines.push(" # Hard link/symlink protection (prevent time-of-check time-of-use)");
163
+ lines.push(" fs.protected_hardlinks = 1");
164
+ lines.push(" fs.protected_symlinks = 1");
165
+ lines.push("");
166
+ lines.push(" # FIFO protection (prevent FIFO attacks on world-writable directories)");
167
+ lines.push(" fs.protected_fifos = 2");
168
+ lines.push("");
169
+ lines.push(" # Regular file protection (prevent file overwrite attacks)");
170
+ lines.push(" fs.protected_regular = 2");
171
+ lines.push("");
172
+ lines.push(" # =================================================================");
173
+ lines.push(" # 7. NETWORK BEHAVIOR TUNING");
174
+ lines.push(" # =================================================================");
175
+ lines.push(" # Enable TCP Fast Open (TFO) for reduced latency");
176
+ lines.push(" net.ipv4.tcp_fastopen = 3");
177
+ lines.push("");
178
+ lines.push(" # Disable source routing (prevent packet routing manipulation)");
179
+ lines.push(" net.ipv4.conf.all.accept_source_route = 0");
180
+ lines.push(" net.ipv4.conf.default.accept_source_route = 0");
181
+ lines.push(" net.ipv6.conf.all.accept_source_route = 0");
182
+ lines.push(" net.ipv6.conf.default.accept_source_route = 0");
183
+ lines.push("");
184
+ lines.push(" # Enable TCP window scaling (RFC 7323) for high-bandwidth links");
185
+ lines.push(" net.ipv4.tcp_window_scaling = 1");
186
+ lines.push("");
187
+ lines.push(" # =================================================================");
188
+ lines.push(" # 8. SECURITY-RELATED KERNEL PARAMETERS");
189
+ lines.push(" # =================================================================");
190
+ lines.push(" # Disable magic sysrq key (prevent console-based attacks)");
191
+ lines.push(" # 0: Disabled, 1: Enable (for debugging only)");
192
+ lines.push(" kernel.sysrq = 0");
193
+ lines.push("");
194
+ lines.push(" # Disable kexec system call (prevent kernel replacement)");
195
+ lines.push(" # 0: Disabled, 1: Enabled");
196
+ lines.push(" kernel.kexec_load = 0");
197
+ lines.push("");
198
+ lines.push(" # Disable user namespaces (prevent container breakouts)");
199
+ lines.push(" # 0: Disabled, 1: Enabled");
200
+ lines.push(" user.max_user_namespaces = 0");
201
+ lines.push("");
202
+ lines.push(" # Enable unprivileged bpf disabled (prevent eBPF-based exploits)");
203
+ lines.push(" # 0: Disabled, 1: Enabled");
204
+ lines.push(" kernel.unprivileged_bpf_disabled = 1");
205
+ lines.push("");
206
+ lines.push(" # =================================================================");
207
+ lines.push(" # 9. ADDITIONAL HARDENING (2026)");
208
+ lines.push(" # =================================================================");
209
+ lines.push(" # Disable IPv6 if not needed (uncomment if IPv6 is disabled)");
210
+ lines.push(" # net.ipv6.conf.all.disable_ipv6 = 1");
211
+ lines.push(" # net.ipv6.conf.default.disable_ipv6 = 1");
212
+ lines.push("");
213
+ lines.push(" # Enable dmesg restriction (prevent kernel info leaks)");
214
+ lines.push(" kernel.dmesg_restrict = 1");
215
+ lines.push("");
216
+ lines.push(" # Restrict ptrace scope (prevent process tracing by non-parent)");
217
+ lines.push(" # 0: Traditional, 1: Restricted, 2: Admin-only, 3: No attach");
218
+ lines.push(" kernel.yama.ptrace_scope = 2");
219
+ lines.push("");
220
+ lines.push(" # =================================================================");
221
+ lines.push(" # 10. PERFORMANCE TUNING (safe defaults)");
222
+ lines.push(" # =================================================================");
223
+ lines.push(" # Increase connection tracking table size (for stateful firewalls)");
224
+ lines.push(" net.netfilter.nf_conntrack_max = 262144");
225
+ lines.push("");
226
+ lines.push(" # Reduce TCP keepalive timeouts for faster dead peer detection");
227
+ lines.push(" net.ipv4.tcp_keepalive_time = 600");
228
+ lines.push(" net.ipv4.tcp_keepalive_intvl = 30");
229
+ lines.push(" net.ipv4.tcp_keepalive_probes = 3");
230
+ lines.push("");
231
+
232
+ return lines;
233
+ }
234
+
235
+ /**
236
+ * Commands to apply kernel hardening settings immediately at first boot.
237
+ * Returns cloud-init YAML lines for the `runcmd:` section.
238
+ *
239
+ * Order matters:
240
+ * 1. Load all sysctl settings from /etc/sysctl.d/*.conf
241
+ * 2. Apply settings immediately (don't wait for reboot)
242
+ * 3. Log applied settings for audit trail
243
+ * 4. Display summary for cloud-init output verification
244
+ */
245
+ export function kernelHardeningRunCmd(): string[] {
246
+ const lines: string[] = [];
247
+
248
+ lines.push(" # Kernel hardening: apply sysctl settings immediately");
249
+ lines.push(" # Settings are already in /etc/sysctl.d/99-security-hardening.conf");
250
+ lines.push("");
251
+ lines.push(" # Apply all sysctl settings (overrides defaults immediately)");
252
+ lines.push(" - sysctl --system");
253
+ lines.push("");
254
+ lines.push(" # Log applied settings for audit trail");
255
+ lines.push(" - sysctl -a | grep -E '(rp_filter|syncookies|randomize_va|suid_dump)' > /var/log/kernel-hardening.log 2>&1 || true");
256
+ lines.push("");
257
+ lines.push(" # Display summary of critical hardening settings");
258
+ lines.push(" - |");
259
+ lines.push(" echo '========================================'");
260
+ lines.push(" echo 'Kernel Hardening Applied (2026)'");
261
+ lines.push(" echo '========================================'");
262
+ lines.push(" echo 'IP Spoof Protection: '$(sysctl -n net.ipv4.conf.all.rp_filter)");
263
+ lines.push(" echo 'SYN Cookies: '$(sysctl -n net.ipv4.tcp_syncookies)");
264
+ lines.push(" echo 'ASLR Level: '$(sysctl -n kernel.randomize_va_space)");
265
+ lines.push(" echo 'SUID Core Dumps: '$(sysctl -n fs.suid_dumpable)");
266
+ lines.push(" echo 'Hard Links Protected: '$(sysctl -n fs.protected_hardlinks)");
267
+ lines.push(" echo 'Ptrace Scope: '$(sysctl -n kernel.yama.ptrace_scope)");
268
+ lines.push(" echo '========================================'");
269
+ lines.push("");
270
+
271
+ return lines;
272
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Security Audit Cloud-Init Components
3
+ *
4
+ * Composable cloud-init blocks for running post-bootstrap security audits.
5
+ * Generates comprehensive security reports for verification and compliance.
6
+ *
7
+ * This module runs LAST in the bootstrap sequence, after all other security
8
+ * hardening is applied. It captures the state of the system for verification.
9
+ *
10
+ * Three composable functions return cloud-init line arrays for splicing into
11
+ * the appropriate YAML sections:
12
+ * - securityAuditPackages() → packages: section
13
+ * - securityAuditWriteFiles() → write_files: section
14
+ * - securityAuditRunCmd() → runcmd: section
15
+ */
16
+ /**
17
+ * Packages required for security auditing.
18
+ * Returns cloud-init YAML lines for the `packages:` section.
19
+ *
20
+ * - lynis: Comprehensive security auditing tool
21
+ */
22
+ export function securityAuditPackages() {
23
+ return [
24
+ " - lynis",
25
+ ];
26
+ }
27
+ /**
28
+ * Files to write at first boot for security auditing.
29
+ * Returns cloud-init YAML lines for the `write_files:` section.
30
+ *
31
+ * Drops 1 file onto the server:
32
+ *
33
+ * 1. /opt/monitoring/security-audit.sh
34
+ * - Collects security metrics (UFW, fail2ban, sshd, sysctl)
35
+ * - Runs Lynis audit with warnings-only output
36
+ * - Generates JSON report at /var/log/security-audit.json
37
+ * - Logs summary to /var/log/security-audit.log
38
+ */
39
+ export function securityAuditWriteFiles() {
40
+ const lines = [];
41
+ // 1. Security audit script - comprehensive security check
42
+ lines.push(" # Security audit script - runs after all hardening");
43
+ lines.push(" - path: /opt/monitoring/security-audit.sh");
44
+ lines.push(" owner: root:root");
45
+ lines.push(" permissions: '0755'");
46
+ lines.push(" content: |");
47
+ lines.push(" #!/bin/bash");
48
+ lines.push(" set -euo pipefail");
49
+ lines.push(" LOGFILE=\"/var/log/security-audit.log\"");
50
+ lines.push(" REPORTFILE=\"/var/log/security-audit.json\"");
51
+ lines.push(" echo \"Security Audit started at $(date -Iseconds)\" | tee \"$LOGFILE\"");
52
+ lines.push("");
53
+ lines.push(" # Firewall status");
54
+ lines.push(" echo \"\" | tee -a \"$LOGFILE\"");
55
+ lines.push(" echo \"=== UFW Firewall Status ===\" | tee -a \"$LOGFILE\"");
56
+ lines.push(" ufw status verbose | tee -a \"$LOGFILE\" || true");
57
+ lines.push("");
58
+ lines.push(" # Fail2ban status");
59
+ lines.push(" echo \"\" | tee -a \"$LOGFILE\"");
60
+ lines.push(" echo \"=== Fail2ban Status ===\" | tee -a \"$LOGFILE\"");
61
+ lines.push(" systemctl status fail2ban --no-pager | tee -a \"$LOGFILE\" || true");
62
+ lines.push(" fail2ban-client status sshd | tee -a \"$LOGFILE\" || true");
63
+ lines.push("");
64
+ lines.push(" # SSHd status");
65
+ lines.push(" echo \"\" | tee -a \"$LOGFILE\"");
66
+ lines.push(" echo \"=== SSHd Status ===\" | tee -a \"$LOGFILE\"");
67
+ lines.push(" systemctl status ssh --no-pager | tee -a \"$LOGFILE\" || true");
68
+ lines.push(" sshd -T | grep -E '(PasswordAuthentication|PermitRootLogin|MaxStartups)' | tee -a \"$LOGFILE\" || true");
69
+ lines.push("");
70
+ lines.push(" # Kernel hardening status");
71
+ lines.push(" echo \"\" | tee -a \"$LOGFILE\"");
72
+ lines.push(" echo \"=== Kernel Hardening Status ===\" | tee -a \"$LOGFILE\"");
73
+ lines.push(" sysctl randomize_va_space kptr_restrict tcp_syncookies | tee -a \"$LOGFILE\" || true");
74
+ lines.push("");
75
+ lines.push(" # Lynis audit (warnings only, non-interactive)");
76
+ lines.push(" echo \"\" | tee -a \"$LOGFILE\"");
77
+ lines.push(" echo \"=== Lynis Security Audit ===\" | tee -a \"$LOGFILE\"");
78
+ lines.push(" lynis audit system --warnings-only --quiet 2>&1 | tee -a \"$LOGFILE\" || true");
79
+ lines.push("");
80
+ lines.push(" # Generate JSON report");
81
+ lines.push(" timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)");
82
+ lines.push(" ufw_active=$(ufw status | grep -c \"Status: active\" || echo \"0\")");
83
+ lines.push(" fail2ban_active=$(systemctl is-active fail2ban 2>/dev/null || echo \"inactive\")");
84
+ lines.push(" sshd_active=$(systemctl is-active ssh 2>/dev/null || echo \"inactive\")");
85
+ lines.push(" aslr_enabled=$(cat /proc/sys/kernel/randomize_va_space 2>/dev/null || echo \"0\")");
86
+ lines.push(" cat > \"$REPORTFILE\" <<AUDEOF");
87
+ lines.push(" {");
88
+ lines.push(" \"timestamp\": \"$timestamp\",");
89
+ lines.push(" \"firewall\": { \"active\": $ufw_active },");
90
+ lines.push(" \"fail2ban\": { \"active\": \"$fail2ban_active\" },");
91
+ lines.push(" \"sshd\": { \"active\": \"$sshd_active\" },");
92
+ lines.push(" \"kernel_hardening\": { \"aslr_enabled\": $aslr_enabled }");
93
+ lines.push(" }");
94
+ lines.push(" AUDEOF");
95
+ lines.push(" echo \"Security Audit completed at $(date -Iseconds)\" | tee -a \"$LOGFILE\"");
96
+ lines.push(" echo \"Report saved to $REPORTFILE\" | tee -a \"$LOGFILE\"");
97
+ lines.push("");
98
+ return lines;
99
+ }
100
+ /**
101
+ * Commands to run security audit at first boot.
102
+ * Returns cloud-init YAML lines for the `runcmd:` section.
103
+ *
104
+ * Order matters:
105
+ * 1. Create /opt/monitoring directory (audit script target)
106
+ * 2. Run security audit script (captures state after all hardening)
107
+ * 3. Log audit completion for verification
108
+ */
109
+ export function securityAuditRunCmd() {
110
+ const lines = [];
111
+ lines.push(" # Security audit: run comprehensive security check");
112
+ lines.push(" - mkdir -p /opt/monitoring");
113
+ lines.push(" - /opt/monitoring/security-audit.sh");
114
+ lines.push(" - echo \"Security audit completed at $(date -Iseconds)\" | tee -a /root/.bootstrap-status");
115
+ lines.push("");
116
+ return lines;
117
+ }
118
+ //# sourceMappingURL=security-audit.js.map
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Security Audit Cloud-Init Components
3
+ *
4
+ * Composable cloud-init blocks for running post-bootstrap security audits.
5
+ * Generates comprehensive security reports for verification and compliance.
6
+ *
7
+ * This module runs LAST in the bootstrap sequence, after all other security
8
+ * hardening is applied. It captures the state of the system for verification.
9
+ *
10
+ * Three composable functions return cloud-init line arrays for splicing into
11
+ * the appropriate YAML sections:
12
+ * - securityAuditPackages() → packages: section
13
+ * - securityAuditWriteFiles() → write_files: section
14
+ * - securityAuditRunCmd() → runcmd: section
15
+ */
16
+
17
+ /**
18
+ * Packages required for security auditing.
19
+ * Returns cloud-init YAML lines for the `packages:` section.
20
+ *
21
+ * - lynis: Comprehensive security auditing tool
22
+ */
23
+ export function securityAuditPackages(): string[] {
24
+ return [
25
+ " - lynis",
26
+ ];
27
+ }
28
+
29
+ /**
30
+ * Files to write at first boot for security auditing.
31
+ * Returns cloud-init YAML lines for the `write_files:` section.
32
+ *
33
+ * Drops 1 file onto the server:
34
+ *
35
+ * 1. /opt/monitoring/security-audit.sh
36
+ * - Collects security metrics (UFW, fail2ban, sshd, sysctl)
37
+ * - Runs Lynis audit with warnings-only output
38
+ * - Generates JSON report at /var/log/security-audit.json
39
+ * - Logs summary to /var/log/security-audit.log
40
+ */
41
+ export function securityAuditWriteFiles(): string[] {
42
+ const lines: string[] = [];
43
+
44
+ // 1. Security audit script - comprehensive security check
45
+ lines.push(" # Security audit script - runs after all hardening");
46
+ lines.push(" - path: /opt/monitoring/security-audit.sh");
47
+ lines.push(" owner: root:root");
48
+ lines.push(" permissions: '0755'");
49
+ lines.push(" content: |");
50
+ lines.push(" #!/bin/bash");
51
+ lines.push(" set -euo pipefail");
52
+ lines.push(" LOGFILE=\"/var/log/security-audit.log\"");
53
+ lines.push(" REPORTFILE=\"/var/log/security-audit.json\"");
54
+ lines.push(" echo \"Security Audit started at $(date -Iseconds)\" | tee \"$LOGFILE\"");
55
+ lines.push("");
56
+ lines.push(" # Firewall status");
57
+ lines.push(" echo \"\" | tee -a \"$LOGFILE\"");
58
+ lines.push(" echo \"=== UFW Firewall Status ===\" | tee -a \"$LOGFILE\"");
59
+ lines.push(" ufw status verbose | tee -a \"$LOGFILE\" || true");
60
+ lines.push("");
61
+ lines.push(" # Fail2ban status");
62
+ lines.push(" echo \"\" | tee -a \"$LOGFILE\"");
63
+ lines.push(" echo \"=== Fail2ban Status ===\" | tee -a \"$LOGFILE\"");
64
+ lines.push(" systemctl status fail2ban --no-pager | tee -a \"$LOGFILE\" || true");
65
+ lines.push(" fail2ban-client status sshd | tee -a \"$LOGFILE\" || true");
66
+ lines.push("");
67
+ lines.push(" # SSHd status");
68
+ lines.push(" echo \"\" | tee -a \"$LOGFILE\"");
69
+ lines.push(" echo \"=== SSHd Status ===\" | tee -a \"$LOGFILE\"");
70
+ lines.push(" systemctl status ssh --no-pager | tee -a \"$LOGFILE\" || true");
71
+ lines.push(" sshd -T | grep -E '(PasswordAuthentication|PermitRootLogin|MaxStartups)' | tee -a \"$LOGFILE\" || true");
72
+ lines.push("");
73
+ lines.push(" # Kernel hardening status");
74
+ lines.push(" echo \"\" | tee -a \"$LOGFILE\"");
75
+ lines.push(" echo \"=== Kernel Hardening Status ===\" | tee -a \"$LOGFILE\"");
76
+ lines.push(" sysctl randomize_va_space kptr_restrict tcp_syncookies | tee -a \"$LOGFILE\" || true");
77
+ lines.push("");
78
+ lines.push(" # Lynis audit (warnings only, non-interactive)");
79
+ lines.push(" echo \"\" | tee -a \"$LOGFILE\"");
80
+ lines.push(" echo \"=== Lynis Security Audit ===\" | tee -a \"$LOGFILE\"");
81
+ lines.push(" lynis audit system --warnings-only --quiet 2>&1 | tee -a \"$LOGFILE\" || true");
82
+ lines.push("");
83
+ lines.push(" # Generate JSON report");
84
+ lines.push(" timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)");
85
+ lines.push(" ufw_active=$(ufw status | grep -c \"Status: active\" || echo \"0\")");
86
+ lines.push(" fail2ban_active=$(systemctl is-active fail2ban 2>/dev/null || echo \"inactive\")");
87
+ lines.push(" sshd_active=$(systemctl is-active ssh 2>/dev/null || echo \"inactive\")");
88
+ lines.push(" aslr_enabled=$(cat /proc/sys/kernel/randomize_va_space 2>/dev/null || echo \"0\")");
89
+ lines.push(" cat > \"$REPORTFILE\" <<AUDEOF");
90
+ lines.push(" {");
91
+ lines.push(" \"timestamp\": \"$timestamp\",");
92
+ lines.push(" \"firewall\": { \"active\": $ufw_active },");
93
+ lines.push(" \"fail2ban\": { \"active\": \"$fail2ban_active\" },");
94
+ lines.push(" \"sshd\": { \"active\": \"$sshd_active\" },");
95
+ lines.push(" \"kernel_hardening\": { \"aslr_enabled\": $aslr_enabled }");
96
+ lines.push(" }");
97
+ lines.push(" AUDEOF");
98
+ lines.push(" echo \"Security Audit completed at $(date -Iseconds)\" | tee -a \"$LOGFILE\"");
99
+ lines.push(" echo \"Report saved to $REPORTFILE\" | tee -a \"$LOGFILE\"");
100
+ lines.push("");
101
+
102
+ return lines;
103
+ }
104
+
105
+ /**
106
+ * Commands to run security audit at first boot.
107
+ * Returns cloud-init YAML lines for the `runcmd:` section.
108
+ *
109
+ * Order matters:
110
+ * 1. Create /opt/monitoring directory (audit script target)
111
+ * 2. Run security audit script (captures state after all hardening)
112
+ * 3. Log audit completion for verification
113
+ */
114
+ export function securityAuditRunCmd(): string[] {
115
+ const lines: string[] = [];
116
+
117
+ lines.push(" # Security audit: run comprehensive security check");
118
+ lines.push(" - mkdir -p /opt/monitoring");
119
+ lines.push(" - /opt/monitoring/security-audit.sh");
120
+ lines.push(" - echo \"Security audit completed at $(date -Iseconds)\" | tee -a /root/.bootstrap-status");
121
+ lines.push("");
122
+
123
+ return lines;
124
+ }