nix: revamp the hierarchy
authorJulien Moutinho <julm@autogeree.net>
Sat, 11 Jan 2020 04:16:31 +0000 (04:16 +0000)
committerJulien Moutinho <julm@autogeree.net>
Sat, 11 Jan 2020 04:17:49 +0000 (04:17 +0000)
84 files changed:
.envrc
.gitignore
.gitmodules
.lib/nixpkgs-sourcephile [deleted submodule]
Makefile
bootstrap/mermet/etc/dropbear/.gitignore [deleted file]
bootstrap/sévy/configuration.nix [deleted file]
bootstrap/sévy/hardware.nix [deleted file]
bootstrap/sévy/system.nix [deleted file]
build/modules.nix [deleted file]
build/modules/nix-plugins.nix [deleted file]
install/logical.nix [deleted file]
install/logical/friot.nix [deleted file]
install/logical/friot/discourse.nix [deleted file]
install/logical/friot/dovecot.nix [deleted file]
install/logical/friot/dovecot/autoconfig.nix [deleted file]
install/logical/friot/gitolite.nix [deleted file]
install/logical/friot/nginx.nix [deleted file]
install/logical/friot/nginx/gitweb.nix [deleted file]
install/logical/friot/nsd.nix [deleted file]
install/logical/friot/nsd/sourcephile.nix [deleted file]
install/logical/friot/openldap.nix [deleted file]
install/logical/friot/openldap/plurasoft.nix [deleted file]
install/logical/friot/openldap/schema/postfix-book.ldif [deleted file]
install/logical/friot/postfix.nix [deleted file]
install/logical/friot/postgresql.nix [deleted file]
install/logical/friot/postgrey.nix [deleted file]
install/logical/friot/redmine.nix [deleted file]
install/logical/friot/rmilter.nix [deleted file]
install/logical/friot/rspamd.nix [deleted file]
install/logical/friot/shorewall.nix [deleted file]
install/logical/machines.list [deleted file]
install/logical/mermet.nix [deleted file]
install/mermet/configuration.nix [deleted file]
install/mermet/logical.nix [deleted file]
install/mermet/logical/boot.nix [deleted file]
install/mermet/logical/networking.nix [deleted file]
install/mermet/physical.nix [deleted file]
install/overlays.nix [deleted file]
install/overlays/applications/version-management/redmine/redmine_git_hosting.nix [deleted file]
install/overlays/servers/mail/rspamd/service.nix [deleted file]
install/overlays/tools/networking/shorewall.nix [deleted file]
install/overlays/tools/networking/shorewall6.nix [deleted file]
install/overlays/tools/networking/shorewall6/service.nix [deleted file]
install/overlays/users-init.nix [deleted file]
install/physical.nix [deleted file]
install/physical/production.nix [deleted file]
install/physical/staging.nix [deleted file]
network.nix [new file with mode: 0644]
network/mermet.nix [new file with mode: 0644]
network/mermet/Makefile [moved from install/mermet/Makefile with 94% similarity]
network/mermet/configuration.nix [new file with mode: 0644]
network/mermet/deployment/lab.nix [new file with mode: 0644]
network/mermet/deployment/production.nix [new file with mode: 0644]
network/mermet/deployment/staging.nix [moved from install/mermet/physical/virtualbox.nix with 100% similarity]
network/mermet/hosting.nix [moved from install/mermet/hosting.nix with 100% similarity]
network/mermet/hosting/lab.nix [moved from install/mermet/hosting/lab.nix with 100% similarity]
network/mermet/hosting/ptt.nix [moved from install/mermet/hosting/ptt.nix with 100% similarity]
network/mermet/machine.nix [new file with mode: 0644]
network/mermet/machine/apu2e4.nix [moved from install/mermet/physical/apu2e4.nix with 95% similarity]
network/mermet/machine/apu2e4/sfdisk.txt [moved from install/mermet/physical/sfdisk.txt with 100% similarity]
network/mermet/system.nix [new file with mode: 0644]
network/mermet/system/zfs.nix [moved from install/mermet/logical/zfs.nix with 99% similarity]
nixos/defaults.nix [moved from install/mermet/logical/system.nix with 59% similarity]
nixos/defaults/readline/inputrc [moved from install/mermet/logical/etc/inputrc with 100% similarity]
nixos/modules.nix [new file with mode: 0644]
nixos/modules/services/mail/dovecot.nix [new file with mode: 0644]
nixos/modules/services/networking/domains.nix [moved from install/options.nix with 80% similarity]
nixos/modules/services/networking/shorewall.nix [moved from install/overlays/tools/networking/shorewall/service.nix with 99% similarity]
nixos/modules/services/security/x509.nix [new file with mode: 0644]
overlays.nix [new file with mode: 0644]
overlays/lib/filesystem.nix [new file with mode: 0644]
overlays/lib/strings.nix [moved from install/overlays/lib/strings.nix with 100% similarity]
overlays/servers/mail/dovecot.nix [moved from install/overlays/servers/mail/dovecot.nix with 100% similarity]
overlays/servers/mail/postfix.nix [moved from install/overlays/servers/mail/postfix.nix with 100% similarity]
pkgs/tools/networking/shorewall/default.nix [moved from install/overlays/tools/networking/shorewall/default.nix with 100% similarity]
shell.nix
shell.sh [moved from shell with 100% similarity]
shell/configuration.nix [new file with mode: 0644]
shell/configuration/gnupg.nix [moved from build/modules/gnupg.nix with 76% similarity]
shell/modules.nix [new file with mode: 0644]
shell/modules/development/libraries/nix-plugins.nix [new file with mode: 0644]
shell/modules/tools/security/gnupg.nix [new file with mode: 0644]
shell/modules/tools/security/gnupg/keyserver.pem [new file with mode: 0644]

diff --git a/.envrc b/.envrc
index 480333ac8231b909e56bb144f7fd923f9ca4c4be..d7a6ca62b0c6291783b1f513691c197af196b3c7 100644 (file)
--- a/.envrc
+++ b/.envrc
@@ -1,6 +1,10 @@
+# Build or reuse .cache/nix/
 source_env .lib/nix/envrc.sh
+
+# Rebuild the .cache/nix/ when a file changes in shell/
+# and its subdirectories.
 while read -r dir
   do watch_file "$dir"
   done <<EOF
-$(find build -type d)
+$(find shell/ -type d)
 EOF
index dc8cb951c2df6123f9659b8e2d7d837d5fa85376..862cb9d456a5ea6595bc0dae1c81dc2fe7ed93f7 100644 (file)
@@ -1,5 +1,6 @@
 .bin
 .cache/
+.config/nix/nix.conf
 .mnt/
 .sec/
 .old/
index f2dde927570088566fd5bbc417d8a76f2622bd92..b4caaa700aa5e14c601ae795e69a22be9ad1699b 100644 (file)
@@ -1,6 +1,3 @@
 [submodule "config/gitolite"]
        path = config/gitolite
        url = ./config/gitolite
-[submodule ".lib/nixpkgs-sourcephile"]
-       path = .lib/nixpkgs-sourcephile
-       url = ../src/nix/nixpkgs-sourcephile
diff --git a/.lib/nixpkgs-sourcephile b/.lib/nixpkgs-sourcephile
deleted file mode 160000 (submodule)
index 4e671ef..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 4e671efa83a5c074730f7ea165b1b37eb130fee6
index 21d5a920fca055cde39b1984e6fd007ee4c26d78..2e25aa7aca4793d4124b71062ac904636ecb6e0b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ all: init
 
 include .lib/nix/Makefile.make
 include .lib/nixops/Makefile.make
-include bootstrap/mermet/Makefile.make
+include machines/mermet/Makefile
 
 #
 ## init
@@ -16,3 +16,20 @@ build:
 
 init: build
        result/bin/init
