at 23.11-pre 8.5 kB view raw
1{ config, pkgs, lib, ... }: with lib; let 2 cfg = config.services.sogo; 3 4 preStart = pkgs.writeShellScriptBin "sogo-prestart" '' 5 touch /etc/sogo/sogo.conf 6 chown sogo:sogo /etc/sogo/sogo.conf 7 chmod 640 /etc/sogo/sogo.conf 8 9 ${if (cfg.configReplaces != {}) then '' 10 # Insert secrets 11 ${concatStringsSep "\n" (mapAttrsToList (k: v: ''export ${k}="$(cat "${v}" | tr -d '\n')"'') cfg.configReplaces)} 12 13 ${pkgs.perl}/bin/perl -p ${concatStringsSep " " (mapAttrsToList (k: v: '' -e 's/${k}/''${ENV{"${k}"}}/g;' '') cfg.configReplaces)} /etc/sogo/sogo.conf.raw > /etc/sogo/sogo.conf 14 '' else '' 15 cp /etc/sogo/sogo.conf.raw /etc/sogo/sogo.conf 16 ''} 17 ''; 18 19in { 20 options.services.sogo = with types; { 21 enable = mkEnableOption (lib.mdDoc "SOGo groupware"); 22 23 vhostName = mkOption { 24 description = lib.mdDoc "Name of the nginx vhost"; 25 type = str; 26 default = "sogo"; 27 }; 28 29 timezone = mkOption { 30 description = lib.mdDoc "Timezone of your SOGo instance"; 31 type = str; 32 example = "America/Montreal"; 33 }; 34 35 language = mkOption { 36 description = lib.mdDoc "Language of SOGo"; 37 type = str; 38 default = "English"; 39 }; 40 41 ealarmsCredFile = mkOption { 42 description = lib.mdDoc "Optional path to a credentials file for email alarms"; 43 type = nullOr str; 44 default = null; 45 }; 46 47 configReplaces = mkOption { 48 description = lib.mdDoc '' 49 Replacement-filepath mapping for sogo.conf. 50 Every key is replaced with the contents of the file specified as value. 51 52 In the example, every occurrence of LDAP_BINDPW will be replaced with the text of the 53 specified file. 54 ''; 55 type = attrsOf str; 56 default = {}; 57 example = { 58 LDAP_BINDPW = "/var/lib/secrets/sogo/ldappw"; 59 }; 60 }; 61 62 extraConfig = mkOption { 63 description = lib.mdDoc "Extra sogo.conf configuration lines"; 64 type = lines; 65 default = ""; 66 }; 67 }; 68 69 config = mkIf cfg.enable { 70 environment.systemPackages = [ pkgs.sogo ]; 71 72 environment.etc."sogo/sogo.conf.raw".text = '' 73 { 74 // Mandatory parameters 75 SOGoTimeZone = "${cfg.timezone}"; 76 SOGoLanguage = "${cfg.language}"; 77 // Paths 78 WOSendMail = "/run/wrappers/bin/sendmail"; 79 SOGoMailSpoolPath = "/var/lib/sogo/spool"; 80 // Enable CSRF protection 81 SOGoXSRFValidationEnabled = YES; 82 // Remove dates from log (jornald does that) 83 NGLogDefaultLogEventFormatterClass = "NGLogEventFormatter"; 84 // Extra config 85 ${cfg.extraConfig} 86 } 87 ''; 88 89 systemd.services.sogo = { 90 description = "SOGo groupware"; 91 after = [ "postgresql.service" "mysql.service" "memcached.service" "openldap.service" "dovecot2.service" ]; 92 wantedBy = [ "multi-user.target" ]; 93 restartTriggers = [ config.environment.etc."sogo/sogo.conf.raw".source ]; 94 95 environment.LDAPTLS_CACERT = "/etc/ssl/certs/ca-certificates.crt"; 96 97 serviceConfig = { 98 Type = "forking"; 99 ExecStartPre = "+" + preStart + "/bin/sogo-prestart"; 100 ExecStart = "${pkgs.sogo}/bin/sogod -WOLogFile - -WOPidFile /run/sogo/sogo.pid"; 101 102 ProtectSystem = "strict"; 103 ProtectHome = true; 104 PrivateTmp = true; 105 PrivateDevices = true; 106 ProtectKernelTunables = true; 107 ProtectKernelModules = true; 108 ProtectControlGroups = true; 109 RuntimeDirectory = "sogo"; 110 StateDirectory = "sogo/spool"; 111 112 User = "sogo"; 113 Group = "sogo"; 114 115 CapabilityBoundingSet = ""; 116 NoNewPrivileges = true; 117 118 LockPersonality = true; 119 RestrictRealtime = true; 120 PrivateMounts = true; 121 PrivateUsers = true; 122 MemoryDenyWriteExecute = true; 123 SystemCallFilter = "@basic-io @file-system @network-io @system-service @timer"; 124 SystemCallArchitectures = "native"; 125 RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6"; 126 }; 127 }; 128 129 systemd.services.sogo-tmpwatch = { 130 description = "SOGo tmpwatch"; 131 132 startAt = [ "hourly" ]; 133 script = '' 134 SOGOSPOOL=/var/lib/sogo/spool 135 136 find "$SOGOSPOOL" -type f -user sogo -atime +23 -delete > /dev/null 137 find "$SOGOSPOOL" -mindepth 1 -type d -user sogo -empty -delete > /dev/null 138 ''; 139 140 serviceConfig = { 141 Type = "oneshot"; 142 143 ProtectSystem = "strict"; 144 ProtectHome = true; 145 PrivateTmp = true; 146 PrivateDevices = true; 147 ProtectKernelTunables = true; 148 ProtectKernelModules = true; 149 ProtectControlGroups = true; 150 StateDirectory = "sogo/spool"; 151 152 User = "sogo"; 153 Group = "sogo"; 154 155 CapabilityBoundingSet = ""; 156 NoNewPrivileges = true; 157 158 LockPersonality = true; 159 RestrictRealtime = true; 160 PrivateMounts = true; 161 PrivateUsers = true; 162 PrivateNetwork = true; 163 SystemCallFilter = "@basic-io @file-system @system-service"; 164 SystemCallArchitectures = "native"; 165 RestrictAddressFamilies = ""; 166 }; 167 }; 168 169 systemd.services.sogo-ealarms = { 170 description = "SOGo email alarms"; 171 172 after = [ "postgresql.service" "mysqld.service" "memcached.service" "openldap.service" "dovecot2.service" "sogo.service" ]; 173 restartTriggers = [ config.environment.etc."sogo/sogo.conf.raw".source ]; 174 175 startAt = [ "minutely" ]; 176 177 serviceConfig = { 178 Type = "oneshot"; 179 ExecStart = "${pkgs.sogo}/bin/sogo-ealarms-notify${optionalString (cfg.ealarmsCredFile != null) " -p ${cfg.ealarmsCredFile}"}"; 180 181 ProtectSystem = "strict"; 182 ProtectHome = true; 183 PrivateTmp = true; 184 PrivateDevices = true; 185 ProtectKernelTunables = true; 186 ProtectKernelModules = true; 187 ProtectControlGroups = true; 188 StateDirectory = "sogo/spool"; 189 190 User = "sogo"; 191 Group = "sogo"; 192 193 CapabilityBoundingSet = ""; 194 NoNewPrivileges = true; 195 196 LockPersonality = true; 197 RestrictRealtime = true; 198 PrivateMounts = true; 199 PrivateUsers = true; 200 MemoryDenyWriteExecute = true; 201 SystemCallFilter = "@basic-io @file-system @network-io @system-service"; 202 SystemCallArchitectures = "native"; 203 RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6"; 204 }; 205 }; 206 207 # nginx vhost 208 services.nginx.virtualHosts."${cfg.vhostName}" = { 209 locations."/".extraConfig = '' 210 rewrite ^ https://$server_name/SOGo; 211 allow all; 212 ''; 213 214 # For iOS 7 215 locations."/principals/".extraConfig = '' 216 rewrite ^ https://$server_name/SOGo/dav; 217 allow all; 218 ''; 219 220 locations."^~/SOGo".extraConfig = '' 221 proxy_pass http://127.0.0.1:20000; 222 proxy_redirect http://127.0.0.1:20000 default; 223 224 proxy_set_header X-Real-IP $remote_addr; 225 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 226 proxy_set_header Host $host; 227 proxy_set_header x-webobjects-server-protocol HTTP/1.0; 228 proxy_set_header x-webobjects-remote-host 127.0.0.1; 229 proxy_set_header x-webobjects-server-port $server_port; 230 proxy_set_header x-webobjects-server-name $server_name; 231 proxy_set_header x-webobjects-server-url $scheme://$host; 232 proxy_connect_timeout 90; 233 proxy_send_timeout 90; 234 proxy_read_timeout 90; 235 proxy_buffer_size 4k; 236 proxy_buffers 4 32k; 237 proxy_busy_buffers_size 64k; 238 proxy_temp_file_write_size 64k; 239 client_max_body_size 50m; 240 client_body_buffer_size 128k; 241 break; 242 ''; 243 244 locations."/SOGo.woa/WebServerResources/".extraConfig = '' 245 alias ${pkgs.sogo}/lib/GNUstep/SOGo/WebServerResources/; 246 allow all; 247 ''; 248 249 locations."/SOGo/WebServerResources/".extraConfig = '' 250 alias ${pkgs.sogo}/lib/GNUstep/SOGo/WebServerResources/; 251 allow all; 252 ''; 253 254 locations."~ ^/SOGo/so/ControlPanel/Products/([^/]*)/Resources/(.*)$".extraConfig = '' 255 alias ${pkgs.sogo}/lib/GNUstep/SOGo/$1.SOGo/Resources/$2; 256 ''; 257 258 locations."~ ^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\\.(jpg|png|gif|css|js)$".extraConfig = '' 259 alias ${pkgs.sogo}/lib/GNUstep/SOGo/$1.SOGo/Resources/$2; 260 ''; 261 }; 262 263 # User and group 264 users.groups.sogo = {}; 265 users.users.sogo = { 266 group = "sogo"; 267 isSystemUser = true; 268 description = "SOGo service user"; 269 }; 270 }; 271}