]> git.immae.eu Git - perso/Immae/Config/Nix.git/blame - modules/private/system/quatresaisons.nix
Add quatresaisons server
[perso/Immae/Config/Nix.git] / modules / private / system / quatresaisons.nix
CommitLineData
75489e72
IB
1{ privateFiles }:
2{ config, pkgs, lib, ... }:
3let
4 serverSpecificConfig = config.myEnv.serverSpecific.quatresaisons;
5 yarnModules = pkgs.yarn2nix-moretea.mkYarnModules rec {
6 name = "landing";
7 pname = name;
8 version = "v1.0.0";
9 packageJSON = "${pkgs.sources.webapps-landing}/package.json";
10 yarnLock = "${pkgs.sources.webapps-landing}/yarn.lock";
11 yarnNix = ../websites/tools/tools/landing/yarn-packages.nix;
12 };
13 toLanding = landingConfig: pkgs.stdenv.mkDerivation rec {
14 pname = "landing";
15 version = "v1.0.0";
16 src = pkgs.sources.webapps-landing;
17
18 buildInputs = [ yarnModules pkgs.yarn2nix-moretea.yarn ];
19 configurePhase = ''
20 ln -s ${yarnModules}/node_modules .
21 '';
22 buildPhase = ''
23 yarn build
24 '';
25 installPhase = ''
26 cp -a dist $out
27 cp -f ${landingConfig} $out/config.yml
28 ln -s service-worker.js $out/worker.js
29 '';
30 };
31 normalUsers = serverSpecificConfig.users;
32 sponsoredUser = pkgs.writeScriptBin "sponsored_user" ''
33 #!/usr/bin/env bash
34
35 set -euo pipefail
36 [ -z "''${SUDO_USER+x}" ] && echo "Must be run with sudo" && exit 1
37
38 mygroup=$(id -ng $SUDO_USER)
39
40 sponsored=$(getent group $mygroup | cut -d':' -f4)
41
42 echo "Sponsored users: ''${sponsored:-<none>}"
43
44 log () {
45 touch /var/log/sponsored_users
46 chmod go-rwx /var/log/sponsored_users
47 echo "`date` $mygroup $1" | LANG=C cat -v | tr '\012' ' ' | sed 's:$:\x0a:' >> /var/log/sponsored_users
48 }
49
50 create_user () {
51 log "creates $1: $2"
52 useradd -m -G users,$mygroup -g $mygroup -p '!' "$1"
53 touch /var/lib/nixos/sponsored_users
54 chmod go-rwx /var/lib/nixos/sponsored_users
55 echo "$mygroup $1 $2" >> /var/lib/nixos/sponsored_users
56 (${pkgs.openldap}/bin/ldapadd -c -D cn=root,dc=salle-s,dc=org \
57 -y /var/secrets/ldap/sync_password 2>/dev/null >/dev/null || true) <<EOF
58 dn: uid=$1,uid=$mygroup,ou=users,dc=salle-s,dc=org
59 objectClass: inetOrgPerson
60 cn: $1
61 description:: $(echo -n "$2" | base64)
62 sn: $1
63 uid: $1
64 EOF
65 while ! passwd "$1"; do
66 echo "please give an initial password"
67 done
68 }
69
70 delete_user () {
71 IFS=",";
72 for u in $sponsored; do
73 if [ "$u" = "$1" ]; then
74 log "deletes $1"
75 userdel -r "$1"
76 sed -i -e "/^$mygroup $1/d" /var/lib/nixos/sponsored_users
77 ${pkgs.openldap}/bin/ldapdelete -D cn=root,dc=salle-s,dc=org \
78 -y /var/secrets/ldap/sync_password \
79 "uid=$1,uid=$mygroup,ou=users,dc=salle-s,dc=org"
80 echo "deleted"
81 exit 0
82 fi
83 done
84
85 echo "User does not exist or does not belong to you";
86 exit 1
87 }
88
89 reset_password () {
90 IFS=",";
91 for u in $sponsored; do
92 if [ "$u" = "$1" ]; then
93 log "resets password for $1"
94 passwd "$1"
95 exit 0
96 fi
97 done
98
99 echo "User does not exist or does not belong to you";
100 exit 1
101 }
102
103 reset_ldap_password () {
104 if [ "$1" = "$mygroup" ]; then
105 log "resets web password"
106 ${pkgs.openldap}/bin/ldappasswd -D cn=root,dc=salle-s,dc=org \
107 -y /var/secrets/ldap/sync_password \
108 -S "uid=$mygroup,ou=users,dc=salle-s,dc=org"
109 else
110 IFS=",";
111 for u in $sponsored; do
112 if [ "$u" = "$1" ]; then
113 log "resets web password of $1"
114 ${pkgs.openldap}/bin/ldappasswd -D cn=root,dc=salle-s,dc=org \
115 -y /var/secrets/ldap/sync_password \
116 -S "uid=$1,uid=$mygroup,ou=users,dc=salle-s,dc=org"
117 exit 0
118 fi
119 done
120
121 echo "User does not exist or does not belong to you";
122 exit 1
123 fi
124 }
125
126 show_help () {
127 echo "sponsored_users create username realname"
128 echo " create a new sub-user attached to your account"
129 echo "sponsored_users (delete|reset_password) username"
130 echo " delete a sub-user attached to your account or reset his password"
131 echo "sponsored_users reset_ldap_password username"
132 echo " reset the web password of a sub-user or yourself"
133 }
134
135 [ -z "''${1+x}" -o -z "''${2+x}" ] && { show_help ; exit 0; }
136 action="$1"
137 username="$2"
138 shift
139 shift
140
141 case "$action" in
142 create)
143 [ -z "''${1+x}" ] && { show_help ; echo "Conformément à la charte https://4c.salle-s.org/charte veuillez préciser le nom réel du futur utilisateur du compte $username, juste pour root." ; exit 1; }
144 create_user "$username" "$*";
145 ;;
146 delete)
147 delete_user "$username";
148 ;;
149 reset_password)
150 reset_password "$username";
151 ;;
152 reset_ldap_password)
153 reset_ldap_password "$username";
154 ;;
155 *)
156 show_help
157 ;;
158 esac
159 '';
160in
161{
162 deployment = {
163 targetUser = "root";
164 targetHost = config.hostEnv.ips.main.ip4;
165 substituteOnDestination = true;
166 };
167
168 programs.ssh.package = pkgs.openssh.overrideAttrs(old: {
169 PATH_PASSWD_PROG = "/run/wrappers/bin/passwd";
170 buildFlags = [ "SSH_KEYSIGN=/run/wrappers/bin/ssh-keysign" ];
171 });
172
173 imports = builtins.attrValues (import ../..) ++
174 [ ./quatresaisons/nextcloud.nix ./quatresaisons/databases.nix ];
175
176 myEnv = import "${privateFiles}/environment.nix" // { inherit privateFiles; };
177
178 fileSystems = {
179 "/" = { device = "/dev/disk/by-uuid/865931b4-c5cc-439f-8e42-8072c7a30634"; fsType = "ext4"; };
180 "/home" = { device = "/dev/disk/by-uuid/76020bc4-5b88-464c-8952-9a59072c597f"; fsType = "ext4"; neededForBoot = true; };
181 "/boot" = { device = "/dev/disk/by-uuid/0fb8421a-61e5-4ed5-a795-4dd3a9b2152a"; fsType = "ext4"; };
182 "/var/lib" = { device = "/home/var_lib"; fsType = "none"; options = [ "defaults,bind" ]; };
183 };
184 powerManagement.cpuFreqGovernor = "powersave";
185 hardware.enableRedistributableFirmware = true;
186
187 boot.initrd.availableKernelModules = [ "ahci" "megaraid_sas" "sd_mod" ];
188 boot.initrd.kernelModules = [ "dm-snapshot" ];
189 boot.kernelModules = [ "kvm-intel" ];
190
191 boot.loader.grub.enable = true;
192 boot.loader.grub.version = 2;
193 boot.loader.grub.device = "/dev/sda";
194
195 networking.firewall.enable = false;
196 networking.firewall.allowedTCPPorts = [ 80 443 ];
197 networking.useDHCP = false;
198 networking.interfaces.eth0.useDHCP = true;
199 networking.interfaces.eth0.ipv6.addresses = [
200 { address = pkgs.lib.head config.hostEnv.ips.main.ip6; prefixLength = 64; }
201 ];
202 networking.defaultGateway6 = { address = "fe80::1"; interface = "eth0"; };
203 services.udev.extraRules = ''
204 ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="c8:60:00:8b:2f:f0", NAME="eth0"
205 '';
206 security.pam.services.chage.text = ''
207 auth sufficient pam_rootok.so
208 auth required pam_unix.so
209 account required pam_unix.so
210 session required pam_unix.so
211 password required pam_permit.so
212 '';
213 security.pam.services.sshd.makeHomeDir = true;
214 security.pam.services.passwd_default = {};
215 security.pam.services.passwd.text = ''
216 password required pam_cracklib.so enforce_for_root difok=2 minlen=8 dcredit=2 ocredit=2 retry=3
217 '' + config.security.pam.services.passwd_default.text;
218
219 system.activationScripts.ldapSync = {
220 deps = [ "secrets" "users" ];
221 text =
222 let
223 com = "-D cn=root,dc=salle-s,dc=org -y /var/secrets/ldap/sync_password";
224 in ''
225 # Add users
226 ${pkgs.openldap}/bin/ldapadd -c ${com} -f /var/secrets/ldap/ldaptree.ldif 2>/dev/null >/dev/null || true
227
228 # Remove obsolete users
229 ${pkgs.openldap}/bin/ldapsearch -LLL ${com} -s one -b "ou=users,dc=salle-s,dc=org" "uid" |\
230 grep "^uid" | ${pkgs.gnused}/bin/sed -e "s/uid: //" | while read ldapuser; do
231
232 for user in ${builtins.concatStringsSep " " (builtins.attrNames normalUsers)}; do
233 if [ "$user" = "$ldapuser" ]; then
234 continue 2
235 fi
236 done
237 ${pkgs.openldap}/bin/ldapdelete -r ${com} uid=$ldapuser,ou=users,dc=salle-s,dc=org
238 done
239
240 # Subusers
241 if [ -f /var/lib/nixos/sponsored_users ]; then
242 cat /var/lib/nixos/sponsored_users | while read mainUser subUser name; do
243 (${pkgs.openldap}/bin/ldapadd -c ${com} 2>/dev/null >/dev/null || true) <<EOF
244 dn: uid=$subUser,uid=$mainUser,ou=users,dc=salle-s,dc=org
245 objectClass: inetOrgPerson
246 cn: $subUser
247 description:: $(echo -n "$name" | base64)
248 sn: $subUser
249 uid: $subUser
250 EOF
251 done
252 fi
253 '';
254 };
255
256 secrets.keys = [
257 {
258 dest = "ldap/sync_password";
259 permissions = "0400";
260 text = serverSpecificConfig.ldap_sync_password;
261 }
262 {
263 dest = "ldap/ldaptree.ldif";
264 permissions = "0400";
265 text = serverSpecificConfig.ldap_service_users
266 + (builtins.concatStringsSep "\n" (lib.mapAttrsToList (n: v: ''
267 dn: uid=${n},ou=users,dc=salle-s,dc=org
268 objectClass: inetOrgPerson
269 cn: ${n}
270 description: ${v._meta.name or n} ${v._meta.email}
271 sn: ${n}
272 uid: ${n}
273 '') normalUsers));
274 }
275 ];
276
277 myServices.certificates.enable = true;
278 users.mutableUsers = true;
279 system.stateVersion = "21.03";
280 programs.zsh.enable = true;
281
282 users.motd = ''
283 Bienvenue sur quatresaisons.salle-s.org !
284
285 * Charte :
286 https://4c.salle-s.org/charte
287 * Gérer les utilisateurs unix additionnels :
288 sudo sponsored_user -h
289 * Applications web :
290 * tableau de bord : https://4c.salle-s.org/
291 * nextcloud : https://nextcloud.4c.salle-s.org/
292 '';
293
294 users.groups =
295 lib.mapAttrs (n: v: { gid = v.uid; }) normalUsers
296 // { wwwrun = { gid = config.ids.gids.wwwrun; }; };
297 users.users =
298 let
299 defaultNormal = n: {
300 group = n;
301 extraGroups = [ "users" ];
302 isNormalUser = true;
303 };
304 in
305 lib.mapAttrs (n: v: defaultNormal n // (lib.filterAttrs (k: _: k != "_meta") v)) normalUsers
306 // {
307 sponsored-separator = {
308 uid = 10000;
309 group = "users";
310 home = "/var/empty";
311 extraGroups = [];
312 isNormalUser = true;
313 createHome = false;
314 };
315 wwwrun = {
316 group = "wwwrun";
317 description = "Apache httpd user";
318 uid = config.ids.uids.wwwrun;
319 extraGroups = [ "keys" ];
320 };
321 };
322
323 system.activationScripts.usersPost = {
324 deps = [ "users" "groups" ];
325 text = builtins.concatStringsSep "\n" (lib.mapAttrsToList (n: v: ''
326 if getent shadow "${n}" | grep -q '^${n}:${v.initialHashedPassword or "!"}:1'; then
327 chage -d 0 "${n}"
328 [ '${v.initialHashedPassword or "!"}' = '!' ] && passwd -d "${n}"
329 fi
330 '') normalUsers);
331 };
332 security.sudo.extraRules = [
333 {
334 commands = [
335 { command = "${sponsoredUser}/bin/sponsored_user"; options = [ "NOPASSWD" ]; }
336 ];
337 users = builtins.attrNames normalUsers;
338 runAs = "root";
339 }
340 ];
341
342 environment.systemPackages = [
343 sponsoredUser
344 pkgs.git
345 pkgs.vim
346 pkgs.rsync
347 pkgs.strace
348 pkgs.home-manager
349 pkgs.telnet
350 pkgs.htop
351 pkgs.iftop
352 pkgs.bind.dnsutils
353 pkgs.httpie
354 pkgs.iotop
355 pkgs.whois
356 pkgs.ngrep
357 pkgs.tcpdump
358 pkgs.tshark
359 pkgs.tcpflow
360 pkgs.nmap
361 pkgs.p0f
362 pkgs.socat
363 pkgs.lsof
364 pkgs.psmisc
365 pkgs.openssl
366 pkgs.wget
367 pkgs.pv
368 pkgs.smartmontools
369 ];
370
371 services.websites.env.production = {
372 enable = true;
373 adminAddr = "httpd@immae.eu";
374 httpdName = "Prod";
375 modules = [ "http2" "deflate" "filter" ];
376 extraConfig = [
377 ''
378 LogFormat "%{Host}i:%p %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combinedVhost
379 Protocols h2 http/1.1
380 AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript
381 '' ];
382 ips =
383 let ips = config.hostEnv.ips.main;
384 in [ips.ip4] ++ (ips.ip6 or []);
385
386 fallbackVhost = {
387 certName = "quatresaisons";
388 hosts = [ "quatresaisons.immae.eu" ];
389 root = pkgs.runCommand "empty" {} "mkdir $out && touch $out/index.html";
390 extraConfig = [ "DirectoryIndex index.html" ];
391 };
392 vhostConfs.salle-s = {
393 certName = "quatresaisons";
394 addToCerts = true;
395 hosts = [ "salle-s.org" ];
396 root = toLanding ./quatresaisons/landing.yml;
397 extraConfig = [
398 ''
399 <Directory ${toLanding ./quatresaisons/landing.yml}>
400 AllowOverride None
401 Require all granted
402 DirectoryIndex index.html
403 </Directory>
404 ''
405 ];
406 };
407 vhostConfs.tools = {
408 certName = "quatresaisons";
409 addToCerts = true;
410 hosts = [ "4c.salle-s.org" "quatresaisons.salle-s.org" "quatre-saisons.salle-s.org" ];
411 root = toLanding ./quatresaisons/landing_4c.yml;
412 extraConfig = [
413 ''
414 Alias /charte ${serverSpecificConfig.charte_path}
415 <Directory ${serverSpecificConfig.charte_path}>
416 AllowOverride None
417 Require all granted
418 DirectoryIndex index.html index.txt
419 </Directory>
420
421 <Directory ${toLanding ./quatresaisons/landing_4c.yml}>
422 AllowOverride None
423 Require all granted
424 DirectoryIndex index.html
425 </Directory>
426 ''
427 ];
428 };
429 };
430 system.activationScripts.httpd = ''
431 install -d -m 0750 -o wwwrun -g wwwrun /var/lib/php
432 install -d -m 0750 -o wwwrun -g wwwrun /var/lib/php/sessions
433 '';
434
435 services.phpfpm = {
436 phpOptions = ''
437 session.save_path = "/var/lib/php/sessions"
438 post_max_size = 20M
439 ; 15 days (seconds)
440 session.gc_maxlifetime = 1296000
441 ; 30 days (minutes)
442 session.cache_expire = 43200
443 '';
444 settings = {
445 log_level = "notice";
446 };
447 };
448
449}