+
+#sudo zfs mount rpool/ROOT/$(machine)
+#sudo zfs create -o canmount=noauto -o mountpoint=legacy bpool/BOOT/$(machine)
+#sudo zfs mount bpool/BOOT/$(machine)
+#blkid -t TYPE=ext2 $(disk)-part1; test $$? != 2 || \
+#sudo $$(which mkfs.ext2) $(disk)-part1
+#sudo $$(which tune2fs) -L mermet-root -m 5 $(disk)-part1
+#blkid -t TYPE=swap $(disk)-part2; test $$? != 2 || \
+#sudo $$(which mkswap) -L mermet-swap $(disk)-part2
+#blkid -t TYPE=ext4 $(disk)-part3; test $$? != 2 || \
+#sudo $$(which mkfs.ext4) $(disk)-part3
+#sudo $$(which tune2fs) -L mermet-root -m 5 $(disk)-part3
+#blkid -t TYPE=ext4 $(disk)-part4; test $$? != 2 || \
+#sudo $$(which mkfs.ext4) $(disk)-part4
+#sudo $$(which tune2fs) -L mermet-data -m 0 $(disk)-part4
+#sudo $$(which gdisk) -l $(disk)
+#sudo $$(which mdadm) --create /disk/md/$(machine) --level raid1 --raid-devices=2 --metadata=1.2 $(disk) missing
diff --git a/bootstrap/mermet/etc/dropbear/.gitignore b/bootstrap/mermet/etc/dropbear/.gitignore
deleted file mode 100644 (file)
index 5e74a2f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-*-key
diff --git a/bootstrap/sévy/configuration.nix b/bootstrap/sévy/configuration.nix
deleted file mode 100644 (file)
index 80b157c..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-# Fichier principal de configuration de NixOS
-# TODO: penser à git commit les modifications.
-#
-# Commandes usuelles pour configurer NixOS :
-# - nix-upgrade  : Applique au système la présente configuration.
-#                  NOTE: à faire pour prendre en compte toute modification,
-#                  comme l’ajout ou la suppression d’un logiciel.
-#
-# - nix-rollback : Applique au système la précédente configuration disponible.
-#                  NOTE: utile pour retrouver un état fonctionnel
-#                  si problème avec la nouvelle configuration.
-#
-# - nix-history  : Liste les anciennes configurations encore diponibles.
-#
-# - nix-clean    : Supprime les anciennes configurations
-#                  (vers lesquelles faire un nix-rollback)
-#                  et libère l’espace utilisé par les paquets inutilisés
-#                  (avec le ramasse-miettes, aka. garbage collector).
-#                  NOTE: à faire si le système convient depuis un moment
-#                  ou si manque d’espace sur la partition racine.
-#
-# - nix-catalog  : Liste les catalogues des paquets disponibles.
-# 
-# - nix-update   : Récupère les mise-à-jours depuis les catalogues des paquets disponibles.
-#                  NOTE: à faire de temps en temps avant un nix-upgrade.
-#
-# - nix-upstream : Affiche la version de NixOS stabilisée bi-annuellement
-#                  (de mars ou de septembre) et utilisée
-#                  pour récupérer le catalogue des paquets (avec nix-update).
-#                  NOTE: À changer grosso-modo en avril et en octobre,
-#                  par exemple en avril 2019 :
-#                  $ sudo nix-channel --remove nixos
-#                  $ sudo nix-channel --add https://nixos.org/channels/nixos-19.03 nixos
-#                  et en octobre 2019 :
-#                  $ sudo nix-channel --remove nixos
-#                  $ sudo nix-channel --add https://nixos.org/channels/nixos-19.09 nixos
-#                  
-#                  C’est une manip' qui pourrait être évitée en suivant
-#                  https://nixos.org/channels/nixos-unstable,
-#                  mais c’est plus... stable comme ça.
-
-# Entête usuelle d”une configuration de NixOS.
-{ config, pkgs, ... }: {
-
-# Import d’autres fichiers de configuration. 
-imports =
-  [ ./hardware.nix # Fichier de configuration du matériel.
-                   # NOTE: à modifier seulement en cas de changement
-                   # d’ordinateur ou de disque dur.
-    ./system.nix   # Fichier de configuration de base du système.
-                   # NOTE: pour la configuration experte.
-  ];
-
-# Configuration de l’user sevy
-users.users.sevy = {
-  isNormalUser = true;
-  uid = 1000;
-  extraGroups = [
-    "wheel" # Permet d’utiliser sudo.
-    "networkmanager"
-  ];
-};
-
-# Liste de programmes à installer
-environment.systemPackages = with pkgs; [
-  # Internet
-  amule
-  chromium
-  firefox
-  liferea
-  transmission-gtk
-  thunderbird
-  
-  # Bureautique 
-  #djview
-  evince
-  geeqie
-  gimp
-  git
-  gnome3.gnome-calculator
-  hledger
-  imagemagick # convert, mogrify, ...
-  parcellite # Presse papier
-  libreoffice
-  vimHugeX # gvim
-  xsane # scan
-  
-  # Sécurité
-  gnupg
-  networkmanager-openvpn
-  pass # Trousseau de clés
-       # - Créer     : pass generate example.com/mon-compte@mon-mail.coop 24
-       # - Récupérer : pass -c       example.com/mon-compte@mon-mail.coop
-  #torbrowser
-  firefoxPackages.tor-browser
-  
-  # Multimédia
-  libdvdcss # Clés pour lire les DVD
-  mplayer
-  vlc
-  #youtubeDL
-  
-  # Jeux
-  #freeciv_gtk
-];
-# Le nom du paquet est suggéré en essayant
-# de lancer dans un terminal une commande qu’il fournit,
-# par exemple :
-#   $ inkscape
-#   The program ‘inkscape’ is currently not installed. You can install it by typing:
-#     nix-env -iA nixos.inkscape
-#
-# NOTE: installer avec nix-env est possible
-# mais cela revient à fonctionner comme avec apt install sous Debian
-# c’est-à-dire à perdre la reproductibilité que fournit
-# la déclaration complète de ce que l’on veut en l’écrivant
-# dans le présent fichier de configuration.
-# Mais ça peut être pertinent pour tester de manière jetable.
-#
-# Alternativement, on peut chercher un paquet ainsi :
-#   $ nix search inkscape
-#   * nixpkgs.inkscape (inkscape)
-#     Vector graphics editor
-
-# VirtualBox
-virtualisation.virtualbox.host.enable = true;
-users.extraUsers.sevy.extraGroups = ["vboxusers"];
-}
diff --git a/bootstrap/sévy/hardware.nix b/bootstrap/sévy/hardware.nix
deleted file mode 100644 (file)
index 6091594..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-{ config, lib, pkgs, ... }: {
-imports =
-  [ <nixpkgs/nixos/modules/installer/scan/not-detected.nix>
-  ];
-
-# https://bugzilla.kernel.org/show_bug.cgi?id=110941
-boot.kernelParams = [ "intel_pstate=no_hwp" ];
-boot.kernelModules = [ "kvm-intel" ];
-boot.extraModulePackages = [
-  config.boot.kernelPackages.exfat-nofuse
-];
-boot.extraModprobeConfig = ''
-  options thinkpad_acpi fan_control=1
-'';
-
-boot.loader.grub = {
-  enable  = true;
-  version = 2;
-  device  = "/dev/disk/by-id/ata-Samsung_SSD_860_EVO_250GB_S3YJNX0K863141Y";
-  #enableCryptodisk = true;
-};
-
-boot.initrd.availableKernelModules = [
-  "aes_x86_64"
-  "aesni_intel"
-  "ahci"
-  "cryptd"
-  "dm_crypt"
-  "dm_mod"
-  "drbg"
-  "ehci_pci"
-  "gf128mul"
-  "hmac"
-  "sd_mod"
-  "sha256_generic"
-  "uas"
-  "xts"
-  ];
-boot.initrd.luks.cryptoModules = ["aes_x86_64" "sha256" "sha1" "xts"];
-boot.initrd.luks.devices = [
-  {
-    name   = "crypted";
-    device = "/dev/disk/by-id/ata-Samsung_SSD_860_EVO_250GB_S3YJNX0K863141Y-part2";
-    allowDiscards = true;
-    #preLVM = false;
-  }
-];
-
-boot.kernel.sysctl = {
-  "vm.swappiness" = 10;
-  "vm.vfs_cache_pressure" = 50;
-};
-
-fileSystems."/boot" =
-  { device = "/dev/disk/by-uuid/8f84431f-f646-4da9-9f34-af0f7d9bb914";
-    fsType = "ext4";
-  };
-
-fileSystems."/" =
-  {
-    device  = "/dev/disk/by-uuid/30c38c75-4fc7-4185-a7db-b5e2c989e853";
-    fsType  = "ext4";
-    options = [ "noatime" "nodiratime" "discard" ];
-  };
-fileSystems."/home" =
-  { device  = "/dev/disk/by-uuid/62ca342a-9c6e-47bf-9eac-bc8c28b491bb";
-    fsType  = "ext4";
-    options = [ "noatime" "nodiratime" "discard" ];
-  };
-swapDevices =
-  [ { device = "/dev/disk/by-uuid/27af6bf3-5884-49aa-aa5b-dae43c2fd634"; }
-  ];
-
-nix.maxJobs = lib.mkDefault 4;
-powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand";
-}
diff --git a/bootstrap/sévy/system.nix b/bootstrap/sévy/system.nix
deleted file mode 100644 (file)
index 6a9d51f..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-{ config, pkgs, ... }: {
-
-nix = {
-  extraOptions = ''
-    auto-optimise-store = true
-  '';
-  gc = {
-    automatic = true;
-    dates = "weekly";
-    options = "--delete-older-than 30d";
-  };
-};
-
-nixpkgs.config = {
-  allowUnfree = false;
-};
-
-time.timeZone = "Europe/Paris";
-
-i18n = { # internationalization
-  consoleFont   = "Lat2-Terminus16";
-  consoleKeyMap = "fr";
-  defaultLocale = "fr_FR.UTF-8";
-};
-
-networking = {
-  networkmanager = {
-    enable = true;
-  };
-  firewall = {
-    enable = true;
-    allowedTCPPorts = [
-      51413 # transmission-gtk
-      4662 # edonkey
-    ];
-    allowedUDPPorts = [
-      51413 # transmission-gtk
-      4667 # edonkey
-      4672 # edonkey
-    ];
-  };
-};
-
-sound.enable = true;
-hardware.pulseaudio.enable = true;
-
-environment = {
-  variables = {
-    EDITOR = "gvim";
-    PAGER  = "less -R";
-  }; 
-  systemPackages = with pkgs; [
-    acpi
-    binutils
-    coreutils
-    cryptsetup
-    curl
-    direnv
-    dstat
-    e2fsprogs
-    elementary-xfce-icon-theme
-    file
-    glib # gio
-    gnome3.defaultIconTheme
-    gnome3.file-roller
-    gnome3.gnome-keyring 
-    gnome3.seahorse
-    gvfs
-    gnumake
-    gnupg
-    gparted
-    ffmpeg
-    hicolor-icon-theme
-    htop
-    less
-    libfaketime
-    lsof
-    man
-    miniupnpc
-    ncdu
-    ncurses
-    networkmanagerapplet
-    ntfs3g
-    #pasystray
-    pavucontrol
-    powertop
-    procps
-    python
-    redshift
-    sudo
-    tig
-    tmux
-    tree
-    utillinux
-    wget
-    which
-    xdg_utils
-    xfce.thunar-volman
-  ];
-};
-
-programs = {
-  bash = {
-    interactiveShellInit = ''
-      bind '"\e[A":history-search-backward'
-      bind '"\e[B":history-search-forward'
-      
-      # Ignore duplicate commands, ignore commands starting with a space
-      export HISTCONTROL=erasedups:ignorespace
-      export HISTSIZE=42000
-      # Append to the history instead of overwriting (good for multiple connections)
-      shopt -s histappend
-      fan () {
-        if [ $# -gt 0 ]
-        then sudo tee /proc/acpi/ibm/fan <<<"level $1"
-        else grep '^\(level\|speed\):' /proc/acpi/ibm/fan
-        fi
-        acpi -t
-      }
-    '';
-    shellAliases = {
-      cl = "clear";
-      l  = "ls -alh";
-      ll = "ls -l";
-      ls = "ls --color=tty";
-  
-      s="sudo systemctl";
-      s-u="systemctl --user";
-      
-      nix-clean="sudo nix-collect-garbage -d";
-      nix-catalog="sudo nix-channel --list";
-      nix-history="sudo nix-env --list-generations --profile /nix/var/nix/profiles/system";
-      nix-rollback="sudo nixos-rebuild switch --rollback";
-      nix-update="sudo nix-channel --update";
-      nix-upgrade="sudo nixos-rebuild switch";
-      nix-upstream="sudo nix-channel --list";
-      nix-config="gvim ~/.config/nixos/*.nix";
-    };
-  };
-
-  dconf.enable = true;
-
-  gnupg.agent = {
-    enable = true;
-    enableSSHSupport = true;
-  };
-
-  mtr.enable = true;
-};
-
-services = {
-  avahi = {
-    enable  = true;
-    nssmdns = true;
-  };
-
-  dbus = {
-    packages = [ pkgs.gnome3.dconf ];
-  };
-
-  gnome3 = {
-    gvfs = {
-      enable = true;
-    };
-  };
-
-  physlock = {
-    enable = true;
-    allowAnyUser = true;
-    # NOTE: xfconf-query -c xfce4-session -p /general/LockCommand -s "physlock" --create -t string
-  };
-
-  printing = {
-    enable = true;
-    drivers = [
-      pkgs.gutenprint
-    ];
-  };
-
-  xserver = {
-    enable = true;
-    layout = "fr";
-    xkbOptions = "eurosign:e";
-    libinput.enable = true;
-
-    desktopManager = {
-      default = "xfce";
-      xfce = {
-        enable = true;
-        thunarPlugins = [
-          pkgs.xfce.thunar-archive-plugin
-        ];
-      };
-      xterm.enable = false;
-    };
-
-  };
-};
-
-# This value determines the NixOS release with which your system is to be
-# compatible, in order to avoid breaking some software such as database
-# servers. You should change this only after NixOS release notes say you should.
-system.stateVersion = "19.09"; # Did you read the comment?
-}
diff --git a/build/modules.nix b/build/modules.nix
deleted file mode 100644 (file)
index d0c3e6c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{config, ...}:
-{
-  imports = [
-    modules/gnupg.nix
-    modules/nix-plugins.nix
-  ];
-  config = {
-    init = {
-      enable = true;
-    };
-  };
-}
diff --git a/build/modules/nix-plugins.nix b/build/modules/nix-plugins.nix
deleted file mode 100644 (file)
index 9afbcf5..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{ config, ... }:
-{
-  config = {
-    nix-plugins = {
-      enable = true;
-    };
-  };
-}
diff --git a/install/logical.nix b/install/logical.nix
deleted file mode 100644 (file)
index def0af8..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  network = {
-    description = "Sourcephile";
-    #enableRollback = true;
-  };
-
-  defaults = {
-    imports = [ ];
-  };
-
-  # machines
-  #friot = import logical/friot.nix;
-  mermet = import mermet/configuration.nix;
-}
diff --git a/install/logical/friot.nix b/install/logical/friot.nix
deleted file mode 100644 (file)
index e121543..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-{pkgs, lib, config, system, ...}:
-let inherit (builtins.extraBuiltins) pass;
-    inherit (lib) types;
-    inherit (config) networking;
-    inherit (config.services) dovecot2;
-    userPass = name: pass "${networking.domainBase}/${networking.hostName}/login/${name}";
-in {
-imports = [
-  <nixpkgs-sourcephile/install/modules.nix>
-  ../options.nix
-  ../overlays/tools/networking/shorewall/service.nix
-  ../overlays/tools/networking/shorewall6/service.nix
-  ../overlays/servers/mail/rspamd/service.nix
-  friot/dovecot.nix
-  friot/gitolite.nix
-  friot/nginx.nix
-  friot/nsd.nix
-  friot/postfix.nix
-  friot/postgrey.nix
-  friot/postgresql.nix
-  #friot/rmilter.nix
-  friot/rspamd.nix
-  #friot/redmine.nix
-  friot/shorewall.nix
-  friot/openldap.nix
-  #friot/discourse.nix
-];
-config = {
-  nix = {
-    extraOptions = ''
-      auto-optimise-store = true
-    '';
-    gc = {
-      automatic = true;
-      dates = "weekly";
-      options = "--delete-older-than 30d";
-    };
-  };
-
-  nixpkgs = {
-    config = {
-      allowUnfree = false;
-      packageOverrides = pkgs: {
-        postfix = pkgs.postfix.override {
-          withLDAP = true;
-        };
-      };
-    };
-    overlays = import ../overlays.nix;
-  };
-
-  boot = {
-    initrd = {
-      network = {
-        enable = config.deployment.targetEnv != "virtualbox";
-        ssh = {
-          enable = true;
-          authorizedKeys = [ (pass "${networking.domain}/ssh/pub/julm") ];
-        };
-      };
-    };
-    kernel = {
-      sysctl = {
-        "vm.swappiness" = 10;
-        "vm.vfs_cache_pressure" = 50;
-      };
-    };
-  };
-
-  time = {
-    timeZone = "Europe/Paris";
-  };
-
-  i18n = {
-    consoleFont   = "Lat2-Terminus16";
-    consoleKeyMap = "fr";
-    defaultLocale = "fr_FR.UTF-8";
-  };
-
-  networking = {
-    domainBase    = "sourcephile";
-    domain        = "${networking.domainBase}.fr";
-    domainAliases = [
-     #"${networking.domainBase}.coop"
-    ];
-  };
-
-  users = {
-    mutableUsers = false;
-    users = {
-        root.initialPassword = userPass "root";
-        root.password        = config.users.users.root.initialPassword;
-        julm = {
-          uid             = 1000;
-          extraGroups     = [ "sudo" ];
-          description     = "Julien Moutinho";
-          home            = "/home/julm";
-          shell           = lib.mkDefault config.users.defaultUserShell;
-          group           = "users"; # FIXME: unknown group
-          initialPassword = userPass "julm";
-          password        = config.users.users.julm.initialPassword;
-        };
-    };
-    groups = {
-      julm = {
-        gid = config.users.users.julm.uid;
-      };
-    };
-  };
-
-  documentation.nixos = {
-    enable = false; # NOTE: useless on this machine, and CPU intensive.
-  };
-
-  services = {
-    redis = {
-      enable = true;
-    };
-    disnix = {
-      enable = false;
-    };
-    openssh = {
-      enable = true;
-      extraConfig = ''
-      '';
-    };
-    gitea = {
-      enable = false;
-    };
-    sssd = {
-      enable = false;
-    };
-    dovecot2 = {
-      #debug = true;
-    };
-    journald = {
-      extraConfig = ''
-        SystemMaxUse=50M
-      '';
-    };
-    x509 = {
-      domains =
-        lib.concatMap
-         (dom: map (sub: "${sub}.${dom}")
-           ["www" "git" "mail"])
-         ([networking.domain] ++ networking.domainAliases)
-        ++ networking.domainAliases;
-    };
-    #postfix.aliases = {
-    #        "root@${networking.domain}" = [ "test@${networking.domain}" ];
-    #  "postmaster@${networking.domain}" = [ "test@${networking.domain}" ];
-    #       "abuse@${networking.domain}" = [ "test@${networking.domain}" ];
-    #};
-    #dovecot2.domains = {
-    #  "${networking.domain}" = {
-    #    accounts = {
-    #      julm = {
-    #        password = pass "${networking.domain}/mail/julm";
-    #         # "${networking.domain}/dovecot2/julm";
-    #           #  "{SSHA512}uyjL1KYx4z7HpfNvnKzuVxpMLD2KVueGGBvOcj7AF1EZCTVhT++IIKUVOC4xpZtWdqVD0OVmZqgYr2qpn/3t3Aj4oU0=";
-    #        aliases  = ["julien.moutinho@${networking.domain}"];
-    #        quota    = "512M";
-    #      };
-    #      test = {
-    #        password = pass "${networking.domain}/mail/test";
-    #         # "${networking.domain}/dovecot2/test";
-    #           #  "{SSHA512}uyjL1KYx4z7HpfNvnKzuVxpMLD2KVueGGBvOcj7AF1EZCTVhT++IIKUVOC4xpZtWdqVD0OVmZqgYr2qpn/3t3Aj4oU0=";
-    #        aliases  = ["test-alias@${networking.domain}"];
-    #        quota    = "512M";
-    #      };
-    #    };
-    #  };
-    #};
-  };
-
-  environment = {
-    systemPackages = with pkgs; [
-      htop
-      tree
-      vim
-      tcpdump
-      #mysql
-      #procmail
-      postgrey
-      duplicity
-      pypolicyd-spf
-      unbound
-      dropbear
-      cryptsetup
-      openssl
-      postgresql
-      openldap
-      #mail
-      #sympa
-      multitail
-      dnsutils
-      inetutils
-      binutils
-      mailutils
-      ncdu
-      cgit
-      #sssd
-      #docker
-      #nss_ldap
-      #nss_pam_ldapd
-      tmux
-      socat
-      users-init
-      which
-    ];
-    etc."inputrc".text = ''
-      # /etc/inputrc - global inputrc for libreadline
-      # See readline(3readline) and `info rluserman' for more information.
-
-      # Be 8 bit clean.
-      set input-meta on
-      set output-meta on
-
-      # To allow the use of 8bit-characters like the german umlauts, uncomment
-      # the line below. However this makes the meta key not work as a meta key,
-      # which is annoying to those which don't need to type in 8-bit characters.
-
-      # set convert-meta off
-
-      # try to enable the application keypad when it is called.  Some systems
-      # need this to enable the arrow keys.
-      # set enable-keypad on
-
-      # see /usr/share/doc/bash/inputrc.arrows for other codes of arrow keys
-
-      # do not bell on tab-completion
-      # set bell-style none
-      # set bell-style visible
-
-      # some defaults / modifications for the emacs mode
-      $if mode=emacs
-
-      # allow the use of the Home/End keys
-      "\e[1~": beginning-of-line
-      "\e[4~": end-of-line
-
-      # allow the use of the Delete/Insert keys
-      "\e[3~": delete-char
-      "\e[2~": quoted-insert
-
-      # mappings for "page up" and "page down" to step to the beginning/end
-      # of the history
-      # "\e[5~": beginning-of-history
-      # "\e[6~": end-of-history
-
-      # alternate mappings for "page up" and "page down" to search the history
-      # "\e[5~": history-search-backward
-      # "\e[6~": history-search-forward
-
-      # mappings for Ctrl-left-arrow and Ctrl-right-arrow for word moving
-      "\e[1;5C": forward-word
-      "\e[1;5D": backward-word
-      "\e[5C": forward-word
-      "\e[5D": backward-word
-      "\e\e[C": forward-word
-      "\e\e[D": backward-word
-
-      $if term=rxvt
-      "\e[7~": beginning-of-line
-      "\e[8~": end-of-line
-      "\eOc": forward-word
-      "\eOd": backward-word
-      $endif
-
-      # for non RH/Debian xterm, can't hurt for RH/Debian xterm
-      # "\eOH": beginning-of-line
-      # "\eOF": end-of-line
-
-      # for freebsd console
-      # "\e[H": beginning-of-line
-      # "\e[F": end-of-line
-
-      $endif
-    '';
-  };
-
-  programs = {
-    bash = {
-      interactiveShellInit = ''
-        bind '"\e[A":history-search-backward'
-        bind '"\e[B":history-search-forward'
-        
-        # Ignore duplicate commands, ignore commands starting with a space
-        export HISTCONTROL=erasedups:ignorespace
-        export HISTSIZE=42000
-        # Append to the history instead of overwriting (good for multiple connections)
-        shopt -s histappend
-      '';
-      shellAliases = {
-        cl = "clear";
-        l  = "ls -alh";
-        ll = "ls -l";
-        ls = "ls --color=tty";
-    
-        s="sudo systemctl";
-        s-u="systemctl --user";
-        
-        nix-clean="sudo nix-collect-garbage -d";
-        nix-history="sudo nix-env --list-generations --profile /nix/var/nix/profiles/system";
-        nix-rollback="sudo nixos-rebuild switch --rollback";
-        nix-update="sudo nix-channel --update";
-        nix-upgrade="sudo nixos-rebuild switch";
-        nix-upstream="sudo nix-channel --list";
-        nix-config="gvim ~/.config/nixos/*.nix";
-      };
-    };
-  
-    /*
-    dconf.enable = true;
-  
-    gnupg.agent = {
-      enable = true;
-      enableSSHSupport = true;
-    };
-    */
-  
-    mtr.enable = true;
-  };
-};
-}
diff --git a/install/logical/friot/discourse.nix b/install/logical/friot/discourse.nix
deleted file mode 100644 (file)
index 2073346..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-{config, lib, pkgs, ...}:
-{
-  options = {
-    services.discourse = {
-      hostname = lib.mkOption {
-        type = lib.types.str;
-      };
-
-      config = lib.mkOption {
-        type = lib.types.str;
-        default =
-          ''
-            ## this is the all-in-one, standalone Discourse Docker container template
-            ##
-            ## After making changes to this file, you MUST rebuild
-            ## /var/discourse/launcher rebuild app
-            ##
-            ## BE *VERY* CAREFUL WHEN EDITING!
-            ## YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!
-            ## visit http://www.yamllint.com/ to validate this file as needed
-
-            templates:
-              - "templates/postgres.template.yml"
-              - "templates/redis.template.yml"
-              - "templates/web.template.yml"
-              - "templates/web.ratelimited.template.yml"
-            ## Uncomment these two lines if you wish to add Lets Encrypt (https)
-              #- "templates/web.ssl.template.yml"
-              #- "templates/web.letsencrypt.ssl.template.yml"
-
-            ## which TCP/IP ports should this container expose?
-            ## If you want Discourse to share a port with another webserver like Apache or nginx,
-            ## see https://meta.discourse.org/t/17247 for details
-            expose:
-              - "80:80"   # http
-              - "443:443" # https
-
-            params:
-              db_default_text_search_config: "pg_catalog.english"
-
-              ## Set db_shared_buffers to a max of 25% of the total memory.
-              ## will be set automatically by bootstrap based on detected RAM, or you can override
-              db_shared_buffers: "256MB"
-
-              ## can improve sorting performance, but adds memory usage per-connection
-              #db_work_mem: "40MB"
-
-              ## Which Git revision should this container use? (default: tests-passed)
-              #version: tests-passed
-
-            env:
-              LANG: en_US.UTF-8
-              # DISCOURSE_DEFAULT_LOCALE: en
-
-              ## How many concurrent web requests are supported? Depends on memory and CPU cores.
-              ## will be set automatically by bootstrap based on detected CPUs, or you can override
-              UNICORN_WORKERS: 2
-
-              ## TODO: The domain name this Discourse instance will respond to
-              DISCOURSE_HOSTNAME: ${config.networking.domain}
-
-              ## Uncomment if you want the container to be started with the same
-              ## hostname (-h option) as specified above (default "$hostname-$config")
-              #DOCKER_USE_HOSTNAME: true
-
-              ## TODO: List of comma delimited emails that will be made admin and developer
-              ## on initial signup example 'user1@example.com,user2@example.com'
-              DISCOURSE_DEVELOPER_EMAILS: 'julm@autogeree.net'
-
-              ## TODO: The SMTP mail server used to validate new accounts and send notifications
-              DISCOURSE_SMTP_ADDRESS: smtp.${config.networking.domain}
-              DISCOURSE_SMTP_PORT: 2525
-              DISCOURSE_SMTP_USER_NAME: discourse@${config.networking.domain}
-              DISCOURSE_SMTP_PASSWORD: password
-              #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (optional, default true)
-
-              ## If you added the Lets Encrypt template, uncomment below to get a free SSL certificate
-              #LETSENCRYPT_ACCOUNT_EMAIL: me@example.com
-
-              ## The CDN address for this Discourse instance (configured to pull)
-              ## see https://meta.discourse.org/t/14857 for details
-              #DISCOURSE_CDN_URL: //discourse-cdn.example.com
-
-            ## The Docker container is stateless; all data is stored in /shared
-            volumes:
-              - volume:
-                  host: /var/discourse/shared/standalone
-                  guest: /shared
-              - volume:
-                  host: /var/discourse/shared/standalone/log/var-log
-                  guest: /var/log
-
-            ## Plugins go here
-            ## see https://meta.discourse.org/t/19157 for details
-            hooks:
-              after_code:
-                - exec:
-                    cd: $home/plugins
-                    cmd:
-                      - git clone https://github.com/discourse/docker_manager.git
-                      - git clone https://github.com/teozkr/discourse-plugin-discord-auth.git
-
-            ## Any custom commands to run after building
-            run:
-              - exec: echo "Beginning of custom commands"
-              ## If you want to set the 'From' email address for your first registration, uncomment and change:
-              ## After getting the first signup email, re-comment the line. It only needs to run once.
-              - exec: rails r "SiteSetting.notification_email='noreply@${config.networking.domain}'"
-              - replace:
-                 filename: "/etc/nginx/conf.d/discourse.conf"
-                 from: /listen 80;/
-                 to: |
-                   listen 80;
-                   set_real_ip_from 0.0.0.0/0;
-              - exec: echo "End of custom commands"
-          '';
-      };
-    };
-  };
-
-  config = {
-    virtualisation.docker.enable = true;
-    #networking.firewall.enable = false;
-    environment.systemPackages = [ pkgs.git ];
-    systemd.services.discourse-setup = {
-      wants = [ "docker.service" ];
-      after = [ "network.target" "docker.service" ];
-      wantedBy = [ "multi-user.target" ];
-      path = [ pkgs.git pkgs.bash pkgs.nettools pkgs.which pkgs.gawk pkgs.docker ];
-      script =
-      ''
-        if [[ ! -e /var/discourse ]]; then
-          git clone --depth 1 https://github.com/discourse/discourse_docker.git /var/discourse
-        fi
-        cp ${pkgs.writeText "discourse-app.yml" config.services.discourse.config} \
-         /var/discourse/containers/app.yml
-        cd /var/discourse
-        git pull --depth 1
-        bash ./launcher rebuild app
-      '';
-      serviceConfig = {
-        Type = "simple";
-        RemainAfterExit = "yes";
-      };
-    };
-  };
-}
diff --git a/install/logical/friot/dovecot.nix b/install/logical/friot/dovecot.nix
deleted file mode 100644 (file)
index 3f80959..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-{pkgs, lib, config, system, ...}:
-let inherit (builtins) toString toFile;
-    inherit (lib) types;
-    inherit (pkgs.lib) unlines unlinesAttrs unlinesValues unwords;
-    inherit (config) networking;
-    inherit (config.services) dovecot2 postfix x509 openldap;
-    when        = x: y: if x == null then "" else y;
-    extSep      = postfix.recipientDelimiter;
-    dirSep      = extSep;
-    stateDir      = "/var/lib/dovecot";
-      # NOTE: nixpkgs' dovecot2.stateDir is currently not exported
-    mailDir     = "${stateDir}/mail";
-    sieveDir    = "${stateDir}/sieve";
-    authDir     = "${stateDir}/auth";
-    authUser    = dovecot2.mailUser;  # TODO: php_roundcube
-    authGroup   = dovecot2.mailGroup; # TODO: php_roundcube
-    escapeGroup = lib.stringAsChars (c: if "a"<=c && c<="z"
-                                        || "0"<=c && c<="9"
-                                        || c=="-"
-                                        then c else "_");
-    domainGroup = escapeGroup "${networking.domainBase}";
-    etc_dovecot = [
-      { target = "dovecot/${networking.domain}/dovecot-ldap.conf";
-        source = pkgs.writeText "dovecot-ldap.conf" ''
-          ${lib.optionalString dovecot2.debug ''
-            debug_level = 1
-          ''}
-
-          # LDAP database
-          uris = ldapi://
-          base = ou=posix,${openldap.domainSuffix}
-          scope = subtree
-          deref = never
-          blocking = no
-            # NOTE: sufficient for small systems and uses less resources.
-
-          # LDAP auth
-          sasl_bind = yes
-          sasl_mech = EXTERNAL
-          #dn = cn=admin,${openldap.domainSuffix}
-          #dnpass = useless with sasl_mech=EXTERNAL
-          auth_bind = no
-          #auth_bind_userdn = cn=%n,ou=accounts,ou=posix,dc=${openldap.domainSuffix}
-
-          # dovecot passdb query
-          # DOC: http://wiki2.dovecot.org/PasswordDatabase/ExtraFields
-          pass_filter = (&(objectClass=posixAccount)(uid=%n)(mailEnabled=TRUE))
-          pass_attrs = userPassword=password,\
-                       uidNumber=userdb_uid,\
-                       gidNumber=userdb_gid,\
-                       mailGroupMember=userdb_mail_access_groups=${domainGroup},\
-                       quotaBytes=userdb_quota_rule=*:bytes=%{ldap:quotaBytes},\
-                       =user=%n@%d
-                       #homeDirectory=userdb_home
-            # TODO: userdb_quota_rule=*:storage=
-          default_pass_scheme = CRYPT
-
-          # dovecot userdb query
-          # DOC: http://wiki2.dovecot.org/UserDatabase/ExtraFields
-          user_filter = (&(objectClass=posixAccount)(uid=%n)(mailEnabled=TRUE))
-          #user_filter = (&(objectClass=inetOrgPerson)(uid=%n))
-          #user_attrs = homeDirectory=home,uidNumber=uid,gidNumber=gid
-          #user_attrs = mailHomeDirectory=home,\
-          #              mailStorageDirectory=mail,\
-          #              mailUidNumber=uid,\
-          #              mailGidNumber=gid,\
-          #              mailQuota=quota_rule=*:bytes=%$
-
-          # doveadm user query
-          iterate_attrs = =user=%{ldap:uid}@${networking.domain}
-          iterate_filter = (&(objectClass=posixAccount)(mailEnabled=TRUE))
-        '';
-      }
-    ];
-    dovecot-virtual = pkgs.writeTextFile {
-      name = "dovecot-virtual";
-      destination = "/pop3/INBOX/dovecot-virtual";
-      text = ''
-        all
-        all+*
-          all
-      '';
-    };
-
-    sieve-rspamd-filter =
-      pkgs.stdenv.mkDerivation {
-        name = "sieve-rspamd-filter";
-        nativeBuildInputs = [ pkgs.makeWrapper ];
-        phases = [ "installPhase" ];
-        installPhase = ''
-          mkdir -p $out/bin
-          cat > $out/bin/learn-spam.sh <<EOF
-          #!/bin/sh
-          exec ${pkgs.rspamd}/bin/rspamc -h /run/rspamd.sock learn_spam
-          EOF
-          cat > $out/bin/learn-ham.sh <<EOF
-          #!/bin/sh
-          exec ${pkgs.rspamd}/bin/rspamc -h /run/rspamd.sock learn_ham
-          EOF
-          chmod +x $out/bin/*.sh
-        '';
-      };
-in
-{
-  imports = [
-    dovecot/autoconfig.nix
-  ];
-  options = {
-    services.dovecot2.sieves = {
-      global = lib.mkOption {
-        description = "global scripts.";
-        type = types.attrsOf types.str;
-        default = {};
-      };
-      before = lib.mkOption {
-        description = "before scripts.";
-        type = types.attrsOf types.str;
-        default = {};
-      };
-      after = lib.mkOption {
-        description = "after scripts.";
-        type = types.attrsOf types.str;
-        default = {};
-      };
-    };
-  };
-  config = {
-    environment.etc = etc_dovecot;
-    #services.postfix.mapFiles."transport-dovecot" =
-    #  toFile "transport-dovecot"
-    #   (unlines
-    #     (lib.mapAttrsToList
-    #       (dom: {...}: "${transportSubDomain}.${dom} lmtp:unix:private/dovecot-lmtp")
-    #       dovecot2.domains));
-    systemd.services.dovecot2 = {
-      after = [
-        "postfix.service"
-        "openldap.service"
-      ];
-      restartTriggers =
-        map (f: f.source) etc_dovecot;
-      environment  = {
-        #LD_LIBRARY_PATH = config.system.nssModules.path;
-      };
-      preStart = unlinesValues {
-        installMailDir = ''
-          # SEE: http://wiki2.dovecot.org/SharedMailboxes/Permissions
-          install -D -d -m 0771 \
-           -o ${dovecot2.mailUser} \
-           -g ${dovecot2.mailGroup} \
-           ${mailDir}
-        '';
-
-        installSieve = ''
-          rm -rf "${sieveDir}"
-          install -D -d -m 0755 -o root -g root \
-           "${sieveDir}/bin"
-        '' + unlinesAttrs (dir: sieves: ''
-          install -D -d -m 0755 -o root -g root \
-           ${sieveDir} ${sieveDir}/${dir}.d
-          '' + unlinesAttrs (name: text: ''
-            src=${pkgs.writeText "${name}.sieve" text}
-            dst="${sieveDir}/${dir}.d/${name}.sieve"
-            ln -fns "$src" "$dst"
-            ${pkgs.dovecot_pigeonhole}/bin/sievec "$dst"
-          '') sieves
-        ) dovecot2.sieves;
-
-        installDomains = ''
-          # NOTE: make sure nslcd cache is in sync with the LDAP data
-          systemctl restart nslcd
-          install -D -d -m 1770 \
-           -o ${dovecot2.mailUser} \
-           -g ${domainGroup} \
-           ${mailDir}/${networking.domain} \
-           ${stateDir}/control/${networking.domain} \
-           ${stateDir}/index/${networking.domain}
-
-          # NOTE: do not set the sticky bit (+t)
-          #       on acl/<domain>/, to let dovecot
-          #       rename acl.db.lock (own by new user)
-          #       to     acl.db      (own by old user)
-          install -D -d -m 0770 \
-           -o ${dovecot2.mailUser} \
-           -g ${domainGroup} \
-           ${stateDir}/acl/${networking.domain}
-
-          # NOTE: domainAliases point to the very same mailboxes as domain's.
-          for domainAlias in ${unwords networking.domainAliases}
-           do
-            ln -fns ${networking.domain} ${mailDir}/$domainAlias
-            ln -fns ${networking.domain} ${stateDir}/control/$domainAlias
-            ln -fns ${networking.domain} ${stateDir}/index/$domainAlias
-            ln -fns ${networking.domain} ${stateDir}/acl/$domainAlias
-           done
-        '';
-      };
-    };
-    services.dovecot2 = {
-      enable    = true;
-      debug     = true;
-      mailUser  = "dovemail";
-      mailGroup = "dovemail";
-      modules   = [
-        #pkgs.dovecot_antispam
-        pkgs.dovecot_pigeonhole
-      ];
-      sieves = {
-        global = {
-          list = ''
-            require
-             [ "date"
-             , "fileinto"
-             , "mailbox"
-             , "variables"
-             ];
-
-            if currentdate :matches "year"  "*" { set "year"  "''${1}"; }
-            if currentdate :matches "month" "*" { set "month" "''${1}"; }
-
-            if exists "List-ID" {
-              if header :matches "List-ID" "*<*.*.*.*>*" {
-                set "list"   "''${2}";
-                set "domain" "''${4}";
-              }
-              elsif header :matches "List-ID" "*<*.*.*>*" {
-                set "list"   "''${2}";
-                set "domain" "''${3}";
-              }
-              fileinto :create "Listes+''${domain}+''${list}+''${year}+''${month}";
-              stop;
-             }
-          '';
-          spam = ''
-            require
-             [ "imap4flags"
-             ];
-
-            if header :contains "X-Spam-Level" "***" {
-              addflag "Junk";
-            }
-          '';
-          /*
-            require ["fileinto","mailbox"];
-
-            if header :contains "X-Spam" "Yes" {
-             fileinto :create "INBOX.Junk";
-             stop;
-            }
-          */
-          extension = ''
-            require
-             [ "envelope"
-             , "fileinto"
-             , "mailbox"
-             , "subaddress"
-             , "variables"
-             ];
-            if envelope :matches :detail "TO" "*" {
-              set "extension" "''${1}";
-            }
-            if not string :is "''${extension}" "" {
-              fileinto :create "Plus+''${extension}";
-              stop;
-            }
-          '';
-          report-spam = ''
-            require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
-
-            if environment :matches "imap.user" "*" {
-              set "username" "''${1}";
-            }
-
-            pipe :copy "learn-spam.sh" [ "''${username}" ];
-          '';
-          report-ham = ''
-            require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
-
-            if environment :matches "imap.mailbox" "*" {
-              set "mailbox" "''${1}";
-            }
-
-            if string "''${mailbox}" "Trash" {
-              stop;
-            }
-
-            if environment :matches "imap.user" "*" {
-              set "username" "''${1}";
-            }
-
-            pipe :copy "learn-ham.sh" [ "''${username}" ];
-          '';
-        };
-      };
-      configFile = toString (pkgs.writeText "dovecot.conf" ''
-        passdb {
-          driver = ldap
-          args = /etc/dovecot/${networking.domain}/dovecot-ldap.conf
-          default_fields = userdb_mail_access_groups=${domainGroup}
-          override_fields =
-        }
-        userdb {
-          driver = prefetch
-        }
-        userdb {
-          # NOTE: this userdb is only used by lda.
-          driver = ldap
-          args = /etc/dovecot/${networking.domain}/dovecot-ldap.conf
-          default_fields = mail_access_groups=${domainGroup}
-          override_fields =
-          skip = found
-        }
-        #passdb {
-        #  driver = passwd-file
-        #  args   = scheme=crypt username_format=%n ${authDir}/%d/passwd
-        #}
-        #userdb {
-        #  # NOTE: this userdb is only used by lda.
-        #  driver = passwd-file
-        #  args = username_format=%n ${authDir}/%d/passwd
-        #  #default_fields = home=${mailDir}/%d/%n
-        #  skip = found
-        #}
-        mail_home = ${mailDir}/%d/%n
-          # NOTE: if needed, may be overrided by userdb_mail
-        mail_location = maildir:${mailDir}/%d/%n/Maildir:LAYOUT=fs:INDEX=${stateDir}/index/%d/%n:INDEXPVT=${stateDir}/index/%d/%n:CONTROL=${stateDir}/control/%d/%n
-          # NOTE: if needed, may be overrided by userdb_mail
-          # NOTE: INDEX and CONTROL are on a partition without quota, as explain in the doc.
-          # SEE: http://wiki2.dovecot.org/Quota/FS
-        auth_mechanisms = plain login
-        auth_ssl_require_client_cert = no
-          # NOTE: postfix does not supply a client cert.
-        auth_ssl_username_from_cert = yes
-        auth_verbose = yes
-        auth_username_format = %Lu
-          # NOTE: lowercase the username, help with LDAP?
-        ${lib.optionalString dovecot2.debug ''
-          auth_debug  = yes
-          mail_debug  = yes
-          verbose_ssl = yes
-        ''}
-        default_internal_user = ${dovecot2.user}
-        default_internal_group = ${dovecot2.group}
-        disable_plaintext_auth = yes
-        first_valid_uid = 10000
-          # NOTE: sync with LDAP's data.
-        lda_mailbox_autocreate = yes
-        lda_mailbox_autosubscribe = yes
-        listen = *
-        log_timestamp = "%Y-%m-%d %H:%M:%S "
-        #maildir_copy_with_hardlinks = yes
-        namespace inbox {
-          # NOTE: here because protocol sieve {namespace inbox{}} does not seem to work.
-          type      = private
-          inbox     = yes
-          location  =
-          list      = yes
-          prefix    =
-          separator = ${dirSep}
-        }
-        namespace {
-          type = shared
-          #list = children
-          list = yes
-            # NOTE: always listed in the LIST command.
-          location = maildir:${mailDir}/%%d/%%n/Maildir:LAYOUT=fs:INDEX=${stateDir}/index/%%d/%%n/Shared:INDEXPVT=${stateDir}/index/%d/%n/Shared/%%n:CONTROL=${stateDir}/control/%d/%n/Shared
-            # NOTE: how to access the other users' mailboxes.
-            # NOTE: %var expands to the logged in user's variable, while
-            #       %%var expands to the other users' variables.
-            # NOTE: INDEX and CONTROL are shared, INDEXPVT is not.
-          prefix = Partages+%%n+
-          separator = ${dirSep}
-          subscriptions = yes
-        }
-        mail_plugins = $mail_plugins acl quota virtual
-        #mail_uid = ${dovecot2.mailUser}
-        #mail_gid = ${dovecot2.mailGroup}
-          # NOTE: each user has a dedicated (uid,gid) pair
-        #mail_privileged_group = mail
-        #mail_access_groups =
-        plugin {
-          acl = vfile:/etc/dovecot/acl/global.d
-          acl_anyone = allow
-          acl_shared_dict = file:${stateDir}/acl/%d/acl.db
-            # NOTE: to let users LIST mailboxes shared by other users,
-            #       Dovecot needs a shared mailbox dictionary.
-            # FIXME: %d not working with userdb ldap
-          ##antispam_allow_append_to_spam = yes
-          # # NOTE: pour offlineimap
-          #antispam_backend = pipe
-          ##antispam_crm_args = -u;${mailDir}/%d/.crm114;/usr/share/crm114/mailfilter.crm
-          #antispam_crm_args = -u;${mailDir}/crm114;/usr/share/crm114/mailfilter.crm
-          #antispam_crm_binary = /usr/bin/crm
-          #antispam_debug_target = syslog
-          ##antispam_crm_env = HOME=%h;USER=%u
-          #antispam_ham_keywords = NonJunk
-          #antispam_pipe_program = /usr/bin/crm
-          #antispam_pipe_program_args = -u;${mailDir}/crm114;/usr/share/crm114/mailfilter.crm;--stats_only;--force
-          #antispam_pipe_program_notspam_arg = --learnnonspam
-          #antispam_pipe_program_spam_arg = --learnspam
-          #antispam_pipe_program_unlearn_spam_args = --unlearn;--learnspam
-          #antispam_pipe_program_unlearn_notspam_args = --unlearn;--learnnonspam
-          #antispam_pipe_tmpdir = ${mailDir}/crm114/tmp
-          #antispam_signature = X-CRM114-CacheID
-          #antispam_signature_missing = move
-          #antispam_spam = Junk
-          #antispam_spam_keywords = Junk
-          #antispam_trash = Trash
-          #antispam_unsure = Unsure
-          #antispam_verbose_debug = 0
-          quota = maildir:User quota
-          quota_rule = *:storage=256M
-          quota_rule2 = Trash:storage=+64M
-          quota_max_mail_size = 20M
-          #quota_exceeded_message = </path/to/quota_exceeded_message.txt
-          quota_warning  = storage=95%% quota-warning 95 %u
-          quota_warning2 = storage=80%% quota-warning 80 %u
-          quota_warning3 = -storage=100%% quota-warning below %u
-           # NOTE: user is no longer over quota
-          recipient_delimiter = ${extSep}
-          sieve = file:${mailDir}/%d/%n/sieve;active=${mailDir}/%d/%n/sieve/main.sieve
-          #sieve_default = file:${mailDir}/%u/default.sieve
-          #sieve_default_name = default
-          sieve_after  = ${sieveDir}/after.d/
-          sieve_before = ${sieveDir}/before.d/
-          sieve_dir = ${mailDir}/%d/%n/sieve/
-          #sieve_extensions = +spamtest +spamtestplus
-          sieve_global_dir = ${sieveDir}/global.d/
-          sieve_max_script_size = 1M
-          sieve_quota_max_scripts = 0
-          sieve_quota_max_storage = 10M
-          sieve_spamtest_max_value = 10
-          sieve_spamtest_status_header = X-Spam-Score
-          sieve_spamtest_status_type = strlen
-          sieve_user_log = /var/log/dovecot/%d/sieve.%n.log
-
-          sieve_plugins = sieve_imapsieve sieve_extprograms
-          sieve_pipe_bin_dir = ${sieve-rspamd-filter}/bin
-          sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
-          # From elsewhere to Spam folder
-          imapsieve_mailbox1_name = Spam
-          imapsieve_mailbox1_causes = COPY
-          imapsieve_mailbox1_before = file:${sieveDir}/global.d/report-spam.sieve
-
-          # From Spam folder to elsewhere
-          imapsieve_mailbox2_name = *
-          imapsieve_mailbox2_from = Spam
-          imapsieve_mailbox2_causes = COPY
-          imapsieve_mailbox2_before = file:${sieveDir}/global.d/report-ham.sieve
-        }
-        # If you have Dovecot v2.2.8+ you may get a significant performance improvement with fetch-headers:
-        imapc_features = $imapc_features fetch-headers
-        # Read multiple mails in parallel, improves performance
-        mail_prefetch_count = 20
-        service quota-warning {
-          executable = script ${
-            pkgs.writeScript "quota-warning" ''
-              #!/bin/sh -eu
-              PERCENT=$1
-              USER=$2
-              cat << EOF | ${pkgs.dovecot}/libexec/dovecot/dovecot-lda -d $USER -o
-              "plugin/quota=maildir:User quota:noenforcing"
-              From: postmaster@${networking.domain}
-              Subject: [WARNING] your mailbox is now $PERCENT% full.
-
-              Please remove some mails to make room for new ones.
-              EOF
-            ''
-          }
-          # use some unprivileged user for executing the quota warnings
-          user = ${dovecot2.user}
-          unix_listener quota-warning {
-          }
-        }
-        protocol imap {
-          #mail_max_userip_connections = 10
-          mail_plugins = $mail_plugins imap_acl imap_quota imap_sieve # antispam
-          namespace inbox {
-            inbox = yes
-            location =
-            list = yes
-            mailbox Drafts {
-              special_use = \Drafts
-            }
-            mailbox Junk {
-              special_use = \Junk
-              auto = subscribe
-              #autoexpunge = 30d
-            }
-            mailbox Sent {
-              special_use = \Sent
-              auto = subscribe
-            }
-            mailbox "Sent Messages" {
-              special_use = \Sent
-              auto = subscribe
-            }
-            mailbox Trash {
-              special_use = \Trash
-              auto = subscribe
-              #autoexpunge = 30d
-            }
-            prefix =
-            separator = ${dirSep}
-          }
-        }
-        protocol lda {
-          auth_socket_path = /var/run/dovecot/auth-userdb
-          hostname         = ${networking.domain}
-          info_log_path    =
-          log_path         =
-          mail_plugins     = $mail_plugins sieve
-          namespace inbox {
-            inbox     = yes
-            location  =
-            list      = yes
-            prefix    =
-            separator = ${dirSep}
-          }
-          postmaster_address = postmaster${extSep}dovecot${extSep}lda@${networking.domain}
-          syslog_facility = mail
-        }
-        protocol lmtp {
-          #info_log_path = /tmp/dovecot-lmtp.log
-          mail_plugins = $mail_plugins sieve
-          namespace inbox {
-            inbox     = yes
-            location  =
-            list      = yes
-            prefix    =
-            separator = ${dirSep}
-          }
-          postmaster_address = postmaster${extSep}dovecot${extSep}lmtp@${networking.domain}
-        }
-        protocol pop3 {
-          #mail_max_userip_connections = 10
-          namespace all {
-            # NOTE: used by ${dovecot-virtual}/pop3/INBOX/dovecot-virtual
-            hidden    = yes
-            list      = no
-            location  =
-            prefix    = all+
-            separator = ${dirSep}
-          }
-          # Virtual namespace for the virtual INBOX.
-          # Use a global directory for dovecot-virtual files.
-          namespace inbox {
-            inbox     = yes
-            hidden    = yes
-            list      = no
-            location  = virtual:${dovecot-virtual}/pop3:INDEX=${stateDir}/index/%d/%n/POP3:LAYOUT=fs
-            prefix    = pop3+
-            separator = ${dirSep}
-          }
-          pop3_client_workarounds =
-          pop3_fast_size_lookups = yes
-          pop3_lock_session = yes
-          pop3_no_flag_updates = yes
-          # Use GUIDs to avoid accidental POP3 UIDL changes instead of IMAP UIDs.
-          pop3_uidl_format = %g
-        }
-        protocol sieve {
-          #mail_max_userip_connections = 10
-          #managesieve_implementation_string = Dovecot Pigeonhole
-          managesieve_max_compile_errors = 5
-          #managesieve_max_line_length = 65536
-          #managesieve_notify_capability = mailto
-          #managesieve_sieve_capability = fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date ihave
-        }
-        protocols = imap lmtp pop3 sieve
-        service lmtp {
-          #executable = lmtp -L
-          process_min_avail = 2
-          unix_listener /var/lib/postfix/queue/private/dovecot-lmtp {
-            user  = ${postfix.user}
-            group = ${postfix.group}
-            mode  = 0600
-          }
-          #user = mail
-        }
-        service auth {
-          user = root
-            # FIXME: may be user=dovecot-auth with LDAP?
-          unix_listener auth-userdb {
-            user  = ${dovecot2.user}
-            group = ${dovecot2.group}
-            mode  = 0660
-          }
-          unix_listener /var/lib/postfix/queue/private/auth {
-            user  = ${postfix.user}
-            group = ${postfix.group}
-            mode  = 0660
-          }
-        }
-        service imap {
-          # Most of the memory goes to mmap()ing files.
-          # You may need to increase this limit if you have huge mailboxes.
-          #vsz_limit =
-          process_limit = 1024
-        }
-        service imap-login {
-          #inet_listener imap {
-          #  address = 127.0.0.1
-          #  port    = 143
-          #  ssl     = no
-          #}
-          inet_listener imaps {
-            port = 993
-            ssl  = yes
-          }
-        }
-        service pop3 {
-          process_limit = 1024
-        }
-        service pop3-login {
-          inet_listener pop3s {
-            port = 995
-            ssl  = yes
-          }
-        }
-        ssl = required
-        ssl_dh = <${x509.dir}/dh.pem
-        ssl_cipher_list = HIGH:!LOW:!SSLv2:!EXP:!aNULL
-        ssl_cert = <${x509.cert}
-        ssl_key = <${x509.key}
-        #ssl_ca   = <''${caPath}
-        #ssl_verify_client_cert = yes
-      '');
-        #${lib.concatMapStringsSep "\n"
-        #    (dom: ''
-        #      local_name mail.${dom} {
-        #        #ssl_ca   = <''${caPath}
-        #        ssl_cert = <${x509.cert dom}
-        #        ssl_key  = <${x509.key dom}
-        #        }
-        #    '')
-        #    dovecot2.domains
-        #}
-    };
-  };
-}
diff --git a/install/logical/friot/dovecot/autoconfig.nix b/install/logical/friot/dovecot/autoconfig.nix
deleted file mode 100644 (file)
index 236933b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (builtins) attrNames;
-    inherit (config.services) dovecot2;
-in
-{
-config = {
-  services.nginx = {
-    virtualHosts."autoconfig" =
-    let servers = lib.concatMapStringsSep " "
-                   (dom: "autoconfig.${dom}")
-                   (attrNames dovecot2.domains);
-    in
-    {
-      serverName = "autoconfig.${config.networking.domain}";
-      serverAliases =
-        map (domainAlias: "autoconfig." + domainAlias)
-            config.networking.domainAliases;
-      #addSSL = true;
-      extraConfig = ''
-        access_log off;
-        log_not_found off;
-      '';
-      root = pkgs.writeTextFile {
-        name = "autoconfig";
-        destination = "/mail/config-v1.1.xml";
-        text = ''
-          <?xml version="1.0"?>
-          <clientConfig version="1.1">
-            <emailProvider id="%EMAILDOMAIN%">
-              <!-- <displayName></displayName> -->
-              <!-- <displayShortName></displayShortName> -->
-              <domain>%EMAILDOMAIN%</domain>
-              <incomingServer type="imap">
-                <hostname>mail.%EMAILDOMAIN%</hostname>
-                <port>993</port>
-                <socketType>SSL</socketType>
-                <username>%EMAILADDRESS%</username>
-                <authentication>password-cleartext</authentication>
-              </incomingServer>
-              <incomingServer type="pop3">
-                <hostname>mail.%EMAILDOMAIN%</hostname>
-                <port>995</port>
-                <socketType>SSL</socketType>
-                <username>%EMAILADDRESS%</username>
-                <authentication>password-cleartext</authentication>
-                <pop3>
-                  <leaveMessagesOnServer>false</leaveMessagesOnServer>
-                  <downloadOnBiff>true</downloadOnBiff>
-                </pop3>
-              </incomingServer>
-              <outgoingServer type="smtp">
-                <hostname>mail.%EMAILDOMAIN%</hostname>
-                <port>465</port>
-                <socketType>SSL</socketType> <!-- see above -->
-                <username>%EMAILADDRESS%</username> <!-- if smtp-auth -->
-                <authentication>password-cleartext</authentication>
-                <!-- <restriction>client-IP-address</restriction> -->
-                <addThisServer>true</addThisServer>
-                <useGlobalPreferredServer>false</useGlobalPreferredServer>
-              </outgoingServer>
-            </emailProvider>
-            <!-- <clientConfigUpdate url="https://www.example.com/config/mozilla.xml" /> -->
-          </clientConfig>
-        '';
-      };
-    };
-  };
-};
-}
diff --git a/install/logical/friot/gitolite.nix b/install/logical/friot/gitolite.nix
deleted file mode 100644 (file)
index 1992c3c..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-{pkgs, lib, config, system, ...}:
-let inherit (builtins.extraBuiltins) pass;
-    inherit (lib) types;
-    inherit (config) networking;
-    inherit (config.services) gitolite;
-    inherit (config.users) users groups;
-    gitolite-admin = "julm";
-in
-{
-  config = {
-    environment.systemPackages = [ pkgs.gitolite ];
-      # NOTE: make confortable to call gitolite from a shell
-      #      (but mind the sudo -u git).
-
-    services = {
-      gitolite = {
-        enable = true;
-        user   = "git";
-        group  = users."git-daemon".name;
-        adminPubkey = pass "${networking.domainBase}/ssh/pub/${gitolite-admin}";
-        extraGitoliteRc = ''
-          $RC{UMASK}           = 0027; # NOTE: no quote around in Perl, so it's octal
-          $RC{LOG_DEST}        = 'repo-log,syslog';
-          $RC{LOG_FACILITY}    = 'local0';
-          #$RC{GIT_CONFIG_KEYS} = 'hooks.* gitweb.*';
-          $RC{GIT_CONFIG_KEYS} = '.*';
-          #$RC{LOCAL_CODE} = "$rc{GL_ADMIN_BASE}/local"
-          #  if -d "$rc{GL_ADMIN_BASE}/local";
-          $RC{LOCAL_CODE} = "$ENV{HOME}/local";
-          push(@{$RC{ENABLE}}, ( 'Alias'
-                               , 'cgit'
-                                 # NOTE: without this "cgit" option,
-                                 # the repositories' "description" files are not modified
-                               , 'D'
-                               , 'Shell ${gitolite-admin}'
-                               , 'create'
-                               , 'expand-deny-messages'
-                               , 'fork'
-                               , 'keysubdirs-as-groups'
-                               , 'readme'
-                               , (-d "$ENV{HOME}/local" ? 'repo-specific-hooks' : ())
-                               , 'ssh-authkeys-split'
-                               ));
-        '';
-      };
-    };
-    systemd.services.gitolite-init = {
-      preStart = ''
-        chmod g+x "${gitolite.dataDir}"
-          # NOTE: allow git-daemon to enter ~git
-        install -D -d -o ${gitolite.user} -g ${gitolite.group} -m 750 \
-         ${gitolite.dataDir}/local \
-         ${gitolite.dataDir}/local/hooks \
-         ${gitolite.dataDir}/local/hooks/common \
-         ${gitolite.dataDir}/local/hooks/repo-specific
-      '';
-    };
-    systemd.services.git-daemon = {
-      # NOTE: not using nixpkgs' gitDaemon, to avoid running it as root.
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
-      serviceConfig = {
-        User       = users."git-daemon".name;
-        Group      = groups."git-daemon".name;
-        Restart    = "always";
-        RestartSec = 5;
-      };
-      script = "${pkgs.git}/bin/git daemon --verbose --reuseaddr"
-        + " --base-path=${gitolite.dataDir}/repositories"
-        #+ (optionalString (cfg.listenAddress != "") "--listen=${cfg.listenAddress} ")
-        #+ "--port=${toString cfg.port} "
-        ;
-    };
-    users.users = lib.singleton
-      { name = "git-daemon";
-        uid = config.ids.uids.git;
-        description = "Git daemon user";
-      };
-  };
-}
diff --git a/install/logical/friot/nginx.nix b/install/logical/friot/nginx.nix
deleted file mode 100644 (file)
index 01aa7a7..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-{pkgs, lib, config, system, ...}:
-let inherit (lib) types;
-    inherit (config.services) nginx x509;
-    domainDir = dom: lib.concatStringsSep "/" (lib.reverseList (lib.splitString "." dom));
-in
-{
-imports = [
-  nginx/gitweb.nix
-];
-options.services.nginx = {
-  webDir = lib.mkOption {
-    type    = types.str;
-    default = "/var/lib/nginx";
-  };
-  logDir = lib.mkOption {
-    type    = types.str;
-    default = "/var/log/nginx";
-  };
-};
-config = {
-  security.dhparams = {
-    enable = true;
-    params = {
-      nginx = 1024;
-    };
-  };
-  systemd.services.nginx = {
-    preStart = lib.mkBefore ''
-      install -D -d -o ${nginx.user} -g ${nginx.group} -m 0700 \
-       ${nginx.webDir} \
-       ${nginx.logDir}
-    '';
-  };
-  services.nginx = {
-    enable = true;
-    stateDir = "/dev/shm/nginx";
-    eventsConfig = ''
-      multi_accept on;
-      use epoll;
-      worker_connections 1024;
-    '';
-    clientMaxBodySize = "20m";
-    recommendedProxySettings = true;
-    recommendedTlsSettings = true;
-    serverTokens = false;
-    sslCiphers = "HIGH:!ADH:!MD5:!CAMELLIA:!SEED:!3DES:!DES:!RC4:!eNULL";
-    #sslCiphers = "EECDH+aRSA+AESGCM:EDH+aRSA:EECDH+aRSA:+AES256:+AES128:+SHA1:!CAMELLIA:!SEED:!3DES:!DES:!RC4:!eNULL;";
-    #sslProtocols = "TLSv1.2";
-    commonHttpConfig = ''
-      log_format main '$remote_addr - $remote_user [$time_local] "$request" '
-                      '$status $body_bytes_sent "$http_referer" '
-                      '"$http_user_agent" "$http_x_forwarded_for"';
-      #charset UTF-8;
-      '' +
-      lib.concatStringsSep "\n" (lib.attrValues {
-        default = ''
-          default_type application/octet-stream;
-          root ${nginx.webDir};
-        '';
-        security = ''
-          error_page 403 = 404;
-          #ssl_certificate     ${x509.cert};
-          #ssl_certificate_key ${x509.key};
-        '';
-        log = ''
-          access_log ${nginx.logDir}/access.log main buffer=32k;
-          error_log  ${nginx.logDir}/error.log warn;
-          open_log_file_cache max=1000 inactive=20s min_uses=2 valid=1m;
-        '';
-        proxy = ''
-          proxy_cache_use_stale updating;
-          proxy_temp_path ${nginx.stateDir}/proxy_temp 1 2;
-        '';
-        fastcgi = ''
-          # DOC: http://wiki.nginx.org/HttpFastcgiModule
-          fastcgi_buffer_size 128k;
-          fastcgi_buffers 256 4k;
-          fastcgi_busy_buffers_size 256k;
-          fastcgi_cache_key "$request_method $scheme://$http_host$request_uri";
-          fastcgi_cache_path ${nginx.stateDir}/fastcgi_cache
-                             inactive=10m
-                             keys_zone=microcache:2M
-                             levels=1:2
-                             loader_files=100000
-                             loader_sleep=1
-                             loader_threshold=2592000000
-                             max_size=64M;
-          fastcgi_connect_timeout 60;
-          fastcgi_ignore_client_abort off;
-          fastcgi_intercept_errors on;
-          fastcgi_max_temp_file_size 2M;
-          #fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
-          fastcgi_param SCRIPT_FILENAME $request_filename;
-          fastcgi_temp_path ${nginx.stateDir}/fastcgi_temp 1 2;
-        '';
-        connexion = ''
-          sendfile on;
-          send_timeout 60;
-            # ^ If the client stops reading data,
-            # free up the stale client connection after this much time.
-          tcp_nopush on;
-            # ^ Causes nginx to attempt to send its HTTP response head
-            # in one packet, instead of using partial frames.
-            # This is useful for prepending headers before calling sendfile,
-            # or for throughput optimization.
-          tcp_nodelay on;
-            # ^ Don't buffer data-sends (disable Nagle algorithm).
-            # Good for sending frequent small bursts of data in real time.
-          keepalive_timeout 20;
-          reset_timedout_connection on;
-          server_names_hash_bucket_size 128;
-          types_hash_max_size 2048;
-        '';
-        map = ''
-          # User agents that are to be blocked.
-          #map $http_user_agent $bad_bot {
-          #  default 0;
-          #  libwww-perl 1;
-          #  ~(?i)(httrack|htmlparser|libwww) 1;
-          #}
-          # Referrers that are to be blocked.
-          #map $http_referer $bad_referer {
-          #  default 0;
-          #  ~(?i)(babes|casino|click|diamond|forsale|girl|jewelry|love|nudit|organic|poker|porn|poweroversoftware|replica|sex|teen|webcam|zippo) 1;
-          #}
-          #geo $not_local {
-          #  default 1;
-          #  127.0.0.1 0;
-          #}
-        '';
-        gzip = ''
-          gzip on;
-          gzip_buffers 16 8k;
-          gzip_comp_level 6;
-          gzip_disable "MSIE [1-6]\.";
-          gzip_http_version 1.1;
-          gzip_min_length 1024;
-          gzip_proxied any;
-          gzip_static on;
-          gzip_vary on;
-          gzip_types application/atom+xml
-                     application/javascript
-                     application/json
-                     application/rss+xml
-                     application/vnd.ms-fontobject
-                     application/x-font-ttf
-                     application/x-javascript
-                     application/xml
-                     application/xml+rss
-                     font/opentype
-                     font/truetype
-                     image/svg+xml
-                     text/css
-                     text/javascript
-                     text/plain
-                     text/x-component
-                     text/xml;
-        '';
-        cache = ''
-          client_body_buffer_size 4K;
-            # ^ getconf PAGESIZE
-            # 4096
-          client_body_temp_path ${nginx.stateDir}/client_body_temp 1 2;
-          client_body_timeout 60;
-          client_header_buffer_size 1k;
-          client_header_timeout 60;
-          large_client_header_buffers 4 8k;
-          
-          open_file_cache max=200000 inactive=20s;
-          open_file_cache_errors on;
-          open_file_cache_min_uses 2;
-          open_file_cache_valid 30s;
-        '';
-      });
-    appendConfig = ''
-      worker_processes 2;
-    '';
-  };
-};
-}
diff --git a/install/logical/friot/nginx/gitweb.nix b/install/logical/friot/nginx/gitweb.nix
deleted file mode 100644 (file)
index f095779..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (config) networking;
-    inherit (config.services) gitweb gitolite nginx;
-    package = pkgs.gitweb.override (lib.optionalAttrs gitweb.gitwebTheme {
-      gitwebTheme = true;
-    });
-    RuntimeDirectory = "gitweb";
-    gitwebSocket = "/run/${RuntimeDirectory}/gitweb.sock";
-    static-custom = pkgs.writeTextFile {
-      name = "static-custom";
-      destination = "/static-custom/style.css";
-      text = ''
-        .project_list {
-          width:100%;
-        }
-      '';
-    };
-in
-{
-  config = {
-    services.nginx = {
-      virtualHosts."git" = {
-        serverName = "git.${networking.domain}";
-        serverAliases =
-          map (domainAlias: "git." + domainAlias)
-              config.networking.domainAliases;
-        #listen = [
-        #  { addr = "0.0.0.0"; port = 80; ssl = false; }
-        #];
-        #default = true;
-        locations = {
-          "/" = {
-            extraConfig = ''
-              include ${pkgs.nginx}/conf/fastcgi_params;
-              fastcgi_param PATH_INFO $fastcgi_script_name;
-               # NOTE: used by gitweb's pathinfo feature.
-              fastcgi_param GITWEB_CONFIG ${gitweb.gitwebConfigFile};
-              fastcgi_pass unix:${gitwebSocket};
-            '';
-          };
-          "/static/" = {
-            alias = "${pkgs.gitweb}/static/";
-          };
-          "/static-custom/" = {
-            alias = "${static-custom}/static-custom/";
-          };
-        };
-      };
-    };
-    systemd.services.gitweb = {
-      description = "GitWeb FastCGI service";
-      script = "${pkgs.gitweb}/gitweb.cgi --fastcgi --nproc=1";
-      environment  = {
-        FCGI_SOCKET_PATH = gitwebSocket;
-        FCGI_SOCKET_PERM = "432"; # decimal of 660 in octal, since current CGI::Fast doesn't use perl's oct()
-      };
-      serviceConfig = {
-        User             = gitolite.user;
-        Group            = nginx.group;
-        RuntimeDirectory = [ RuntimeDirectory ];
-        Restart          = "always";
-        RestartSec       = 10;
-      };
-      wantedBy = [ "multi-user.target" ];
-    };
-    services.gitweb = {
-      gitwebTheme = false;
-      projectroot = "${gitolite.dataDir}/repositories";
-      extraConfig = ''
-        use utf8;
-        my $s = $cgi->https() ? "s"  : "";
-        @extra_breadcrumbs = (["${networking.domainBase}" => "http''${s}://${networking.domain}"]);
-        $home_link_str = "git";
-        $projects_list = "${gitolite.dataDir}/projects.list";
-        $projects_list_group_categories = 1;
-        $default_projects_order = "age";
-        $omit_owner = 1;
-        $export_ok = "git-daemon-export-ok";
-        $prevent_xss = 0;
-        @git_base_url_list =
-         ( "git://git.${networking.domain}"
-         , "git\@git.${networking.domain}:"
-         );
-        $feature{'pathinfo'}{'default'} = [1];
-         # NOTE: more readable URL.
-        @stylesheets = ( "/static/gitweb.css"
-                       , "/static-custom/style.css" 
-                       );
-        $logo        =  "/static/git-logo.png";
-        $favicon     =  "/static/git-favicon.png";
-        $javascript  =  "/static/gitweb.js";
-        $feature{'highlight'}{'default'} = [1];
-        # FIX: gitweb bug: FCGI is not Unicode aware.
-        if ($first_request) {
-            my $enc = Encode::find_encoding('UTF-8');
-            my $org = \&FCGI::Stream::PRINT;
-            no warnings 'redefine';
-            *FCGI::Stream::PRINT = sub {
-                my @OUTPUT = @_;
-                for (my $i = 1; $i < @_; $i++) {
-                    $OUTPUT[$i] = $enc->encode($_[$i], Encode::FB_CROAK|Encode::LEAVE_SRC);
-                }
-                @_ = @OUTPUT;
-                goto $org;
-            };
-        };
-      '';
-    };
-
-  };
-}
diff --git a/install/logical/friot/nsd.nix b/install/logical/friot/nsd.nix
deleted file mode 100644 (file)
index 9aabb64..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (config.services) nsd;
-in
-{
-  imports = [
-    nsd/sourcephile.nix
-  ];
-  config = {
-    services.nsd = {
-      enable = true;
-      ipv4 = true;
-      ipv6 = true;
-      verbosity = 5;
-      # SEE: http://www.nlnetlabs.nl/blog/2012/10/11/nsd-ratelimit/
-      ratelimit.size = 10000;
-      extraConfig = ''
-      '';
-      interfaces = lib.unique [
-        "127.0.0.1"
-        "::1"
-        config.networking.zones.lan.ipv4
-        config.networking.zones.net.ipv4
-      ];
-    };
-  };
-}
diff --git a/install/logical/friot/nsd/sourcephile.nix b/install/logical/friot/nsd/sourcephile.nix
deleted file mode 100644 (file)
index f83a07f..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (builtins) toString toPath readFile;
-    inherit (builtins.extraBuiltins) pass;
-    inherit (pkgs.lib) unlinesAttrs;
-    inherit (config) networking;
-    inherit (config.services) nsd dkim;
-    serial = zone: toString (builtins.extraBuiltins.git ./. [ "log" "-1" "--format=%ct" "--" (zone + ".nix") ]);
-    /*
-    serial = file: lib.removeSuffix "\n" (readFile
-      (pkgs.runCommand "zone-serial"
-        { buildInputs      = [ pkgs.git ];
-          buildDepends     = [ (toPath ./. + file) ];
-          preferLocalBuild = true;
-          allowSubstitutes = false;
-        } ''
-        cd ${toPath ./.}
-        ${pkgs.git}/bin/git log -1 --format="%ct" -- ${file} >$out
-      ''));
-    */
-    ipv4 = networking.zones.net.ipv4;
-    sourcephileZone = domain: ''
-      ; A (DNS -> IPv4)
-      @                   A ${ipv4}
-      autoconfig          A ${ipv4}
-      git                 A ${ipv4}
-      imap                A ${ipv4}
-      mail                A ${ipv4}
-      ns                  A ${ipv4}
-      pop                 A ${ipv4}
-      redmine             A ${ipv4}
-      smtp                A ${ipv4}
-      submission          A ${ipv4}
-      www                 A ${ipv4}
-
-      ; SPF (Sender Policy Framework)
-      @ 3600 IN SPF "v=spf1 mx ip4:${ipv4} -all"
-      @ 3600 IN TXT "v=spf1 mx ip4:${ipv4} -all"
-
-      ; MX (Mail eXchange)
-      @ 180 MX 5 mail
-
-      ; SRV (SeRVice)
-      _git._tcp.git 18000 IN SRV 0 0 9418 git
-
-      ; TXT (TeXT)
-      ''
-      + unlinesAttrs
-          (selector: sel: sel.dns)
-          dkim.domains."${domain}".selectors;
-in
-{
-  config = {
-    services.dkim.domains =
-      let domain = rec {
-        selector = "2020010101";
-        selectors = {
-          "2020010101" = {
-            key = pass "${networking.domainBase}/dkim/2020010101/key" + "\n";
-            dns = ''
-              2020010101._domainkey IN TXT ( "v=DKIM1; k=rsa; "
-                      "p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7EKzverbG+5JF+yFjH3MrxLyauiHyLqBbV/8LEMunoKXF8sqhBpQtAQXruLqsyUkxR/4CAyPMyzmcdrU43boMj9yFqLrg/kEz2RIvai9jXBqRoWRW1y7F0LbZmdtOTncuDSP8Zzo02XUzsOC4f/C3tEQHS5rchzfhU5FY1CeO6eBMV79qKBOvGMKahQTrrtU6olAAJxOhn6wRuwSf"
-                      "+m3on1OqiuXYYIgNHKdRhJ8gDwIm/3LEpYMD0gTgJiyclCLoLGHGtKZy1Wf9xV9/7V6fHE4JW5SDivwslVTL+KPXOlIpo5NDHpMxPYOcIg2K4Rj/j7jhavo+fG43q1LhwaPkEMQMbplgnjeMY8300odRiklTkMMpH0m35ZNeHQJSRpEtV8y5xUNxVaGzfqX5iStwV/mQ1KnZSe8ORTNq+eTTFnDk6zdUXjagcf0wO6QsSTeAz/G8CqOBbwmrU+q"
-                      "F8WbGAeRnhz51mH6fTTfsQ1nwjAiF4ou+eQGTkTMN23KkCKpuozJnxqx4DCEr6J1bL83fhXw7CgcfgKgTOk/HFJpeiGhqodw18r4DWBA6G57z9utm7Mr/9SoVnMq6iK9iEcbCllLR8Sz4viatLSRzhodbk7hfvXS3jmCFjILAjFmA7aMTemDMBDQhpAGF9F8sjFUbEJIZjKrWWtSTdO8DilDqN8CAwEAAQ=="
-              ) ;
-            '';
-          };
-        };
-      }; in
-      {
-        "${networking.domainBase}.fr"   = domain;
-      };
-    services.nsd = {
-      zones = {
-        # NOTE: cannot use networking.domain as attr key: infinite recursion
-        "sourcephile.fr" = {
-          data = ''
-            $ORIGIN ${networking.domainBase}.fr.
-            $TTL    86400
-
-            ; SOA (Start Of Authority)
-            @ SOA ns admin (
-              ${serial networking.domainBase} ; Serial number
-              1d      ; Refresh
-              15m     ; Retry
-              2592000 ; Expire
-              1d      ; TTL (Time To Live) minimum
-            )
-
-            ; NS (Name Server)
-            @ NS ns
-            ;@ NS ns6.gandi.net.
-          ''
-          + sourcephileZone "${networking.domainBase}.fr";
-        };
-      };
-    };
-  };
-}
diff --git a/install/logical/friot/openldap.nix b/install/logical/friot/openldap.nix
deleted file mode 100644 (file)
index 79b8eda..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (builtins) baseNameOf readFile;
-    inherit (lib) types;
-    inherit (pkgs.lib) unlinesAttrs;
-    inherit (config.services) openldap;
-    inherit (config.users) ldap;
-    copyFile = file: pkgs.writeText (baseNameOf file) (readFile file);
-    configLDIF = pkgs.writeText "cn=config.ldif" (''
-      dn: cn=config
-      objectClass: olcGlobal
-      #olcPidFile: /run/slapd/slapd.pid
-      # List of arguments that were passed to the server
-      #olcArgsFile: /run/slapd/slapd.args
-      # Read slapd-config(5) for possible values
-      olcLogLevel: none
-      # The tool-threads parameter sets the actual amount of CPU's
-      # that is used for indexing.
-      olcToolThreads: 1
-
-      dn: olcDatabase={-1}frontend,cn=config
-      objectClass: olcDatabaseConfig
-      objectClass: olcFrontendConfig
-      # The maximum number of entries that is returned for a search operation
-      olcSizeLimit: 500
-      # Allow unlimited access to local connection from the local root user
-      olcAccess: to *
-        by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
-        by * break
-      # Allow unauthenticated read access for schema and base DN autodiscovery
-      olcAccess: to dn.exact=""
-        by * read
-      olcAccess: to dn.base="cn=Subschema"
-        by * read
-
-      dn: olcDatabase=config,cn=config
-      objectClass: olcDatabaseConfig
-      olcRootDN: cn=admin,cn=config
-      # Access to cn=config, system root can be manager
-      # with SASL mechanism (-Y EXTERNAL) over unix socket (-H ldapi://)
-      olcAccess: to *
-        by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
-        by * break
-
-      dn: cn=schema,cn=config
-      objectClass: olcSchemaConfig
-
-      include: file://${pkgs.openldap}/etc/schema/core.ldif
-      include: file://${pkgs.openldap}/etc/schema/cosine.ldif
-      include: file://${pkgs.openldap}/etc/schema/nis.ldif
-      include: file://${pkgs.openldap}/etc/schema/inetorgperson.ldif
-      include: file://${copyFile openldap/schema/postfix-book.ldif}
-
-      dn: cn=module{0},cn=config
-      objectClass: olcModuleList
-      # Where the dynamically loaded modules are stored
-      #olcModulePath: /usr/lib/ldap
-      olcModuleLoad: back_mdb
-
-    '' + unlinesAttrs (olcSuffix: {conf, olcDbDirectory, ...}:
-      "include: file://" + pkgs.writeText "config.ldif" (conf + ''
-        olcSuffix: ${olcSuffix}
-        olcDbDirectory: ${olcDbDirectory}
-      '')
-    ) openldap.databases);
-in
-{
-  imports = [
-    openldap/sourcephile.nix
-  ];
-  options = {
-    services.openldap.domainSuffix = lib.mkOption {
-      type    = types.str;
-      default = "dc=${lib.concatStringsSep ",dc=" (lib.splitString "." config.networking.domain)}";
-      description = ''
-        LDAP suffix for config.networking.domain.
-      '';
-    };
-    services.openldap.databases = lib.mkOption {
-      default = {};
-      type = types.attrsOf (types.submodule ({name, options, config, ...}: {
-        options = {
-          conf = lib.mkOption {
-            type = types.lines;
-            description = "The database's config in LDIF.";
-          };
-          data = lib.mkOption {
-            type = types.lines;
-            description = "The database's data in LDIF.";
-          };
-          olcDbDirectory = lib.mkOption {
-            type = types.str;
-            description = "The directory where the database is stored.";
-            default = "${openldap.dataDir}/${name}";
-          };
-          resetData = lib.mkOption {
-            type = types.bool;
-            description = "Whether to reset the data at each start of the slapd service.";
-            default = false;
-          };
-        };
-      }));
-    };
-  };
-  config = {
-    users.ldap = {
-      enable = true;
-      server = "ldapi:///";
-      base = "ou=posix,${openldap.domainSuffix}";
-      bind = {
-        #distinguishedName = "cn=admin,${openldap.domainSuffix}";
-      };
-      daemon = {
-        enable = true;
-        extraConfig = ''
-          sasl_mech EXTERNAL
-          # NOTE: nslcd cannot use SASL to bind to rootpwmoddn
-          # which is the DN used by nslcd when passwd is run by root
-          # to change the userPassword of an LDAP user.
-          # SEE: https://www.reddit.com/r/linuxadmin/comments/53sxpl/how_do_i_configure_nslcd_to_use_a_sasl_external/d7w9awd/
-          # Thus, use: ldappasswd -H ldapi:// -Y EXTERNAL uid=$SomeUID,ou=accounts,ou=posix,dc=sourcephile,dc=fr
-        '';
-      };
-    };
-    services.openldap = {
-      enable    = true;
-      dataDir   = "/var/db/ldap";
-      configDir = "/var/db/slapd";
-      urlList   = [ "ldapi:///" ]; # UNIX socket
-    };
-    systemd.services.openldap = {
-      preStart = ''
-          set -e
-          # NOTE: slapd's config is always re-initialized.
-          rm -rf "${openldap.configDir}"/cn=config \
-                 "${openldap.configDir}"/cn=config.ldif
-          install -D -d -m 0700 -o "${openldap.user}" -g "${openldap.group}" "${openldap.configDir}"
-          # NOTE: olcDbDirectory must be created before adding the config.
-          '' +
-          unlinesAttrs (olcSuffix: {data, olcDbDirectory, resetData, ...}:
-            lib.optionalString resetData ''
-              rm -rf "${olcDbDirectory}"
-            '' + ''
-            install -D -d -m 0700 -o "${openldap.user}" -g "${openldap.group}" "${olcDbDirectory}"
-            '') openldap.databases
-          + ''
-          # NOTE: slapd is supposed to have been stopped by systemd
-          # before entering this preStart,
-          # hence slap* commands can safely be used.
-          #
-          # NOTE: slapadd(8):
-          # To populate the config database slapd-config(5),
-          # use -n 0 as it is always the first database.
-          # It must physically exist on the filesystem prior to this, however.
-          umask 0077
-          ${pkgs.openldap}/bin/slapadd -n 0 \
-           -F "${openldap.configDir}" \
-           -l ${configLDIF}
-          chown -R "${openldap.user}:${openldap.group}" "${openldap.configDir}"
-        '' +
-        unlinesAttrs (olcSuffix: {data, olcDbDirectory, resetData, ...}:
-          lib.optionalString resetData ''
-            ${pkgs.openldap}/bin/slapadd \
-             -F "${openldap.configDir}" \
-             -l ${pkgs.writeText "data.ldif" data}
-          '' + ''
-          test ! -e "${olcDbDirectory}" ||
-          chown -R "${openldap.user}:${openldap.group}" "${olcDbDirectory}"
-        '') openldap.databases;
-    };
-  };
-}
diff --git a/install/logical/friot/openldap/plurasoft.nix b/install/logical/friot/openldap/plurasoft.nix
deleted file mode 100644 (file)
index 9a13f28..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (config) networking;
-    inherit (config.services) openldap;
-    inherit (config.users) users groups;
-    inherit (pkgs.lib) unlines;
-    domainSuffix = openldap.domainSuffix;
-    posixAccount =
-     { uid
-     , uidNumber ? null
-     , gidNumber ? uidNumber
-     , cn ? ""
-     , sn ? ""
-     , userPassword ? "{SSHA}JtC8S4nzm+eX9cVgbyL6gquPWDZD4xXY"
-       # NOTE: doveadm pw -s SSHA -u $user -p $pass
-     , mailAlias ? []
-     , loginShell ? "/run/current-system/sw/bin/bash"
-     , mailEnabled ? true
-     , mailForwardingAddress ? []
-     , domain ? networking.domain
-     }: "\n" + lib.concatStringsSep "\n\n" [
-      (unlines ([ ''
-        dn: uid=${uid},ou=accounts,ou=posix,${domainSuffix}
-        objectClass: person
-        objectClass: posixAccount
-        objectClass: shadowAccount
-        objectClass: PostfixBookMailAccount
-        objectClass: PostfixBookMailForward
-        cn: ${cn}
-        sn: ${sn}
-        mail: ${uid}${lib.optionalString (networking.domain != "") "@${networking.domain}"}
-        mailEnabled: ${if mailEnabled then "TRUE" else "FALSE"}
-        #mailGroupMember: ${networking.domainBase}
-        homeDirectory: /home/${uid}
-        uidNumber: ${toString uidNumber}
-        gidNumber: ${toString gidNumber}
-        loginShell: ${loginShell}'' ]
-        ++ lib.optional (userPassword != "") "userPassword: ${userPassword}"
-        ++ map (forward: "mailForwardingAddress: ${forward}") mailForwardingAddress
-        ++ map (alias: "mailAlias: ${alias}@${networking.domain}") mailAlias
-        ++ lib.optional (mailAlias == []) "mailAlias:"
-             # NOTE: required by PostfixBookMailForward
-      ))
-      ''
-        dn: cn=${uid},ou=groups,ou=posix,${domainSuffix}
-        objectClass: top
-        objectClass: posixGroup
-        gidNumber: ${toString gidNumber}
-        memberUid: ${uid}
-      ''
-    ];
-in
-{
-  config = lib.mkIf config.users.ldap.enable {
-    services.openldap = {
-      databases = {
-        "${domainSuffix}" = {
-          resetData = true;
-          conf = ''
-            # sudo ldapsearch -LLL -H ldapi:// -D cn=admin,cn=config -Y EXTERNAL -b 'olcDatabase={1}mdb,cn=config' -s sub
-            dn: olcBackend={1}mdb,cn=config
-            objectClass: olcBackendConfig
-
-            dn: olcDatabase={1}mdb,cn=config
-            objectClass: olcDatabaseConfig
-            objectClass: olcMdbConfig
-            # NOTE: checkpoint the database periodically in case of system failure
-            # and to speed slapd shutdown.
-            olcDbCheckpoint: 512 30
-            # Database max size is 1G
-            olcDbMaxSize: 1073741824
-            olcLastMod: TRUE
-            # NOTE: database superuser. Needed for syncrepl.
-            olcRootDN: cn=admin,${domainSuffix}
-            # NOTE: superuser password, generated with slappasswd -h "{SSHA}" -s "$password"
-            #olcRootPW: {SSHA}COkATGNe7rs/g8vWcYP5rqt4u5sWdMgP
-            #
-            olcDbIndex: objectClass eq
-            olcDbIndex: cn,uid eq
-            olcDbIndex: uidNumber,gidNumber eq
-            olcDbIndex: member,memberUid eq
-            olcDbIndex: mail eq
-            olcDbIndex: mailAlias eq
-            olcDbIndex: mailEnabled eq
-            #
-            olcAccess: to attrs=userPassword
-              by self write
-              by anonymous auth
-              by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
-              by * none
-            olcAccess: to attrs=shadowLastChange
-              by self write
-              by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
-              by * none
-            olcAccess: to dn.sub="ou=posix,${domainSuffix}"
-              by self read
-              by dn="gidNumber=${toString groups.nslcd.gid}+uidNumber=${toString users.nslcd.uid},cn=peercred,cn=external,cn=auth" read
-              by dn="gidNumber=${toString groups.postfix.gid}+uidNumber=${toString users.postfix.uid},cn=peercred,cn=external,cn=auth" read
-              by dn="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read
-            # NOTE: dovecot/auth runs as root, hence the gidNumber=0+uidNumber=0
-            olcAccess: to *
-              by self read
-              by * none
-          '';
-          data = ''
-            dn: ${domainSuffix}
-            objectClass: top
-            objectClass: dcObject
-            objectClass: organization
-            o: ${networking.domainBase}
-
-            dn: cn=admin,${domainSuffix}
-            objectClass: simpleSecurityObject
-            objectClass: organizationalRole
-            description: ${networking.domainBase} LDAP administrator
-            roleOccupant: ${domainSuffix}
-            userPassword: 
-            #userPassword: {SSHA}NONVwwKnKsCBmFxkMqTCFekdu3SJQHc9
-
-            dn: ou=posix,${domainSuffix}
-            objectClass: top
-            objectClass: organizationalUnit
-
-            dn: ou=accounts,ou=posix,${domainSuffix}
-            objectClass: top
-            objectClass: organizationalUnit
-
-            dn: ou=groups,ou=posix,${domainSuffix}
-            objectClass: top
-            objectClass: organizationalUnit
-
-            dn: cn=${networking.domainBase},ou=groups,ou=posix,${domainSuffix}
-            objectClass: top
-            objectClass: posixGroup
-            gidNumber: 20000
-            memberUid: ju
-            memberUid: sevy
-
-          ''
-          + lib.concatMapStrings posixAccount [
-            { uid="ju"; uidNumber=10000; cn="Julien M."; sn="julm"; mailAlias = ["juju"]; }
-            { uid="sevy"; uidNumber=10001; cn="Séverine P."; sn="sévy"; mailAlias = ["severine.popek" "ouais-ouais"]; }
-            { uid="nomail"; uidNumber=10002; mailAlias = ["noalias"]; mailEnabled = false; }
-            { uid="post"; domain="friot"; mailForwardingAddress = ["ju@${networking.domain}"]; }
-            { uid="host"; mailForwardingAddress = ["ju@${networking.domain}"]; }
-          ];
-        };
-      };
-    };
-  };
-}
diff --git a/install/logical/friot/openldap/schema/postfix-book.ldif b/install/logical/friot/openldap/schema/postfix-book.ldif
deleted file mode 100644 (file)
index d61c582..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-# SOURCE: https://github.com/variablenix/ldap-mail-schema/
-dn: cn=postfix-book,cn=schema,cn=config
-objectClass: olcSchemaConfig
-olcAttributeTypes: ( 1.3.6.1.4.1.29426.1.10.1
-  NAME 'mailHomeDirectory'
-  DESC 'The absolute path to the mail user home directory'
-  EQUALITY caseExactIA5Match
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
-  SINGLE-VALUE )
-olcAttributeTypes: ( 1.3.6.1.4.1.29426.1.10.2
-  NAME 'mailAlias'
-  DESC 'RFC822 Mailbox - mail alias'
-  EQUALITY caseIgnoreIA5Match
-  SUBSTR caseIgnoreIA5SubstringsMatch
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
-olcAttributeTypes: ( 1.3.6.1.4.1.29426.1.10.3
-  NAME 'mailUidNumber'
-  DESC 'UID required to access the mailbox'
-  EQUALITY integerMatch
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
-  SINGLE-VALUE )
-olcAttributeTypes: ( 1.3.6.1.4.1.29426.1.10.4
-  NAME 'mailGidNumber'
-  DESC 'GID required to access the mailbox'
-  EQUALITY integerMatch
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
-  SINGLE-VALUE )
-olcAttributeTypes: ( 1.3.6.1.4.1.29426.1.10.5
-  NAME 'mailEnabled'
-  DESC 'TRUE to enable, FALSE to disable account'
-  EQUALITY booleanMatch
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
-  SINGLE-VALUE )
-olcAttributeTypes: ( 1.3.6.1.4.1.29426.1.10.6
-  NAME 'mailGroupMember'
-  DESC 'Name of a mail distribution list'
-  EQUALITY caseExactIA5Match
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-olcAttributeTypes: ( 1.3.6.1.4.1.29426.1.10.7
-  NAME 'mailQuota'
-  DESC 'Mail quota limit in kilobytes'
-  EQUALITY caseExactIA5Match
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-olcAttributeTypes: ( 1.3.6.1.4.1.29426.1.10.8
-  NAME 'mailStorageDirectory'
-  DESC 'The absolute path to the mail users mailbox'
-  EQUALITY caseExactIA5Match
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
-  SINGLE-VALUE )
-olcAttributeTypes: ( 1.3.6.1.4.1.29426.1.10.9
-  NAME 'mailSieveRuleSource'
-  DESC 'Sun ONE Messaging Server defined attribute'
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
-  X-ORIGIN 'Sun ONE Messaging Server' )
-olcAttributeTypes: ( 1.3.6.1.4.1.29426.1.10.10
-  NAME 'mailForwardingAddress'
-  DESC 'Address(es) to forward all incoming messages to.'
-  EQUALITY caseIgnoreIA5Match
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{320} )
-olcObjectClasses: ( 1.3.6.1.4.1.29426.1.2.2.1
-  NAME 'PostfixBookMailAccount'
-  DESC 'Mail account used in Postfix Book'
-  SUP top AUXILIARY
-  MUST mail
-  MAY ( mailHomeDirectory $ mailAlias $ mailGroupMember $
-  mailUidNumber $ mailGidNumber $ mailEnabled $
-  mailQuota $ mailStorageDirectory $ mailSieveRuleSource ) )
-olcObjectClasses: ( 1.3.6.1.4.1.29426.1.2.2.2
-  NAME 'PostfixBookMailForward'
-  DESC 'Mail forward used in Postfix Book'
-  SUP top AUXILIARY
-  MUST ( mail $ mailAlias )
-  MAY mailForwardingAddress )
diff --git a/install/logical/friot/postfix.nix b/install/logical/friot/postfix.nix
deleted file mode 100644 (file)
index bf36337..0000000
+++ /dev/null
@@ -1,475 +0,0 @@
-{pkgs, lib, config, nodes, ...}:
-let inherit (builtins) attrNames toFile;
-    inherit (lib) types;
-    inherit (pkgs.lib) unlines unlinesAttrs;
-    inherit (config) networking;
-    inherit (config.services) x509 postfix dovecot2 openldap;
-    unwords = lib.concatStringsSep " ";
-    when    = x: y: if x == null then "" else y;
-
-    submissionHeaderCleanupRules = pkgs.writeText "submission_header_cleanup_rules" ''
-      # Removes sensitive headers from mails handed in via the submission or smtps port.
-      # See https://thomas-leister.de/mailserver-debian-stretch/
-      # Uses "pcre" style regex.
-
-      /^Received:/         IGNORE
-      /^User-Agent:/       IGNORE
-      /^X-Enigmail:/       IGNORE
-      /^X-Mailer:/         IGNORE
-      /^X-Originating-IP:/ IGNORE
-    '';
-in
-{
-options.services.postfix.aliases = lib.mkOption {
-  type    = with types; attrsOf (listOf str);
-  default = {};
-  example = { "root@${networking.domain}" = [
-                "user1@${networking.domain}"
-                "user2@${networking.domain}"
-              ];
-              "@example.coop" = ["user1@${networking.domain}"];
-            };
-};
-config = {
-  systemd.services.postfix.after =
-    [ "openldap.service" ] ++
-    (if x509.scheme == "letsencrypt"
-    then [ "nginx.service" ] # XXX: not sure if this is enough
-    else []);
-  services.postfix = {
-    enable = true;
-    #hostname = networking.domain;
-    #domain = "localdomain";
-    networksStyle = "host";
-    #mapFiles."valias" = toFile "valias" (unlines (all_valiases_postfix ++ catchAllPostfix));
-    # See https://blog.grimneko.de/2011/12/24/a-bunch-of-tips-for-improving-your-postfix-setup/
-    # for details on how this file looks. By using the same file as valias,
-    # every alias is uniquely owned by its user.
-    # The user's own address is already in all_valiases_postfix.
-    #mapFiles."vaccounts" = toFile "vaccounts" (unlines all_valiases_postfix);
-    mapFiles."virtual_alias_maps" =
-      toFile "virtual_alias_maps"
-        (unlinesAttrs
-         (from: to: "${from} ${unwords to}")
-         postfix.aliases);
-    mapFiles."ldap-virtual_alias_maps.cf" =
-      toFile "ldap-virtual_alias_maps.cf" ''
-        version          = 3
-        debuglevel       = 0
-        server_host      = ldapi://
-        bind             = sasl
-        sasl_mechs       = EXTERNAL
-        search_base      = ou=posix,${openldap.domainSuffix}
-        scope            = sub
-        dereference      = 0
-        query_filter     = (&(mailAlias=%s)(mailEnabled=TRUE))
-        result_format    = %s
-        result_attribute = mail
-      '';
-    mapFiles."ldap-forward.cf" =
-      toFile "ldap-forward.cf" ''
-        version          = 3
-        debuglevel       = 0
-        server_host      = ldapi://
-        bind             = sasl
-        sasl_mechs       = EXTERNAL
-        search_base      = ou=posix,${openldap.domainSuffix}
-        scope            = sub
-        dereference      = 0
-        query_filter     = (&(mail=%s)(mailEnabled=TRUE))
-        result_format    = %s
-        result_attribute = mailForwardingAddress
-      '';
-    sslCert = x509.cert;
-    sslKey = x509.key;
-    #enableSubmission = true;
-    #enableSmtp = true;
-    destination = [
-      "localhost"
-      "localhost.localdomain"
-      networking.hostName
-      "${networking.hostName}.localdomain"
-    ];
-    networks = [
-      "127.0.0.0/8"
-      "[::1]/128"
-    ];
-    recipientDelimiter = "+";
-    config = {
-      # Appending .domain is the MUA's job
-      append_dot_mydomain = false;
-      # No console bell on new mail
-      biff = false;
-      body_checks = "";
-      #content_filter = "amavisfeed:[127.0.0.1]:10024";
-      #debug_peer_level = 4;
-      #debug_peer_list = ".$myhostname";
-      default_extra_recipient_limit = "5000";
-      # Uncomment the next line to generate "delayed mail" warnings
-      #delay_warning_time = "4h";
-      # Stops some techniques used to harvest email addresses
-      disable_vrfy_command = true;
-      duplicate_filter_limit = "5000";
-      enable_long_queue_ids = false;
-      # Pass unexisting $mydestination recipients to dovecot
-      fallback_transport = "lmtp:unix:private/dovecot-lmtp";
-      forward_path = [
-        ''$home/.forward''${recipient_delimiter}''${extension}''
-        "$home/.forward"
-      ];
-      #header_checks = "regexp:/var/lib/postfix/conf/header_checks";
-      #inet_interfaces = "all";
-      line_length_limit = "2048";
-
-      # Let $fallback_transport check existence of recipients
-      local_recipient_maps = "";
-      #mail_spool_directory = "/var/spool/mail";
-        # NOTE: nixpkgs's default
-      #local_header_rewrite_clients = "";
-      #home_mailbox = "Maildir/";
-      #mailbox_command = ''
-      #  ${pkgs.procmail}/bin/procmail -t -a "$SENDER" -a "$RECIPIENT" -a "$USER" -a "$EXTENSION" -a "$DOMAIN" -a "$ORIGINAL_RECIPIENT" "$HOME/.procmailrc"
-      #'';
-      mailbox_size_limit = "204800000";
-
-      masquerade_classes = [ "envelope_sender" "header_sender" "header_recipient" ];
-      masquerade_domains = "";
-      masquerade_exceptions = "root";
-      maximal_queue_lifetime = "5d";
-      message_size_limit = "20480000";
-      mime_header_checks = "";
-      milter_header_checks = "";
-      nested_header_checks = "";
-      #non_smtpd_milters = "";
-      parent_domain_matches_subdomains = [
-        #"debug_peer_list"
-        #"fast_flush_domains"
-        #"mynetworks"
-        #"permit_mx_backup_networks"
-        #"qmqpd_authorized_clients"
-        #"smtpd_access_maps"
-      ];
-      permit_mx_backup_networks = "";
-      #policy-spf_time_limit = "3600s";
-      propagate_unmatched_extensions = [ "canonical" "virtual" "alias" ];
-      queue_minfree = "0";
-      #receive_override_options = "no_address_mappings";
-        # no_unknown_recipient_checks
-        #         Do not try to reject unknown recipients (SMTP server only).
-        #         This is typically specified AFTER an external content filter.
-        # no_address_mappings
-        #         Disable canonical address mapping, virtual alias map expansion,
-        #         address masquerading, and automatic BCC (blind carbon-copy) recipients.
-        #         This is typically specified BEFORE an external content filter (eg. amavis).
-        # no_header_body_checks
-        #         Disable header/body_checks. This is typically specified AFTER
-        #         an external content filter.
-        # no_milters
-        #         Disable Milter (mail filter) applications.
-        #         This is typically specified AFTER an external content filter.
-      # Parse the extension in email address, eg. contact+extension@
-      relayhost = "";
-      #relay_clientcerts = hash:/var/lib/postfix/conf/relay_clientcerts
-      # This is where to put backup MX domains
-      relay_domains = "$mydestination";
-      relay_recipient_maps = "";
-      smtp_body_checks = "";
-      #smtp_cname_overrides_servername = false;
-      smtp_connect_timeout = "60s";
-      #smtp_header_checks = "regexp:/var/lib/postfix/smtp_header_checks";
-      smtp_mime_header_checks = "";
-      smtp_nested_header_checks = "";
-      smtp_tls_exclude_ciphers = [ "ADH" "MD5" "CAMELLIA" "SEED" "3DES" "DES" "RC4" "eNULL" "aNULL" ];
-      #smtp_tls_fingerprint_digest = "sha1";
-      smtp_tls_loglevel = "1";
-      #smtp_tls_note_starttls_offer = true;
-      #smtp_tls_policy_maps = "hash:/var/lib/postfix/conf/tls_policy";
-      # Only allow TLSv* protocols
-      smtp_tls_protocols = [ "!SSLv2" "!SSLv3" ];
-      smtp_tls_scert_verifydepth = "5";
-      #smtp_tls_secure_cert_match = [ "nexthop" "dot-nexthop" ];
-      smtp_tls_security_level = "may";
-      smtp_tls_session_cache_database = "btree:$data_directory/smtp_tls_session_cache";
-      #smtp_tls_session_cache_timeout = "3600s";
-      #smtp_tls_verify_cert_match = "hostname";
-      # Useful to test restrictions
-      smtpd_authorized_xclient_hosts = "127.0.0.1";
-      smtpd_banner = "${networking.fqdn} ESMTP $mail_name (NixOS)";
-      smtpd_client_connection_count_limit = "50";
-      smtpd_client_connection_rate_limit = "0";
-      smtpd_client_event_limit_exceptions = "$mynetworks";
-      smtpd_client_message_rate_limit = "0";
-      smtpd_client_new_tls_session_rate_limit = "0";
-      smtpd_client_port_logging = false;
-      smtpd_client_recipient_rate_limit = "0";
-      smtpd_client_restrictions = [
-        #"check_client_access hash:/var/lib/postfix/conf/client_blacklist"
-      ];
-      smtpd_data_restrictions = [
-        "reject_unauth_pipelining"
-          # Force the smtp client to wait OK before sending
-        "permit"
-      ];
-      # Disable opportunistic encryption
-      smtpd_discard_ehlo_keywords = "starttls";
-      #smtpd_end_of_data_restrictions = "";
-      # Ban 5 sec on error
-      smtpd_error_sleep_time = "5";
-      smtpd_helo_required = true;
-      smtpd_helo_restrictions = [
-        "reject_invalid_helo_hostname"
-        "reject_non_fqdn_helo_hostname"
-        #"reject_unknown_helo_hostname"
-          # May be useful to fight spam
-        "permit"
-      ];
-      #smtpd_milters = "";
-      smtpd_peername_lookup = true;
-      smtpd_recipient_limit = "5000";
-      smtpd_recipient_overshoot_limit = "5000";
-      smtpd_recipient_restrictions = [
-        "reject_non_fqdn_recipient"
-        #"reject_invalid_hostname"
-        "reject_unknown_recipient_domain"
-        #"reject_non_fqdn_sender"
-        "reject_unauth_pipelining"
-        #"check_policy_service inet:localhost:12340"
-        # check quota
-        "permit_mynetworks"
-        #"permit_tls_clientcerts"
-        "permit_sasl_authenticated"
-        "reject_unverified_recipient"
-          # $fallback_transport is responsible of checking the existence of the recipient
-          # WARNING: verify(8) has a cache, dumpable if verify(8) is stopped, with:
-          # postmap -s btree:/var/lib/postfix/data/verify_cache
-        # Bypass SPF check and postgrey if the recipient is not for us or someone in backup_mx
-        "reject_unauth_destination"
-        # Check SPF
-        #"check_policy_service unix:private/spfcheck"
-        # Greylisting using postgrey
-        #"check_policy_service unix:${postgrey.socket.path}"
-        "permit_auth_destination"
-        "reject"
-        #"reject_unknown_sender_domain"
-          # Maybe better in smtpd_sender_restrictions
-        #"reject_rbl_client bl.spamcop.net"
-        #"reject_rbl_client list.dsbl.org"
-        #"reject_rbl_client zen.spamhaus.org"
-        #"reject_rbl_client dnsbl.sorbs.net"
-      ];
-      smtpd_relay_restrictions = [
-        "permit_mynetworks"
-        "permit_sasl_authenticated"
-          # NOTE: permit auth through dovecot's SASL
-        "reject_unauth_destination"
-      ];
-      #smtpd_restriction_classes = "";
-      broken_sasl_auth_clients = false;
-      #smtpd_sasl_auth_enable = true;
-      #smtpd_sasl_path = "private/auth";
-      #smtpd_sasl_security_options = "noanonymous";
-      #smtpd_sasl_type = "dovecot";
-      smtpd_sender_restrictions = [
-        "permit_mynetworks"
-        #"permit_tls_clientcerts"
-        "permit_sasl_authenticated"
-          # NOTE: permit auth through dovecot's SASL
-        #"check_sender_access hash:/var/lib/postfix/conf/sender_access"
-        "reject_unauth_pipelining"
-        "reject_non_fqdn_sender"
-        #"reject_sender_login_mismatch"
-        #"reject_unknown_sender_domain"
-        "permit"
-      ];
-      smtpd_starttls_timeout = "300s";
-      #smtpd_tls_always_issue_session_ids = true;
-      # No SASL AUTH without TLS
-      smtpd_tls_auth_only = true;
-      #smtpd_tls_CApath = "/etc/postfix/x509/ca/";
-      smtpd_tls_ask_ccert = false;
-      #smtpd_tls_ccert_verifydepth = "5";
-      smtpd_tls_ciphers = "high";
-      smtpd_tls_eecdh_grade = "ultra";
-      # Disable weak ciphers as reported by https://ssl-tools.net
-      # https://serverfault.com/questions/744168/how-to-disable-rc4-on-postfix
-      smtpd_tls_exclude_ciphers = [ "RC4" "aNULL" ];
-      smtpd_tls_fingerprint_digest = "sha512";
-      # Log only a summary message on TLS handshake completion
-      smtpd_tls_loglevel = "1";
-      smtpd_tls_mandatory_ciphers = "high";
-      smtpd_tls_mandatory_protocols = "TLSv1"; # FIXME: TLSv1.3
-      # Only allow TLSv*
-      smtpd_tls_protocols = [ "!SSLv2" "!SSLv3" ];
-      #smtpd_tls_received_header = false;
-      smtpd_tls_req_ccert = false;
-      # Postfix 2.3 and later
-      # encrypt
-      #  Mandatory TLS encryption: announce STARTTLS support to SMTP clients, and require that clients use TLS
-      #  encryption. According to [1720]RFC 2487 this MUST NOT be applied in case of a publicly-referenced
-      #  SMTP server. Instead, this option should be used only on dedicated servers.
-      smtpd_tls_security_level = "may";
-      smtpd_tls_session_cache_database = "btree:$data_directory/smtpd_tls_session_cache";
-      #smtpd_tls_session_cache_timeout = "3600s";
-      # Stops mail from poorly written software
-      strict_rfc821_envelopes = true;
-      #sympa_destination_recipient_limit = "1";
-      #sympabounce_destination_recipient_limit = "1";
-      # postconf(5) discourages to change this
-      #tls_high_cipherlist = "AES256-SHA";
-      #tls_random_bytes = "32";
-      # Must not be in a chroot
-      #tls_random_exchange_name = "$data_directory/prng_exch";
-      #tls_random_prng_update_period = "3600s";
-      #tls_random_reseed_period = "3600s";
-      # Use a non blocking source of randomness
-      tls_random_source = "dev:/dev/urandom";
-      transport_maps = [
-        #"ldap:transport"
-        #"hash:/etc/postfix/transport-dovecot"
-        #"hash:/etc/postfix/$mydomain/transport"
-        #"hash:/etc/dovecot/transport"
-        #"regexp:/etc/sympa/transport"
-      ];
-      # Rejects immediately what $fallback_transport rejects
-      unverified_recipient_reject_code = "550";
-      # Do not specify virtual alias domain names in mydestination
-      # or relay_domains configuration parameters
-      #
-      # With  a  virtual  alias  domain,  the  Postfix SMTP server
-      # accepts  mail  for  known-user@virtual-alias.domain,   and
-      # rejects   mail  for  unknown-user@virtual-alias.domain  as
-      # undeliverable.
-      virtual_alias_domains = [];
-      virtual_alias_maps = [
-        #"hash:/etc/postfix/virtual_alias_maps"
-        #"hash:/etc/postfix/virtual_domain_alias_maps"
-        "ldap:/etc/postfix/ldap-forward.cf"
-        "ldap:/etc/postfix/ldap-virtual_alias_maps.cf"
-        #"hash:/etc/postfix/virtual_alias-dovecot"
-        #"hash:/var/lib/postfix/conf/valias"
-        #"regexp:/etc/sympa/virtual_alias"
-      ];
-      #virtual_uid_maps = "static:5000";
-      #virtual_gid_maps = "static:5000";
-      #virtual_mailbox_base = dovecot2.mailDir;
-      virtual_mailbox_domains = [ networking.domain ] ++ networking.domainAliases;
-      #virtual_mailbox_maps = "hash:/etc/postfix/virtual_mailbox_maps";
-      virtual_transport = "lmtp:unix:private/dovecot-lmtp";
-    };
-    #submissionOptions = {
-    #  smtpd_tls_security_level     = "encrypt";
-    #  smtpd_sasl_auth_enable       = "yes";
-    #  smtpd_sasl_type              = "dovecot";
-    #  smtpd_sasl_path              = "private/auth";
-    #  smtpd_sasl_security_options  = "noanonymous";
-    #  smtpd_sasl_local_domain      = "$myhostname";
-    #  smtpd_client_restrictions    = "permit_sasl_authenticated,reject";
-    #  smtpd_sender_login_maps      = "hash:/etc/postfix/vaccounts";
-    #  smtpd_sender_restrictions    = "reject_sender_login_mismatch";
-    #  smtpd_recipient_restrictions = "reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject";
-    #  cleanup_service_name         = "submission-header-cleanup";
-    #};
-    extraMasterConf = ''
-      #spfcheck    unix  -        n       n       -        0        spawn
-      #  user=policyd-spf argv=/usr/sbin/postfix-policyd-spf-perl
-      465         inet  n        -       -       -        -        smtpd
-        -o milter_macro_daemon_name=ORIGINATING
-        -o smtpd_client_restrictions=permit_sasl_authenticated,reject
-        -o smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject
-        -o smtpd_sasl_auth_enable=yes
-        -o smtpd_sasl_local_domain=$myhostname
-        -o smtpd_sasl_path=private/auth
-        -o smtpd_sasl_security_options=noanonymous
-        -o smtpd_sasl_type=dovecot
-        -o smtpd_tls_ask_ccert=no
-        -o smtpd_tls_auth_only=yes
-        -o smtpd_tls_ccert_verifydepth=0
-        -o smtpd_tls_loglevel=1
-        -o smtpd_tls_req_ccert=no
-        -o smtpd_tls_security_level=encrypt
-        -o smtpd_tls_wrappermode=yes
-      # -o smtpd_sender_restrictions=reject_sender_login_mismatch
-      # -o smtpd_sender_login_maps=hash:/etc/postfix/vaccounts
-      # -o cleanup_service_name=submission-header-cleanup
-      submission-header-cleanup unix n - n    -       0       cleanup
-        -o header_checks=pcre:${submissionHeaderCleanupRules}
-      #spfcheck  unix  -       n       n       -       0       spawn
-      #  user=policyd-spf argv=/usr/bin/postfix-policyd-spf-perl
-      #uucp      unix  -       n       n       -       -       pipe
-      #  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
-      #smtp      inet  n       -       -       -       -       smtpd
-      #  -o cleanup_service_name=pre-cleanup
-      #  -o content_filter=amavis:[127.0.0.1]:10024
-      #  -o smtpd_sender_restrictions=reject_unauth_pipelining,reject_non_fqdn_sender,permit
-      #  -o receive_override_options=no_address_mappings
-      #amavis    unix  -       -       n        -      2       lmtp
-      #  -o lmtp_data_done_timeout=1200
-      #  -o lmtp_send_xforward_command=yes
-      #  -o lmtp_tls_note_starttls_offer=no
-      #127.0.0.1:10025 inet n  -       n       -       -       smtpd
-      #  -o content_filter=
-      #  -o local_header_rewrite_clients=
-      #  -o local_recipient_maps=
-      #  -o mynetworks=127.0.0.0/8
-      #  -o receive_override_options=no_header_body_checks,no_milters,no_unknown_recipient_checks
-      #  -o relay_recipient_maps=
-      #  -o smtpd_client_connection_count_limit=0
-      #  -o smtpd_client_connection_rate_limit=0
-      #  -o smtpd_client_restrictions=permit_mynetworks,reject
-      #  -o smtpd_data_restrictions=reject_unauth_pipelining
-      #  -o smtpd_delay_reject=no
-      #  -o smtpd_end_of_data_restrictions=
-      #  -o smtpd_error_sleep_time=0
-      #  -o smtpd_hard_error_limit=1000
-      #  -o smtpd_helo_restrictions=
-      #  -o smtpd_milters=
-      #  -o smtpd_recipient_restrictions=permit_mynetworks,reject
-      #  -o smtpd_restriction_classes=
-      #  -o smtpd_sender_restrictions=
-      #  -o smtpd_soft_error_limit=1001
-      #  -o strict_rfc821_envelopes=yes
-      #submission inet n       -       -       -       -       smtpd
-      #  -o cleanup_service_name=pre-cleanup
-      #  -o content_filter=amavis:[127.0.0.1]:10024
-      #  -o milter_macro_daemon_name=ORIGINATING
-      #  -o receive_override_options=no_address_mappings
-      #  -o smtpd_sender_restrictions=permit_tls_clientcerts,reject
-      #  -o smtpd_tls_ask_ccert=yes
-      #  -o smtpd_tls_auth_only=yes
-      #  -o smtpd_tls_ccert_verifydepth=2
-      #  -o smtpd_tls_loglevel=1
-      #  -o smtpd_tls_req_ccert=yes
-      #  -o smtpd_tls_security_level=encrypt
-      #smtps     inet  n       -       -       -       -       smtpd
-      #  -o milter_macro_daemon_name=ORIGINATING
-      #  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
-      #  -o smtpd_sasl_auth_enable=yes
-      #  -o smtpd_tls_ask_ccert=yes
-      #  -o smtpd_tls_auth_only=yes
-      #  -o smtpd_tls_ccert_verifydepth=0
-      #  -o smtpd_tls_loglevel=1
-      #  -o smtpd_tls_req_ccert=no
-      #  -o smtpd_tls_security_level=encrypt
-      #  -o smtpd_tls_wrappermode=yes
-      #pickup    fifo  n       -       -       60      1       pickup
-      #  -o cleanup_service_name=pre-cleanup
-      #  -o content_filter=amavis:[127.0.0.1]:10024
-      #pre-cleanup unix n      -       -       -       0       cleanup
-      #  -o virtual_alias_maps=
-      #cleanup   unix  n       -       -       -       0       cleanup
-      #  -o mime_header_checks=
-      #  -o nested_header_checks=
-      #  -o body_checks=
-      #  -o header_checks=
-      #-- SYMPA begin
-      #sympa unix - n n - - pipe
-      #  flags=R user=sympa argv=/usr/lib/sympa/bin/queue ''${recipient}
-      #sympabounce unix - n n - - pipe
-      #  flags=R user=sympa argv=/usr/lib/sympa/bin/bouncequeue ''${recipient}
-      #-- SYMPA end
-    '';
-     #noclue    unix  -       n       n       -       -       pipe
-     #  flags=q user=noclue argv=/usr/local/bin/noclue-delivery ${recipient} ${sender}
-  };
-};
-}
diff --git a/install/logical/friot/postgresql.nix b/install/logical/friot/postgresql.nix
deleted file mode 100644 (file)
index bc7e6f7..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (lib) types;
-    inherit (pkgs.lib) unlines unlinesAttrs;
-    inherit (config) networking users;
-    inherit (config.services) postgresql;
-    psql = "${pkgs.postgresql}/bin/psql --set ON_ERROR_STOP=1 -U ${postgresql.superUser}";
-    psqlRun = args: sql: "${psql} ${args} -f - <<EOF\n" + sql + "\nEOF\n";
-    initLanguages = initLanguagePLPGSQL;
-    initLanguagePLPGSQL =
-      psqlRun "template1" ''
-        CREATE OR REPLACE FUNCTION create_language_plpgsql()
-          RETURNS BOOLEAN AS \$\$
-            CREATE LANGUAGE plpgsql;
-            SELECT TRUE;
-          \$\$ LANGUAGE SQL;
-        SELECT CASE WHEN NOT (
-          SELECT  TRUE AS exists
-          FROM    pg_language
-          WHERE   lanname = 'plpgsql'
-          UNION
-          SELECT  FALSE AS exists
-          ORDER BY exists DESC
-          LIMIT 1
-         )
-        THEN
-          create_language_plpgsql()
-        ELSE
-          FALSE
-        END AS plpgsql_created;
-        DROP FUNCTION create_language_plpgsql();
-      '';
-    initSchemas =
-      initSchemaPublic +
-      psqlRun "" (unlinesAttrs (schema: {owner, extraConfig, ...}: ''
-        DO LANGUAGE plpgsql \$\$
-        BEGIN
-          IF NOT EXISTS (SELECT * FROM pg_catalog.pg_namespace WHERE nspname = "${schema}" LIMIT 1) THEN
-            CREATE SCHEMA ${schema}
-             AUTHORIZATION ${owner};
-          END IF;
-        END;
-        \$\$;
-        ${extraConfig}
-      '') postgresql.schemas);
-    initSchemaPublic =
-      psqlRun "template1" ''
-        -- NOTE: deny access to public schema,
-        --       so that users do not see others' databases
-        REVOKE ALL ON DATABASE template1 FROM public;
-        REVOKE ALL ON SCHEMA   public    FROM public;
-        GRANT  ALL ON SCHEMA   public    TO   ${postgresql.superUser};
-      '' +
-      psqlRun "template1" ''
-        -- NOTE: deny public access to all tables
-        REVOKE ALL ON ALL TABLES IN SCHEMA pg_catalog FROM public;
-        REVOKE ALL ON               SCHEMA pg_catalog FROM public;
-      '';
-    initUsers = psqlRun ""
-      (unlinesAttrs (user: {auth, extraConfig, ...}: ''
-        DO LANGUAGE plpgsql \$\$
-        BEGIN
-          IF NOT EXISTS (SELECT * FROM pg_catalog.pg_user WHERE usename = '${user}' LIMIT 1) THEN
-            CREATE ROLE ${user}
-             LOGIN
-             NOCREATEDB
-             NOCREATEROLE
-             NOINHERIT
-             NOSUPERUSER;
-          END IF;
-        END;
-        \$\$;
-        GRANT USAGE ON SCHEMA public TO ${user};
-        ${extraConfig}
-      '') postgresql.users);
-    initRoles = psqlRun ""
-      (unlinesAttrs (role: {...}: ''
-        DO LANGUAGE plpgsql \$\$
-        BEGIN
-          IF NOT EXISTS (SELECT * FROM pg_catalog.pg_roles WHERE rolname = "${role}" LIMIT 1) THEN
-            CREATE ROLE ${role}
-             NOLOGIN
-             NOCREATEDB
-             NOCREATEROLE
-             NOINHERIT
-             NOSUPERUSER;
-          END IF;
-        END;
-        \$\$;
-      '') postgresql.roles);
-    initDatabases =
-      unlinesAttrs (db: {owner ? db, users, extraConfig, ...}: ''
-        # NOTE: CREATE DATABASE cannot be done inside a function or multi-lines input.
-        exists="$(${psql} template1 -t -c "SELECT datname FROM pg_catalog.pg_database WHERE datname = '${db}' LIMIT 1")"
-        test -n "$exists" ||
-        ${psql} template1 -c "CREATE DATABASE ${db} WITH OWNER=${owner};"
-        '' + psqlRun "template1" ''
-          REVOKE ALL ON DATABASE ${db} FROM public;
-          ${unlines (map (user: "GRANT CONNECT,TEMPORARY ON DATABASE ${db} TO ${user};") users)}
-        '' +
-        psqlRun db ''
-          GRANT ALL ON SCHEMA public TO ${owner} WITH GRANT OPTION;
-          ${extraConfig}
-        ''
-      ) postgresql.databases;
-in
-{
-  options = {
-    services.postgresql.databases = lib.mkOption {
-      default = {};
-      type = types.attrsOf (types.submodule ({name, options, config, ...}: {
-        options = {
-          data = lib.mkOption {
-            type = types.lines;
-            description = "The database's data in SQL.";
-          };
-          owner = lib.mkOption {
-            type = types.str;
-            description = "The database's owner.";
-            default = name;
-          };
-          users = lib.mkOption {
-            type = types.listOf types.str;
-            description = "Databases' users.";
-            default = [];
-          };
-          resetData = lib.mkOption {
-            type = types.bool;
-            description = "Whether to reset the data at each start of the postgresql service.";
-            default = false;
-          };
-          extraConfig = lib.mkOption {
-            type = types.lines;
-            description = "Extra SQL config code (run on the database).";
-            default = "";
-          };
-        };
-      }));
-    };
-    services.postgresql.schemas = lib.mkOption {
-      default = {};
-      type = types.attrsOf (types.submodule ({name, options, config, ...}: {
-        options = {
-          data = lib.mkOption {
-            type = types.lines;
-            description = "The schema's data in SQL.";
-          };
-          resetData = lib.mkOption {
-            type = types.bool;
-            description = "Whether to reset the data at each start of the postgresql service.";
-            default = false;
-          };
-          extraConfig = lib.mkOption {
-            type = types.lines;
-            description = "Extra SQL config code.";
-            default = "";
-          };
-        };
-      }));
-    };
-    services.postgresql.users = lib.mkOption {
-      default = {};
-      type = types.attrsOf (types.submodule ({name, options, config, ...}: {
-        options = {
-          auth = lib.mkOption {
-            type = types.enum [ "unix" "password" ];
-            description = "Authentification method.";
-            default = "unix";
-          };
-          extraConfig = lib.mkOption {
-            type = types.lines;
-            description = "Extra SQL config code.";
-            default = "";
-          };
-        };
-      }));
-    };
-    services.postgresql.roles = lib.mkOption {
-      default = {};
-      type = types.attrsOf (types.submodule ({name, options, config, ...}: {
-        options = {
-        };
-      }));
-    };
-  };
-  config = {
-    users.users = lib.mapAttrs (user: {auth, ...}:
-      { extraGroups = lib.optionals (auth == "unix")
-          [ users.users.postgres.group ];
-      }
-    ) postgresql.users;
-    systemd.services.postgresql = {
-      postStart = unlines [
-        "set -x"
-        initLanguages
-        initSchemas
-        initUsers
-        initRoles
-        initDatabases
-      ];
-      #serviceConfig = {
-      #  RuntimeDirectory     = [ "postgresql" ];
-      #  RuntimeDirectoryMode = "0775";
-      #};
-    };
-    services = {
-      postgresql = {
-        enable = true;
-        extraConfig = ''
-          #unix_socket_directories = '/run/postgresql'
-          #unix_socket_group = '${postgresql.superUser}-data'
-          unix_socket_permissions = 0770 # begin with 0 to use octal notation
-        '';
-        identMap = lib.mkForce ''
-          # MAPNAME  SYSTEM-USERNAME          PG-USERNAME
-          admin      ${postgresql.superUser}  ${postgresql.superUser}
-          admin      root                     ${postgresql.superUser}
-          ${unlinesAttrs (user: {...}: ''user  root  ${user}'') postgresql.users}
-          user       /^(.*)$                  \1
-        '';
-        authentication = lib.mkForce ''
-          # CONNECTION  DATABASE  USER      AUTH  OPTIONS
-          local         all       postgres  peer  map=admin
-          local         all       backup    peer
-          local         sameuser  all       peer  map=user
-          local         samerole  all       peer  map=role
-        '';
-      };
-      postgresqlBackup = {
-        enable = true;
-      };
-    };
-    #users.groups."${postgresql.superUser}-data" = {
-    #  name = "${postgresql.superUser}-data";
-    #};
-  };
-}
diff --git a/install/logical/friot/postgrey.nix b/install/logical/friot/postgrey.nix
deleted file mode 100644 (file)
index 2fa18ab..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (config.services) postgrey;
-in
-{
-  config = {
-    services.postgrey = {
-      enable        = true;
-      autoWhitelist = 5;
-      maxAge        = 35;
-      delay         = 65;
-      privacy       = true;
-    };
-  };
-}
diff --git a/install/logical/friot/redmine.nix b/install/logical/friot/redmine.nix
deleted file mode 100644 (file)
index 38f659b..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (builtins.extraBuiltins) pass;
-    inherit (config) networking;
-    inherit (config.services) redmine postgresql gitolite;
-    redmine_git_hosting_settings = pkgs.writeText "settings.yml" ''
-      ---
-      # Gitolite SSH Config
-      gitolite_user:                  '${gitolite.user}'
-      gitolite_server_host:           'localhost'
-      gitolite_server_port:           '22'
-      #gitolite_ssh_private_key:       <%= Rails.root.join('plugins', 'redmine_git_hosting', 'ssh_keys', 'redmine_gitolite_admin_id_rsa') %>
-      #gitolite_ssh_public_key:        <%= Rails.root.join('plugins', 'redmine_git_hosting', 'ssh_keys', 'redmine_gitolite_admin_id_rsa.pub') %>
-      gitolite_ssh_private_key:       '${redmine.stateDir}/.ssh/id_ed25519'
-      gitolite_ssh_public_key:        '${redmine.stateDir}/.ssh/id_ed25519.pub'
-
-      # Gitolite Storage Config
-      gitolite_global_storage_dir:    'repositories/'
-      gitolite_redmine_storage_dir:   ""
-      gitolite_recycle_bin_dir:       'recycle_bin/'
-      gitolite_lib_dir:               '${pkgs.gitolite}/bin/lib'
-      gitolite_local_code_dir:        'local/'
-
-      # Gitolite Config File
-      gitolite_config_file:              'gitolite.conf'
-      gitolite_identifier_prefix:        'redmine_'
-      gitolite_identifier_strip_user_id: 'false'
-
-      # Gitolite Global Config
-      gitolite_temp_dir:                     <%= Rails.root.join('tmp', 'redmine_git_hosting') %>
-      gitolite_recycle_bin_expiration_time:  '24.0'
-      gitolite_log_level:                    'info'
-      git_config_username:                   'Redmine Git Hosting'
-      git_config_email:                      'redmine@${networking.domain}'
-
-      # Gitolite Hooks Config
-      gitolite_overwrite_existing_hooks: 'true'
-      gitolite_hooks_are_asynchronous:   'false'
-      gitolite_hooks_debug:              'false'
-      gitolite_hooks_url:                'http://localhost:3000'
-
-      # Gitolite Cache Config
-      gitolite_cache_max_time:          '86400'
-      gitolite_cache_max_size:          '16'
-      gitolite_cache_max_elements:      '2000'
-      gitolite_cache_adapter:           'database'
-
-      # Gitolite Access Config
-      ssh_server_domain:                'localhost'
-      http_server_domain:               'localhost'
-      https_server_domain:              'localhost'
-      http_server_subdir:               ""
-      show_repositories_url:            'true'
-      gitolite_daemon_by_default:       'false'
-      gitolite_http_by_default:         '1'
-
-      # Redmine Config
-      redmine_has_rw_access_on_all_repos: 'true'
-      all_projects_use_git:               'false'
-      init_repositories_on_create:        'false'
-      delete_git_repositories:            'true'
-
-      # This params work together!
-      # When hierarchical_organisation = true unique_repo_identifier MUST be false
-      # When hierarchical_organisation = false unique_repo_identifier MUST be true
-      hierarchical_organisation:        'true'
-      unique_repo_identifier:           'false'
-
-      # Download Revision Config
-      download_revision_enabled:        'true'
-
-      # Git Mailing List Config
-      gitolite_notify_by_default:            'false'
-      gitolite_notify_global_prefix:         '[REDMINE]'
-      gitolite_notify_global_sender_address: 'redmine@${networking.domain}'
-      gitolite_notify_global_include:        []
-      gitolite_notify_global_exclude:        []
-
-      # Sidekiq Config
-      gitolite_use_sidekiq:                  'false'
-    '';
-in
-{
-  config = {
-    services = {
-      redmine = {
-        enable = true;
-        package = with pkgs.redmine.plugins; pkgs.redmineWithPlugins [
-          #redmine_git_hosting
-          #clipboard_image_paste
-          #redmine_revision_branches
-        ];
-        database = {
-          type = "postgresql";
-          host = "/tmp";
-          port = postgresql.port;
-        };
-        config = {
-          "configuration.yml" = lib.mkForce ''
-            default:
-              scm_git_command: ${pkgs.git}/bin/git
-          '';
-        };
-      };
-      postgresql = {
-        users."${redmine.user}" = {
-          auth = "unix";
-        };
-        databases."${redmine.database.name}" = {
-          owner = redmine.user;
-          users = [ redmine.user ];
-          extraConfig = ''
-            GRANT USAGE  ON SCHEMA pg_catalog TO ${redmine.user};
-            GRANT SELECT ON ALL TABLES IN SCHEMA pg_catalog TO ${redmine.user};
-          '';
-        };
-      };
-      nginx = {
-        upstreams."redmine" = {
-          servers = { "localhost:3000" = {}; };
-        };
-        virtualHosts."redmine" = {
-          serverName = "redmine.${networking.domain}";
-          serverAliases =
-            map (domainAlias: "redmine." + domainAlias)
-                config.networking.domainAliases;
-          locations = {
-            "/" = {
-              extraConfig = ''
-                proxy_next_upstream error timeout
-                 invalid_header http_500 http_502 http_503;
-                proxy_pass http://localhost:3000;
-              '';
-            };
-          };
-        };
-      };
-    };
-    systemd.services.redmine = {
-      path = lib.mkForce [
-        pkgs.gitAndTools.git
-        pkgs.imagemagickBig
-        pkgs.coreutils
-        pkgs.findutils
-        pkgs.gnused
-        /*
-        pkgs.gitolite
-        pkgs.coreutils
-        pkgs.openssh
-        (config.security.wrapperDir + "/..")
-        */
-      ];
-      #environment.REDMINE_LANG = lib.mkForce "fr";
-      /*
-      path = [
-        pkgs.gitolite
-        pkgs.coreutils
-        pkgs.openssh
-        (config.security.wrapperDir + "/..")
-      ];
-      after = [ "keys.target" ];
-      preStart = ''
-        # comply with openssh's strict mode
-        install -D -d -o ${redmine.user} -g ${redmine.group} -m 0700 \
-         ${redmine.stateDir}/.ssh
-        install -o ${redmine.user} -g ${redmine.group} -m 0400 \
-         /run/keys/redmine_git_hosting_id_ed25519 \
-         ${redmine.stateDir}/.ssh/id_ed25519
-        install -o ${redmine.user} -g ${redmine.group} -m 0400 \
-         ${pkgs.writeText "redmine_git_hosting_id_ed25519.pub"
-          (builtins.readFile ../../../sec/var/ssh/redmine_git_hosting/id_ed25519.pub)} \
-         ${redmine.stateDir}/.ssh/id_ed25519.pub
-        install -o ${redmine.user} -g ${redmine.group} -m 0400 \
-         ${pkgs.writeText "config" ''
-          Host localhost
-            PasswordAuthentication no
-            PreferredAuthentications publickey
-            StrictHostKeyChecking no
-            UserKnownHostsFile /dev/null
-         ''} \
-         ${redmine.stateDir}/.ssh/config
-
-        # push settings.yml
-        ln -fns ${redmine_git_hosting_settings} \
-         ${redmine.stateDir}/redmine_git_hosting.yml
-        ${redmine.stateDir}/bundle exec rake redmine_git_hosting:update_settings
-         install hooks and parameters
-        ${redmine.stateDir}/bundle exec rake redmine_git_hosting:install_gitolite_hooks
-      '';
-      */
-    };
-    users.users."${redmine.user}" = {
-      extraGroups = [
-        gitolite.group
-      ];
-    };
-    deployment.keys.redmine_git_hosting_id_ed25519 = {
-      text    = pass "${networking.domain}/${networking.hostName}/redmine_git_hosting/ssh" + "\n";
-      #destDir = "${redmine.stateDir}/.ssh";
-      #path    = "${redmine.stateDir}/.ssh/id_ed25519";
-      user    = redmine.user;
-      group   = redmine.group;
-      permissions = "0400"; # XXX: not enforced when deployment.storeKeysOnMachine = true
-    };
-    security.sudo.extraRules = [
-      { users    = [ redmine.user ];
-        groups   = [ redmine.group ];
-        runAs    = gitolite.user;
-        commands = [ { command = "ALL"; options = [ "SETENV" "NOPASSWD" ]; } ];
-      }
-    ];
-  };
-}
diff --git a/install/logical/friot/rmilter.nix b/install/logical/friot/rmilter.nix
deleted file mode 100644 (file)
index 0fded48..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (builtins) attrNames;
-    inherit (lib) types;
-    inherit (config.services) dkim dovecot2 rmilter;
-
-    createDomainDkimCert = domain:
-      let dkim_key = "${dkim.keyDir}/${domain}.${dkim.selector}.key";
-          dkim_txt = "${dkim.keyDir}/${domain}.${dkim.selector}.txt";
-      in ''
-      if [ ! -f "${dkim_key}" ] || [ ! -f "${dkim_txt}" ]
-       then
-        ${pkgs.opendkim}/bin/opendkim-genkey \
-          --domain "${domain}" \
-          --selector "${dkim.selector}" \
-          --directory="${dkim.keyDir}"
-        mv "${dkim.keyDir}/${dkim.selector}.private" "${dkim_key}"
-        mv "${dkim.keyDir}/${dkim.selector}.txt" "${dkim_txt}"
-       fi
-    '';
-in
-{
-  options.services.dkim = lib.mkOption {
-    default = {};
-    type = types.submodule {
-      options = {
-        keyDir = lib.mkOption {
-          type        = types.path;
-          default     = "/var/lib/dkim";
-          description = ''
-          '';
-        };
-        selector = lib.mkOption {
-          type        = types.str;
-          default     = "mail";
-          description = ''
-          '';
-        };
-      };
-    };
-  };
-  config = {
-    services.rspamd = {
-      enable = true;
-    };
-    /*
-    services.redis = {
-      enable = true;
-    };
-    */
-    services.rmilter = {
-      enable = true;
-      #debug = true;
-      postfix = {
-        enable = true;
-      };
-      rspamd = {
-        enable      = true;
-        extraConfig = "extended_spam_headers = yes;";
-      };
-      extraConfig = ''
-        use_redis = true;
-        max_size  = 20M;
-        #clamav {
-        #  servers = /var/run/clamav/clamd.ctl;
-        #};
-        # NOTE: domain = "*"; causes rmilter to try to search key in the key path
-        # as keypath/domain.selector.key for any domain.
-        dkim {
-          domain {
-            domain   = "*";
-            key      = "${dkim.keyDir}";
-            selector = "${dkim.selector}";
-          };
-          sign_alg  = sha256;
-          auth_only = yes;
-        };
-      '';
-      bindSocket.type = "unix";
-      bindSocket.path = "/run/rmilter.sock";
-        # NOTE: fix default which is in wiped out directory /run/rmilter/rmilter.sock
-    };
-    #systemd.sockets.rmilter.socketConfig.Accept = false;
-    systemd.services.rmilter = {
-      requires = [ "rmilter.socket" ];
-      after    = [ "rmilter.socket" ];
-      preStart = ''
-        install -D -d -o rmilter -g rmilter ${dkim.keyDir}
-        ${lib.concatStringsSep "\n" (map createDomainDkimCert (attrNames dovecot2.domains))}
-        chown -R rmilter:rmilter "${dkim.keyDir}"
-      '';
-    };
-  };
-}
diff --git a/install/logical/friot/rspamd.nix b/install/logical/friot/rspamd.nix
deleted file mode 100644 (file)
index 9395db0..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (builtins) attrNames;
-    inherit (builtins.extraBuiltins) pass;
-    inherit (lib) types;
-    inherit (pkgs.lib) unlinesAttrs;
-    inherit (config) networking;
-    inherit (config.services) rspamd-upstream dkim;
-    /*
-    localConfig = pkgs.writeText "local.conf" ''
-      classifier "bayes" {
-        autolearn = true;
-      }
-      dkim_signing {
-        path = "/var/lib/rspamd/dkim/$domain.$selector.key";
-        selector = "default";
-        allow_username_mismatch = true;
-      }
-      arc {
-        path = "/var/lib/rspamd/dkim/$domain.$selector.key";
-        selector = "default";
-        allow_username_mismatch = true;
-      }
-      milter_headers {
-        use = ["authentication-results", "x-spam-status"];
-        authenticated_headers = ["authentication-results"];
-      }
-      replies {
-        action = "no action";
-      }
-      url_reputation {
-        enabled = true;
-      }
-      phishing {
-        openphish_enabled = true;
-        phishtank_enabled = true;
-      }
-    '';
-    */
-in
-{
-  options.services.dkim = lib.mkOption {
-    default = {};
-    type = types.submodule {
-      options = {
-        domains = lib.mkOption {
-          default = {};
-          type = types.attrsOf (types.submodule {
-            options = {
-              selector = lib.mkOption {
-                type = types.str;
-                description = ''Current selector.'';
-              };
-              selectors = lib.mkOption {
-                default = {};
-                description = ''Available selectors.'';
-                type = types.attrsOf (types.submodule {
-                  options = {
-                    key = lib.mkOption {
-                      type = types.str;
-                      description = ''Private key.'';
-                    };
-                    dns = lib.mkOption {
-                      type = types.str;
-                      description = ''DNS record.'';
-                    };
-                  };
-                });
-              };
-            };
-          });
-        };
-      };
-    };
-  };
-  config = {
-    deployment.keys = builtins.listToAttrs (map
-      (domain:
-        let selector = dkim.domains."${domain}".selector; in
-        { name  = "dkim.${domain}.${selector}.key";
-          value = {
-            text    = pass "${networking.domainBase}/dkim/${selector}/key" + "\n";
-            #destDir = "${redmine.stateDir}/.ssh";
-            #path    = "${redmine.stateDir}/.ssh/id_ed25519";
-            user    = rspamd-upstream.user;
-            group   = rspamd-upstream.group;
-            permissions = "0400"; # XXX: not enforced when deployment.storeKeysOnMachine = true
-          };
-        })
-      ([ networking.domain ] ++ networking.domainAliases));
-
-    systemd.services.rspamd-upstream = {
-      path = [
-        pkgs.coreutils
-      ];
-      after = [ "keys.target" ];
-      preStart = unlinesAttrs (domain: dom: ''
-        install -D -o ${rspamd-upstream.user} -g ${rspamd-upstream.group} -m 0400 \
-         /run/keys/dkim.${domain}.${dom.selector}.key \
-         /var/lib/rspamd/dkim/${domain}.${dom.selector}.key
-      '') dkim.domains;
-    };
-
-    services.rspamd-upstream = {
-      enable = true;
-      debug = false;
-      postfix = {
-        enable = true;
-      };
-      locals =
-        let selector_map_file =
-          pkgs.writeText "dkim_selectors.map"
-            (pkgs.lib.unlinesAttrs
-              (domain: dom: "${domain} ${dom.selector}")
-              dkim.domains); in {
-        "dkim_signing.conf".text = ''
-          path = "/var/lib/rspamd/dkim/$domain.$selector.key";
-          selector_map = ${selector_map_file};
-          allow_username_mismatch = true;
-        '';
-        "arc.conf".text = ''
-          path = "/var/lib/rspamd/dkim/$domain.$selector.key";
-          selector_map = ${selector_map_file};
-          allow_username_mismatch = true;
-        '';
-        /*
-        "logging.conf" = ''
-          debug_modules = [“dkim_signing”]
-        '';
-        */
-      };
-      overrides = {
-        "milter_headers.conf".text = ''
-          extended_spam_headers = true;
-        '';
-        "actions.conf".text = ''
-          actions {
-            reject     = 15; # Reject when reaching this score
-            add_header =  6; # Add header when reaching this score
-            greylist   =  4; # Apply greylisting when reaching this score (will emit `soft reject action`)
-          }
-        '';
-      };
-      workers = {
-        normal = {
-          /*
-          includes = [ "$CONFDIR/worker-normal.inc" ];
-          bindSockets = [{
-            socket = "/run/rspamd/rspamd.sock";
-            mode = "0660";
-            owner = "${cfg.user}";
-            group = "${cfg.group}";
-          }];
-          */
-        };
-        controller = {
-          #includes = [ "$CONFDIR/worker-controller.inc" ];
-          bindSockets = [ "*:11334" ]; # FIXME: localhost only
-          extraConfig = ''
-            #count = 1;
-            #static_dir = "''${WWWDIR}";
-            # USE: rspamadm pw
-            password = "$2$fy8padyutwigfchjbye88h7i4exwx9gw$m3ohkqu9fartjkjz5oeok5xwxamwime63998awryxdt8dt431eoy";
-          '';
-        };
-      };
-    };
-    /*
-    services.rspamd-upstream = {
-      enable = true;
-      # FIXME: the order of sockets is messed up
-      socketActivation = false;
-      extraConfig = ''
-        .include(priority=1,duplicate=merge) "${localConfig}"
-      '';
-
-      workers.controller = {
-        extraConfig = ''
-          count = 1;
-          static_dir = "''${WWWDIR}";
-          password = "$2$cifyu958qabanmtjyofmf5981posxie7$dz3taiiumir9ew5ordg8n1ia3eb73y1t55kzc9qsjdq1n8esmqqb";
-          enable_password = "$2$cifyu958qabanmtjyofmf5981posxie7$dz3taiiumir9ew5ordg8n1ia3eb73y1t55kzc9qsjdq1n8esmqqb";
-        '';
-      };
-
-      workers.rspamd_proxy = {
-        type = "proxy";
-        extraConfig = ''
-          milter = yes; # Enable milter mode
-          timeout = 120s; # Needed for Milter usually
-          upstream "local" {
-            default = yes;
-            self_scan = yes;
-          }
-          count = 1; # Do not spawn too many processes of this type
-        '';
-        bindSockets = [{
-          socket = "/run/rspamd.sock";
-          mode = "0666";
-          owner = "rspamd";
-          group = "rspamd";
-        }];
-      };
-    };
-    */
-
-    /*
-    services.postfix.extraConfig = ''
-      smtpd_milters = unix:/run/rspamd.sock
-      milter_default_action = accept
-    '';
-    # Allow users to run 'rspamc' and 'rspamadm'.
-    environment.systemPackages = [ pkgs.rspamd ];
-    */
-
-    /*
-    services.redis = {
-      enable = true;
-    };
-    */
-  };
-}
diff --git a/install/logical/friot/shorewall.nix b/install/logical/friot/shorewall.nix
deleted file mode 100644 (file)
index 0def4e8..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-{pkgs, lib, config, ...}:
-let inherit (builtins) hasAttr readFile;
-    inherit (pkgs.lib) unlinesAttrs;
-    inherit (config.services) shorewall shorewall6;
-    zones4 = config.networking.zones;
-    zones6 = config.networking.zones;
-    "macro.Git" = ''
-      ?FORMAT 2
-      #ACTION SOURCE  DEST    PROTO   DEST    SOURCE  RATE    USER/
-      #                               PORT(S) PORT(S) LIMIT   GROUP
-      PARAM   -       -       tcp     9418
-      '';
-in
-{
-config = {
-  services.shorewall = {
-    enable  = true;
-    configs = {
-      "shorewall.conf" = ''
-        ${readFile "${shorewall.package}/etc-example/shorewall/shorewall.conf"}
-        #
-        ## Custom config
-        ###
-        STARTUP_ENABLED=Yes
-        ZONE2ZONE=2
-        '';
-      zones = ''
-        # DOC: shorewall-zones(5)
-        fw firewall
-        '' + unlinesAttrs (zone: _: "${zone} ipv4") zones4;
-      interfaces = ''
-        # DOC: shorewall-interfaces(5)
-        ?FORMAT 2
-        '' + unlinesAttrs (zone: {iface, ...}:
-          "${zone} ${iface} arp_filter,nosmurfs,routefilter,tcpflags") zones4;
-      policy = ''
-        # DOC: shorewall-policy(5)
-        $FW all DROP
-        '' + unlinesAttrs (zone: _: "${zone} all DROP none") zones4
-        + ''
-        # XXX: the following policy must be last
-        all all REJECT none
-        '';
-      rules = ''
-        # DOC: shorewall-rules(5)
-        #SECTION ALL
-        #SECTION ESTABLISHED
-        #SECTION RELATED
-        ?SECTION NEW
-        ''
-        + lib.optionalString (hasAttr "lan" zones4) ''
-        # ----------
-        # $FW -> lan
-        # ----------
-        ACCEPT $FW lan:${zones4.lan.ipv4}/24
-
-        # ----------
-        # lan -> $FW
-        # ----------
-        ACCEPT lan:${zones4.lan.ipv4}/24 $FW
-        ''
-        + lib.optionalString (hasAttr "net" zones4) ''
-        # ----------
-        # $FW -> net
-        # ----------
-
-        # By protocol
-        Ping(ACCEPT) $FW net
-
-        # By port
-        DNS(ACCEPT)   $FW net
-        Git(ACCEPT)   $FW net
-        HTTP(ACCEPT)  $FW net
-        HTTPS(ACCEPT) $FW net
-        SMTP(ACCEPT)  $FW net
-        SMTPS(ACCEPT) $FW net
-        SSH(ACCEPT)   $FW net
-
-        # ----------
-        # net -> $FW
-        # ----------
-
-        # By protocol
-        Ping(ACCEPT)  net $FW
-
-        # By port
-        #HTTPS(ACCEPT) net $FW
-        DNS(ACCEPT)    net $FW
-        IMAPS(ACCEPT)  net $FW
-        POP3S(ACCEPT)  net $FW
-        SMTP(ACCEPT)   net $FW
-        SMTPS(ACCEPT)  net $FW
-        '';
-      inherit "macro.Git";
-    };
-  };
-  services.shorewall6 = {
-    enable  = true;
-    configs = {
-      "shorewall6.conf" = ''
-        ${readFile "${shorewall6.package}/etc-example/shorewall6/shorewall6.conf"}
-        #
-        ## Custom config
-        ###
-        STARTUP_ENABLED=Yes
-        ZONE2ZONE=2
-        '';
-      zones = ''
-        # DOC: shorewall-zones(5)
-        fw firewall
-        '' + unlinesAttrs (zone: _: "${zone} ipv6") zones6;
-      interfaces = ''
-        # DOC: shorewall-interfaces(5)
-        ?FORMAT 2
-        '' + unlinesAttrs (zone: {iface, ...}: "${zone} ${iface} nosmurfs,tcpflags") zones6;
-      policy = ''
-        # DOC: shorewall-policy(5)
-        $FW all DROP
-        '' + unlinesAttrs (zone: _: "${zone} all DROP none") zones6
-        + ''
-        # XXX: the following policy must be last
-        all all REJECT none
-        '';
-      rules = ''
-        # DOC: shorewall-rules(5)
-        #SECTION ALL
-        #SECTION ESTABLISHED
-        #SECTION RELATED
-        ?SECTION NEW
-        ''
-        + lib.optionalString (hasAttr "lan" zones6) ''
-        # ----------
-        # $FW -> lan
-        # ----------
-        Ping(ACCEPT) $FW lan:fe80::/10
-
-        # ----------
-        # lan -> $FW
-        # ----------
-        Ping(ACCEPT) lan:fe80::/10 $FW
-        SSH(ACCEPT)  lan:fe80::/10 $FW
-        Git(ACCEPT)  lan:fe80::/10 $FW
-        '';
-      inherit "macro.Git";
-    };
-  };
-};
-}
diff --git a/install/logical/machines.list b/install/logical/machines.list
deleted file mode 100644 (file)
index 8a632c1..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-barrau (Aurélien Barrau)
-calimaq (Lionel Maurel)
-casilli (Antonio Casilli)
-colasse (Bernard Colasse)
-friot (Bernard Friot)
-greenwald (Glenn Greenwald)
-herrou (Cédric Herrou)
-jancovici (Jean-Marc Jancovici)
-lacroix-riz (Annie Lacroix-Riz)
-lordon (Frédéric Lordon)
-losurdo (Domenico Losurdo)
-pauwels (Jacques Pauwels)
-pincon-charlot (Michel Pinçon & Monique Pinçon-Charlot)
-roberts (Denis Roberts)
-scahill (Jeremy Scahill)
-dupuis-deri (Françis Dupuis-Déri)
-deneault (Alain Deneault)
-mermet (Laurent Mermet)
diff --git a/install/logical/mermet.nix b/install/logical/mermet.nix
deleted file mode 100644 (file)
index 6df6654..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-{pkgs, lib, config, system, ...}:
-let inherit (builtins.extraBuiltins) pass;
-    inherit (lib) types;
-    inherit (config) networking;
-    userPass = name: pass "${networking.domainBase}/${networking.hostName}/login/${name}";
-in {
-imports = [
-  <nixpkgs-sourcephile/install/modules.nix>
-  ../overlays/tools/networking/shorewall/service.nix
-  ../overlays/tools/networking/shorewall6/service.nix
-  ../overlays/servers/mail/rspamd/service.nix
-  ../overlays.nix
-  ../options.nix
-];
-}
diff --git a/install/mermet/configuration.nix b/install/mermet/configuration.nix
deleted file mode 100644 (file)
index 1c0b494..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{ pkgs, lib, config, ... }:
-{
-  imports =
-    [ ./physical.nix
-      ./hosting.nix
-      ./logical.nix
-    ];
-}
diff --git a/install/mermet/logical.nix b/install/mermet/logical.nix
deleted file mode 100644 (file)
index 9f84450..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{ config, lib, pkgs, ... }:
-{
-  imports =
-    [ ./logical/boot.nix
-      ./logical/zfs.nix
-      ./logical/system.nix
-    ];
-}
diff --git a/install/mermet/logical/boot.nix b/install/mermet/logical/boot.nix
deleted file mode 100644 (file)
index 96c205b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-{ pkgs, lib, config, ... }:
-{
-  # Clean /tmp automatically on boot.
-  boot.cleanTmpDir = true;
-}
diff --git a/install/mermet/logical/networking.nix b/install/mermet/logical/networking.nix
deleted file mode 100644 (file)
index dcf53ce..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-{ config, lib, pkgs, ... }:
-{
-  networking = {
-    hostName = "mermet";
-  };
-}
diff --git a/install/mermet/physical.nix b/install/mermet/physical.nix
deleted file mode 100644 (file)
index acea9dd..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-with builtins;
-import (toPath ./. + "/physical/" + getEnv "MERMET_PHYSICAL" + ".nix")
diff --git a/install/overlays.nix b/install/overlays.nix
deleted file mode 100644 (file)
index 7f1d9cd..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-map import
-[ overlays/servers/mail/postfix.nix
-  overlays/servers/mail/dovecot.nix
-   # TODO: remove when using a nixpkgs including the fix
-   # https://github.com/NixOS/nixpkgs/pull/46859
-  overlays/lib/strings.nix
-  overlays/users-init.nix
-  overlays/tools/networking/shorewall.nix
-  overlays/tools/networking/shorewall6.nix
-  #overlays/applications/version-management/redmine/redmine_git_hosting.nix
-]
diff --git a/install/overlays/applications/version-management/redmine/redmine_git_hosting.nix b/install/overlays/applications/version-management/redmine/redmine_git_hosting.nix
deleted file mode 100644 (file)
index f0cac14..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-self: super:
-{}
-/*
-let lib = super.lib;
-    version = "1.2.3";
-    rubyEnv = self.bundlerEnv {
-      name = "redmine_git_hosting-env-${version}";
-      ruby = self.ruby;
-      gemdir = ./.;
-    };
-in
-{
-  redmine_git_hosting =
-    super.stdenv.mkDerivation rec {
-      name = "redmine_git_hosting-${version}";
-      inherit version;
-
-      src = super.fetchurl {
-        url = "https://www.redmine.org/attachments/download/18780/${name}.tar.gz";
-        sha256 = "1kkd5cqxa7q9jckrwrjr4gfwf5ncakrjqyypiqz9agrmipdqmxh2";
-      };
-      buildInputs = [ rubyEnv rubyEnv.wrappedRuby rubyEnv.bundler ];
-      installPhase = ''
-        cp -a . $out
-      '';
-
-      meta = with super.stdenv.lib; {
-        homepage = https://www.redmine.org/plugins/redmine_git_hosting;
-        platforms = super.lib.platforms.linux;
-        license = super.lib.licenses.mit;
-      };
-    };
-}
-*/
diff --git a/install/overlays/servers/mail/rspamd/service.nix b/install/overlays/servers/mail/rspamd/service.nix
deleted file mode 100644 (file)
index 481684e..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-{ config, options, pkgs, lib, ... }:
-
-with lib;
-
-let
-
-  cfg = config.services.rspamd-upstream;
-  opts = options.services.rspamd-upstream;
-  postfixCfg = config.services.postfix;
-
-  bindSocketOpts = {options, config, ... }: {
-    options = {
-      socket = mkOption {
-        type = types.str;
-        example = "localhost:11333";
-        description = ''
-          Socket for this worker to listen on in a format acceptable by rspamd.
-        '';
-      };
-      mode = mkOption {
-        type = types.str;
-        default = "0644";
-        description = "Mode to set on unix socket";
-      };
-      owner = mkOption {
-        type = types.str;
-        default = "${cfg.user}";
-        description = "Owner to set on unix socket";
-      };
-      group = mkOption {
-        type = types.str;
-        default = "${cfg.group}";
-        description = "Group to set on unix socket";
-      };
-      rawEntry = mkOption {
-        type = types.str;
-        internal = true;
-      };
-    };
-    config.rawEntry = let
-      maybeOption = option:
-        optionalString options.${option}.isDefined " ${option}=${config.${option}}";
-    in
-      if (!(hasPrefix "/" config.socket)) then "${config.socket}"
-      else "${config.socket}${maybeOption "mode"}${maybeOption "owner"}${maybeOption "group"}";
-  };
-
-  traceWarning = w: x: builtins.trace "\e[1;31mwarning: ${w}\e[0m" x;
-
-  workerOpts = { name, options, ... }: {
-    options = {
-      enable = mkOption {
-        type = types.nullOr types.bool;
-        default = null;
-        description = "Whether to run the rspamd worker.";
-      };
-      name = mkOption {
-        type = types.nullOr types.str;
-        default = name;
-        description = "Name of the worker";
-      };
-      type = mkOption {
-        type = types.nullOr (types.enum [
-          "normal" "controller" "fuzzy_storage" "rspamd_proxy" "lua" "proxy"
-        ]);
-        description = ''
-          The type of this worker. The type <literal>proxy</literal> is
-          deprecated and only kept for backwards compatibility and should be
-          replaced with <literal>rspamd_proxy</literal>.
-        '';
-        apply = let
-            from = "services.rspamd-upstream.workers.\”${name}\".type";
-            files = options.type.files;
-            warning = "The option `${from}` defined in ${showFiles files} has enum value `proxy` which has been renamed to `rspamd_proxy`";
-          in x: if x == "proxy" then traceWarning warning "rspamd_proxy" else x;
-      };
-      bindSockets = mkOption {
-        type = types.listOf (types.either types.str (types.submodule bindSocketOpts));
-        default = [];
-        description = ''
-          List of sockets to listen, in format acceptable by rspamd
-        '';
-        example = [{
-          socket = "/run/rspamd.sock";
-          mode = "0666";
-          owner = "rspamd";
-        } "*:11333"];
-        apply = value: map (each: if (isString each)
-          then if (isUnixSocket each)
-            then {socket = each; owner = cfg.user; group = cfg.group; mode = "0644"; rawEntry = "${each}";}
-            else {socket = each; rawEntry = "${each}";}
-          else each) value;
-      };
-      count = mkOption {
-        type = types.nullOr types.int;
-        default = null;
-        description = ''
-          Number of worker instances to run
-        '';
-      };
-      includes = mkOption {
-        type = types.listOf types.str;
-        default = [];
-        description = ''
-          List of files to include in configuration
-        '';
-      };
-      extraConfig = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Additional entries to put verbatim into worker section of rspamd config file.";
-      };
-    };
-    config = mkIf (name == "normal" || name == "controller" || name == "fuzzy" || name == "rspamd_proxy") {
-      type = mkDefault name;
-      includes = mkDefault [ "$CONFDIR/worker-${if name == "rspamd_proxy" then "proxy" else name}.inc" ];
-      bindSockets =
-        let
-          unixSocket = name: {
-            mode = "0660";
-            socket = "/run/rspamd/${name}.sock";
-            owner = cfg.user;
-            group = cfg.group;
-          };
-        in mkDefault (if name == "normal" then [(unixSocket "rspamd")]
-          else if name == "controller" then [ "localhost:11334" ]
-          else if name == "rspamd_proxy" then [ (unixSocket "proxy") ]
-          else [] );
-    };
-  };
-
-  isUnixSocket = socket: hasPrefix "/" (if (isString socket) then socket else socket.socket);
-
-  mkBindSockets = enabled: socks: concatStringsSep "\n  "
-    (flatten (map (each: "bind_socket = \"${each.rawEntry}\";") socks));
-
-  rspamdConfFile = pkgs.writeText "rspamd.conf"
-    ''
-      .include "$CONFDIR/common.conf"
-
-      options {
-        pidfile = "$RUNDIR/rspamd.pid";
-        .include "$CONFDIR/options.inc"
-        .include(try=true; priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/options.inc"
-        .include(try=true; priority=10) "$LOCAL_CONFDIR/override.d/options.inc"
-      }
-
-      logging {
-        type = "syslog";
-        .include "$CONFDIR/logging.inc"
-        .include(try=true; priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/logging.inc"
-        .include(try=true; priority=10) "$LOCAL_CONFDIR/override.d/logging.inc"
-      }
-
-      ${concatStringsSep "\n" (mapAttrsToList (name: value: let
-          includeName = if name == "rspamd_proxy" then "proxy" else name;
-          tryOverride = if value.extraConfig == "" then "true" else "false";
-        in ''
-        worker "${value.type}" {
-          type = "${value.type}";
-          ${optionalString (value.enable != null)
-            "enabled = ${if value.enable != false then "yes" else "no"};"}
-          ${mkBindSockets value.enable value.bindSockets}
-          ${optionalString (value.count != null) "count = ${toString value.count};"}
-          ${concatStringsSep "\n  " (map (each: ".include \"${each}\"") value.includes)}
-          .include(try=true; priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/worker-${includeName}.inc"
-          .include(try=${tryOverride}; priority=10) "$LOCAL_CONFDIR/override.d/worker-${includeName}.inc"
-        }
-      '') cfg.workers)}
-
-      ${optionalString (cfg.extraConfig != "") ''
-        .include(priority=10) "$LOCAL_CONFDIR/override.d/extra-config.inc"
-      ''}
-   '';
-
-  filterFiles = files: filterAttrs (n: v: v.enable) files;
-  rspamdDir = pkgs.linkFarm "etc-rspamd-dir" (
-    (mapAttrsToList (name: file: { name = "local.d/${name}"; path = file.source; }) (filterFiles cfg.locals)) ++
-    (mapAttrsToList (name: file: { name = "override.d/${name}"; path = file.source; }) (filterFiles cfg.overrides)) ++
-    (optional (cfg.localLuaRules != null) { name = "rspamd.local.lua"; path = cfg.localLuaRules; }) ++
-    [ { name = "rspamd.conf"; path = rspamdConfFile; } ]
-  );
-
-  configFileModule = prefix: { name, config, ... }: {
-    options = {
-      enable = mkOption {
-        type = types.bool;
-        default = true;
-        description = ''
-          Whether this file ${prefix} should be generated.  This
-          option allows specific ${prefix} files to be disabled.
-        '';
-      };
-
-      text = mkOption {
-        default = null;
-        type = types.nullOr types.lines;
-        description = "Text of the file.";
-      };
-
-      source = mkOption {
-        type = types.path;
-        description = "Path of the source file.";
-      };
-    };
-    config = {
-      source = mkIf (config.text != null) (
-        let name' = "rspamd-${prefix}-" + baseNameOf name;
-        in mkDefault (pkgs.writeText name' config.text));
-    };
-  };
-
-  configOverrides =
-    (mapAttrs' (n: v: nameValuePair "worker-${if n == "rspamd_proxy" then "proxy" else n}.inc" {
-      text = v.extraConfig;
-    })
-    (filterAttrs (n: v: v.extraConfig != "") cfg.workers))
-    // (if cfg.extraConfig == "" then {} else {
-      "extra-config.inc".text = cfg.extraConfig;
-    });
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    services.rspamd-upstream = {
-
-      enable = mkEnableOption "rspamd, the Rapid spam filtering system";
-
-      debug = mkOption {
-        type = types.bool;
-        default = false;
-        description = "Whether to run the rspamd daemon in debug mode.";
-      };
-
-      locals = mkOption {
-        type = with types; attrsOf (submodule (configFileModule "locals"));
-        default = {};
-        description = ''
-          Local configuration files, written into <filename>/etc/rspamd/local.d/{name}</filename>.
-        '';
-        example = literalExample ''
-          { "redis.conf".source = "/nix/store/.../etc/dir/redis.conf";
-            "arc.conf".text = "allow_envfrom_empty = true;";
-          }
-        '';
-      };
-
-      overrides = mkOption {
-        type = with types; attrsOf (submodule (configFileModule "overrides"));
-        default = {};
-        description = ''
-          Overridden configuration files, written into <filename>/etc/rspamd/override.d/{name}</filename>.
-        '';
-        example = literalExample ''
-          { "redis.conf".source = "/nix/store/.../etc/dir/redis.conf";
-            "arc.conf".text = "allow_envfrom_empty = true;";
-          }
-        '';
-      };
-
-      localLuaRules = mkOption {
-        default = null;
-        type = types.nullOr types.path;
-        description = ''
-          Path of file to link to <filename>/etc/rspamd/rspamd.local.lua</filename> for local
-          rules written in Lua
-        '';
-      };
-
-      workers = mkOption {
-        type = with types; attrsOf (submodule workerOpts);
-        description = ''
-          Attribute set of workers to start.
-        '';
-        default = {
-          normal = {};
-          controller = {};
-        };
-        example = literalExample ''
-          {
-            normal = {
-              includes = [ "$CONFDIR/worker-normal.inc" ];
-              bindSockets = [{
-                socket = "/run/rspamd/rspamd.sock";
-                mode = "0660";
-                owner = "${cfg.user}";
-                group = "${cfg.group}";
-              }];
-            };
-            controller = {
-              includes = [ "$CONFDIR/worker-controller.inc" ];
-              bindSockets = [ "[::1]:11334" ];
-            };
-          }
-        '';
-      };
-
-      extraConfig = mkOption {
-        type = types.lines;
-        default = "";
-        description = ''
-          Extra configuration to add at the end of the rspamd configuration
-          file.
-        '';
-      };
-
-      user = mkOption {
-        type = types.string;
-        default = "rspamd";
-        description = ''
-          User to use when no root privileges are required.
-        '';
-      };
-
-      group = mkOption {
-        type = types.string;
-        default = "rspamd";
-        description = ''
-          Group to use when no root privileges are required.
-        '';
-      };
-
-      postfix = {
-        enable = mkOption {
-          type = types.bool;
-          default = false;
-          description = "Add rspamd milter to postfix main.conf";
-        };
-
-        config = mkOption {
-          type = with types; attrsOf (either bool (either str (listOf str)));
-          description = ''
-            Addon to postfix configuration
-          '';
-          default = {
-            smtpd_milters = ["unix:/run/rspamd/rspamd-milter.sock"];
-            non_smtpd_milters = ["unix:/run/rspamd/rspamd-milter.sock"];
-          };
-          example = {
-            smtpd_milters = ["unix:/run/rspamd/rspamd-milter.sock"];
-            non_smtpd_milters = ["unix:/run/rspamd/rspamd-milter.sock"];
-          };
-        };
-      };
-    };
-  };
-
-
-  ###### implementation
-
-  config = mkIf cfg.enable {
-    services.rspamd-upstream.overrides = configOverrides;
-    services.rspamd-upstream.workers = mkIf cfg.postfix.enable {
-      controller = {};
-      rspamd_proxy = {
-        bindSockets = [ {
-          mode = "0660";
-          socket = "/run/rspamd/rspamd-milter.sock";
-          owner = cfg.user;
-          group = postfixCfg.group;
-        } ];
-        extraConfig = ''
-          upstream "local" {
-            default = yes; # Self-scan upstreams are always default
-            self_scan = yes; # Enable self-scan
-          }
-        '';
-      };
-    };
-    services.postfix.config = mkIf cfg.postfix.enable cfg.postfix.config;
-
-    # Allow users to run 'rspamc' and 'rspamadm'.
-    environment.systemPackages = [ pkgs.rspamd ];
-
-    users.users = singleton {
-      name = cfg.user;
-      description = "rspamd daemon";
-      uid = config.ids.uids.rspamd;
-      group = cfg.group;
-    };
-
-    users.groups = singleton {
-      name = cfg.group;
-      gid = config.ids.gids.rspamd;
-    };
-
-    environment.etc."rspamd".source = rspamdDir;
-
-    systemd.services.rspamd-upstream = {
-      description = "Rspamd Service";
-
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ];
-      restartTriggers = [ rspamdDir ];
-
-      serviceConfig = {
-        ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} --user=${cfg.user} --group=${cfg.group} --pid=/run/rspamd.pid -c /etc/rspamd/rspamd.conf -f";
-        Restart = "always";
-        RuntimeDirectory = "rspamd";
-        PrivateTmp = true;
-      };
-
-      preStart = ''
-        ${pkgs.coreutils}/bin/mkdir -p /var/lib/rspamd
-        ${pkgs.coreutils}/bin/chown ${cfg.user}:${cfg.group} /var/lib/rspamd
-      '';
-    };
-  };
-  imports = [
-    (mkRemovedOptionModule [ "services" "rspamd-upstream" "socketActivation" ]
-            "Socket activation never worked correctly and could at this time not be fixed and so was removed")
-    (mkRenamedOptionModule [ "services" "rspamd-upstream" "bindSocket" ]
-                           [ "services" "rspamd-upstream" "workers" "normal" "bindSockets" ])
-    (mkRenamedOptionModule [ "services" "rspamd-upstream" "bindUISocket" ]
-                           [ "services" "rspamd-upstream" "workers" "controller" "bindSockets" ])
-  ];
-}
diff --git a/install/overlays/tools/networking/shorewall.nix b/install/overlays/tools/networking/shorewall.nix
deleted file mode 100644 (file)
index 8f655c8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-self: super:  {
-  shorewall = super.callPackage ./shorewall {};
-}
diff --git a/install/overlays/tools/networking/shorewall6.nix b/install/overlays/tools/networking/shorewall6.nix
deleted file mode 100644 (file)
index a5000bc..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-self: super:  {
-  shorewall6 = super.callPackage ./shorewall6 {};
-}
diff --git a/install/overlays/tools/networking/shorewall6/service.nix b/install/overlays/tools/networking/shorewall6/service.nix
deleted file mode 100644 (file)
index 9c22a03..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-{ config, lib, pkgs, ... }:
-let
-  types = lib.types;
-  cfg = config.services.shorewall6;
-in {
-  options = {
-    services.shorewall6 = {
-      enable = lib.mkOption {
-        type        = types.bool;
-        default     = false;
-        description = ''
-          Whether to enable Shorewall IPv6 Firewall.
-          <warning>
-            <para>
-            Enabling this service WILL disable the existing NixOS
-            firewall! Default firewall rules provided by packages are not
-            considered at the moment.
-            </para>
-          </warning>
-        '';
-      };
-      package = lib.mkOption {
-        type        = types.package;
-        default     = pkgs.shorewall;
-        defaultText = "pkgs.shorewall";
-        description = "The shorewall package to use.";
-      };
-      configs = lib.mkOption {
-        type        = types.attrsOf types.str;
-        default     = {};
-        description = ''
-          This option defines the Shorewall configs.
-          The attribute name defines the name of the config,
-          and the attribute value defines the content of the config.
-        '';
-        apply = lib.mapAttrs (name: text: pkgs.writeText "${name}" text);
-      };
-    };
-  };
-
-  config = lib.mkIf cfg.enable {
-    systemd.services.firewall.enable = false;
-    systemd.services.shorewall6 = {
-      description     = "Shorewall IPv6 Firewall";
-      after           = [ "ipset.target" ];
-      before          = [ "network-pre.target" ];
-      wants           = [ "network-pre.target" ];
-      wantedBy        = [ "multi-user.target" ];
-      reloadIfChanged = true;
-      restartTriggers = lib.attrValues cfg.configs;
-      serviceConfig = {
-        Type            = "oneshot";
-        RemainAfterExit = "yes";
-        ExecStart       = "${cfg.package}/bin/shorewall6 start";
-        ExecReload      = "${cfg.package}/bin/shorewall6 reload";
-        ExecStop        = "${cfg.package}/bin/shorewall6 stop";
-      };
-      preStart = ''
-        install -D -d -m 750 /var/lib/shorewall6
-        install -D -d -m 755 /var/lock/subsys
-        touch                /var/log/shorewall6.log
-        chown 750            /var/log/shorewall6.log
-      '';
-    };
-    environment = {
-      etc = lib.mapAttrsToList
-              (name: file:
-                { source = file;
-                  target = "shorewall6/${name}";
-                })
-              cfg.configs;
-      systemPackages = [ cfg.package ];
-    };
-  };
-}
diff --git a/install/overlays/users-init.nix b/install/overlays/users-init.nix
deleted file mode 100644 (file)
index 492ef78..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-self: super:
-let lib = super.lib; in
-{
-  users-init = super.writeScriptBin "users-init.pl" ''
-    #!${self.perl}/bin/perl -e
-    print "HELLO";
-  '';
-}
diff --git a/install/physical.nix b/install/physical.nix
deleted file mode 100644 (file)
index d6b0d45..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-with builtins;
-import (toPath ./. + "/physical/" + getEnv "NIXOPS_DEPLOYMENT" + ".nix")
diff --git a/install/physical/production.nix b/install/physical/production.nix
deleted file mode 100644 (file)
index 68731ab..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# Sourcephile physical network
-{
-  /*
-  friot = {pkgs, lib, config, ...}: {
-    deployment.targetHost = "1.2.3.4";
-    deployment.autoLuks = {
-      # NOTE: not working on virtualbox deployment
-      secretdisk = {
-        device     = "/dev/sda";
-        passphrase = "foobar";
-        autoFormat = true;
-        cipher     = "aes-cbc-essiv:sha256";
-      };
-    };
-    networking.zones = {
-      net = {
-        iface = null;
-        ipv4  = null;
-      };
-      lan = {
-        iface = null;
-        ipv4  = null;
-      };
-    };
-  };
-  */
-  mermet = {pkgs, lib, config, ...}: {
-    deployment.targetHost = "mermet.sourcephile.fr";
-  };
-}
diff --git a/install/physical/staging.nix b/install/physical/staging.nix
deleted file mode 100644 (file)
index 23ea068..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-{
-  network.rollBack = false;
-  friot = {pkgs, lib, config, options, ...}:
-    let ipv4 = if options.networking.privateIPv4.isDefined
-               then config.networking.privateIPv4
-               else "X.X.X.X";
-    in {
-    config = {
-      deployment.targetEnv             = "virtualbox";
-      deployment.virtualbox.headless   = true;
-      deployment.virtualbox.memorySize = 1024;
-      deployment.virtualbox.vcpu       = 2;
-      deployment.virtualbox.disks.disk1.baseImage = ../../.cache/nixops/virtualbox/nixops.vmdk;
-      #deployment.virtualbox.disks.disk1.size = 6024;
-       # NOTE: resize not yet supported.
-
-      deployment.storeKeysOnMachine = true;
-      networking = {
-        interfaces."enp0s8" = {
-          #macAddress = "00:11:22:33:44:55";
-          #ipv4.addresses = [ { address = ipv4; prefixLength = 32; } ];
-          ipv6.addresses = [ { address = "fe80::1"; prefixLength = 10; } ];
-        };
-        zones = {
-          net = {
-            iface = "enp0s3";
-            ipv4  = ipv4;
-          };
-          lan = {
-            iface = "enp0s8";
-            ipv4  = ipv4;
-            #ipv6  = "fe80::1";
-          };
-        };
-      };
-    };
-  };
-}
-
-#{
-#  vbox =
-#    { deployment.targetEnv = "virtualbox"; };
-#
-#  machine =
-#    { resources, ... }:
-#    { deployment.targetEnv = "container";
-#      deployment.container.host = resources.machines.vbox;
-#    };
-#}
diff --git a/network.nix b/network.nix
new file mode 100644 (file)
index 0000000..b97e22a
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  network = {
+    description = "Sourcephile";
+    #enableRollback = true;
+  };
+
+  defaults = {
+    #imports = [ network/defaults.nix ];
+  };
+
+  #friot = import network/friot.nix;
+  mermet = import network/mermet.nix;
+}
diff --git a/network/mermet.nix b/network/mermet.nix
new file mode 100644 (file)
index 0000000..f13b008
--- /dev/null
@@ -0,0 +1,7 @@
+{pkgs, lib, config, ...}:
+{
+  imports = [
+    mermet/configuration.nix
+    (builtins.toPath ./mermet + "/deployment/" + builtins.getEnv "NIXOPS_DEPLOYMENT" + ".nix")
+  ];
+}
similarity index 94%
rename from install/mermet/Makefile
rename to network/mermet/Makefile
index b9aa950969de5a714c469af4daa71309ed61fc99..3ad3ddd8b62a1464eb057a771b80e7dbf28e3fd1 100644 (file)
@@ -1,11 +1,15 @@
-mermet_disk        := $(shell sed -ne 's/^device: \(.*\)/\1/p' physical/sfdisk.txt)
+#cwd := $(notdir $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))))
+MERMET_MACHINE     ?= apu2e4
+MERMET_HOSTING     ?= lab
+mermet_disk        := $(shell sed -ne 's/^device: \(.*\)/\1/p' machine/$(MERMET_MACHINE)/sfdisk.txt)
 mermet_cipher      :=
 #mermet_cipher      := aes-128-gcm
 mermet_autotrim    :=
 mermet_reservation := 40G
 #mermet_channel     := $$(nix-env -p /nix/var/nix/profiles/per-user/$$USER/channels -q nixpkgs --no-name --out-path)
