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