diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | modules/private/environment.nix | 1 | ||||
-rw-r--r-- | modules/private/system/quatresaisons.nix | 449 | ||||
-rw-r--r-- | modules/private/system/quatresaisons/databases.nix | 146 | ||||
-rw-r--r-- | modules/private/system/quatresaisons/landing.yml | 32 | ||||
-rw-r--r-- | modules/private/system/quatresaisons/landing_4c.yml | 24 | ||||
-rw-r--r-- | modules/private/system/quatresaisons/nextcloud.nix | 141 | ||||
-rw-r--r-- | nixops/Makefile | 3 | ||||
-rw-r--r-- | nixops/default.nix | 2 | ||||
m--------- | nixops/secrets | 0 |
10 files changed, 800 insertions, 2 deletions
@@ -1,6 +1,6 @@ | |||
1 | subrecipes = setup nix-info edit_env | 1 | subrecipes = setup nix-info edit_env |
2 | subrecipes += ssh-eldiron ssh-backup-2 ssh-monitoring-1 | 2 | subrecipes += ssh-eldiron ssh-backup-2 ssh-monitoring-1 ssh-4c |
3 | subrecipes += debug build upload deploy deploy-reboot | 3 | subrecipes += debug build dry-run upload deploy deploy-reboot |
4 | subrecipes += list-generations delete-generations cleanup | 4 | subrecipes += list-generations delete-generations cleanup |
5 | ${subrecipes}: | 5 | ${subrecipes}: |
6 | @$(MAKE) --no-print-directory -C nixops/ $@ | 6 | @$(MAKE) --no-print-directory -C nixops/ $@ |
diff --git a/modules/private/environment.nix b/modules/private/environment.nix index a8799d2..e79feec 100644 --- a/modules/private/environment.nix +++ b/modules/private/environment.nix | |||
@@ -1171,6 +1171,7 @@ in | |||
1171 | }; | 1171 | }; |
1172 | }; | 1172 | }; |
1173 | }; | 1173 | }; |
1174 | serverSpecific = mkOption { type = attrsOf unspecified; description = "Server specific configuration"; }; | ||
1174 | websites = mkOption { | 1175 | websites = mkOption { |
1175 | description = "Websites configurations"; | 1176 | description = "Websites configurations"; |
1176 | type = submodule { | 1177 | type = submodule { |
diff --git a/modules/private/system/quatresaisons.nix b/modules/private/system/quatresaisons.nix new file mode 100644 index 0000000..395b604 --- /dev/null +++ b/modules/private/system/quatresaisons.nix | |||
@@ -0,0 +1,449 @@ | |||
1 | { privateFiles }: | ||
2 | { config, pkgs, lib, ... }: | ||
3 | let | ||
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 | ''; | ||
160 | in | ||
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 | } | ||
diff --git a/modules/private/system/quatresaisons/databases.nix b/modules/private/system/quatresaisons/databases.nix new file mode 100644 index 0000000..3491ae4 --- /dev/null +++ b/modules/private/system/quatresaisons/databases.nix | |||
@@ -0,0 +1,146 @@ | |||
1 | { pkgs, config, lib, ... }: | ||
2 | { | ||
3 | config = let | ||
4 | serverSpecificConfig = config.myEnv.serverSpecific.quatresaisons; | ||
5 | phpLdapAdmin = pkgs.webapps.phpldapadmin.override { config = "/var/secrets/webapps/tools-ldap"; }; | ||
6 | in { | ||
7 | services.postgresql.enable = true; | ||
8 | services.postgresql.package = pkgs.postgresql_12; | ||
9 | secrets.keys = [ | ||
10 | { | ||
11 | dest = "ldap/password"; | ||
12 | permissions = "0400"; | ||
13 | user = "openldap"; | ||
14 | group = "openldap"; | ||
15 | text = "rootpw ${serverSpecificConfig.ldap_root_pw}"; | ||
16 | } | ||
17 | { | ||
18 | dest = "webapps/tools-ldap"; | ||
19 | user = "wwwrun"; | ||
20 | group = "wwwrun"; | ||
21 | permissions = "0400"; | ||
22 | text = '' | ||
23 | <?php | ||
24 | $config->custom->appearance['show_clear_password'] = true; | ||
25 | $config->custom->appearance['hide_template_warning'] = true; | ||
26 | $config->custom->appearance['theme'] = "tango"; | ||
27 | $config->custom->appearance['minimalMode'] = false; | ||
28 | $config->custom->appearance['tree'] = 'AJAXTree'; | ||
29 | |||
30 | $servers = new Datastore(); | ||
31 | |||
32 | $servers->newServer('ldap_pla'); | ||
33 | $servers->setValue('server','name','LDAP'); | ||
34 | $servers->setValue('server','host','ldap://localhost'); | ||
35 | $servers->setValue('login','auth_type','cookie'); | ||
36 | $servers->setValue('login','bind_id','${serverSpecificConfig.ldap_phpldapadmin_dn}'); | ||
37 | $servers->setValue('login','bind_pass','${serverSpecificConfig.ldap_phpldapadmin_password}'); | ||
38 | $servers->setValue('appearance','pla_password_hash','ssha'); | ||
39 | $servers->setValue('login','attr','uid'); | ||
40 | $servers->setValue('login','fallback_dn',true); | ||
41 | ''; | ||
42 | } | ||
43 | ]; | ||
44 | |||
45 | users.users.openldap.extraGroups = [ "keys" ]; | ||
46 | services.openldap = { | ||
47 | enable = true; | ||
48 | dataDir = "/var/lib/openldap"; | ||
49 | urlList = [ "ldap://localhost" ]; | ||
50 | logLevel = "none"; | ||
51 | extraConfig = '' | ||
52 | pidfile /run/slapd/slapd.pid | ||
53 | argsfile /run/slapd/slapd.args | ||
54 | |||
55 | moduleload back_hdb | ||
56 | backend hdb | ||
57 | ''; | ||
58 | |||
59 | extraDatabaseConfig = '' | ||
60 | moduleload memberof | ||
61 | overlay memberof | ||
62 | |||
63 | moduleload syncprov | ||
64 | overlay syncprov | ||
65 | syncprov-checkpoint 100 10 | ||
66 | |||
67 | index objectClass eq | ||
68 | index uid pres,eq | ||
69 | #index uidMember pres,eq | ||
70 | index mail pres,sub,eq | ||
71 | index cn pres,sub,eq | ||
72 | index sn pres,sub,eq | ||
73 | index dc eq | ||
74 | index member eq | ||
75 | index memberOf eq | ||
76 | |||
77 | # No one must access that information except root | ||
78 | access to attrs=description | ||
79 | by * none | ||
80 | |||
81 | access to attrs=entry,uid filter="(uid=*)" | ||
82 | by dn.exact="${serverSpecificConfig.ldap_phpldapadmin_dn}" read | ||
83 | by * break | ||
84 | |||
85 | access to dn.subtree="ou=users,dc=salle-s,dc=org" | ||
86 | by dn.subtree="ou=services,dc=salle-s,dc=org" read | ||
87 | by * break | ||
88 | |||
89 | access to * | ||
90 | by self read | ||
91 | by anonymous auth | ||
92 | by * break | ||
93 | ''; | ||
94 | rootpwFile = "${config.secrets.location}/ldap/password"; | ||
95 | suffix = "dc=salle-s,dc=org"; | ||
96 | rootdn = "cn=root,dc=salle-s,dc=org"; | ||
97 | database = "hdb"; | ||
98 | }; | ||
99 | |||
100 | services.websites.env.production.modules = [ "proxy_fcgi" ]; | ||
101 | services.websites.env.production.vhostConfs.tools.extraConfig = [ | ||
102 | '' | ||
103 | Alias /ldap "${phpLdapAdmin}/htdocs" | ||
104 | <Directory "${phpLdapAdmin}/htdocs"> | ||
105 | DirectoryIndex index.php | ||
106 | <FilesMatch "\.php$"> | ||
107 | SetHandler "proxy:unix:${config.services.phpfpm.pools.ldap.socket}|fcgi://localhost" | ||
108 | </FilesMatch> | ||
109 | |||
110 | AllowOverride None | ||
111 | Require all granted | ||
112 | </Directory> | ||
113 | '' | ||
114 | ]; | ||
115 | services.phpfpm.pools.ldap = { | ||
116 | user = "wwwrun"; | ||
117 | group = "wwwrun"; | ||
118 | settings = | ||
119 | let | ||
120 | basedir = builtins.concatStringsSep ":" [ phpLdapAdmin "/var/secrets/webapps/tools-ldap" ]; | ||
121 | in { | ||
122 | "listen.owner" = "wwwrun"; | ||
123 | "listen.group" = "wwwrun"; | ||
124 | "pm" = "ondemand"; | ||
125 | "pm.max_children" = "60"; | ||
126 | "pm.process_idle_timeout" = "60"; | ||
127 | |||
128 | # Needed to avoid clashes in browser cookies (same domain) | ||
129 | "php_value[session.name]" = "LdapPHPSESSID"; | ||
130 | "php_admin_value[open_basedir]" = "${basedir}:/tmp:/var/lib/php/sessions/phpldapadmin"; | ||
131 | "php_admin_value[session.save_path]" = "/var/lib/php/sessions/phpldapadmin"; | ||
132 | }; | ||
133 | phpPackage = pkgs.php72; | ||
134 | }; | ||
135 | system.activationScripts.ldap = { | ||
136 | deps = [ "users" ]; | ||
137 | text = '' | ||
138 | install -m 0755 -o wwwrun -g wwwrun -d /var/lib/php/sessions/phpldapadmin | ||
139 | ''; | ||
140 | }; | ||
141 | systemd.services.phpfpm-ldap = { | ||
142 | after = lib.mkAfter [ "openldap.service" ]; | ||
143 | wants = [ "openldap.service" ]; | ||
144 | }; | ||
145 | }; | ||
146 | } | ||
diff --git a/modules/private/system/quatresaisons/landing.yml b/modules/private/system/quatresaisons/landing.yml new file mode 100644 index 0000000..cf4ba87 --- /dev/null +++ b/modules/private/system/quatresaisons/landing.yml | |||
@@ -0,0 +1,32 @@ | |||
1 | --- | ||
2 | # Homepage configuration | ||
3 | # See https://fontawesome.com/icons for icons options | ||
4 | |||
5 | title: "Websites dashboard" | ||
6 | subtitle: "Salle-S" | ||
7 | footer: false | ||
8 | #footer: '<p>Created with <span class="has-text-danger">❤️</span> with <a href="https://bulma.io/">bulma</a>, <a href="https://vuejs.org/">vuejs</a> & <a href="https://fontawesome.com/">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i class="fab fa-github-alt"></i></a></p>' # set false if you want to hide it. | ||
9 | |||
10 | # Optional navbar | ||
11 | # links: [] # Allows for navbar (dark mode, layout, and search) without any links | ||
12 | links: [] | ||
13 | |||
14 | # Services | ||
15 | # First level array represent a group. | ||
16 | # Leave only a "items" key if not using group (group name, icon & tagstyle are optional, section separation will not be displayed). | ||
17 | services: | ||
18 | - name: "Quatramaran" | ||
19 | items: | ||
20 | - name: "Roundcube" | ||
21 | logo: "assets/tools/roundcube.svg" | ||
22 | url: "https://quatramaran.salle-s.org/roundcube/" | ||
23 | - name: "Les dessous de paillasse" | ||
24 | url: "https://dessous-de-paillasse.salle-s.org" | ||
25 | - name: "Quatre Saisons" | ||
26 | items: | ||
27 | - name: "Charte d’utilisation" | ||
28 | icon: "fas fa-scroll" | ||
29 | url: "https://4c.salle-s.org/charte/" | ||
30 | - name: "Nextcloud" | ||
31 | logo: "assets/tools/nextcloud.png" | ||
32 | url: "https://nextcloud.4c.salle-s.org" | ||
diff --git a/modules/private/system/quatresaisons/landing_4c.yml b/modules/private/system/quatresaisons/landing_4c.yml new file mode 100644 index 0000000..0b9f6b6 --- /dev/null +++ b/modules/private/system/quatresaisons/landing_4c.yml | |||
@@ -0,0 +1,24 @@ | |||
1 | --- | ||
2 | # Homepage configuration | ||
3 | # See https://fontawesome.com/icons for icons options | ||
4 | |||
5 | title: "Websites dashboard" | ||
6 | subtitle: "Quatre saisons" | ||
7 | footer: false | ||
8 | #footer: '<p>Created with <span class="has-text-danger">❤️</span> with <a href="https://bulma.io/">bulma</a>, <a href="https://vuejs.org/">vuejs</a> & <a href="https://fontawesome.com/">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i class="fab fa-github-alt"></i></a></p>' # set false if you want to hide it. | ||
9 | |||
10 | # Optional navbar | ||
11 | # links: [] # Allows for navbar (dark mode, layout, and search) without any links | ||
12 | links: [] | ||
13 | |||
14 | # Services | ||
15 | # First level array represent a group. | ||
16 | # Leave only a "items" key if not using group (group name, icon & tagstyle are optional, section separation will not be displayed). | ||
17 | services: | ||
18 | - items: | ||
19 | - name: "Charte d’utilisation" | ||
20 | icon: "fas fa-scroll" | ||
21 | url: "https://4c.salle-s.org/charte/" | ||
22 | - name: "Nextcloud" | ||
23 | logo: "assets/tools/nextcloud.png" | ||
24 | url: "https://nextcloud.4c.salle-s.org" | ||
diff --git a/modules/private/system/quatresaisons/nextcloud.nix b/modules/private/system/quatresaisons/nextcloud.nix new file mode 100644 index 0000000..047d17e --- /dev/null +++ b/modules/private/system/quatresaisons/nextcloud.nix | |||
@@ -0,0 +1,141 @@ | |||
1 | { lib, pkgs, config, ... }: | ||
2 | let | ||
3 | nextcloud = pkgs.webapps.nextcloud.withApps (a: [ | ||
4 | a.apporder a.audioplayer a.bookmarks a.calendar a.carnet a.circles | ||
5 | a.contacts a.cookbook a.deck a.extract a.files_markdown | ||
6 | a.files_readmemd a.flowupload a.gpxedit a.gpxpod a.keeweb a.maps | ||
7 | a.metadata a.music a.notes a.ocsms a.passman a.polls a.spreed | ||
8 | a.social a.tasks | ||
9 | ]); | ||
10 | varDir = "/var/lib/nextcloud"; | ||
11 | phpFpm = rec { | ||
12 | basedir = builtins.concatStringsSep ":" ([ nextcloud varDir ] ++ nextcloud.apps); | ||
13 | pool = { | ||
14 | "listen.owner" = "wwwrun"; | ||
15 | "listen.group" = "wwwrun"; | ||
16 | "pm" = "ondemand"; | ||
17 | "pm.max_children" = "60"; | ||
18 | "pm.process_idle_timeout" = "60"; | ||
19 | |||
20 | "php_admin_value[output_buffering]" = "0"; | ||
21 | "php_admin_value[max_execution_time]" = "1800"; | ||
22 | "php_admin_value[zend_extension]" = "opcache"; | ||
23 | #already enabled by default? | ||
24 | #"php_value[opcache.enable]" = "1"; | ||
25 | "php_value[opcache.enable_cli]" = "1"; | ||
26 | "php_value[opcache.interned_strings_buffer]" = "8"; | ||
27 | "php_value[opcache.max_accelerated_files]" = "10000"; | ||
28 | "php_value[opcache.memory_consumption]" = "128"; | ||
29 | "php_value[opcache.save_comments]" = "1"; | ||
30 | "php_value[opcache.revalidate_freq]" = "1"; | ||
31 | "php_admin_value[memory_limit]" = "512M"; | ||
32 | |||
33 | "php_admin_value[open_basedir]" = "/run/wrappers/bin/sendmail:${basedir}:/proc/meminfo:/dev/urandom:/proc/self/fd:/tmp"; | ||
34 | "php_admin_value[session.save_path]" = "${varDir}/phpSessions"; | ||
35 | }; | ||
36 | }; | ||
37 | in { | ||
38 | config = { | ||
39 | services.postgresql.ensureDatabases = [ "nextcloud" ]; | ||
40 | services.postgresql.ensureUsers = [ | ||
41 | { name = "nextcloud"; ensurePermissions = { "DATABASE nextcloud" = "ALL PRIVILEGES"; }; } | ||
42 | ]; | ||
43 | services.websites.env.production.modules = [ "proxy_fcgi" ]; | ||
44 | |||
45 | services.websites.env.production.vhostConfs.cloud = { | ||
46 | certName = "quatresaisons"; | ||
47 | addToCerts = true; | ||
48 | hosts = ["nextcloud.4c.salle-s.org" ]; | ||
49 | root = nextcloud; | ||
50 | extraConfig = | ||
51 | [ | ||
52 | '' | ||
53 | SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 | ||
54 | <Directory ${nextcloud}> | ||
55 | AcceptPathInfo On | ||
56 | DirectoryIndex index.php | ||
57 | Options FollowSymlinks | ||
58 | Require all granted | ||
59 | AllowOverride all | ||
60 | |||
61 | <IfModule mod_headers.c> | ||
62 | Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains; preload" | ||
63 | </IfModule> | ||
64 | <FilesMatch "\.php$"> | ||
65 | CGIPassAuth on | ||
66 | SetHandler "proxy:unix:${config.services.phpfpm.pools.nextcloud.socket}|fcgi://localhost" | ||
67 | </FilesMatch> | ||
68 | |||
69 | </Directory> | ||
70 | '' | ||
71 | ]; | ||
72 | }; | ||
73 | services.websites.env.production.vhostConfs.cloud_wait = let | ||
74 | content = pkgs.writeText "contenu" '' | ||
75 | nextcloud est un service qui a besoin de pérennité du nom | ||
76 | "nextcloud.salle-s.org", on va peut-etre y arriver, c'est une | ||
77 | question de jours, voir le message informatique.internet:8017 | ||
78 | ''; | ||
79 | in { | ||
80 | certName = "quatresaisons"; | ||
81 | addToCerts = true; | ||
82 | hosts = ["nextcloud.salle-s.org" ]; | ||
83 | root = content; | ||
84 | extraConfig = | ||
85 | [ | ||
86 | '' | ||
87 | Alias / ${content} | ||
88 | '' | ||
89 | ]; | ||
90 | }; | ||
91 | |||
92 | users.users.root.packages = let | ||
93 | occ = pkgs.writeScriptBin "nextcloud-occ" '' | ||
94 | #! ${pkgs.stdenv.shell} | ||
95 | cd ${nextcloud} | ||
96 | NEXTCLOUD_CONFIG_DIR="${nextcloud}/config" \ | ||
97 | exec \ | ||
98 | sudo -u wwwrun ${pkgs.php74}/bin/php \ | ||
99 | -c ${pkgs.php74}/etc/php.ini \ | ||
100 | occ $* | ||
101 | ''; | ||
102 | in [ occ ]; | ||
103 | |||
104 | system.activationScripts.nextcloud = { | ||
105 | deps = [ "users" ]; | ||
106 | text = let | ||
107 | confs = lib.attrsets.mapAttrs (n: v: pkgs.writeText "${n}.json" (builtins.toJSON v)) nextcloud.otherConfig; | ||
108 | in | ||
109 | '' | ||
110 | install -m 0755 -o wwwrun -g wwwrun -d ${varDir} | ||
111 | install -m 0755 -o wwwrun -g wwwrun -d ${varDir}/config | ||
112 | install -m 0750 -o wwwrun -g wwwrun -d ${varDir}/phpSessions | ||
113 | ${builtins.concatStringsSep "\n" (lib.attrsets.mapAttrsToList (n: v: | ||
114 | "install -D -m 0644 -o wwwrun -g wwwrun -T ${v} ${varDir}/config/${n}.json" | ||
115 | ) confs)} | ||
116 | ''; | ||
117 | }; | ||
118 | services.phpfpm.pools.nextcloud = { | ||
119 | user = "wwwrun"; | ||
120 | group = "wwwrun"; | ||
121 | settings = phpFpm.pool; | ||
122 | phpPackage = pkgs.php74.withExtensions({ enabled, all }: enabled ++ [ all.redis all.apcu all.opcache all.imagick ]); | ||
123 | }; | ||
124 | |||
125 | services.cron = { | ||
126 | enable = true; | ||
127 | systemCronJobs = let | ||
128 | script = pkgs.writeScriptBin "nextcloud-cron" '' | ||
129 | #! ${pkgs.stdenv.shell} | ||
130 | export LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive | ||
131 | export PATH=/run/wrappers/bin:$PATH | ||
132 | ${pkgs.php74}/bin/php -d memory_limit=512M -f ${nextcloud}/cron.php | ||
133 | ''; | ||
134 | in [ | ||
135 | '' | ||
136 | */15 * * * * wwwrun ${script}/bin/nextcloud-cron | ||
137 | '' | ||
138 | ]; | ||
139 | }; | ||
140 | }; | ||
141 | } | ||
diff --git a/nixops/Makefile b/nixops/Makefile index cefd677..27d8d95 100644 --- a/nixops/Makefile +++ b/nixops/Makefile | |||
@@ -40,6 +40,9 @@ ssh-backup-2: | |||
40 | ssh-monitoring-1: | 40 | ssh-monitoring-1: |
41 | ./scripts/with_env bash -c 'ssh -i $$SSH_IDENTITY_FILE root@monitoring-1 $(SSH_ARGS)' | 41 | ./scripts/with_env bash -c 'ssh -i $$SSH_IDENTITY_FILE root@monitoring-1 $(SSH_ARGS)' |
42 | 42 | ||
43 | ssh-4c: | ||
44 | ./scripts/with_env bash -c 'ssh -i $$SSH_IDENTITY_FILE root@quatresaisons $(SSH_ARGS)' | ||
45 | |||
43 | debug: | 46 | debug: |
44 | ./scripts/with_env morph build --show-trace default.nix $(MORPH_ARGS) | 47 | ./scripts/with_env morph build --show-trace default.nix $(MORPH_ARGS) |
45 | 48 | ||
diff --git a/nixops/default.nix b/nixops/default.nix index 7c6dd38..f048c80 100644 --- a/nixops/default.nix +++ b/nixops/default.nix | |||
@@ -6,4 +6,6 @@ in | |||
6 | eldiron = import ../modules/private/system/eldiron.nix { inherit privateFiles; }; | 6 | eldiron = import ../modules/private/system/eldiron.nix { inherit privateFiles; }; |
7 | backup-2 = import ../modules/private/system/backup-2.nix { inherit privateFiles; }; | 7 | backup-2 = import ../modules/private/system/backup-2.nix { inherit privateFiles; }; |
8 | monitoring-1 = import ../modules/private/system/monitoring-1.nix { inherit privateFiles; }; | 8 | monitoring-1 = import ../modules/private/system/monitoring-1.nix { inherit privateFiles; }; |
9 | |||
10 | quatresaisons = import ../modules/private/system/quatresaisons.nix { inherit privateFiles; }; | ||
9 | } | 11 | } |
diff --git a/nixops/secrets b/nixops/secrets | |||
Subproject c91ba443bf2849b8fb81fc72818b77be77b3aab | Subproject 3475398eed524be65d0516cf2a648b20a2418f3 | ||