-MERMET_PHYSICAL    ?= apu2e4
-MERMET_HOSTING     ?= lab
+
+echo:
+       echo $(MAKEFILES)
 
 mermet-wipeout: mermet-umount
        sudo zpool labelclear -f $(mermet_disk)-part3 || true
@@ -14,7 +18,7 @@ mermet-wipeout: mermet-umount
 
 mermet-partition:
        sudo modprobe zfs
-       sudo $$(which sfdisk) $(mermet_disk) <physical/sfdisk.txt
+       sudo $$(which sfdisk) $(mermet_disk) <machine/$(MERMET_MACHINE)/sfdisk.txt
        sudo $$(which sgdisk) --randomize-guids $(mermet_disk)
        sudo partprobe
 
@@ -206,7 +210,7 @@ mermet-bootstrap: mermet-mount
         LANG="$$LANG" \
         LC_CTYPE="$$LC_CTYPE" \
         MERMET_HOSTING="$(MERMET_HOSTING)" \
-        MERMET_PHYSICAL="$(MERMET_PHYSICAL)" \
+        MERMET_MACHINE="$(MERMET_MACHINE)" \
         NIXOS_CONFIG="$$(readlink -e ./configuration.nix)" \
         NIX_CONF_DIR="$$NIX_CONF_DIR" \
         NIX_PATH="$$NIX_PATH" \
