]>
Commit | Line | Data |
---|---|---|
b48bbe83 | 1 | { config, pkgs, lib, ports, name, secrets, ... }: |
1a64deeb IB |
2 | { |
3 | # ssh-keyscan eldiron | nix-shell -p ssh-to-age --run ssh-to-age | |
4 | secrets.ageKeys = [ "age1dxr5lhvtnjssfaqpnf6qx80h8gfwkxg3tdf35m6n9wljmk7wadfs3kmahj" ]; | |
5 | boot = { | |
6 | kernelModules = [ "kvm-intel" ]; | |
7 | blacklistedKernelModules = [ "nvidiafb" ]; | |
8 | loader.timeout = 1; | |
9 | loader.grub.devices = [ "/dev/sda" "/dev/sdc" ]; | |
10 | kernel.sysctl = { | |
11 | # https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-001.md | |
12 | "net.ipv4.tcp_sack" = 0; | |
13 | }; | |
14 | supportedFilesystems = [ "zfs" ]; | |
15 | kernelParams = ["zfs.zfs_arc_max=6442450944"]; | |
16 | kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages; | |
17 | initrd.availableKernelModules = [ "ahci" "sd_mod" ]; | |
18 | initrd.secrets = { | |
19 | "/boot/pass.key" = "/boot/pass.key"; | |
20 | }; | |
21 | }; | |
22 | services.udev.extraRules = '' | |
23 | ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="c8:60:00:56:a0:88", NAME="eth0" | |
24 | ''; | |
25 | nix.settings.max-jobs = 8; | |
26 | nixpkgs.config.permittedInsecurePackages = [ | |
27 | "python-2.7.18.6" # for nagios-cli | |
28 | "nodejs-16.20.2" # for landing page building | |
29 | ]; | |
30 | ||
b48bbe83 | 31 | nixpkgs.overlays = builtins.attrValues ports.overlays; |
1a64deeb IB |
32 | powerManagement.cpuFreqGovernor = "powersave"; |
33 | ||
34 | security.acme.certs."${name}".postRun = builtins.concatStringsSep "\n" [ | |
35 | (lib.optionalString config.services.websites.env.production.enable "/run/current-system/sw/bin/machinectl shell httpd-production /usr/bin/env systemctl reload httpd.service") | |
36 | (lib.optionalString config.services.websites.env.integration.enable "/run/current-system/sw/bin/machinectl shell httpd-integration /usr/bin/env systemctl reload httpd.service") | |
37 | ]; | |
38 | ||
39 | fileSystems = { | |
40 | # pools: | |
41 | # zpool: ashift=12 | |
42 | # zfast: ashift=12 | |
43 | # zfs: | |
44 | # zpool/: acltype=posixacl ; xattr=sa ; atime=off ; mountpoint=legacy | |
45 | # zpool/root: encryption=on ; keyformat=passphrase ; keylocation=file:///boot/pass.key | |
46 | # zpool/root/var: atime=on | |
47 | # zfast/: acltype=posixacl ; xattr=sa ; atime=off ; mountpoint=legacy | |
48 | # zfast/root: encryption=on ; keyformat=passphrase ; keylocation=file:///boot/pass.key | |
49 | # zfast/root/etc: ø | |
50 | # zfast/root/nix: ø | |
51 | # zfast/root/tmp: async=disabled | |
52 | # zfast/root/var: atime=on | |
53 | # zfast/root/var/lib: ø | |
54 | # zfast/root/var/lib/mysql: logbias=throughput ; atime=off ; primarycache=metadata | |
55 | # zfast/root/var/lib/postgresql: recordsize=8K ; atime=off ; logbias=throughput | |
56 | # zfast/root/var/lib/postgresql/11.0: ø | |
57 | # zfast/root/var/lib/postgresql/11.0/pg_wal: ø | |
58 | "/" = { fsType = "zfs"; device = "zpool/root"; }; | |
59 | "/boot" = { fsType = "ext4"; device = "/dev/disk/by-uuid/e6bb18fb-ff56-4b5f-ae9f-e60d40dc0622"; }; | |
60 | "/etc" = { fsType = "zfs"; device = "zpool/root/etc"; }; | |
61 | "/nix" = { fsType = "zfs"; device = "zfast/root/nix"; }; | |
62 | "/tmp" = { fsType = "zfs"; device = "zfast/root/tmp"; }; | |
63 | "/var" = { fsType = "zfs"; device = "zpool/root/var"; }; | |
64 | "/var/lib/mysql" = { fsType = "zfs"; device = "zfast/root/var/lib/mysql"; }; | |
65 | "/var/lib/postgresql" = { fsType = "zfs"; device = "zfast/root/var/lib/postgresql"; }; | |
66 | "/var/lib/postgresql/11.0" = { fsType = "zfs"; device = "zfast/root/var/lib/postgresql/11.0"; }; | |
67 | "/var/lib/postgresql/11.0/pg_wal" = { fsType = "zfs"; device = "zfast/root/var/lib/postgresql/11.0/pg_wal"; }; | |
68 | }; | |
69 | swapDevices = [ { label = "swap1"; } { label = "swap2"; } ]; | |
70 | hardware.enableRedistributableFirmware = true; | |
71 | ||
72 | services.zfs = { | |
73 | autoScrub = { | |
74 | enable = false; | |
75 | }; | |
76 | }; | |
77 | networking = { | |
78 | hostId = "8262ca33"; # generated with head -c4 /dev/urandom | od -A none -t x4 | |
79 | firewall.enable = true; | |
80 | firewall.allowedTCPPorts = [ config.myEnv.ports.zrepl_flony ]; | |
81 | # FIXME: on next reboot, remove the /27 and the localCommands | |
82 | interfaces."eth0".ipv4.addresses = pkgs.lib.flatten (pkgs.lib.attrsets.mapAttrsToList | |
83 | (n: ips: map (ip: { address = ip; prefixLength = 32; }) (ips.ip4 or [])) | |
84 | (pkgs.lib.attrsets.filterAttrs (n: v: n != "main") config.hostEnv.ips)) | |
85 | ++ [ { address = lib.head config.hostEnv.ips.main.ip4; prefixLength = 27; } ]; | |
86 | interfaces."eth0".ipv6.addresses = pkgs.lib.flatten (pkgs.lib.attrsets.mapAttrsToList | |
87 | (n: ips: map (ip: { address = ip; prefixLength = (if n == "main" && ip == pkgs.lib.head ips.ip6 then 64 else 128); }) (ips.ip6 or [])) | |
88 | config.hostEnv.ips); | |
89 | defaultGateway = "176.9.151.65"; | |
90 | localCommands = '' | |
91 | # FIXME: Those commands were added by nixops and may not be | |
92 | # actually needed | |
93 | ip -6 addr add '2a01:4f8:160:3445::/64' dev 'eth0' || true | |
94 | ip -4 route change '176.9.151.64/27' via '176.9.151.65' dev 'eth0' || true | |
95 | ip -6 route add default via 'fe80::1' dev eth0 || true | |
96 | ''; | |
97 | nameservers = [ | |
98 | "213.133.98.98" | |
99 | "213.133.99.99" | |
100 | "213.133.100.100" | |
101 | "2a01:4f8:0:a0a1::add:1010" | |
102 | "2a01:4f8:0:a102::add:9999" | |
103 | "2a01:4f8:0:a111::add:9898" | |
104 | ]; | |
105 | }; | |
106 | ||
107 | imports = [ | |
108 | secrets.nixosModules.users-config-eldiron | |
109 | ./databases | |
110 | ./databases/mariadb.nix | |
111 | ./databases/openldap | |
112 | ./databases/postgresql.nix | |
113 | ./databases/redis.nix | |
114 | ||
115 | ||
116 | ./monitoring.nix | |
117 | ./ejabberd | |
118 | ./buildbot | |
119 | ./coturn.nix | |
120 | ./dns.nix | |
121 | ./duply_backup.nix | |
122 | ./gemini | |
123 | ./gitolite | |
124 | ||
125 | ./websites | |
126 | ./webstats | |
127 | ./irc.nix | |
128 | ./pub | |
129 | ./tasks | |
130 | ./ftp.nix | |
131 | ./mpd.nix | |
132 | ./vpn | |
133 | ]; | |
134 | ||
135 | myServices.buildbot.enable = true; | |
136 | myServices.databases.enable = true; | |
137 | myServices.gitolite.enable = true; | |
138 | myServices.monitoring.enable = true; | |
139 | myServices.irc.enable = true; | |
140 | myServices.pub.enable = true; | |
141 | myServices.tasks.enable = true; | |
142 | myServices.mpd.enable = true; | |
143 | myServices.dns.enable = true; | |
144 | myServices.websites.enable = true; | |
145 | myServices.gemini.enable = true; | |
146 | myServices.mail.enable = true; | |
147 | myServices.ejabberd.enable = true; | |
148 | myServices.vpn.enable = true; | |
149 | myServices.ftp.enable = true; | |
150 | ||
151 | myServices.chatonsProperties.hostings.infogerance = { | |
152 | file.datetime = "2022-08-27T18:50:00"; | |
153 | hosting = { | |
154 | name = "Infogérance"; | |
155 | description = "Administration de serveurs"; | |
156 | website = "https://www.immae.eu/"; | |
157 | logo = "https://assets.immae.eu/logo.jpg"; | |
158 | type = "HOSTEDSERVER"; | |
159 | status.level = "OK"; | |
160 | status.description = "OK"; | |
161 | registration.load = "OPEN"; | |
162 | install.type = "PACKAGE"; | |
163 | }; | |
164 | }; | |
165 | ||
1a64deeb IB |
166 | secrets.keys = { |
167 | "ldap/pam_pgsql" = { | |
168 | user = "root"; | |
169 | group = "root"; | |
170 | permissions = "0400"; | |
171 | text = '' | |
172 | database = immae | |
173 | user = immae_auth_read | |
174 | password = {{ .postgresql.immae_auth_read }} | |
175 | table = ldap_users | |
176 | user_column = login | |
177 | pw_type = function | |
ce983e8b | 178 | auth_query = SELECT ((mechanism = 'SSHA' AND password = encode(digest( %p || salt, 'sha1'), 'hex')) OR (mechanism = 'PLAIN' AND password = %p)) FROM ldap_users WHERE login = %u OR login || '@' || realm = %u |
1a64deeb IB |
179 | #pwd_query = WITH newsalt as (select gen_random_bytes(4)) UPDATE ldap_users SET password = encode(digest( %p || (SELECT * FROM newsalt), 'sha1'), 'hex'), salt = (SELECT * FROM newsalt), mechanism = 'SSHA' WHERE login = %u OR login || '@' || realm = %u |
180 | ''; | |
181 | }; | |
182 | ||
1a64deeb IB |
183 | "zrepl_backup/identity" = { |
184 | user = "root"; | |
185 | group = "root"; | |
186 | permissions = "0400"; | |
187 | text = config.myEnv.zrepl_backup.ssh_key.private; | |
188 | }; | |
189 | "zrepl/${name}.key" = { | |
190 | permissions = "0400"; | |
191 | text = config.myEnv.zrepl_backup.certs."${name}".key; | |
192 | user = "root"; | |
193 | group = "root"; | |
194 | }; | |
195 | } // builtins.listToAttrs (map (x: lib.attrsets.nameValuePair "zrepl/certificates/${x}.crt" { | |
196 | permissions = "0400"; | |
197 | text = config.myEnv.zrepl_backup.certs."${x}".certificate; | |
198 | user = "root"; | |
199 | group = "root"; | |
200 | }) (builtins.attrNames config.myEnv.zrepl_backup.certs)); | |
201 | ||
202 | programs.ssh.knownHosts.dilion = { | |
203 | extraHostNames = ["dilion.immae.eu"]; | |
204 | publicKey = config.myEnv.servers.dilion.hostKey; | |
205 | }; | |
206 | ||
207 | services.cron = { | |
208 | enable = true; | |
209 | mailto = "cron@immae.eu"; | |
210 | systemCronJobs = [ | |
211 | '' | |
212 | 0 0 * * * root journalctl -q --since="25 hours ago" -u postfix -t postfix/smtpd -g "immae.eu.*Recipient address rejected" | |
213 | # Need a way to blacklist properly | |
214 | # 0 0 * * * root journalctl -q --since="25 hours ago" -u postfix -t postfix/smtpd -g "NOQUEUE:" | |
215 | 0 0 * * * root journalctl -q --since="25 hours ago" -u postfix -t postfix/smtp -g "status=bounced" | |
216 | '' | |
217 | ]; | |
218 | }; | |
219 | ||
220 | environment.systemPackages = [ pkgs.bindfs ]; | |
221 | ||
222 | environment.etc."mdadm.conf" = { | |
223 | enable = true; | |
224 | mode = "0644"; | |
225 | user = "root"; | |
226 | text = "MAILADDR ${config.myEnv.monitoring.email}"; | |
227 | }; | |
228 | ||
229 | systemd.services.zrepl.path = [ pkgs.openssh ]; | |
230 | services.zrepl = { | |
231 | enable = true; | |
232 | settings = { | |
233 | jobs = [ | |
234 | { | |
235 | type = "push"; | |
236 | # must not change | |
237 | name = "backup-to-dilion"; | |
238 | filesystems."zpool/root" = true; | |
239 | filesystems."zpool/root/etc" = true; | |
240 | filesystems."zpool/root/var<" = true; | |
241 | connect = { | |
242 | address = "dilion.immae.eu:19000"; | |
243 | type = "tls"; | |
244 | server_cn = "dilion"; | |
245 | ca = config.secrets.fullPaths."zrepl/certificates/dilion.crt"; | |
246 | cert = config.secrets.fullPaths."zrepl/certificates/eldiron.crt"; | |
247 | key = config.secrets.fullPaths."zrepl/eldiron.key"; | |
248 | }; | |
249 | snapshotting = { | |
250 | type = "periodic"; | |
251 | prefix = "zrepl_"; | |
252 | interval = "1h"; | |
253 | # hooks = [ | |
254 | # { | |
255 | # type = "mysql-lock-tables"; | |
256 | # dsn = "${config.myEnv.zrepl_backup.mysql.user}:${config.myEnv.zrepl_backup.mysql.password}@tcp(localhost)/"; | |
257 | # filesystems."zpool/root/var" = true; | |
258 | # } | |
259 | # { | |
260 | # type = "command"; | |
261 | # path = pkgs.writeScript "redis-dump" '' | |
262 | # #!${pkgs.stdenv.shell} | |
263 | # ${pkgs.redis}/bin/redis-cli bgsave | |
264 | # ''; | |
265 | # err_is_fatal = false; | |
266 | # filesystems."zpool/root/var" = true; | |
267 | # } | |
268 | # ]; | |
269 | }; | |
270 | send.encrypted = true; | |
271 | pruning.keep_sender = [ | |
272 | { type = "regex"; regex = "^manual_.*"; } | |
273 | { type = "grid"; grid = "24x1h | 7x1d | 4x7d | 6x30d"; regex = "^zrepl_.*"; } | |
274 | ]; | |
275 | pruning.keep_receiver = [ | |
276 | { type = "regex"; regex = "^manual_.*"; } | |
277 | { type = "grid"; grid = "6x4h | 7x1d | 4x7d | 6x30d"; regex = "^zrepl_.*"; } | |
278 | ]; | |
279 | } | |
280 | { | |
281 | type = "source"; | |
282 | # must not change | |
283 | name = "backup-to-wd-zpool"; | |
284 | serve.type = "tls"; | |
285 | serve.listen = ":${builtins.toString config.myEnv.ports.zrepl_flony}"; | |
286 | serve.ca = config.secrets.fullPaths."zrepl/certificates/flony.crt"; | |
287 | serve.cert = config.secrets.fullPaths."zrepl/certificates/eldiron.crt"; | |
288 | serve.key = config.secrets.fullPaths."zrepl/eldiron.key"; | |
289 | serve.client_cns = [ "flony" ]; | |
290 | filesystems."zpool/root" = true; | |
291 | filesystems."zpool/root/etc" = true; | |
292 | filesystems."zpool/root/var<" = true; | |
293 | filesystems."zfast/root/var<" = true; | |
294 | send.encrypted = true; | |
295 | snapshotting.type = "manual"; | |
296 | } | |
297 | ]; | |
298 | }; | |
299 | }; | |
300 | ||
301 | environment.etc."fail2ban/filter.d/postgresql.conf".text = '' | |
302 | [Definition] | |
303 | failregex = <HOST> \S+ FATAL: password authentication failed for user .+$ | |
304 | <HOST> \S+ FATAL: PAM authentication failed for user.+$ | |
305 | <HOST> \S+ FATAL: no pg_hba.conf entry for host.+$ | |
306 | ''; | |
307 | environment.etc."fail2ban/filter.d/mysqld-auth.local".text = '' | |
308 | [Definition] | |
309 | _daemon = mysql[-\w]* | |
310 | ''; | |
311 | services.fail2ban.jails.dovecot = '' | |
312 | enabled = true | |
313 | ''; | |
314 | services.fail2ban.jails.postfix-sasl = '' | |
315 | enabled = true | |
316 | ''; | |
317 | services.fail2ban.jails.proftpd = '' | |
318 | enabled = true | |
319 | ''; | |
320 | services.fail2ban.jails.postgresql = '' | |
321 | enabled = true | |
322 | port = 5432 | |
323 | logpath = %(syslog_daemon)s | |
324 | backend = %(default_backend)s | |
325 | journalmatch = _SYSTEMD_UNIT=postgresql.service + _COMM=postgres | |
326 | ''; | |
327 | services.fail2ban.jails.mysqld-auth = '' | |
328 | enabled = true | |
329 | journalmatch = _SYSTEMD_UNIT=mysql.service + _COMM=mysqld | |
330 | ''; | |
331 | # This value determines the NixOS release with which your system is | |
332 | # to be compatible, in order to avoid breaking some software such as | |
333 | # database servers. You should change this only after NixOS release | |
334 | # notes say you should. | |
335 | # https://nixos.org/nixos/manual/release-notes.html | |
336 | system.stateVersion = "23.05"; # Did you read the comment? | |
337 | ||
338 | security.pam.services.ldap.text = '' | |
339 | # Authentication from ldap for pgsql | |
340 | auth required ${pkgs.pam_pgsql}/lib/security/pam_pgsql.so config_file=/var/secrets/ldap/pam_pgsql | |
341 | account required ${pkgs.pam_pgsql}/lib/security/pam_pgsql.so config_file=/var/secrets/ldap/pam_pgsql | |
342 | ''; | |
343 | services.saslauthd = { | |
344 | enable = true; | |
345 | mechanism = "pam"; | |
346 | }; | |
347 | environment.etc."sasl2/slapd.conf".text = '' | |
348 | mech_list: plain | |
349 | pwcheck_method: saslauthd | |
350 | saslauthd_path: /run/saslauthd/mux | |
351 | ''; | |
352 | } |