@@ -216,7 +220,8 @@ mermet-bootstrap: mermet-mount
         $$(which nixos-install) \
         --root /mnt/mermet \
         $(if $(mermet_channel),--channel "$(mermet_channel)") \
-        --no-root-passwd
+        --no-root-passwd \
+        --show-trace
 
 mermet-umount:
        for p in \
diff --git a/network/mermet/configuration.nix b/network/mermet/configuration.nix
new file mode 100644 (file)
index 0000000..db430c8
--- /dev/null
@@ -0,0 +1,14 @@
+# This is the root configuration of the target machine.
+# Usable by nixos-install and used by nixops.
+# It is NOT copied nor usable on the target,
+# only the resulting closure is copied to the target.
+{ pkgs, lib, config, ... }:
+{
+  nixpkgs.overlays = import ../../overlays.nix;
+  imports =
+    [ ../../nixos/defaults.nix
+      ./machine.nix
+      ./hosting.nix
+      ./system.nix
+    ];
+}
diff --git a/network/mermet/deployment/lab.nix b/network/mermet/deployment/lab.nix
new file mode 100644 (file)
index 0000000..6e6bdbe
--- /dev/null
@@ -0,0 +1,3 @@
+{pkgs, lib, config, ...}: {
+  deployment.targetHost = "mermet";
+}
diff --git a/network/mermet/deployment/production.nix b/network/mermet/deployment/production.nix
new file mode 100644 (file)
index 0000000..e83d139
--- /dev/null
@@ -0,0 +1,3 @@
+{pkgs, lib, config, ...}: {
+  deployment.targetHost = "1.2.3.4";
+}
diff --git a/network/mermet/machine.nix b/network/mermet/machine.nix
new file mode 100644 (file)
index 0000000..7705bd3
--- /dev/null
@@ -0,0 +1,2 @@
+with builtins;
+import (toPath ./. + "/machine/" + getEnv "MERMET_MACHINE" + ".nix")
similarity index 95%
rename from install/mermet/physical/apu2e4.nix
rename to network/mermet/machine/apu2e4.nix
index ea89b0f091ec8691a65f83460eb51d8e72c44b7d..05e090591f6f1ae7b7cbf3d9ab4ad1b3e0311a41 100644 (file)
@@ -78,12 +78,13 @@ in
        port = 2222;
        # dropbear uses key format different from openssh; can be generated by using:
        # $ nix-shell -p dropbear --command "dropbearkey -t ecdsa -f /tmp/initrd-ssh-key"
-       # WARNINg: this key will be in the NixOS store and the initrd and thus maybe on cleartext storage.
+       # WARNING: this key will be in the NixOS store and the initrd and thus maybe on cleartext storage.
        # Unfortunately pass cannot be used here because the key is not a valid Nix string.
-       hostECDSAKey = ../../../.sec/dropbear/mermet-ecdsa.key ;
+       hostECDSAKey = ../../../.sec/dropbear/mermet.dropbear-ecdsa.key ;
        # public ssh key used for login
        authorizedKeys = [
          # julm
+         # readFile ../../../.pub/ssh/julm.ssh-rsa.pub
          "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQD5FtR++UPEg/5wFeyb2JSS09idTaDb4tMIRf1yxCsyIJEp5LQMif/fIptDeHoYc55lwy8vnWWN9PJpb6PS8YSaLLFV5tn8esR8Ml+evNCAD52Tdu1kPRXGLCSF5kSVnbAMoxqiNi8vRRKXwAzGgXmIUzDAE4QTsq3EwZM6cBnDx5O79wBIZ9va2TObL52qv+Vpi+QyINuslKKc+Osu92pdwceIGZUcwA6Y8aH6lavaTyDUQdSjMRMTAiXSPRjmHf1q+V7wENXT/TKXuuahN8NnJShX3Qf9hwNEIU46SOENsrRFQ5eYahAmqUIK4GbsERS2KRDxbvSOl7rKh2sauBxyKfkW/gxQ4LAyywxuumpI0pO7XmdINCGWdXS9gD216lcGuH/TC0KboiOVExh65eRIOeEFTec0VJQEqqnFul7u8YNPmbBpLnM+SQ3TAkdQmfasKgPIazFNCAnC8I9hKlGYpLk/Dgi/sVbwFeoOUQcaTBRnWKUCedX4v4kmPIHuHSNPV2C/0770gH2iJ1N1XEO3YDGiixuHHiLlCV8Ko950CoTh1PwDNCd3Qy/jR/QhE2waVPliFwl2+H6IkIxkUO8A9ktLCJUeaZJN3snoV+9hvpT1E2TrEccsTVx5BaGAJCUkvO2XYlEsNceIIitkrbhidjZvfZ4/czGUKoN1wSSpMw== GnuPG pub=F2E027182397AC0775714F2AD15AF7F467E8299B sub=7819E44BAEEDE91683811BB00E1AAADBE227DDAA"
        ];
     };
diff --git a/network/mermet/system.nix b/network/mermet/system.nix
new file mode 100644 (file)
index 0000000..a24b851
--- /dev/null
@@ -0,0 +1,42 @@
+{ config, lib, pkgs, ... }:
+{
+  imports =
+    [ ./system/zfs.nix
+    ];
+
+  # This value determines the NixOS release with which your system is to be
+  # compatible, in order to avoid breaking some software such as database
+  # servers. You should change this only after NixOS release notes say you should.
+  system.stateVersion = "19.09"; # Did you read the comment?
+
+  # Clean /tmp automatically on boot.
+  boot.cleanTmpDir = true;
+
+  networking = {
+    hostName = "mermet";
+    domain   = "sourcephile.fr";
+  };
+
+  users = {
+    mutableUsers = false;
+    users = {
+        root = {
+          initialPassword = "toor";
+          password        = "toor";
+          openssh.authorizedKeys.keys = [
+            # julm
+            "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQD5FtR++UPEg/5wFeyb2JSS09idTaDb4tMIRf1yxCsyIJEp5LQMif/fIptDeHoYc55lwy8vnWWN9PJpb6PS8YSaLLFV5tn8esR8Ml+evNCAD52Tdu1kPRXGLCSF5kSVnbAMoxqiNi8vRRKXwAzGgXmIUzDAE4QTsq3EwZM6cBnDx5O79wBIZ9va2TObL52qv+Vpi+QyINuslKKc+Osu92pdwceIGZUcwA6Y8aH6lavaTyDUQdSjMRMTAiXSPRjmHf1q+V7wENXT/TKXuuahN8NnJShX3Qf9hwNEIU46SOENsrRFQ5eYahAmqUIK4GbsERS2KRDxbvSOl7rKh2sauBxyKfkW/gxQ4LAyywxuumpI0pO7XmdINCGWdXS9gD216lcGuH/TC0KboiOVExh65eRIOeEFTec0VJQEqqnFul7u8YNPmbBpLnM+SQ3TAkdQmfasKgPIazFNCAnC8I9hKlGYpLk/Dgi/sVbwFeoOUQcaTBRnWKUCedX4v4kmPIHuHSNPV2C/0770gH2iJ1N1XEO3YDGiixuHHiLlCV8Ko950CoTh1PwDNCd3Qy/jR/QhE2waVPliFwl2+H6IkIxkUO8A9ktLCJUeaZJN3snoV+9hvpT1E2TrEccsTVx5BaGAJCUkvO2XYlEsNceIIitkrbhidjZvfZ4/czGUKoN1wSSpMw== GnuPG pub=F2E027182397AC0775714F2AD15AF7F467E8299B sub=7819E44BAEEDE91683811BB00E1AAADBE227DDAA"
+          ];
+        };
+    };
+    groups = {
+    };
+  };
+
+  environment = {
+    systemPackages = with pkgs; [
+      cryptsetup
+      zfs
+    ];
+  };
+}
similarity index 99%
rename from install/mermet/logical/zfs.nix
rename to network/mermet/system/zfs.nix
index 01272d0c38263dfe34f937f4546c7af23897c344..ed495c7ae9903c4648d44999c0ecd2db14b0d564 100644 (file)
@@ -2,6 +2,7 @@
 
 {
   imports = [];
+
   boot.supportedFilesystems = [ "zfs" ];
 
   # The 32-bit host id of the machine, formatted as 8 hexadecimal characters.
similarity index 59%
rename from install/mermet/logical/system.nix
rename to nixos/defaults.nix
index 1777211e5f38edb268a26cb372e0e164d05bef68..a109da4061b0a4c05453ea255e375fcc00d9461f 100644 (file)
@@ -1,5 +1,9 @@
 { pkgs, lib, config, ... }:
 {
+imports = [
+  ./modules.nix
+];
+config = {
   nix = {
     autoOptimiseStore = true;
     extraOptions = ''
     };
     #overlays = import ../overlays.nix;
   };
-  users = {
-    mutableUsers = false;
-    users = {
-        root = {
-          initialPassword = "toor";
-          password        = "toor";
-          openssh.authorizedKeys.keys = [
-            # julm
-            "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQD5FtR++UPEg/5wFeyb2JSS09idTaDb4tMIRf1yxCsyIJEp5LQMif/fIptDeHoYc55lwy8vnWWN9PJpb6PS8YSaLLFV5tn8esR8Ml+evNCAD52Tdu1kPRXGLCSF5kSVnbAMoxqiNi8vRRKXwAzGgXmIUzDAE4QTsq3EwZM6cBnDx5O79wBIZ9va2TObL52qv+Vpi+QyINuslKKc+Osu92pdwceIGZUcwA6Y8aH6lavaTyDUQdSjMRMTAiXSPRjmHf1q+V7wENXT/TKXuuahN8NnJShX3Qf9hwNEIU46SOENsrRFQ5eYahAmqUIK4GbsERS2KRDxbvSOl7rKh2sauBxyKfkW/gxQ4LAyywxuumpI0pO7XmdINCGWdXS9gD216lcGuH/TC0KboiOVExh65eRIOeEFTec0VJQEqqnFul7u8YNPmbBpLnM+SQ3TAkdQmfasKgPIazFNCAnC8I9hKlGYpLk/Dgi/sVbwFeoOUQcaTBRnWKUCedX4v4kmPIHuHSNPV2C/0770gH2iJ1N1XEO3YDGiixuHHiLlCV8Ko950CoTh1PwDNCd3Qy/jR/QhE2waVPliFwl2+H6IkIxkUO8A9ktLCJUeaZJN3snoV+9hvpT1E2TrEccsTVx5BaGAJCUkvO2XYlEsNceIIitkrbhidjZvfZ4/czGUKoN1wSSpMw== GnuPG pub=F2E027182397AC0775714F2AD15AF7F467E8299B sub=7819E44BAEEDE91683811BB00E1AAADBE227DDAA"
-          ];
-        };
-    };
-    groups = {
-    };
-  };
 
   documentation.nixos = {
     enable = false; # NOTE: useless on this machine, and CPU intensive.
 
   environment = {
     systemPackages = with pkgs; [
-      htop
-      tree
-      vim
-      tcpdump
-      cryptsetup
-      multitail
+      binutils
       dnsutils
+      htop
       inetutils
-      binutils
       mailutils
+      multitail
       ncdu
+      tcpdump
       tmux
-      socat
+      tree
+      vim
       which
-      zfs
     ];
 
-    etc."inputrc".text = lib.readFile etc/inputrc;
+    etc."inputrc".text = lib.readFile defaults/readline/inputrc;
   };
 
   programs = {
       interactiveShellInit = ''
         bind '"\e[A":history-search-backward'
         bind '"\e[B":history-search-forward'
-        
+
         # Ignore duplicate commands, ignore commands starting with a space
         export HISTCONTROL=erasedups:ignorespace
         export HISTSIZE=42000
+
         # Append to the history instead of overwriting (good for multiple connections)
         shopt -s histappend
       '';
         l  = "ls -alh";
         ll = "ls -l";
         ls = "ls --color=tty";
-    
+
         s="sudo systemctl";
         s-u="systemctl --user";
-        
+
         nixos-clean="sudo nix-collect-garbage -d";
         nixos-history="sudo nix-env --list-generations --profile /nix/var/nix/profiles/system";
         nixos-rollback="sudo nixos-rebuild switch --rollback";
     };
     mtr.enable = true;
   };
-
-  # This value determines the NixOS release with which your system is to be
-  # compatible, in order to avoid breaking some software such as database
-  # servers. You should change this only after NixOS release notes say you
-  # should.
-  system.stateVersion = "19.09"; # Did you read the comment?
+};
 }
diff --git a/nixos/modules.nix b/nixos/modules.nix
new file mode 100644 (file)
index 0000000..13ff500
--- /dev/null
@@ -0,0 +1,32 @@
+{ pkgs, lib, config, ... }:
+# NOTE: list explicitely the modules loaded by defaults.nix,
+# its clearer, safer and more flexible if not quicker.
+{ imports = [
+  modules/services/mail/dovecot.nix
+  modules/services/networking/domains.nix
+  modules/services/networking/shorewall.nix
+  #modules/services/security/x509.nix
+  ];
+}
+
+/*
+# NOTE: this modules.nix file is put in the imports of the configuration.nix,
+# but using the lib.findFiles defined in the nixpkgs.overlays leads to an infinite recursion,
+# hence it is redefined here:
+let findFiles = pattern:
+      with builtins;
+      let go = curr:
+        let dir = readDir curr; in
+        let files = lib.filterAttrs (name: type:
+          type == "regular" &&
+          match pattern name != null) dir; in
+        let dirs = lib.filterAttrs (name: type: type == "directory") dir; in
+        map (name: "${curr}/${name}") (attrNames files) ++
+        lib.concatMap (name: go "${curr}/${name}") (attrNames dirs)
+        ;
+      in root: go (toPath root);
+in
+{
+  imports = findFiles ".*\\.nix" ./modules;
+}
+*/
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
new file mode 100644 (file)
index 0000000..5e6b5da
--- /dev/null
@@ -0,0 +1,710 @@
+{pkgs, lib, config, system, ...}:
+let inherit (builtins) toString toFile attrNames;
+    inherit (lib) types;
+    inherit (config.services) dovecot2 postfix x509;
+    unlines     = lib.concatStringsSep "\n";
+    when        = x: y: if x == null then "" else y;
+    extSep      = postfix.recipientDelimiter;
+    dirSep      = extSep;
+    libDir      = "/var/lib/dovecot";
+    mailDir     = "${libDir}/mail";
+    sieveDir    = "${libDir}/sieve";
+    authDir     = "${libDir}/auth";
+    authUser    = dovecot2.mailUser;  # TODO: php_roundcube
+    authGroup   = dovecot2.mailGroup; # TODO: php_roundcube
+    escapeGroup = lib.stringAsChars (c: if "a"<=c && c<="z"
+                                        || "0"<=c && c<="9"
+                                        || c=="-"
+                                        then c else "_");
+in
+{
+
+options.services.dovecot2 = {
+  domains = lib.mkOption {
+    default = {};
+    type    = types.attrsOf (types.submodule ({domain, ...}: {
+      #config.domain = lib.mkDefault domain;
+      options = {
+        accounts = lib.mkOption {
+          type = types.attrsOf (types.submodule ({account, ...}: {
+            options = {
+              password = lib.mkOption {
+                type        = types.str;
+                example     = "{SSHA512}uyjL1KYx4z7HpfNvnKzuVxpMLD2KVueGGBvOcj7AF1EZCTVhT++IIKUVOC4xpZtWdqVD0OVmZqgYr2qpn/3t3Aj4oU0=";
+                description = ''Password.
+                Use: `doveadm pw -s SSHA512 -p "$password"`
+                '';
+              };
+              aliases = lib.mkOption {
+                type        = with types; listOf types.str;
+                example     = [ "abuse@${config.networking.domain}" ];
+                default     = [];
+                description = ''Aliases of this account.'';
+              };
+              quota = lib.mkOption {
+                type        = with types; nullOr types.str;
+                default     = null;
+                example     = "2G";
+                description = ''
+                  Per user quota rules. Accepted sizes are `xx k/M/G/T` with the
+                  obvious meaning. Leave blank for the standard quota `100G`.
+                '';
+              };
+              sieves = lib.mkOption {
+                type    = with types; attrsOf str;
+                default = { main = ''
+                              require ["include"];
+  
+                              #include :personal "roundcube";
+                              include :global "spam";
+                              include :global "list";
+                              include :global "extension";
+                            '';
+                          };
+              };
+              groups = lib.mkOption {
+                type    = with types; listOf str;
+                default = [];
+              };
+            };
+          }));
+        };
+      };
+    }));
+  };
+  debug = lib.mkOption {
+    type        = types.bool;
+    default     = false;
+    description = ''
+      Whether to enable verbose logging or not in mail related services.
+    '';
+  };
+};
+
+# config = lib.mkIf dovecot2.enable {
+#   environment.etc."nginx/site.d/autoconfig.conf".source =
+#     let servers = lib.concatMapStringsSep " "
+#                    (dom: "autoconfig.${dom}")
+#                    (attrNames dovecot2.domains);
+#         autoconfigSite = pkgs.writeTextFile {
+#           name = "autoconfig";
+#           destination = "/mail/config-v1.1.xml";
+#           text = ''
+#             <?xml version="1.0"?>
+#             <clientConfig version="1.1">
+#               <emailProvider id="%EMAILDOMAIN%">
+#                 <!-- <displayName></displayName> -->
+#                 <!-- <displayShortName></displayShortName> -->
+#                 <domain>%EMAILDOMAIN%</domain>
+#                 <incomingServer type="imap">
+#                   <hostname>imap.%EMAILDOMAIN%</hostname>
+#                   <port>993</port>
+#                   <socketType>SSL</socketType>
+#                   <username>%EMAILADDRESS%</username>
+#                   <authentication>password-cleartext</authentication>
+#                 </incomingServer>
+#                 <incomingServer type="pop3">
+#                   <hostname>pop.%EMAILDOMAIN%</hostname>
+#                   <port>995</port>
+#                   <socketType>SSL</socketType>
+#                   <username>%EMAILADDRESS%</username>
+#                   <authentication>password-cleartext</authentication>
+#                   <pop3>
+#                     <leaveMessagesOnServer>false</leaveMessagesOnServer>
+#                     <downloadOnBiff>true</downloadOnBiff>
+#                   </pop3>
+#                 </incomingServer>
+#                 <outgoingServer type="smtp">
+#                   <hostname>smtp.%EMAILDOMAIN%</hostname>
+#                   <port>465</port>
+#                   <socketType>SSL</socketType> <!-- see above -->
+#                   <username>%EMAILADDRESS%</username> <!-- if smtp-auth -->
+#                   <authentication>password-cleartext</authentication>
+#                   <!-- <restriction>client-IP-address</restriction> -->
+#                   <addThisServer>true</addThisServer>
+#                   <useGlobalPreferredServer>false</useGlobalPreferredServer>
+#                 </outgoingServer>
+#               </emailProvider>
+#               <!-- <clientConfigUpdate url="https://www.example.com/config/mozilla.xml" /> -->
+#             </clientConfig>
+#           '';
+#         };
+#     in
+#     pkgs.writeText "autoconfig.conf" ''
+#       server {
+#         listen 80;
+#         server_name ${servers};
+#         root ${autoconfigSite};
+#         access_log off;
+#         log_not_found off;
+#       }
+#       server {
+#         listen 443 ssl http2;
+#         ssl on;
+#         server_name ${servers};
+#         root ${autoconfigSite};
+#         access_log off;
+#         log_not_found off;
+#       }
+#     '';
+#   #services.postfix.mapFiles."transport-dovecot" =
+#   #  toFile "transport-dovecot"
+#   #   (unlines
+#   #     (lib.mapAttrsToList
+#   #       (dom: {...}: "${transportSubDomain}.${dom} lmtp:unix:private/dovecot-lmtp")
+#   #       dovecot2.domains));
+#   systemd.services.dovecot2.after = [ "postfix.service" ];
+#   #users.extraUsers = [
+#   #  { name        = "dovecot";
+#   #    uid         = config.ids.uids.dovecot2;
+#   #    description = "Dovecot user";
+#   #    group       = dovecot2.group;
+#   #  }
+#   #];
+#   users.extraGroups = lib.mapAttrs
+#                        (domain: {...}:
+#                         { name = escapeGroup "${dovecot2.mailGroup}-${domain}";
+#                         })
+#                        dovecot2.domains;
+#   systemd.services.dovecot2.preStart =
+#     let sieveList =
+#           pkgs.writeText "list.sieve" ''
+#           require
+#            [ "date"
+#            , "fileinto"
+#            , "mailbox"
+#            , "variables"
+#            ];
+# 
+#           if currentdate :matches "year"  "*" { set "year"  "''${1}"; }
+#           if currentdate :matches "month" "*" { set "month" "''${1}"; }
+# 
+#           if exists "List-ID" {
+#             if header :matches "List-ID" "*<*.*.*.*>*" {
+#               set "list"   "''${2}";
+#               set "domain" "''${4}";
+#             }
+#             elsif header :matches "List-ID" "*<*.*.*>*" {
+#               set "list"   "''${2}";
+#               set "domain" "''${3}";
+#             }
+#             fileinto :create "Listes+''${domain}+''${list}+''${year}+''${month}";
+#             stop;
+#            }
+#           '';
+#         sieveSpam =
+#           pkgs.writeText "spam.sieve" ''
+#           require
+#            [ "imap4flags"
+#            ];
+# 
+#           if header :contains "X-Spam-Level" "***" {
+#             addflag "Junk";
+#           }
+#           '';
+#         sieveExtension =
+#           pkgs.writeText "extension.sieve" ''
+#           require
+#            [ "envelope"
+#            , "fileinto"
+#            , "mailbox"
+#            , "subaddress"
+#            , "variables"
+#            ];
+#           if envelope :matches :detail "TO" "*" {
+#             set "extension" "''${1}";
+#           }
+#           if not string :is "''${extension}" "" {
+#             fileinto :create "Plus+''${extension}";
+#             stop;
+#           }
+#           '';
+#         dovecot-virtual =
+#           pkgs.writeText "dovecot-virtual" ''
+#           all
+#           all+*
+#             all
+#           '';
+#     in ''
+#     # SEE: http://wiki2.dovecot.org/SharedMailboxes/Permissions
+#     # The sticky bit is to allow the acl.db{.lock,} done by dovecot
+#     install -D -d -m 2771 \
+#      -o ${dovecot2.mailUser} \
+#      -g ${dovecot2.mailGroup} \
+#      ${mailDir}
+#     
+#     # Install global sieves
+#     install -D -d -m 0755 \
+#      -o root \
+#      -g root \
+#      ${sieveDir} \
+#      ${sieveDir}/after.d \
+#      ${sieveDir}/before.d \
+#      ${sieveDir}/global.d
+#     ln -fns ${sieveList}      ${sieveDir}/global.d/list.sieve
+#     ln -fns ${sieveExtension} ${sieveDir}/global.d/extension.sieve
+#     ln -fns ${sieveSpam}      ${sieveDir}/global.d/spam.sieve
+#     for f in ${sieveDir}/*/*.sieve
+#      do ${pkgs.dovecot_pigeonhole}/bin/sievec $f
+#      done
+#     
+#     # Install pop3 Inbox
+#     install -D -m 0644 \
+#      -o root \
+#      -g root \
+#      ${dovecot-virtual} \
+#      ${libDir}/pop3/INBOX/dovecot-virtual
+#     ''
+#     + ''
+#     # Install domains
+#     new_uid=5000
+#     ''
+#     + unlines (lib.mapAttrsToList (domain: {accounts, ...}:
+#       let domainGroup = escapeGroup "${dovecot2.mailGroup}-${domain}"; in
+#       ''
+#       install -D -d -m 1770 \
+#        -o ${dovecot2.mailUser} \
+#        -g ${domainGroup} \
+#        ${mailDir}/${domain} \
+#        ${libDir}/control/${domain} \
+#        ${libDir}/index/${domain}
+#       install -D -d -m 1770 \
+#        -o ${dovecot2.mailUser} \
+#        -g ${authGroup} \
+#        ${libDir}/auth \
+#        ${libDir}/auth/${domain}
+#       dir_passwd=${libDir}/auth/${domain}
+#       old_passwd=$dir_passwd/passwd
+#       new_passwd=$(TMPDIR= mktemp --tmpdir=$dir_passwd -t passwd.XXXXXXXX.tmp)
+#       
+#       # Install users
+#       ''
+#       + unlines (lib.mapAttrsToList (user: acct: ''
+#         home=${mailDir}/${domain}/${user}
+#         gecos=
+#         shell=/run/current-system/sw/bin/nologin
+#         if test -e $home
+#          then
+#           uid=$(stat -c %u $home)
+#           gid=$(stat -c %g $home)
+#          fi
+#         [ "''${uid:+set}" ] || {
+#           while test exists = "$(find $(dirname $home) -mindepth 1 -maxdepth 1 -uid $new_uid -printf exists -quit)"
+#            do new_uid=$((new_uid + 1))
+#            done
+#           uid=$new_uid
+#           gid=$new_uid
+#         }
+#         install -D -d -o $uid -g $gid -m 2770 $home $home/Maildir
+#         install    -d -o $uid -g $gid -m 0700 $home/sieve
+#         ''
+#         + unlines (lib.mapAttrsToList
+#             (n: v: ''
+#               install -D -m 640 -o $uid -g $gid \
+#                ${pkgs.writeText "${n}.sieve" v} \
+#                $home/sieve/${n}.sieve
+#               ${pkgs.dovecot_pigeonhole}/bin/sievec \
+#                $home/sieve/${n}.sieve
+#             '')
+#             acct.sieves)
+#         + ''
+#         mail_access_groups=${lib.concatStringsSep "," ([domainGroup] ++ acct.groups)}
+#         quota=${if lib.isString acct.quota
+#                 then ''"userdb_quota_rule=*:storage=${acct.quota}"''
+#                 else ""}
+#         extra_fields="userdb_uid=$uid userdb_gid=$gid userdb_mail_access_groups=$mail_access_groups $quota"
+#         #test ! -e $old_passwd || {
+#         #  # Preserve password changed by another mechanism, eg. roundcube.
+#         #  # But this also does not overwrite any old password set by this config.
+#         #  pass="$(sed -ne "s/^${user}:\([^:]*\):.*/\1/p" $old_passwd)"
+#         #}
+#         [ "''${pass:+set}" ] || {
+#           pass=${lib.escapeShellArg acct.password}
+#         }
+#         printf '%s\n' >>$new_passwd \
+#          "${user}:$pass:$uid:$gid:$gecos:$home:$shell:$extra_fields"
+#       '') accounts)
+#       + ''
+#       install -o ${authUser} -g ${authGroup} -m 0640 $new_passwd $old_passwd
+#       rm $new_passwd
+#       ''
+#     ) dovecot2.domains);
+#   services.dovecot2 = {
+#     enable    = true;
+#     mailUser  = "dovemail";
+#     mailGroup = "dovemail";
+#     modules   = [
+#       #pkgs.dovecot_antispam
+#       pkgs.dovecot_pigeonhole
+#     ];
+#     # ${lib.concatMapStringsSep "\n"
+#     #     (dom: ''
+#     #       local_name imap.${dom} {
+#     #         #ssl_ca   = <''${caPath}
+#     #         ssl_cert = <${x509.cert dom}
+#     #         ssl_key  = <${x509.key dom}
+#     #         }
+#     #       local_name pop.${dom} {
+#     #         #ssl_ca   = <''${caPath}
+#     #         ssl_cert = <${x509.cert dom}
+#     #         ssl_key  = <${x509.key dom}
+#     #         }
+#     #     '')
+#     #     dovecot2.domains
+#     # }
+# 
+#     configFile = toString (pkgs.writeText "dovecot.conf" ''
+#       passdb {
+#         driver = passwd-file
+#         args   = scheme=crypt username_format=%n ${authDir}/%d/passwd
+#         }
+#       userdb {
+#         driver = prefetch
+#         }
+#       userdb {
+#         # NOTE: this userdb is only used by lda.
+#         driver = passwd-file
+#         args = username_format=%n ${authDir}/%d/passwd
+#         #default_fields = home=${mailDir}/%d/%n
+#         }
+#       mail_home = ${mailDir}/%d/%n
+#       auth_mechanisms = plain login
+#       # postfix does not supply a client cert.
+#       auth_ssl_require_client_cert = no
+#       auth_ssl_username_from_cert = yes
+#       auth_verbose = yes
+#       ${lib.optionalString dovecot2.debug ''
+#         auth_debug  = yes
+#         mail_debug  = yes
+#         verbose_ssl = yes
+#       ''}
+#       default_internal_user = ${dovecot2.user}
+#       default_internal_group = ${dovecot2.group}
+#       disable_plaintext_auth = yes
+#       first_valid_uid = 1000
+#       lda_mailbox_autocreate = yes
+#       lda_mailbox_autosubscribe = yes
+#       listen = *
+#       log_timestamp = "%Y-%m-%d %H:%M:%S "
+#       # NOTE: INDEX and CONTROL are on a partition without quota, as explain in the doc.
+#       # SEE: http://wiki2.dovecot.org/Quota/FS
+#       mail_location = maildir:${mailDir}/%d/%n/Maildir:LAYOUT=fs:INDEX=${libDir}/index/%d/%n:CONTROL=${libDir}/control/%d/%n
+#       namespace inbox {
+#         # NOTE: here because protocol sieve {namespace inbox{}} does not seem to work.
+#         inbox     = yes
+#         location  =
+#         list      = yes
+#         prefix    =
+#         separator = ${dirSep}
+#         }
+#       namespace {
+#         #list          = children
+#         list          = yes
+#         location      = maildir:${mailDir}/%%d/%%n/Maildir:LAYOUT=fs:INDEX=${libDir}/index/%d/%n/Shared/%%n:CONTROL=${libDir}/control/%d/%n/Shared/%%n
+#         prefix        = Partages+%%n+
+#         separator     = ${dirSep}
+#         subscriptions = yes
+#         type          = shared
+#         }
+#       mail_plugins = $mail_plugins acl quota virtual
+#       #mail_uid = ${dovecot2.mailUser}
+#       #mail_gid = ${dovecot2.mailGroup}
+#       #mail_privileged_group = mail
+#       #mail_access_groups =
+#       plugin {
+#         acl = vfile:/etc/dovecot/acl/global.d
+#         acl_anyone = allow
+#         acl_shared_dict = file:${mailDir}/%d/acl.db
+#         ##antispam_allow_append_to_spam = yes
+#         # # NOTE: pour offlineimap
+#         #antispam_backend = pipe
+#         ##antispam_crm_args = -u;${mailDir}/%d/.crm114;/usr/share/crm114/mailfilter.crm
+#         #antispam_crm_args = -u;${mailDir}/crm114;/usr/share/crm114/mailfilter.crm
+#         #antispam_crm_binary = /usr/bin/crm
+#         #antispam_debug_target = syslog
+#         ##antispam_crm_env = HOME=%h;USER=%u
+#         #antispam_ham_keywords = NonJunk
+#         #antispam_pipe_program = /usr/bin/crm
+#         #antispam_pipe_program_args = -u;${mailDir}/crm114;/usr/share/crm114/mailfilter.crm;--stats_only;--force
+#         #antispam_pipe_program_notspam_arg = --learnnonspam
+#         #antispam_pipe_program_spam_arg = --learnspam
+#         #antispam_pipe_program_unlearn_spam_args = --unlearn;--learnspam
+#         #antispam_pipe_program_unlearn_notspam_args = --unlearn;--learnnonspam
+#         #antispam_pipe_tmpdir = ${mailDir}/crm114/tmp
+#         #antispam_signature = X-CRM114-CacheID
+#         #antispam_signature_missing = move
+#         #antispam_spam = Junk
+#         #antispam_spam_keywords = Junk
+#         #antispam_trash = Trash
+#         #antispam_unsure = Unsure
+#         #antispam_verbose_debug = 0
+#         quota = maildir:User quota
+#         quota_rule = *:storage=256M
+#         quota_rule2 = Trash:storage=+64M
+#         recipient_delimiter = ${extSep}
+#         sieve = file:${mailDir}/%d/%n/sieve;active=${mailDir}/%d/%n/sieve/main.sieve
+#         #sieve_default = file:${mailDir}/%u/default.sieve
+#         #sieve_default_name = default
+#         sieve_after  = ${sieveDir}/after.d/
+#         sieve_before = ${sieveDir}/before.d/
+#         sieve_dir = ${mailDir}/%d/%n/sieve/
+#         #sieve_extensions = +spamtest +spamtestplus
+#         sieve_global_dir = ${sieveDir}/global.d/
+#         sieve_max_script_size = 1M
+#         sieve_quota_max_scripts = 0
+#         sieve_quota_max_storage = 10M
+#         sieve_spamtest_max_value = 10
+#         sieve_spamtest_status_header = X-Spam-Score
+#         sieve_spamtest_status_type = strlen
+#         sieve_user_log = /var/log/dovecot/%d/sieve.%n.log
+#         }
+#       protocol imap {
+#         #mail_max_userip_connections = 10
+#         mail_plugins = $mail_plugins imap_acl imap_quota # antispam
+#         namespace inbox {
+#           inbox = yes
+#           location =
+#           list = yes
+#           mailbox Drafts {
+#             special_use = \Drafts
+#             }
+#           mailbox Junk {
+#             special_use = \Junk
+#             }
+#           mailbox Sent {
+#             special_use = \Sent
+#             }
+#           mailbox "Sent Messages" {
+#             special_use = \Sent
+#             }
+#           mailbox Trash {
+#             special_use = \Trash
+#             }
+#           prefix =
+#           separator = ${dirSep}
+#           }
+#         }
+#       protocol lda {
+#         auth_socket_path = /var/run/dovecot/auth-userdb
+#         hostname         = ${machine.fqdn}
+#         info_log_path    =
+#         log_path         =
+#         mail_plugins     = $mail_plugins sieve
+#         namespace inbox {
+#           inbox     = yes
+#           location  =
+#           list      = yes
+#           prefix    =
+#           separator = ${dirSep}
+#           }
+#         postmaster_address = postmaster${extSep}dovecot${extSep}lda@${machine.fqdn}
+#         syslog_facility = mail
+#         }
+#       protocol lmtp {
+#         #info_log_path = /tmp/dovecot-lmtp.log
+#         mail_plugins = $mail_plugins sieve
+#         namespace inbox {
+#           inbox     = yes
+#           location  =
+#           list      = yes
+#           prefix    =
+#           separator = ${dirSep}
+#           }
+#         postmaster_address = postmaster${extSep}dovecot${extSep}lmtp@${machine.fqdn}
+#         }
+#       protocol pop3 {
+#         #mail_max_userip_connections = 10
+#         # Used by ${libDir}/pop3/INBOX/dovecot-virtual
+#         namespace all {
+#           hidden    = yes
+#           list      = no
+#           location  =
+#           prefix    = all+
+#           separator = ${dirSep}
+#           }
+#         # Virtual namespace for the virtual INBOX.
+#         # Use a global directory for dovecot-virtual files.
+#         namespace inbox {
+#           inbox     = yes
+#           hidden    = yes
+#           list      = no
+#           location  = virtual:${libDir}/pop3:INDEX=${libDir}/index/%d/%n/POP3:LAYOUT=fs
+#           prefix    = pop3+
+#           separator = ${dirSep}
+#           }
+#         pop3_client_workarounds =
+#         pop3_fast_size_lookups = yes
+#         pop3_lock_session = yes
+#         pop3_no_flag_updates = yes
+#         # Use GUIDs to avoid accidental POP3 UIDL changes instead of IMAP UIDs.
+#         pop3_uidl_format = %g
+#         }
+#       protocol sieve {
+#         #mail_max_userip_connections = 10
+#         #managesieve_implementation_string = Dovecot Pigeonhole
+#         managesieve_max_compile_errors = 5
+#         #managesieve_max_line_length = 65536
+#         #managesieve_notify_capability = mailto
+#         #managesieve_sieve_capability = fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date ihave
+#         }
+#       protocols = imap lmtp pop3 sieve
+#       service lmtp {
+#         #executable = lmtp -L
+#         process_min_avail = 2
+#         unix_listener /var/lib/postfix/queue/private/dovecot-lmtp {
+#           user  = ${postfix.user}
+#           group = ${postfix.group}
+#           mode  = 0600
+#           }
+#         #user = mail
+#         }
+#       service auth {
+#         user = root
+#         unix_listener auth-userdb {
+#           user  = ${dovecot2.user}
+#           group = ${dovecot2.group}
+#           mode  = 0660
+#           }
+#         unix_listener /var/lib/postfix/queue/private/auth {
+#           user  = ${postfix.user}
+#           group = ${postfix.group}
+#           mode  = 0660
+#           }
+#         }
+#       service imap {
+#         # Most of the memory goes to mmap()ing files.
+#         # You may need to increase this limit if you have huge mailboxes.
+#         #vsz_limit =
+#         process_limit = 1024
+#         }
+#       service imap-login {
+#         #inet_listener imap {
+#         #  address = 127.0.0.1
+#         #  port    = 143
+#         #  ssl     = no
+#         #  }
+#         inet_listener imaps {
+#           port = 993
+#           ssl  = yes
+#           }
+#         }
+#       service pop3 {
+#         process_limit = 1024
+#         }
+#       service pop3-login {
+#         inet_listener pop3s {
+#           port = 995
+#           ssl  = yes
+#           }
+#         }
+#       ssl = required
+#       #ssl_ca   = <''${caPath}
+#       ssl_cert = <${x509.cert}
+#       # Only with dovecot >= 2.3
+#       #ssl_dh   = <${x509.dir}/dh.pem
+#       ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL
+#       ssl_key = <${x509.key}
+#       #ssl_verify_client_cert = yes
+#     '');
+#   };
+# };
+
+}
+
+   #loginAccounts = lib.mkOption {
+   #  type = types.loaOf (types.submodule ({name, ...}: {
+   #    config.name = lib.mkDefault name;
+   #    options     = {
+   #      name = lib.mkOption {
+   #        type        = types.str;
+   #        example     = "user1@example.coop";
+   #        description = "Username";
+   #      };
+   #      password = lib.mkOption {
+   #        type        = types.str;
+   #        example     = "$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/";
+   #        description = ''
+   #          Hashed password. Use `mkpasswd` as follows
+   #          
+   #          ```
+   #          mkpasswd -m sha-512 "super secret password"
+   #          ```
+   #        '';
+   #      };
+   #      aliases = lib.mkOption {
+   #        type        = with types; listOf types.str;
+   #        example     = ["abuse@example.coop" "postmaster@example.coop"];
+   #        default     = [];
+   #        description = ''
+   #          A list of aliases of this login account.
+   #        '';
+   #      };
+   #      catchAll = lib.mkOption {
+   #        type        = with types; listOf (enum dovecot2.domains);
+   #        example     = ["example.coop" "example2.coop"];
+   #        default     = [];
+   #        description = ''
+   #          For which domains should this account act as a catch all?
+   #        '';
+   #      };
+   #      sieveScript = lib.mkOption {
+   #        type    = with types; nullOr lines;
+   #        default = null;
+   #        example = ''
+   #          require ["fileinto", "mailbox"];
+   #          
+   #          if address :is "from" "notifications@github.coop" {
+   #            fileinto :create "GitHub";
+   #            stop;
+   #          }
+   #          
+   #          # This must be the last rule, it will check if list-id is set, and
+   #          # file the message into the Lists folder for further investigation
+   #          elsif header :matches "list-id" "<?*>" {
+   #            fileinto :create "Lists";
+   #            stop;
+   #          }
+   #        '';
+   #        description = ''
+   #          Per-user sieve script.
+   #        '';
+   #      };
+   #    };
+   #  }));
+   #  example = {
+   #    user1 = {
+   #      password = "$6$vy7SOr8Cg$l1QwFSkK6YR72ASUBmMmAqg51Fqu96mPZrKzADh5aI7bEOtTzDger9JSVnUhQ/DiqhxO1N55BUikE01mWvBee1";
+   #    };
+   #    user2 = {
+   #      password = "$6$gmebVgh5iJ9IyAJ5$i2aEvWZqS3iUq7mxSAhs5F./uUvQ4zmqFAdH3fsGiwabekdP.On8HCzpDCRS2nzzYNQ8ZisqyIwXf9R2rkC531";
+   #    };
+   #  };
+   #  description = ''
+   #    The login account of the domain. Every account is mapped to a unix user,
+   #    e.g. `user1@example.coop`. To generate the passwords use `mkpasswd` as
+   #    follows
+   #    
+   #    ```
+   #    mkpasswd -m sha-512 "super secret password"
+   #    ```
+   #  '';
+   #  default = {};
+   #};
+   #extraVirtualAliases = lib.mkOption {
+   #  type = with types; attrsOf (enum (builtins.attrNames machine.mail.loginAccounts));
+   #  example = {
+   #    "info@example.coop"       = "user1@example.coop";
+   #    "postmaster@example.coop" = "user1@example.coop";
+   #    "abuse@example.coop"      = "user1@example.coop";
+   #  };
+   #  default = {};
+   #  description = ''
+   #    Virtual Aliases. A virtual alias `"info@example2.coop" = "user1@example.coop"`
+   #    means that all mail to `info@example2.coop` is forwarded to `user1@example.coop`.
+   #    Note that it is expected that `postmaster@example.coop` and `abuse@example.coop` is
+   #    forwarded to some valid email address. (Alternatively you can create login
+   #    accounts for `postmaster` and (or) `abuse`). Furthermore, it also allows
+   #    the user `user1@example.coop` to send emails as `info@example2.coop`.
+   #  '';
+   #};
+
similarity index 80%
rename from install/options.nix
rename to nixos/modules/services/networking/domains.nix
index 5c6cfb79d115c72748d2504524659d482ccc663c..664935dfccafe2256f65d94693cd27a4844baa7e 100644 (file)
@@ -1,17 +1,18 @@
-{pkgs, lib, config, system, ...}: {
-options = {
-  enable = lib.mkEnableOption "friot";
-  networking.domainBase = lib.mkOption {
+{pkgs, lib, config, system, ...}:
+let inherit (lib) types;
+in {
+options.networking = {
+  domainBase = lib.mkOption {
     type        = types.str;
     description = "Base network name.";
     example     = "example";
   };
-  networking.domainAliases = lib.mkOption {
+  domainAliases = lib.mkOption {
     type        = types.listOf types.str;
     description = "Domain aliases.";
     example     = [ "example.org" "example.net" ];
   };
-  networking.zones = lib.mkOption {
+  zones = lib.mkOption {
     type = types.attrsOf (types.submodule ({name, options, config, ...}: {
       options = {
         iface = lib.mkOption {
similarity index 99%
rename from install/overlays/tools/networking/shorewall/service.nix
rename to nixos/modules/services/networking/shorewall.nix
index 0f94d414fcf748faa4845e5e27e817a4b21787e5..75d65bfbf20e344437eaa4e795e7198cb6b63a96 100644 (file)
@@ -39,6 +39,7 @@ in {
   };
 
   config = lib.mkIf cfg.enable {
+    /*
     systemd.services.firewall.enable = false;
     systemd.services.shorewall = {
       description     = "Shorewall IPv4 Firewall";
@@ -71,5 +72,6 @@ in {
               cfg.configs;
       systemPackages = [ cfg.package ];
     };
+    */
   };
 }
diff --git a/nixos/modules/services/security/x509.nix b/nixos/modules/services/security/x509.nix
new file mode 100644 (file)
index 0000000..8e434b3
--- /dev/null
@@ -0,0 +1,261 @@
+{pkgs, lib, config, ...}:
+let inherit (builtins) toString;
+    inherit (lib) types;
+    inherit (config.services) x509;
+    when = x: y: if x == null then "" else y;
+in
+{
+
+options.services.x509 = {
+  enable = lib.mkEnableOption "Generation of X.509 material";
+  scheme = lib.mkOption {
+    type        = types.enum [ "manual" "self-signed" "letsencrypt" ];
+    default     = "self-signed";
+    description = ''
+      Scheme for X.509 material.
+      
+      manual:
+        Use certificate and key manually copied on the target at certFile and keyFile.
+      self-signed:
+        Generate a self-signed certificate.
+      letsencrypt:
+        Generate a certificate signed by Let's Encrypt.
+    '';
+  };
+  dir = lib.mkOption {
+    type        = types.string;
+    default     = "/var/x509";
+    description = ''In "self-signed" scheme: directory of the certificate and key.'';
+  };
+  certFile = lib.mkOption {
+    type        = types.path;
+    example     = "/var/x509/cert.pem";
+    description = ''In "manual" scheme: location of the certificate'';
+  };
+  keyFile = lib.mkOption {
+    type        = types.path;
+    example     = "/var/x509/key.pem";
+    description = ''In "manual" scheme: location of the key file.'';
+  };
+  dh = lib.mkOption {
+    type        = types.int;
+    default     = 4096;
+    description = ''Bit size of Diffie–Hellman parameters.'';
+  };
+  host = lib.mkOption {
+    type    = types.nullOr types.string;
+    default = config.networking.domain;
+  };
+  distributionHost = lib.mkOption {
+    type    = types.string;
+    default = config.networking.domain;
+  };
+  domains = lib.mkOption {
+    type    = with types; listOf string;
+    example = [ "example.coop" ];
+    default = [];
+  };
+  days = lib.mkOption {
+    type    = types.int;
+    default = 3650;
+  };
+  keySize = lib.mkOption {
+    type    = types.int;
+    default = 4096;
+  };
+  cert = lib.mkOption {
+    type    = types.string;
+    default =
+      if x509.scheme == "manual"
+      then x509.certFile
+      else if x509.scheme == "self-signed"
+           then "${x509.dir}/${x509.host}.cert.self-signed.pem"
+           else if x509.scheme == "letsencrypt"
+                then "/var/lib/acme/${x509.host}/fullchain.pem"
+                else throw ''Error: Certificate Scheme must be in [ "manual" "self-signed" "letsencrypt" ]'';
+  };
+  key = lib.mkOption {
+    type    = types.string;
+    default =
+      if x509.scheme == "manual"
+      then x509.keyFile
+      else if x509.scheme == "self-signed"
+           then "${x509.dir}/${x509.host}.key.pem"
+            else if x509.scheme == "letsencrypt"
+                 then "/var/lib/acme/${x509.host}/key.pem"
+                 else throw ''Error: Certificate Scheme must be in [ "manual" "self-signed" "letsencrypt" ]'';
+  };
+  opensslConf = lib.mkOption {
+    type  = (with types; attrsOf string);
+    default = x509.opensslConf_common //
+              x509.opensslConf_self-signed //
+              x509.opensslConf_auth-signed //
+              x509.opensslConf_user-cert;
+    apply = cnf:
+      pkgs.writeText "openssl.conf"
+        (lib.concatStrings
+          (lib.mapAttrsToList
+            (title: body:
+              (if title == "" then "" else "[ ${title} ]\n") +
+              body)
+            cnf));
+  };
+  opensslConf_common = lib.mkOption {
+    type    = (with types; attrsOf string);
+    default = {
+      "" = ''
+        RANDFILE    = /var/x509/openssl.rand
+        oid_section = extra_oids
+      '';
+      extra_oids = ''
+        # NOTE: only useful for Extended Validation (EV)
+        jurisdictionOfIncorporationLocalityName        = 1.3.6.1.4.1.311.60.2.1.1
+        jurisdictionOfIncorporationStateOrProvinceName = 1.3.6.1.4.1.311.60.2.1.2
+        jurisdictionOfIncorporationCountryName         = 1.3.6.1.4.1.311.60.2.1.3
+      '';
+      req = ''
+        prompt = no
+        distinguished_name = distinguished_name
+        string_mask = pkix
+        #x509_extensions = root_extensions
+        #req_extensions = extension
+        #attributes = req_attributes
+      '';
+      distinguished_name = ''
+        commonName = ${x509.host}
+        #countryName =
+        #stateOrProvinceName =
+        #localityName =
+        #"0.organizationName" =
+        #organizationalUnitName =
+        #businessCategory =
+        #jurisdictionOfIncorporationLocalityName = $stateOrProvinceName
+        #jurisdictionOfIncorporationStateOrProvinceName = $stateOrProvinceName
+        #jurisdictionOfIncorporationCountryName = $countryName
+      '';
+    };
+  };
+  opensslConf_self-signed = lib.mkOption {
+    type    = (with types; attrsOf string);
+    default = {
+      self_signed_extensions = ''
+        basicConstraints       = critical,CA:TRUE,pathlen:0
+        keyUsage               = keyCertSign,cRLSign,digitalSignature,keyEncipherment
+        subjectAltName         = ${lib.concatMapStringsSep "," (dom: "DNS:${dom}") x509.domains}
+        subjectKeyIdentifier   = hash
+        issuerAltName          = issuer:copy
+        authorityKeyIdentifier = keyid:always,issuer:always
+        authorityInfoAccess    = caIssuers;URI:http://${x509.distributionHost}/x509/${x509.host}.cert.pem
+        crlDistributionPoints  = URI:http://${x509.distributionHost}/x509/${x509.host}.crl.self-signed.pem
+      '';
+      self_signed_ca = ''
+        dir         = ${x509.dir}/pub
+        private_key = $dir/sec/key.pem
+        crl_dir     = $dir
+        crlnumber   = $dir/crl.self-signed.num
+        crl         = $dir/crl.self-signed.pem
+        database    = $dir/idx.self-signed.txt
+      '';
+    };
+  };
+  opensslConf_auth-signed = lib.mkOption {
+    type    = (with types; attrsOf string);
+    default = {
+      auth_signed_extensions = ''
+        basicConstraints       = critical,CA:FALSE
+        keyUsage               = digitalSignature,keyEncipherment
+        subjectAltName         = ${lib.concatMapStringsSep "," (dom: "DNS:${dom}") x509.domains}
+        subjectKeyIdentifier   = hash
+        issuerAltName          = issuer:copy
+        authorityKeyIdentifier = keyid:always,issuer:always
+        authorityInfoAccess    = caIssuers;URI:http://${x509.distributionHost}/x509/${x509.host}.cert.pem
+        crlDistributionPoints  = URI:http://${x509.distributionHost}/x509/${x509.host}.crl.pem
+        certificatePolicies    = @certificate_policies
+      '';
+      certificate_policies = ''
+        policyIdentifier = 1.2.250.1.42
+        CPS.1 = https://${x509.host}/x509/cps
+      '';
+      ca = ''
+        dir         = ${x509.dir}/pub
+        private_key = $dir/sec/key.pem
+        crl_dir     = $dir
+        crlnumber   = $dir/crl.num
+        crl         = $dir/crl.pem
+        database    = $dir/idx.txt
+      '';
+    };
+  };
+  opensslConf_user-cert = lib.mkOption {
+    type    = (with types; attrsOf string);
+    default = {
+      user_cert_extensions = ''
+        basicConstraints       = critical,CA:FALSE,pathlen:0
+        keyUsage               = digitalSignature,keyEncipherment
+        subjectAltName         = email:$ENV::user@${x509.host}
+        subjectKeyIdentifier   = hash
+        issuerAltName          = issuer:copy
+        authorityKeyIdentifier = keyid:always,issuer:always
+        authorityInfoAccess    = caIssuers;URI:http://${x509.distributionHost}/x509/${x509.host}.cert.pem
+      '';
+    };
+  };
+};
+
+config = {
+  systemd.services.x509 = {
+    enable        = true;
+    wantedBy      = [ "multi-user.target" ];
+    before        = [ "keys.target" ];
+    serviceConfig = {
+      ExecStart = pkgs.writeShellScriptBin "x509.service" (
+        lib.optionalString (x509.scheme == "self-signed") ''
+          # Generate DH parameters
+          { ${pkgs.openssl}/bin/openssl dhparam -in ${x509.dir}/dh.pem -text |
+            head -n 1 |
+            ${pkgs.gnugrep}/bin/grep >/dev/null "(${toString x509.keySize} bit)"
+          } || {
+            mkdir -p ${x509.dir}
+            ${pkgs.openssl}/bin/openssl dhparam \
+              ${toString x509.dh} \
+              >${x509.dir}/dh.pem
+          }
+          # Make private key
+          [ -s "${x509.key}" ] || {
+            mkdir -p ${x509.dir}
+            (
+              umask 077
+              "${pkgs.openssl}/bin/openssl" genrsa \
+               -out "${x509.key}" \
+               -rand /dev/urandom \
+               ${toString x509.keySize}
+            )
+          }
+          # Make self-signed certificate
+          [ -s "${x509.cert}" ] &&
+          [    "${x509.cert}" -nt "${x509.key}" ] || {
+            user= \
+            ${pkgs.openssl}/bin/openssl req \
+             -batch \
+             -new \
+             -x509 \
+             -utf8 \
+             -rand       /dev/urandom \
+             -config     ${x509.opensslConf} \
+             -extensions self_signed_extensions \
+             -reqexts    self_signed_extensions \
+             -inform     PEM \
+             -outform    PEM \
+             -keyform    PEM \
+             ${when x509.days "-days ${toString x509.days}"} \
+             -set_serial 0x$(sleep 1; date '+%Y%m%d%H%M%S') \
+             -reqopt     no_pubkey,no_sigdump \
+             -key        ${x509.key} \
+             -out        ${x509.cert}
+          }
+        '') + "/bin/x509.service";
+    };
+  };
+};
+
+}
diff --git a/overlays.nix b/overlays.nix
new file mode 100644 (file)
index 0000000..04e6e2a
--- /dev/null
@@ -0,0 +1,11 @@
+map import
+[ overlays/lib/filesystem.nix
+  overlays/lib/strings.nix
+  #overlays/servers/mail/postfix.nix
+  #overlays/servers/mail/dovecot.nix
+   # TODO: remove when using a nixpkgs including the fix
+   # https://github.com/NixOS/nixpkgs/pull/46859
+  #overlays/users-init.nix
+]/* ++
+[ (self: super: { shorewall = super.callPackage ../pkgs/tools/networking/shorewall {}; })
+]*/
diff --git a/overlays/lib/filesystem.nix b/overlays/lib/filesystem.nix
new file mode 100644 (file)
index 0000000..e155cf5
--- /dev/null
@@ -0,0 +1,18 @@
+self: super:
+let lib = super.lib; in
+{
+  lib = (super.lib or {}) // {
+    findFiles = pattern:
+      with builtins;
+      let go = curr:
+        let dir = readDir curr; in
+        let files = lib.filterAttrs (name: type:
+          type == "regular" &&
+          match pattern name != null) dir; in
+        let dirs = lib.filterAttrs (name: type: type == "directory") dir; in
+        map (name: "${curr}/${name}") (attrNames files) ++
+        lib.concatMap (name: go "${curr}/${name}") (attrNames dirs)
+        ;
+      in root: go (toPath root);
+  };
+}
index afb6ea50d0be4729b42114cb80124f1a3a66f7a4..0830b728fd2f52eb099b1b92d1dd09234a682409 100644 (file)
--- a/shell.nix
+++ b/shell.nix
@@ -2,13 +2,16 @@ let
   nixpkgs = import .lib/nix/nixpkgs.nix;
   pkgs = import nixpkgs {
     config   = {}; # Make the config pure, ignoring user's config.
-    overlays = import .lib/nixpkgs-sourcephile/build/overlays.nix;
+    overlays = import ./overlays.nix;
   };
-  sourcephile-nix-build-modules =
-    (import .lib/nixpkgs-sourcephile/build/modules.nix {
+  # Using modules enables to separate specific configurations in shell/configuration.nix
+  # from reusable code in shell/modules.nix
+  # which may find its way in another git repository one day.
+  modules =
+    (import shell/modules.nix {
       inherit pkgs;
       inherit (pkgs) lib;
-      modules = [ ( import build/modules.nix ) ];
+      modules = [ ( import shell/configuration.nix ) ];
     }).config;
   /*
   sourcephile-nix-build =
@@ -17,14 +20,14 @@ let
       preferLocalBuild = true;
       allowSubstitutes = false;
       inherit (pkgs) coreutils;
-      builder = pkgs.writeText "builder.sh" sourcephile-nix-build-modules.init.builder;
+      builder = pkgs.writeText "builder.sh" modules.init.builder;
     };
   */
   sourcephile-nix-build =
     pkgs.buildEnv {
       name        = "sourcephile-nix-build";
       pathsToLink = [ "/bin" ];
-      paths       = with sourcephile-nix-build-modules; [
+      paths       = with modules; [
         gnupg.init
         #gnupg.gpg-fingerprint
         #nix-plugins.nix-with-extra-builtins
@@ -96,7 +99,7 @@ pkgs.stdenv.mkDerivation {
 
     # nix
     export NIX_PATH="nixpkgs=${nixpkgs}:nixpkgs-sourcephile=$PWD/.lib/nixpkgs-sourcephile"
-    #NIX_PATH+=":nixpkgs-overlays="$PWD"/install/overlays.nix"
+    NIX_PATH+=":nixpkgs-overlays="$PWD"/overlays"
     #NIX_PATH+=""
 
     # executables
@@ -112,7 +115,7 @@ pkgs.stdenv.mkDerivation {
     install -D /dev/stdin "$PWD"/.config/nix/nix.conf <<-EOF
     auto-optimise-store = true
     plugin-files        = ${pkgs.nix-plugins}/lib/nix/plugins/libnix-extra-builtins.so
-    extra-builtins-file = ${sourcephile-nix-build-modules.nix-plugins.extra-builtins}
+    extra-builtins-file = ${modules.nix-plugins.extra-builtins}
     EOF
 
     # NOTE: sudo needs to be own by root with the setuid bit,
@@ -156,7 +159,7 @@ pkgs.stdenv.mkDerivation {
     # from the local password-store.
     NIXOPS_OPTS+=" --show-trace"
     NIXOPS_OPTS+=" --option plugin-files ${pkgs.nix-plugins}/lib/nix/plugins/libnix-extra-builtins.so"
-    NIXOPS_OPTS+=" --option extra-builtins-file ${sourcephile-nix-build-modules.nix-plugins.extra-builtins}"
+    NIXOPS_OPTS+=" --option extra-builtins-file ${modules.nix-plugins.extra-builtins}"
     export NIXOPS_OPTS
 
     # disnix
diff --git a/shell b/shell.sh
similarity index 100%
rename from shell
rename to shell.sh
diff --git a/shell/configuration.nix b/shell/configuration.nix
new file mode 100644 (file)
index 0000000..d8dacfd
--- /dev/null
@@ -0,0 +1,8 @@
+{config, ...}:
+{
+  imports = [
+    configuration/gnupg.nix
+  ];
+  config = {
+  };
+}
similarity index 76%
rename from build/modules/gnupg.nix
rename to shell/configuration/gnupg.nix
index 39833ae913b9bff81ca5f52d7d34032984727207..4ae3c0e3c120b1cb5e4da1965752145d1b657b4c 100644 (file)
@@ -5,12 +5,12 @@
       enable = true;
       dir.var = toString ../../../sec/gnupg;
       keys = {
-        "Sourcephile <root@sourcephile.fr>" = {
-          uid = "Sourcephile <root@sourcephile.fr>";
+        "Julien Moutinho <julm@sourcephile.fr>" = {
+          uid = "Julien Moutinho <julm@sourcephile.fr>";
           algo   = "rsa4096";
           expire = "3y";
           usage  = ["cert" "sign"];
-          passPath = "sourcephile/gpg/root";
+          passPath = "julm/gpg/julm@sourcephile.fr";
           subKeys = [
             { algo = "rsa4096"; expire = "3y"; usage = ["sign"];}
             { algo = "rsa4096"; expire = "3y"; usage = ["encrypt"];}
diff --git a/shell/modules.nix b/shell/modules.nix
new file mode 100644 (file)
index 0000000..c838ffe
--- /dev/null
@@ -0,0 +1,40 @@
+{ pkgs
+, lib ? pkgs.lib
+, modules ? []
+, extraArgs ? {}
+, specialArgs ? {}
+, check ? true
+, prefix ? []
+}:
+let extraArgs_  = extraArgs;
+    pkgs_       = pkgs;
+    baseModules = map import (lib.findFiles ".*\\.nix" ./modules );
+    pkgsModule  = rec {
+      _file  = ./modules.nix;
+      key    = _file;
+      config = {
+        _module.args.pkgs = lib.mkIf (pkgs_ != null) (lib.mkForce pkgs_);
+      };
+    };
+in
+rec {
+  # Merge the option definitions in all modules,
+  # forming the full system configuration.
+  inherit (lib.evalModules {
+    inherit prefix;
+    inherit check;
+    modules = modules ++ baseModules ++ [ pkgsModule ];
+    args    = extraArgs;
+    inherit specialArgs;
+    #specialArgs = { modulesPath = config/modules.nix; } // specialArgs;
+  }) config options;
+
+  # These are the extra arguments passed to every module.
+  # In particular, Nixpkgs is passed through the "pkgs" argument.
+  extraArgs = extraArgs_ // {
+    inherit modules;
+    inherit baseModules;
+  };
+
+  inherit (config._module.args) pkgs;
+}
diff --git a/shell/modules/development/libraries/nix-plugins.nix b/shell/modules/development/libraries/nix-plugins.nix
new file mode 100644 (file)
index 0000000..3a1b182
--- /dev/null
@@ -0,0 +1,95 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let cfg = config.nix-plugins;
+in
+{
+  options.nix-plugins = {
+    enable = lib.mkEnableOption "nix-plugins";
+    extra-builtins = mkOption {
+      type = types.lines;
+      default = ''
+        pass         = path: exec [ "${config.nix-plugins.nix-pass}/bin/nix-pass" path ];
+        pass-to-file = path: file: exec [ "${config.nix-plugins.nix-pass-to-file}/bin/nix-pass-to-file" path file ];
+        git          = dir: args: exec ([ "${config.nix-plugins.nix-git}/bin/nix-git" (builtins.toPath dir) ] ++ args);
+        git-time     = dir: path: exec [ "${config.nix-plugins.nix-git}/bin/nix-git" (builtins.toPath dir) "log" "-1" "--format=%ct" "--" path ];
+      '';
+      description = ''
+        Content put in extra-builtins.nix for nix-plugins.
+      '';
+      apply = lines: pkgs.writeText "extra-builtins.nix" (''
+        { exec, ... }:
+        {
+        '' + lines + ''
+        }
+        '');
+    };
+
+    nix-with-extra-builtins = mkOption {
+      type = types.str;
+      apply = pkgs.writeShellScriptBin "nix-with-extra-builtins";
+      default = ''
+        ${pkgs.nix}/bin/nix \
+         --option plugin-files ${pkgs.nix-plugins}/lib/nix/plugins/libnix-extra-builtins.so \
+         --option extra-builtins-file ${cfg.extra-builtins} \
+         "$@"
+      '';
+      description = ''
+        Wrapper around nix to load extra-builtins.nix with nix-plugins.
+      '';
+    };
+
+    nix-pass = mkOption {
+      type = types.str;
+      apply = pkgs.writeShellScriptBin "nix-pass";
+      default = ''
+        set -e
+        f=$(mktemp)
+        trap "shred -u $f" EXIT
+        ${pkgs.pass}/bin/pass show "$1" >$f
+        nix-instantiate --eval -E "builtins.readFile $f"
+      '';
+      /*
+        nix-store --add $f
+      */
+      /*
+        set -o pipefail
+        ${pkgs.pass}/bin/pass show "$1" |
+        ${pkgs.gnused}/bin/sed \
+         -e 's:\n:\\n:g;s:\r:\\r:g;s:\t:\\t:g;s:":\\":g;1s:^:":;$s:$:":;'
+      */
+      description = ''
+        Wrapper around pass to call it with exec in extra-builtins.nix.
+        Unfortunately it can only load secrets which can be represented as a Nix string,
+        hence without null-byte and such special characters.
+      '';
+    };
+
+    nix-pass-to-file = mkOption {
+      type = types.str;
+      apply = pkgs.writeShellScriptBin "nix-pass-to-file";
+      default = ''
+        set -e
+        set -o pipefail
+        ${pkgs.pass}/bin/pass show "$1" |
+        install -D -m 400 /dev/stdin "$2"
+        printf '%s\n' "$PWD/$2"
+      '';
+      description = ''
+        Wrapper around pass to call it with exec in extra-builtins.nix and put the output in a file.
+        Needed for boot.initrd.network.ssh.host*Key.
+      '';
+    };
+
+    nix-git = mkOption {
+      type = types.str;
+      apply = pkgs.writeShellScriptBin "nix-git";
+      default = ''
+        cd "$1"; shift
+        ${pkgs.git}/bin/git "$@"
+      '';
+      description = ''
+        Wrapper around git to call it with exec in extra-builtins.nix.
+      '';
+    };
+  };
+}
diff --git a/shell/modules/tools/security/gnupg.nix b/shell/modules/tools/security/gnupg.nix
new file mode 100644 (file)
index 0000000..083e704
--- /dev/null
@@ -0,0 +1,481 @@
+{ pkgs, lib, config, ... }:
+let cfg = config.gnupg;
+    inherit (lib) types;
+    unlines = builtins.concatStringsSep "\n";
+    unwords = builtins.concatStringsSep " ";
+
+    generateKeys = keys: unlines (lib.mapAttrsToList generateKey keys);
+    generateKey =
+     uid:
+     { uid ? uid
+     , algo ? "future-default"
+     , usage ? ["default"]
+     , expire ? "-"
+     , passPath
+     , subKeys ? {}
+     , ...
+     }@primary:
+      ''
+      info "  generateKey uid=\"${uid}\""
+      if ! ${cfg.gpg-with-home}/bin/gpg-with-home --list-secret-keys -- "=${uid}" >/dev/null 2>/dev/null
+       then
+        ${pkgs.pass}/bin/pass "${passPath}" |
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+          --batch --pinentry-mode loopback --passphrase-fd 0 \
+          --quick-generate-key "${uid}" "${algo}" "${unwords usage}" "${expire}"
+       fi
+      ${head1}
+      fpr=$(${cfg.gpg-fingerprint}/bin/gpg-fingerprint -- "=${uid}" | head1)
+      caps=$(${cfg.gpg-with-home}/bin/gpg-with-home \
+              --with-colons --fixed-list-mode --with-fingerprint \
+              --list-secret-keys -- "=${uid}" |
+             ${pkgs.gnugrep}/bin/grep '^ssb:' |
+             ${pkgs.coreutils}/bin/cut -d : -f 12 || true)
+      ''
+      + unlines (map (generateSubKey primary) subKeys)
+      + generateBackupKey "$fpr" primary
+      ;
+    generateSubKey =
+     primary:
+     { expire ? primary.expire
+     , algo   ? primary.algo
+     , usage
+     , ...
+     }:
+      ''
+      info "    generateSubKey usage=[${unwords usage}]"
+      if ! printf '%s\n' "$caps" | ${pkgs.gnugrep}/bin/grep -Fqx "${lettersKeyUsage usage}"
+       then
+        ${pkgs.pass}/bin/pass "${primary.passPath}" |
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+          --batch --pinentry-mode loopback --passphrase-fd 0 \
+          --quick-add-key "$fpr" "${algo}" "${unwords usage}" "${expire}"
+       fi
+      '';
+    generateBackupKey =
+     fpr:
+     { passPath
+     , backupRecipients ? []
+     , uid
+     , ...
+     }:
+      lib.optionalString (backupRecipients != [])
+      ''
+      info "    generateBackupKey backupRecipients=[${unwords (map (s: "\\\"${s}\\\"") backupRecipients)}]"
+      mkdir -p "${cfg.dir.var}/backup/${uid}/"
+      if ! test -s "${cfg.dir.var}/backup/${uid}/${fpr}.pubkey.asc"
+       then
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+          --batch \
+          --armor --yes --output "${cfg.dir.var}/backup/${uid}/${fpr}.pubkey.asc" \
+          --export-options export-backup \
+          --export "${fpr}"
+       fi
+      '' + (if backupRecipients == [""] then
+      ''
+      if ! test -s "${cfg.dir.var}/backup/${uid}/${fpr}.revoke.asc"
+       then
+        ${pkgs.pass}/bin/pass "${passPath}" |
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+          --pinentry-mode loopback --passphrase-fd 0 \
+          --armor --yes --output "${cfg.dir.var}/backup/${uid}/${fpr}.revoke.asc" \
+          --gen-revoke "${fpr}"
+       fi
+      if ! test -s "${cfg.dir.var}/backup/${uid}/${fpr}.privkey.sec"
+       then
+        ${pkgs.pass}/bin/pass "${passPath}" |
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+          --batch --pinentry-mode loopback --passphrase-fd 0 \
+          --armor --yes --output "${cfg.dir.var}/backup/${uid}/${fpr}.privkey.sec" \
+          --export-options export-backup \
+          --export-secret-key "${fpr}"
+       fi
+      if ! test -s "${cfg.dir.var}/backup/${uid}/${fpr}.subkeys.sec"
+       then
+        ${pkgs.pass}/bin/pass "${passPath}" |
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+          --batch --pinentry-mode loopback --passphrase-fd 0 \
+          --armor --yes --output "${cfg.dir.var}/backup/${uid}/${fpr}.subkeys.sec" \
+          --export-options export-backup \
+          --export-secret-subkeys "${fpr}"
+       fi
+      '' else ''
+      if ! test -s "${cfg.dir.var}/backup/${uid}/${fpr}.revoke.asc.gpg"
+       then
+        ${pkgs.pass}/bin/pass "${passPath}" |
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+          --pinentry-mode loopback --passphrase-fd 0 \
+          --armor --gen-revoke "${fpr}" |
+        gpg --encrypt ${recipients backupRecipients} \
+            --armor --yes --output "${cfg.dir.var}/backup/${uid}/${fpr}.revoke.asc.gpg"
+       fi
+      if ! test -s "${cfg.dir.var}/backup/${uid}/${fpr}.privkey.sec.gpg"
+       then
+        ${pkgs.pass}/bin/pass "${passPath}" |
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+          --batch --pinentry-mode loopback --passphrase-fd 0 \
+          --armor --export-options export-backup \
+          --export-secret-key "${fpr}" |
+        gpg --encrypt ${recipients backupRecipients} \
+            --armor --yes --output "${cfg.dir.var}/backup/${uid}/${fpr}.privkey.sec.gpg"
+       fi
+      if ! test -s "${cfg.dir.var}/backup/${uid}/${fpr}.subkeys.sec.gpg"
+       then
+        ${pkgs.pass}/bin/pass "${passPath}" |
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+          --batch --pinentry-mode loopback --passphrase-fd 0 \
+          --armor --export-options export-backup \
+          --export-secret-subkeys "${fpr}" |
+        gpg --encrypt ${recipients backupRecipients} \
+            --armor --yes --output "${cfg.dir.var}/backup/${uid}/${fpr}.subkeys.sec.gpg"
+       fi
+      '');
+    recipients = rs: unwords (map (r: ''--recipient "${refKey r}"'') rs);
+    refKey = key: if builtins.typeOf key == "string" then key else "=${key.uid}";
+    signer = s: if s == null
+                then ""
+                else ''--sign --default-key "${refKey s}"'';
+    lettersKeyUsage = usage:
+      (if builtins.elem "encrypt" usage then "e" else "") +
+      (if builtins.elem "sign"    usage then "s" else "") +
+      (if builtins.elem "cert"    usage then "c" else "") +
+      (if builtins.elem "auth"    usage then "a" else "");
+
+    passOfFingerprint = key:
+      # Return shell code
+      # which fills a map from the fingerprints of the given key
+      # to its password file.
+      ''
+      # shell.gnupg.pass.passOfFingerprint
+      for fpr in $(${cfg.gpg-fingerprint}/bin/gpg-fingerprint -- "=${key.uid}")
+       do eval "pass_$fpr=\"${key.passPath}\""
+       done
+      '';
+    forgetPass =
+      # Return shell code
+      # which installs an exit and keyboard interruption (^C) trap
+      # removing any pass from gpg-agent
+      # whose keygrip is registered in $keygrips.
+      ''
+      # forgetPass
+      keygrips=
+      forgetPass () {
+        for keygrip in $keygrips
+         do
+          echo >&2 "gpg: forget: keygrip=$keygrip"
+          GNUPGHOME=${cfg.dir.var} \
+          ${pkgs.gnupg}/bin/gpg-connect-agent </dev/null >&2 "CLEAR_PASSPHRASE $keygrip" ||
+          true
+         done
+        keygrips=
+       }
+      trap 'forgetPass' EXIT INT
+      '';
+    presetPass = keys: uid:
+      # Return shell code
+      # which preset the pass of given uid into gpg-agent,
+      # using keys to find where the pass is stored.
+      ''
+      ${unlines (map passOfFingerprint keys)}
+      # presetPass
+      GNUPGHOME=${cfg.dir.var} \
+      ${pkgs.gnupg}/bin/gpgconf --launch gpg-agent
+      ${head1}
+      fpr="$(${cfg.gpg-fingerprint}/bin/fingerprint -- "${uid}" | head1)"
+      eval pass="\''${pass_$fpr}"
+      if test -n "$pass"
+       then
+        for keygrip in $(${cfg.gpg-keygrip}/bin/gpg-keygrip -- "$fpr")
+         do
+          keygrips="$keygrips $keygrip"
+          echo >&2 "gpg: preset: keygrip=$keygrip pass=$pass"
+          ${pkgs.pass}/bin/pass "$pass" |
+          GNUPGHOME=${cfg.dir.var} \
+          ${pkgs.gnupg}/libexec/gpg-preset-passphrase --preset ''${XTRACE:+--verbose} $keygrip
+         done
+       fi
+      '';
+
+    head1 = ''
+      head1(){
+        IFS= read -r line
+        cat >/dev/null # NOTE: consuming all the input avoids useless triggering of pipefail
+        printf %s "$line"
+      }
+    '';
+    info = ''
+      info(){
+        echo >&2 "INFO: $*"
+      }
+    '';
+in
+{
+  options.gnupg = {
+    enable = lib.mkEnableOption "GnuPG admin utilities";
+    dir.var = lib.mkOption {
+      type = types.path;
+      default = "sec/gnupg";
+      description = ''
+      '';
+    };
+    gpg-with-home = lib.mkOption {
+      type = types.str;
+      apply = pkgs.writeScriptBin "gpg-with-home";
+      default = ''
+        GNUPGHOME=${cfg.dir.var} \
+        exec ${pkgs.gnupg}/bin/gpg "$@"
+        '';
+      description = ''
+        A wrapper around gpg to set GNUPGHOME.
+      '';
+    };
+    gpg-fingerprint = lib.mkOption {
+      type = types.str;
+      apply = pkgs.writeScriptBin "gpg-fingerprint";
+      default = ''
+        set -eu
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+         --with-colons --fixed-list-mode --with-fingerprint --with-subkey-fingerprint \
+         --list-public-keys "$@" |
+        while IFS=: read -r t x x x key x x x x uid x
+         do case $t in
+           (pub|sub|sec|ssb)
+            while IFS=: read -r t x x x x x x x x fpr x
+             do case $t in (fpr) printf '%s\n' "$fpr"; break;;
+             esac done
+            ;;
+         esac done
+        '';
+      description = ''
+        A wrapper around gpg to get fingerprints.
+      '';
+    };
+    gpg-keygrip = lib.mkOption {
+      type = types.str;
+      apply = pkgs.writeScriptBin "gpg-keygrip";
+      default = ''
+        set -eu
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+         --with-colons --fixed-list-mode --with-keygrip \
+         --list-public-keys "$@" |
+        while IFS=: read -r t x x x key x x x x uid x
+         do case $t in
+           (pub|sub|sec|ssb)
+            while IFS=: read -r t x x x x x x x x grp x
+             do case $t in (grp) printf '%s\n' "$grp"; break;;
+             esac done
+            ;;
+         esac done
+        '';
+      description = ''
+        A wrapper around gpg to get keygrips.
+      '';
+    };
+    gpg-uid = lib.mkOption {
+      type = types.str;
+      apply = pkgs.writeScriptBin "gpg-uid";
+      default = ''
+        set -eu
+        ${cfg.gpg-with-home}/bin/gpg-with-home \
+         --with-colons --fixed-list-mode \
+         --list-public-keys "$@" |
+        while IFS=: read -r t st x x x x x id x uid x
+         do case $t in
+           (uid)
+            case $st in
+             (u) printf '%s\n' "$uid";;
+             esac
+            ;;
+         esac done
+        '';
+      description = ''
+        A wrapper around gpg to get uids.
+      '';
+    };
+    init = lib.mkOption {
+      type = types.str;
+      apply = pkgs.writeShellScriptBin "init-gpg";
+      default = ''
+        set -eu
+        set -o pipefail
+        ${info}
+        info "Init GnuPG"
+        ${pkgs.coreutils}/bin/install -dm0700 -D ${cfg.dir.var}
+        ${pkgs.coreutils}/bin/ln -snf ${cfg.gpgConf}      ${cfg.dir.var}/gpg.conf
+        ${pkgs.coreutils}/bin/ln -snf ${cfg.gpgAgentConf} ${cfg.dir.var}/gpg-agent.conf
+        ${pkgs.coreutils}/bin/ln -snf ${cfg.dirmngrConf}  ${cfg.dir.var}/dirmngr.conf
+        '' +
+        generateKeys cfg.keys;
+      description = ''
+        Setup gpg.
+      '';
+    };
+    keys = lib.mkOption {
+      default = {};
+      example =
+        { "John Doe. <contact@example.coop>" = {
+            algo   = "rsa4096";
+            expire = "1y";
+            usage  = ["cert" "sign"];
+            passPath = "example.coop/gpg/contact";
+            subKeys = [
+              { algo = "rsa4096"; expire = "1y"; usage = ["sign"];}
+              { algo = "rsa4096"; expire = "1y"; usage = ["encrypt"];}
+              { algo = "rsa4096"; expire = "1y"; usage = ["auth"];}
+              ];
+            backupRecipients = ["@john@doe.pro"];
+          };
+        };
+      type = types.attrsOf (types.submodule ({uid, ...}: {
+        #config.uid = lib.mkDefault uid;
+        options = {
+          uid = lib.mkOption {
+            type        = types.str;
+            example     = "John Doe <john.doe@example.coop>";
+            default     = uid;
+            description = ''
+              User ID.
+            '';
+          };
+          algo = lib.mkOption {
+            type        = types.enum [ "rsa4096" ];
+            default     = "future-default";
+            example     = "rsa4096";
+            description = ''
+              Cryptographic algorithm.
+            '';
+          };
+          expire = lib.mkOption {
+            type        = types.str;
+            default     = "1y";
+            example     = "1y";
+            description = ''
+              Expiration timeout.
+            '';
+          };
+          usage = lib.mkOption {
+            type        = with types; listOf (enum [ "cert" "sign" "encrypt" "auth" "default" ]);
+            default     = ["default"];
+            example     = ["cert" "sign" "encrypt" "auth"];
+            description = ''
+              Cryptographic usage.
+            '';
+          };
+          passPath = lib.mkOption {
+            type        = types.str;
+            example     = "gnupg/coop/example/contact@";
+            description = ''
+              Password path.
+            '';
+          };
+          subKeys = lib.mkOption {
+            type = types.listOf (types.submodule {
+              options = {
+                algo = lib.mkOption {
+                  type        = types.enum [ "rsa4096" ];
+                  default     = "default";
+                  example     = "rsa4096";
+                  description = ''
+                    Cryptographic algorithm.
+                  '';
+                };
+                expire = lib.mkOption {
+                  type        = types.str;
+                  default     = "1y";
+                  example     = "1y";
+                  description = ''
+                    Expiration timeout.
+                  '';
+                };
+                usage = lib.mkOption {
+                  type        = with types; listOf (enum [ "sign" "encrypt" "auth" "default" ]);
+                  default     = ["default"];
+                  example     = ["sign" "encrypt" "auth"];
+                  description = ''
+                    Cryptographic usage.
+                  '';
+                };
+              };
+            });
+          };
+          backupRecipients = lib.mkOption {
+            type        = with types; listOf str;
+            default     = [];
+            example     = ["@john@doe.pro"];
+            description = ''
+              Backup keys used to encrypt the a backup copy of the secret keys.
+            '';
+          };
+        };
+      }));
+    };
+    dirmngrConf = lib.mkOption {
+      type = types.str;
+      apply = s: pkgs.writeText "dirmngr.conf" s;
+      default = ''
+        allow-ocsp
+        hkp-cacert ${cfg.keyserverPEM}
+        keyserver hkps://keys.mayfirst.org
+        use-tor
+        #log-file ${cfg.dir.var}/dirmngr.log
+        #standard-resolver
+      '';
+      description = ''
+        GnuPG's dirmngr.conf content.
+      '';
+    };
+    keyserverPEM = lib.mkOption {
+      type = types.str;
+      apply = s: pkgs.writeText "keyserver.pem" s;
+      default = builtins.readFile gnupg/keyserver.pem;
+      description = ''
+        dirmngr's hkp-cacert content.
+      '';
+    };
+    gpgAgentConf = lib.mkOption {
+      type = types.str;
+      apply = s: pkgs.writeText "gpg-agent.conf" s;
+      default = ''
+        allow-preset-passphrase
+        default-cache-ttl 17200
+        default-cache-ttl-ssh 17200
+        enable-ssh-support
+        max-cache-ttl 17200
+        max-cache-ttl-ssh 17200
+      '';
+      description = ''
+        GnuPG's gpg-agent.conf content.
+      '';
+    };
+    gpgConf = lib.mkOption {
+      type = types.str;
+      apply = s: pkgs.writeText "gpg.conf" s;
+      default = ''
+        auto-key-locate keyserver
+        cert-digest-algo SHA512
+        charset utf-8
+        default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 TWOFISH BZIP2 ZLIB ZIP Uncompressed
+        fixed-list-mode
+        keyid-format 0xlong
+        keyserver-options no-honor-keyserver-url
+        no-auto-key-locate
+        no-default-keyring
+        no-emit-version
+        personal-cipher-preferences AES256 AES CAST5
+        personal-digest-preferences SHA512
+        quiet
+        s2k-cipher-algo AES256
+        s2k-count 65536
+        s2k-digest-algo SHA512
+        s2k-mode 3
+        tofu-default-policy unknown
+        trust-model tofu+pgp
+        use-agent
+        utf8-strings
+      '';
+      description = ''
+        GnuPG's gpg.conf content.
+      '';
+    };
+  };
+}
diff --git a/shell/modules/tools/security/gnupg/keyserver.pem b/shell/modules/tools/security/gnupg/keyserver.pem
new file mode 100644 (file)
index 0000000..d71be86
--- /dev/null
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIIFHjCCBAagAwIBAgISA8apfWx1LXVrNYiw3eMAAAH/MA0GCSqGSIb3DQEBCwUA
+MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
+ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODAyMTAxNjE2MjBaFw0x
+ODA1MTExNjE2MjBaMBwxGjAYBgNVBAMTEWtleXMubWF5Zmlyc3Qub3JnMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwnSrjRgOlR5a6Z4TY8RfpY+FFbNN
+9n2nudtB5o2LfTeb7XrMrmpzqYJ31pQjstiLrIOWZCWluzR588cLf8R32f/Qpjf5
+TMvOFROYhDagSqw3AfL3sEIXOybv1e4UqpJFBNiSatzZqEhneCWPj49BGI3qVhc/
+nL9MJvB1o8cnhJ9VEiWiNUbbNcDpLHAYofbO9UuEHTr3ajOdifkeVvl49qHe3XA7
+CH3ep5q8UKELdX/c19JQHYKJG6jRArGhpdZ77flQikwTSyWoZXn2UxTbKkfLv/zE
+Q6CG8ug5IHqQtm4oJ5UyINSgwCovWR0VdNZx84K9nmtLiba4OwiXtwgrCQIDAQAB
+o4ICKjCCAiYwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
+BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBT1XkWOTiiiYSB5fGll18yw
+CTn9qTAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcB
+AQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlw
+dC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlw
+dC5vcmcvMDUGA1UdEQQuMCyCEWtleXMubWF5Zmlyc3Qub3Jnghd6aW1tZXJtYW5u
+Lm1heWZpcnN0Lm9yZzCB/gYDVR0gBIH2MIHzMAgGBmeBDAECATCB5gYLKwYBBAGC
+3xMBAQEwgdYwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5cHQub3Jn
+MIGrBggrBgEFBQcCAjCBngyBm1RoaXMgQ2VydGlmaWNhdGUgbWF5IG9ubHkgYmUg
+cmVsaWVkIHVwb24gYnkgUmVseWluZyBQYXJ0aWVzIGFuZCBvbmx5IGluIGFjY29y
+ZGFuY2Ugd2l0aCB0aGUgQ2VydGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBz
+Oi8vbGV0c2VuY3J5cHQub3JnL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IB
+AQBL4mihf2XgbQIb/3GHyY69WPGKTCIKRogqbvWQTVmgSda0y+H22Y4g10PSBl5n
+a9Z5deYCuFdYg6xXmtb7mMXmh5fNVyA032BFZGh3QqV5EQGGr2aiSg98lEGZHTeg
+uU14TTsZek3BmiIY9uSDDLmGombWfP6AryDZlSUCxzlB9j0nSFIwXSNoC9TXkeEA
+sbX1rC/Cf3SC6ErrJ+348LGf/9+7x0gArr5hofolXdKwX3ezcTgkLiWC1JxFW8uk
+giN9PM09UfbX6ro1TIBWKr9nM8HC5HFMgd9aMSxDqwxR1J2GfX/Q+fhCiK9/XXTn
+RvFK7S8tJgyLACLU1uC7ue43
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
+SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
+GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
+q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
+SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
+Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
+a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
+/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
+AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
+CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
+bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
+c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
+VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
+ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
+MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
+Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
+AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
+uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
+wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
+X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
+PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
+KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+-----END CERTIFICATE-----